diff --git a/.github/workflows/udd.yml b/.github/workflows/udd.yml index 353f088..7bc1850 100644 --- a/.github/workflows/udd.yml +++ b/.github/workflows/udd.yml @@ -16,8 +16,8 @@ jobs: - name: Update dependencies run: > deno run --allow-net --allow-read --allow-write=deps/ - --allow-run=deno https://deno.land/x/udd@0.7.2/main.ts deps/*.ts - --test="deno test --allow-read --allow-write" + --allow-run=deno https://deno.land/x/udd@0.8.2/main.ts deps/*.ts + --test="deno test --allow-read" - name: Create Pull Request uses: peter-evans/create-pull-request@v3 with: diff --git a/deps/scrapbox-rest.ts b/deps/scrapbox-rest.ts index 63b2633..f6cfa5b 100644 --- a/deps/scrapbox-rest.ts +++ b/deps/scrapbox-rest.ts @@ -16,7 +16,8 @@ export type { NotPrivilegeError, Page, PageList, - PageSnapshot, + PageSnapshotList, + PageSnapshotResult, ProjectId, ProjectResponse, ProjectSearchResult, @@ -25,4 +26,4 @@ export type { SessionError, Snapshot, TweetInfo, -} from "https://raw.githubusercontent.com/scrapbox-jp/types/0.7.1/rest.ts"; +} from "https://raw.githubusercontent.com/scrapbox-jp/types/0.9.0/rest.ts"; diff --git a/deps/scrapbox.ts b/deps/scrapbox.ts index bac461b..98efe9a 100644 --- a/deps/scrapbox.ts +++ b/deps/scrapbox.ts @@ -2,8 +2,8 @@ export type { BaseLine, Line, Scrapbox, -} from "https://raw.githubusercontent.com/scrapbox-jp/types/0.7.1/userscript.ts"; +} from "https://raw.githubusercontent.com/scrapbox-jp/types/0.9.0/userscript.ts"; export type { BaseStore, -} from "https://raw.githubusercontent.com/scrapbox-jp/types/0.7.1/baseStore.ts"; +} from "https://raw.githubusercontent.com/scrapbox-jp/types/0.9.0/baseStore.ts"; export * from "https://esm.sh/@progfay/scrapbox-parser@9.0.0"; diff --git a/rest/getSnapshots.ts b/rest/getSnapshots.ts deleted file mode 100644 index e369207..0000000 --- a/rest/getSnapshots.ts +++ /dev/null @@ -1,138 +0,0 @@ -import type { - ErrorLike, - NotFoundError, - NotLoggedInError, - NotMemberError, - PageSnapshot, - Snapshot, -} from "../deps/scrapbox-rest.ts"; -import { cookie } from "./auth.ts"; -import { BaseOptions, Result, setDefaults } from "./util.ts"; -import { makeError } from "./error.ts"; - -/** 不正なfollowingIdを渡されたときに発生するエラー */ -export interface InvalidPageSnapshotIdError extends ErrorLike { - name: "InvalidPageSnapshotIdError"; -} - -export interface GetSnapshotsOptions extends BaseOptions { - /** 次のsnapshots listを示すID */ - followingId?: string; -} - -/** get page snapshots - * - * @param options connect.sid etc. - */ -export const getSnapshots = async ( - project: string, - pageId: string, - options?: GetSnapshotsOptions, -): Promise< - Result< - (PageSnapshot & { followingId: string }), - | NotFoundError - | NotLoggedInError - | NotMemberError - | InvalidPageSnapshotIdError - > -> => { - const { sid, hostName, fetch, followingId } = setDefaults(options ?? {}); - - const req = new Request( - `https://${hostName}/api/page-snapshots/${project}/${pageId}/${ - followingId ? `?followingId=${followingId}` : "" - }`, - sid ? { headers: { Cookie: cookie(sid) } } : undefined, - ); - - const res = await fetch(req); - - if (!res.ok) { - if (res.status === 422) { - return { - ok: false, - value: { - name: "InvalidPageSnapshotIdError", - message: await res.text(), - }, - }; - } - return makeError(res); - } - - const data = (await res.json()) as PageSnapshot; - return { - ok: true, - value: { ...data, followingId: res.headers.get("X-following-id") ?? "" }, - }; -}; - -/** 指定したページのsnapshotsを、responseに入っている塊ごとに全て返す - * - * @param project ページのproject name - * @param pageId page id - * @return 認証が通らなかったらエラーを、通ったらasync generatorを返す - */ -export const readSnapshotsBulk = async ( - project: string, - pageId: string, - options?: BaseOptions, -): Promise< - | NotFoundError - | NotLoggedInError - | NotMemberError - | InvalidPageSnapshotIdError - | AsyncGenerator -> => { - const first = await getSnapshots(project, pageId, options); - if (!first.ok) return first.value; - - return async function* () { - yield first.value.snapshots; - let followingId = first.value.followingId; - - while (followingId) { - const result = await getSnapshots(project, pageId, { - followingId, - ...options, - }); - - // すでに認証は通っているので、ここでエラーになるはずがない - if (!result.ok) { - throw new Error("The authorization cannot be unavailable"); - } - yield result.value.snapshots; - followingId = result.value.followingId; - } - }(); -}; - -/** 指定したページの全てのsnapshotsを取得し、一つづつ返す - * - * @param project ページのproject name - * @param pageId page id - * @return 認証が通らなかったらエラーを、通ったらasync generatorを返す - */ -export const readSnapshots = async ( - project: string, - pageId: string, - options?: BaseOptions, -): Promise< - | NotFoundError - | NotLoggedInError - | NotMemberError - | InvalidPageSnapshotIdError - | AsyncGenerator -> => { - const reader = await readSnapshotsBulk(project, pageId, options); - if ("name" in reader) return reader; - - return async function* () { - for await (const titles of reader) { - for (const title of titles) { - yield title; - } - } - }(); -}; diff --git a/rest/mod.ts b/rest/mod.ts index 916fa9a..849fefe 100644 --- a/rest/mod.ts +++ b/rest/mod.ts @@ -4,7 +4,7 @@ export * from "./project.ts"; export * from "./profile.ts"; export * from "./replaceLinks.ts"; export * from "./page-data.ts"; -export * from "./getSnapshots.ts"; +export * from "./snapshot.ts"; export * from "./link.ts"; export * from "./search.ts"; export * from "./getWebPageTitle.ts"; diff --git a/rest/snapshot.ts b/rest/snapshot.ts new file mode 100644 index 0000000..85d9973 --- /dev/null +++ b/rest/snapshot.ts @@ -0,0 +1,93 @@ +import type { + ErrorLike, + NotFoundError, + NotLoggedInError, + NotMemberError, + PageSnapshotList, + PageSnapshotResult, +} from "../deps/scrapbox-rest.ts"; +import { cookie } from "./auth.ts"; +import { BaseOptions, Result, setDefaults } from "./util.ts"; +import { makeError } from "./error.ts"; + +/** 不正な`timestampId`を渡されたときに発生するエラー */ +export interface InvalidPageSnapshotIdError extends ErrorLike { + name: "InvalidPageSnapshotIdError"; +} + +/** get a page snapshot + * + * @param options connect.sid etc. + */ +export const getSnapshot = async ( + project: string, + pageId: string, + timestampId: string, + options?: BaseOptions, +): Promise< + Result< + PageSnapshotResult, + | NotFoundError + | NotLoggedInError + | NotMemberError + | InvalidPageSnapshotIdError + > +> => { + const { sid, hostName, fetch } = setDefaults(options ?? {}); + + const req = new Request( + `https://${hostName}/api/page-snapshots/${project}/${pageId}/${timestampId}`, + sid ? { headers: { Cookie: cookie(sid) } } : undefined, + ); + + const res = await fetch(req); + + if (!res.ok) { + if (res.status === 422) { + return { + ok: false, + value: { + name: "InvalidPageSnapshotIdError", + message: await res.text(), + }, + }; + } + return makeError(res); + } + + const value = (await res.json()) as PageSnapshotResult; + return { ok: true, value }; +}; + +/** + * Retrieves the timestamp IDs for a specific page in a project. + * + * @param project - The name of the project. + * @param pageId - The ID of the page. + * @param options - Optional configuration options. + * @returns A promise that resolves to a {@link Result} object containing the page snapshot list if successful, + * or an error if the request fails. + */ +export const getTimestampIds = async ( + project: string, + pageId: string, + options?: BaseOptions, +): Promise< + Result +> => { + const { sid, hostName, fetch } = setDefaults(options ?? {}); + + const req = new Request( + `https://${hostName}/api/page-snapshots/${project}/${pageId}`, + sid ? { headers: { Cookie: cookie(sid) } } : undefined, + ); + + const res = await fetch(req); + + if (!res.ok) { + return makeError(res); + } + + const value = (await res.json()) as PageSnapshotList; + return { ok: true, value }; +};