diff --git a/deno.jsonc b/deno.jsonc index a3a183e..26a1717 100644 --- a/deno.jsonc +++ b/deno.jsonc @@ -27,7 +27,7 @@ "@cosense/std/browser/websocket": "./websocket/mod.ts", "@cosense/std/rest": "./rest/mod.ts", "@cosense/std/websocket": "./websocket/mod.ts", - "@cosense/types": "jsr:@cosense/types@^0.10.4", + "@cosense/types": "jsr:@cosense/types@^0.10.7", "@cosense/types/rest": "jsr:@cosense/types@0.10/rest", "@cosense/types/userscript": "jsr:@cosense/types@0.10/userscript", "@progfay/scrapbox-parser": "jsr:@progfay/scrapbox-parser@9", diff --git a/deno.lock b/deno.lock index d6da85b..c85995c 100644 --- a/deno.lock +++ b/deno.lock @@ -2,18 +2,20 @@ "version": "4", "specifiers": { "jsr:@core/unknownutil@4": "4.3.0", - "jsr:@cosense/types@0.10": "0.10.4", + "jsr:@cosense/types@0.10": "0.10.7", + "jsr:@cosense/types@~0.10.7": "0.10.7", "jsr:@progfay/scrapbox-parser@9": "9.2.0", - "jsr:@std/assert@1": "1.0.10", - "jsr:@std/assert@^1.0.10": "1.0.10", - "jsr:@std/async@1": "1.0.9", - "jsr:@std/encoding@1": "1.0.6", - "jsr:@std/fs@^1.0.8": "1.0.8", + "jsr:@std/assert@1": "1.0.11", + "jsr:@std/assert@^1.0.10": "1.0.11", + "jsr:@std/async@1": "1.0.10", + "jsr:@std/data-structures@^1.0.6": "1.0.6", + "jsr:@std/encoding@1": "1.0.7", + "jsr:@std/fs@^1.0.9": "1.0.9", "jsr:@std/internal@^1.0.5": "1.0.5", "jsr:@std/json@1": "1.0.1", "jsr:@std/path@^1.0.8": "1.0.8", "jsr:@std/streams@^1.0.7": "1.0.8", - "jsr:@std/testing@1": "1.0.8", + "jsr:@std/testing@1": "1.0.9", "jsr:@takker/md5@0.1": "0.1.0", "npm:option-t@51": "51.0.1", "npm:socket.io-client@^4.7.5": "4.8.1" @@ -22,26 +24,29 @@ "@core/unknownutil@4.3.0": { "integrity": "538a3687ffa81028e91d148818047df219663d0da671d906cecd165581ae55cc" }, - "@cosense/types@0.10.4": { - "integrity": "04423c152a525df848c067f9c6aa05409baadf9da15d8e4569e1bcedfa3c7624" + "@cosense/types@0.10.7": { + "integrity": "ce62b4cc7dc599f0f55abc5f4b88d6fe3f5aa7fbacdc46cc1ff32a62fea60176" }, "@progfay/scrapbox-parser@9.2.0": { "integrity": "82ebb95e72dd0ea44547fd48e2bcb479fd2275fc26c4515598f742e5aaf6e0e5" }, - "@std/assert@1.0.10": { - "integrity": "59b5cbac5bd55459a19045d95cc7c2ff787b4f8527c0dd195078ff6f9481fbb3", + "@std/assert@1.0.11": { + "integrity": "2461ef3c368fe88bc60e186e7744a93112f16fd110022e113a0849e94d1c83c1", "dependencies": [ "jsr:@std/internal" ] }, - "@std/async@1.0.9": { - "integrity": "c6472fd0623b3f3daae023cdf7ca5535e1b721dfbf376562c0c12b3fb4867f91" + "@std/async@1.0.10": { + "integrity": "2ff1b1c7d33d1416159989b0f69e59ec7ee8cb58510df01e454def2108b3dbec" }, - "@std/encoding@1.0.6": { - "integrity": "ca87122c196e8831737d9547acf001766618e78cd8c33920776c7f5885546069" + "@std/data-structures@1.0.6": { + "integrity": "76a7fd8080c66604c0496220a791860492ab21a04a63a969c0b9a0609bbbb760" }, - "@std/fs@1.0.8": { - "integrity": "161c721b6f9400b8100a851b6f4061431c538b204bb76c501d02c508995cffe0", + "@std/encoding@1.0.7": { + "integrity": "f631247c1698fef289f2de9e2a33d571e46133b38d042905e3eac3715030a82d" + }, + "@std/fs@1.0.9": { + "integrity": "3eef7e3ed3d317b29432c7dcb3b20122820dbc574263f721cb0248ad91bad890", "dependencies": [ "jsr:@std/path" ] @@ -61,10 +66,11 @@ "@std/streams@1.0.8": { "integrity": "b41332d93d2cf6a82fe4ac2153b930adf1a859392931e2a19d9fabfb6f154fb3" }, - "@std/testing@1.0.8": { - "integrity": "ceef535808fb7568e91b0f8263599bd29b1c5603ffb0377227f00a8ca9fe42a2", + "@std/testing@1.0.9": { + "integrity": "9bdd4ac07cb13e7594ac30e90f6ceef7254ac83a9aeaa089be0008f33aab5cd4", "dependencies": [ "jsr:@std/assert@^1.0.10", + "jsr:@std/data-structures", "jsr:@std/fs", "jsr:@std/internal", "jsr:@std/path" @@ -84,8 +90,8 @@ "ms" ] }, - "engine.io-client@6.6.2": { - "integrity": "sha512-TAr+NKeoVTjEVW8P3iHguO1LO6RlUz9O5Y8o7EY0fU+gY1NYqas7NN3slpFtbXEsLMHk0h90fJMfKjRkQ0qUIw==", + "engine.io-client@6.6.3": { + "integrity": "sha512-T0iLjnyNWahNyv/lcjS2y4oE358tVS/SYQNxYXGAJ9/GLgH4VCvOQ/mhTjqU88mLZCQgiG8RIegFHYCdVC+j5w==", "dependencies": [ "@socket.io/component-emitter", "debug", @@ -130,7 +136,7 @@ "dependencies": [ "jsr:@core/unknownutil@4", "jsr:@cosense/types@0.10", - "jsr:@cosense/types@~0.10.4", + "jsr:@cosense/types@~0.10.7", "jsr:@progfay/scrapbox-parser@9", "jsr:@std/assert@1", "jsr:@std/async@1", diff --git a/websocket/applyCommit.ts b/websocket/applyCommit.ts index 947eec3..600f077 100644 --- a/websocket/applyCommit.ts +++ b/websocket/applyCommit.ts @@ -1,4 +1,4 @@ -import type { CommitNotification } from "./listen-events.ts"; +import type { CommitNotification } from "@cosense/types/websocket"; import type { BaseLine } from "@cosense/types/rest"; import { getUnixTimeFromId } from "./id.ts"; diff --git a/websocket/change.ts b/websocket/change.ts deleted file mode 100644 index a66dbc2..0000000 --- a/websocket/change.ts +++ /dev/null @@ -1,90 +0,0 @@ -export type Change = - | InsertChange - | UpdateChange - | DeleteChange - | LinksChange - | ProjectLinksChange - | IconsChange - | DescriptionsChange - | ImageChange - | FilesChange - | HelpFeelsChange - | infoboxDefinitionChange - | TitleChange - | LinesCountChange - | charsCountChange - | PinChange; -export interface InsertChange { - _insert: string; - lines: { - id: string; - text: string; - }; -} -export interface UpdateChange { - _update: string; - lines: { - text: string; - }; - noTimestampUpdate?: unknown; -} -export interface DeleteChange { - _delete: string; - lines: -1; -} -export interface LinksChange { - links: string[]; -} -export interface ProjectLinksChange { - projectLinks: string[]; -} -export interface IconsChange { - icons: string[]; -} -export interface DescriptionsChange { - descriptions: string[]; -} -export interface ImageChange { - image: string | null; -} -export interface TitleChange { - title: string; -} -export interface FilesChange { - /** Array of file IDs - * - * These IDs reference files that have been uploaded to the page. - * Files can include images, documents, or other attachments. - */ - files: string[]; -} -export interface HelpFeelsChange { - /** Array of Helpfeel entries without the leading "? " prefix - * - * Helpfeel is a Scrapbox notation for creating help/documentation entries. - * Example: "? How to use" becomes "How to use" in this array. - * These entries are used to build the page's help documentation. - */ - helpfeels: string[]; -} -export interface infoboxDefinitionChange { - /** Array of trimmed lines from infobox tables - * - * Contains lines from tables marked with either `table:infobox` or `table:cosense` - */ - infoboxDefinition: string[]; -} -export interface LinesCountChange { - linesCount: number; -} -export interface charsCountChange { - charsCount: number; -} - -export interface PinChange { - pin: number; -} -export interface DeletePageChange { - deleted: true; - merged?: true; -} diff --git a/websocket/diffToChanges.ts b/websocket/diffToChanges.ts index 1a585d5..efd6f1d 100644 --- a/websocket/diffToChanges.ts +++ b/websocket/diffToChanges.ts @@ -1,6 +1,7 @@ import { diff, toExtendedChanges } from "../deps/onp.ts"; import type { Line } from "@cosense/types/userscript"; -import type { DeleteChange, InsertChange, UpdateChange } from "./change.ts"; +import type { UpdateChange } from "@cosense/types/websocket"; +import type { DeleteChange, InsertChange } from "@cosense/types/rest"; import { createNewLineId } from "./id.ts"; type Options = { diff --git a/websocket/emit-events.ts b/websocket/emit-events.ts deleted file mode 100644 index a54da90..0000000 --- a/websocket/emit-events.ts +++ /dev/null @@ -1,75 +0,0 @@ -import type { Change, DeletePageChange, PinChange } from "./change.ts"; - -export interface EmitEvents { - "socket.io-request": ( - req: { method: "commit"; data: PageCommit } | { - method: "room:join"; - data: JoinRoomRequest; - }, - callback: ( - res: - | { data: PageCommitResponse | JoinRoomResponse } - | { error: { name: string; message?: string } }, - ) => void, - ) => void; - cursor: (req: Omit) => void; -} - -export interface PageCommit { - kind: "page"; - parentId: string; - projectId: string; - pageId: string; - userId: string; - changes: Change[] | [PinChange] | [DeletePageChange]; - cursor?: null; - freeze: true; -} - -export interface PageCommitResponse { - commitId: string; -} - -export type JoinRoomRequest = - | JoinPageRoomRequest - | JoinProjectRoomRequest - | JoinStreamRoomRequest; - -export interface JoinProjectRoomRequest { - pageId: null; - projectId: string; - projectUpdatesStream: false; -} - -export interface JoinPageRoomRequest { - pageId: string; - projectId: string; - projectUpdatesStream: false; -} - -export interface JoinStreamRoomRequest { - pageId: null; - projectId: string; - projectUpdatesStream: true; -} - -export interface JoinRoomResponse { - success: true; - pageId: string | null; - projectId: string; -} - -export interface MoveCursorData { - user: { - id: string; - name: string; - displayName: string; - }; - pageId: string; - position: { - line: number; - char: number; - }; - visible: boolean; - socketId: string; -} diff --git a/websocket/emit.ts b/websocket/emit.ts index 8049176..dfe7bf5 100644 --- a/websocket/emit.ts +++ b/websocket/emit.ts @@ -2,10 +2,11 @@ import { createErr, createOk, type Result } from "option-t/plain_result"; import type { Socket } from "socket.io-client"; import type { JoinRoomRequest, + JoinRoomResponse, MoveCursorData, PageCommit, PageCommitResponse, -} from "./emit-events.ts"; +} from "@cosense/types/websocket"; import { isPageCommitError, type PageCommitError, @@ -13,7 +14,6 @@ import { type TimeoutError, type UnexpectedRequestError, } from "./error.ts"; -import type { JoinRoomResponse } from "./emit-events.ts"; import type { ScrapboxSocket } from "./socket.ts"; export interface WrapperdEmitEvents { diff --git a/websocket/listen-events.ts b/websocket/listen-events.ts deleted file mode 100644 index c2d60f2..0000000 --- a/websocket/listen-events.ts +++ /dev/null @@ -1,106 +0,0 @@ -import type { MoveCursorData, PageCommit } from "./emit-events.ts"; -import type { - DeleteChange, - DeletePageChange, - DescriptionsChange, - IconsChange, - ImageChange, - InsertChange, - LinksChange, - TitleChange, - UpdateChange, -} from "./change.ts"; - -export interface ListenEvents { - "projectUpdatesStream:commit": (event: ProjectUpdatesStreamCommit) => void; - "projectUpdatesStream:event": (event: ProjectUpdatesStreamEvent) => void; - commit: (event: CommitNotification) => void; - cursor: (event: MoveCursorData) => void; - "quick-search:commit": (event: QuickSearchCommit) => void; - "quick-search:replace-link": QuickSearchReplaceLink; - "infobox:updating": boolean; - "infobox:reload": void; - "literal-database:reload": void; -} - -export interface ProjectUpdatesStreamCommit { - kind: "page"; - id: string; - parentId: string; - projectId: string; - pageId: string; - userId: string; - changes: - | ( - | InsertChange - | UpdateChange - | DeleteChange - | TitleChange - | LinksChange - | IconsChange - )[] - | [DeletePageChange]; - cursor: null; - freeze: true; -} - -export type ProjectUpdatesStreamEvent = - | PageDeleteEvent - | MemberJoinEvent - | MemberAddEvent - | AdminAddEvent - | AdminDeleteEvent - | OwnerSetEvent - | InvitationResetEvent; - -export interface ProjectEvent { - id: string; - pageId: string; - userId: string; - projectId: string; - created: number; - updated: number; -} - -export interface PageDeleteEvent extends ProjectEvent { - type: "page.delete"; - data: { - titleLc: string; - }; -} -export interface MemberJoinEvent extends ProjectEvent { - type: "member.join"; -} -export interface MemberAddEvent extends ProjectEvent { - type: "member.add"; -} -export interface InvitationResetEvent extends ProjectEvent { - type: "invitation.reset"; -} -export interface AdminAddEvent extends ProjectEvent { - type: "admin.add"; - targetUserId: string; -} -export interface AdminDeleteEvent extends ProjectEvent { - type: "admin.delete"; - targetUserId: string; -} -export interface OwnerSetEvent extends ProjectEvent { - type: "owner.set"; - targetUserId: string; -} - -export interface CommitNotification extends PageCommit { - id: string; -} - -export interface QuickSearchCommit extends Omit { - changes: - | (TitleChange | LinksChange | DescriptionsChange | ImageChange)[] - | [DeletePageChange]; -} - -export interface QuickSearchReplaceLink { - from: string; - to: string; -} diff --git a/websocket/listen.ts b/websocket/listen.ts index 5e3f37d..8314265 100644 --- a/websocket/listen.ts +++ b/websocket/listen.ts @@ -6,12 +6,7 @@ import type { import type { HTTPError } from "../rest/responseIntoResult.ts"; import type { AbortError, NetworkError } from "../rest/robustFetch.ts"; import type { ScrapboxSocket } from "./socket.ts"; -import type { ListenEvents } from "./listen-events.ts"; - -export type { - ProjectUpdatesStreamCommit, - ProjectUpdatesStreamEvent, -} from "./listen-events.ts"; +import type { ListenEventMap } from "@cosense/types/websocket"; export interface ListenStreamOptions { signal?: AbortSignal; @@ -34,7 +29,7 @@ export type ListenStreamError = * - Supports automatic cleanup with AbortSignal * * @param socket - ScrapboxSocket instance for WebSocket communication - * @param event - Event name to listen for (from {@linkcode ListenEvents} type) + * @param event - Event name to listen for (from {@linkcode ListenEventMap} type) * @param listener - Callback function to handle the event * @param options - Optional configuration * @@ -52,10 +47,10 @@ export type ListenStreamError = * }); * ``` */ -export const listen = ( +export const listen = ( socket: ScrapboxSocket, event: EventName, - listener: ListenEvents[EventName], + listener: ListenEventMap[EventName], options?: ListenStreamOptions, ): void => { if (options?.signal?.aborted) return; diff --git a/websocket/makeChanges.ts b/websocket/makeChanges.ts index 6627ec5..de42787 100644 --- a/websocket/makeChanges.ts +++ b/websocket/makeChanges.ts @@ -1,6 +1,6 @@ import { diffToChanges } from "./diffToChanges.ts"; import type { Page } from "@cosense/types/rest"; -import type { Change } from "./change.ts"; +import type { ChangeToPush } from "@cosense/types/websocket"; import { getHelpfeels, getPageMetadataFromLines, @@ -12,7 +12,7 @@ export function* makeChanges( before: Page, after: (string | { text: string })[], userId: string, -): Generator { +): Generator { // Prevent newline characters from being included in the text // This ensures consistent line handling across different platforms const after_ = after.flatMap((text) => diff --git a/websocket/mod.ts b/websocket/mod.ts index 79196b2..aaa3130 100644 --- a/websocket/mod.ts +++ b/websocket/mod.ts @@ -6,6 +6,4 @@ export * from "./pin.ts"; export * from "./listen.ts"; export * from "./updateCodeBlock.ts"; export * from "./updateCodeFile.ts"; -export * from "./listen-events.ts"; -export * from "./emit-events.ts"; -export * from "./change.ts"; +export * from "@cosense/types/websocket"; diff --git a/websocket/patch.ts b/websocket/patch.ts index f36cb39..0a51c50 100644 --- a/websocket/patch.ts +++ b/websocket/patch.ts @@ -1,4 +1,4 @@ -import type { Change, DeletePageChange } from "./change.ts"; +import type { ChangeToPush, DeletePageChange } from "@cosense/types/websocket"; import { makeChanges } from "./makeChanges.ts"; import type { BaseLine, Page } from "@cosense/types/rest"; import { push, type PushError, type PushOptions } from "./push.ts"; @@ -86,7 +86,7 @@ export const patch = ( return prev.map((change) => { if ("title" in change) change.title = fallbackTitle; return change; - }) as Change[] | [DeletePageChange]; + }) as ChangeToPush[] | [DeletePageChange]; } const pending = update(page.lines, { ...page, attempts }); const newContent = pending instanceof Promise ? await pending : pending; diff --git a/websocket/pin.ts b/websocket/pin.ts index 06d412a..698f4d0 100644 --- a/websocket/pin.ts +++ b/websocket/pin.ts @@ -1,5 +1,5 @@ import type { Result } from "option-t/plain_result"; -import type { Change } from "./change.ts"; +import type { ChangeToPush } from "@cosense/types/websocket"; import { push, type PushError, type PushOptions } from "./push.ts"; export interface PinOptions extends PushOptions { @@ -48,7 +48,7 @@ export const pin = ( page.pin > 0 || (!page.persistent && !(options?.create ?? false)) ) return []; // Create page and pin it in a single operation - const changes: Change[] = [{ pin: pinNumber() }]; + const changes: ChangeToPush[] = [{ pin: pinNumber() }]; if (!page.persistent) changes.unshift({ title }); return changes; }, diff --git a/websocket/push.ts b/websocket/push.ts index a9176bd..3ffef56 100644 --- a/websocket/push.ts +++ b/websocket/push.ts @@ -1,5 +1,8 @@ -import type { Change, DeletePageChange } from "./change.ts"; -import type { PageCommit } from "./emit-events.ts"; +import type { + ChangeToPush, + DeletePageChange, + PageCommit, +} from "@cosense/types/websocket"; import { connect, disconnect } from "./socket.ts"; import type { Socket } from "socket.io-client"; import { emit } from "./emit.ts"; @@ -125,11 +128,11 @@ export type PushError = export type CommitMakeHandler = ( page: PushMetadata, attempts: number, - prev: Change[] | [DeletePageChange], + prev: ChangeToPush[] | [DeletePageChange], reason?: "NotFastForwardError" | "DuplicateTitleError", ) => - | Promise - | Change[] + | Promise + | ChangeToPush[] | [DeletePageChange]; /** Push changes to a specific page using WebSocket @@ -173,7 +176,7 @@ export const push = async ( try { let attempts = 0; - let changes: Change[] | [DeletePageChange] = []; + let changes: ChangeToPush[] | [DeletePageChange] = []; let reason: "NotFastForwardError" | "DuplicateTitleError" | undefined; // Outer loop: handles diff creation and conflict resolution diff --git a/websocket/socket.ts b/websocket/socket.ts index aaa46d9..f04785a 100644 --- a/websocket/socket.ts +++ b/websocket/socket.ts @@ -1,11 +1,10 @@ import { io, type Socket } from "socket.io-client"; import { createErr, createOk, type Result } from "option-t/plain_result"; -import type { ListenEvents } from "./listen-events.ts"; -import type { EmitEvents } from "./emit-events.ts"; +import type { EmitEventMap, ListenEventMap } from "@cosense/types/websocket"; import { cookie } from "../rest/auth.ts"; /** A pre-configured {@linkcode Socket} type for Scrapbox */ -export type ScrapboxSocket = Socket; +export type ScrapboxSocket = Socket; /** connect to websocket * diff --git a/websocket/updateCodeBlock.ts b/websocket/updateCodeBlock.ts index 22db25b..f6626d9 100644 --- a/websocket/updateCodeBlock.ts +++ b/websocket/updateCodeBlock.ts @@ -1,5 +1,6 @@ import type { BaseLine } from "@cosense/types/rest"; -import type { DeleteChange, InsertChange, UpdateChange } from "./change.ts"; +import type { UpdateChange } from "@cosense/types/websocket"; +import type { DeleteChange, InsertChange } from "@cosense/types/rest"; import type { TinyCodeBlock } from "../rest/getCodeBlocks.ts"; import { diffToChanges } from "./diffToChanges.ts"; import { isSimpleCodeFile } from "./isSimpleCodeFile.ts"; diff --git a/websocket/updateCodeFile.ts b/websocket/updateCodeFile.ts index 851f89b..14f92d4 100644 --- a/websocket/updateCodeFile.ts +++ b/websocket/updateCodeFile.ts @@ -1,5 +1,6 @@ import type { BaseLine } from "@cosense/types/rest"; -import type { DeleteChange, InsertChange, UpdateChange } from "./change.ts"; +import type { UpdateChange } from "@cosense/types/websocket"; +import type { DeleteChange, InsertChange } from "@cosense/types/rest"; import { getCodeBlocks, type TinyCodeBlock } from "../rest/getCodeBlocks.ts"; import { createNewLineId } from "./id.ts"; import { diff, toExtendedChanges } from "../deps/onp.ts";