@book.dev/sdk 1.66.0 → 1.67.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/authors.d.ts +31 -0
- package/dist/authors.js +49 -19
- package/dist/authors.js.map +1 -1
- package/dist/backup.d.ts +5 -3
- package/dist/backup.js +11 -3
- package/dist/backup.js.map +1 -1
- package/dist/client.d.ts +149 -0
- package/dist/client.js +351 -21
- package/dist/client.js.map +1 -1
- package/dist/forwarding/tunnelClient.js +9 -0
- package/dist/forwarding/tunnelClient.js.map +1 -1
- package/dist/identity.d.ts +27 -0
- package/dist/identity.js +36 -0
- package/dist/identity.js.map +1 -1
- package/dist/import.d.ts +265 -0
- package/dist/import.js +313 -0
- package/dist/import.js.map +1 -0
- package/dist/importAssets.d.ts +167 -0
- package/dist/importAssets.js +332 -0
- package/dist/importAssets.js.map +1 -0
- package/dist/index.d.ts +6 -2
- package/dist/index.js +6 -2
- package/dist/index.js.map +1 -1
- package/dist/markdownImport.d.ts +79 -0
- package/dist/markdownImport.js +348 -0
- package/dist/markdownImport.js.map +1 -0
- package/dist/notionImport.d.ts +58 -0
- package/dist/notionImport.js +539 -0
- package/dist/notionImport.js.map +1 -0
- package/dist/routes.d.ts +47 -0
- package/dist/routes.js +48 -0
- package/dist/routes.js.map +1 -1
- package/package.json +11 -5
package/dist/authors.d.ts
CHANGED
|
@@ -1,4 +1,23 @@
|
|
|
1
1
|
import type { PageSnapshot } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Compute the `[blockId, subject]` authorship for `next`. Unchanged blocks keep
|
|
4
|
+
* their prior author; changed/new blocks get `authorSubject` when it is a
|
|
5
|
+
* verified identity (a non-empty subject), and are otherwise left unattributed
|
|
6
|
+
* (an anonymous/guest edit honestly clears a block's verified author rather than
|
|
7
|
+
* falsely keeping the previous one). Returns a sparse map — only blocks with a
|
|
8
|
+
* known author — or `null` when none are attributed (so the field stays absent
|
|
9
|
+
* on single-user / unverified documents).
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Resolve the *verified* author subject for a **changed/new** block. Returns a
|
|
13
|
+
* non-empty subject to attribute the block, or `''`/`undefined` to leave it
|
|
14
|
+
* unattributed (an anonymous/guest edit honestly clears a block's verified
|
|
15
|
+
* author). Only consulted for changed blocks; unchanged blocks keep their prior
|
|
16
|
+
* author regardless. This is the seam that lets one snapshot carry per-block
|
|
17
|
+
* attribution from *different* principals — the server-authoritative persist path
|
|
18
|
+
* (Collab T9), where one durable checkpoint merges edits from several writers.
|
|
19
|
+
*/
|
|
20
|
+
export type BlockAuthorResolver = (blockId: string) => string | undefined;
|
|
2
21
|
/**
|
|
3
22
|
* Compute the `[blockId, subject]` authorship for `next`. Unchanged blocks keep
|
|
4
23
|
* their prior author; changed/new blocks get `authorSubject` when it is a
|
|
@@ -17,6 +36,18 @@ export declare function computeBlockAuthors(prev: PageSnapshot | null | undefine
|
|
|
17
36
|
* is attributed, so it never appears on single-user/unverified snapshots.
|
|
18
37
|
*/
|
|
19
38
|
export declare function stampSnapshotAuthors(prev: PageSnapshot | null | undefined, next: PageSnapshot, authorSubject: string): PageSnapshot;
|
|
39
|
+
/**
|
|
40
|
+
* Per-block variant of {@link stampSnapshotAuthors} for the server-authoritative
|
|
41
|
+
* persist path (Collab T9). When the SERVER persists one converged snapshot that
|
|
42
|
+
* merges edits from several principals, a single `authorSubject` would misattribute
|
|
43
|
+
* every changed block to one writer. Instead each **changed** block is attributed
|
|
44
|
+
* to `authorByBlock.get(blockId)` — the *verified* subject of the principal whose
|
|
45
|
+
* ingested update last changed that block (`''`/absent ⇒ a guest/unverified change,
|
|
46
|
+
* left unattributed). Unchanged blocks keep their prior author. So attribution
|
|
47
|
+
* reflects who actually made each change, never "the server" and never a forged
|
|
48
|
+
* writer. Idempotent when the document is unchanged.
|
|
49
|
+
*/
|
|
50
|
+
export declare function stampSnapshotAuthorsPerBlock(prev: PageSnapshot | null | undefined, next: PageSnapshot, authorByBlock: ReadonlyMap<string, string>): PageSnapshot;
|
|
20
51
|
/**
|
|
21
52
|
* The verified author of a snapshot's most-recently-changed attributed block —
|
|
22
53
|
* the snapshot's "last verified editor", read on the receiving instance to
|
package/dist/authors.js
CHANGED
|
@@ -13,39 +13,45 @@
|
|
|
13
13
|
*/
|
|
14
14
|
import { snapshotBlocks } from './mtime';
|
|
15
15
|
/**
|
|
16
|
-
* Compute the `[blockId, subject]` authorship for `next`. Unchanged
|
|
17
|
-
* their prior author; changed/new blocks
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
16
|
+
* Compute the `[blockId, subject]` authorship for `next` against `prev`. Unchanged
|
|
17
|
+
* blocks (same content hash) keep their prior author; changed/new blocks are
|
|
18
|
+
* attributed to `resolve(blockId)` when it yields a verified (non-empty) subject,
|
|
19
|
+
* and are otherwise left unattributed. Returns a sparse map — only blocks with a
|
|
20
|
+
* known author — or `null` when none are attributed (so the field stays absent on
|
|
21
|
+
* single-user / unverified documents). The single-principal
|
|
22
|
+
* {@link computeBlockAuthors} and the per-block {@link stampSnapshotAuthorsPerBlock}
|
|
23
|
+
* are both thin resolvers over this one diff.
|
|
23
24
|
*/
|
|
24
|
-
|
|
25
|
-
const prevBlocks = snapshotBlocks(prev);
|
|
25
|
+
function computeBlockAuthorsBy(prev, next, resolve) {
|
|
26
26
|
const prevHash = new Map();
|
|
27
|
-
for (const b of
|
|
27
|
+
for (const b of snapshotBlocks(prev))
|
|
28
28
|
prevHash.set(b.id, b.hash);
|
|
29
29
|
const prevAuthor = new Map(prev?.authors ?? []);
|
|
30
|
-
const verified = authorSubject.length > 0;
|
|
31
30
|
const out = [];
|
|
32
31
|
for (const b of snapshotBlocks(next)) {
|
|
33
32
|
const unchanged = prevHash.get(b.id) === b.hash;
|
|
34
|
-
const author = unchanged ? prevAuthor.get(b.id) ?? '' :
|
|
33
|
+
const author = unchanged ? prevAuthor.get(b.id) ?? '' : resolve(b.id) ?? '';
|
|
35
34
|
if (author)
|
|
36
35
|
out.push([b.id, author]);
|
|
37
36
|
}
|
|
38
37
|
return out.length > 0 ? out : null;
|
|
39
38
|
}
|
|
40
39
|
/**
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
40
|
+
* Compute the `[blockId, subject]` authorship for `next`. Unchanged blocks keep
|
|
41
|
+
* their prior author; changed/new blocks get `authorSubject` when it is a
|
|
42
|
+
* verified identity (a non-empty subject), and are otherwise left unattributed
|
|
43
|
+
* (an anonymous/guest edit honestly clears a block's verified author rather than
|
|
44
|
+
* falsely keeping the previous one). Returns a sparse map — only blocks with a
|
|
45
|
+
* known author — or `null` when none are attributed (so the field stays absent
|
|
46
|
+
* on single-user / unverified documents).
|
|
46
47
|
*/
|
|
47
|
-
export function
|
|
48
|
-
const
|
|
48
|
+
export function computeBlockAuthors(prev, next, authorSubject) {
|
|
49
|
+
const author = authorSubject.length > 0 ? authorSubject : '';
|
|
50
|
+
return computeBlockAuthorsBy(prev, next, () => author);
|
|
51
|
+
}
|
|
52
|
+
/** Set `next.authors` from a computed map, or drop the key entirely when nothing
|
|
53
|
+
* is attributed (so it never appears on single-user/unverified snapshots). */
|
|
54
|
+
function withAuthors(next, authors) {
|
|
49
55
|
if (!authors) {
|
|
50
56
|
// Nothing attributed: drop any stale `authors` rather than carry an empty map.
|
|
51
57
|
if (next.authors === undefined)
|
|
@@ -56,6 +62,30 @@ export function stampSnapshotAuthors(prev, next, authorSubject) {
|
|
|
56
62
|
}
|
|
57
63
|
return { ...next, authors };
|
|
58
64
|
}
|
|
65
|
+
/**
|
|
66
|
+
* Return `next` with its `authors` stamped relative to `prev`. `authorSubject` is
|
|
67
|
+
* the request's *verified* principal subject (`iss#sub`), or `''` for an
|
|
68
|
+
* unverified/guest/local write (which carries no new attribution). Idempotent
|
|
69
|
+
* when the document is unchanged. Omits the `authors` key entirely when nothing
|
|
70
|
+
* is attributed, so it never appears on single-user/unverified snapshots.
|
|
71
|
+
*/
|
|
72
|
+
export function stampSnapshotAuthors(prev, next, authorSubject) {
|
|
73
|
+
return withAuthors(next, computeBlockAuthors(prev, next, authorSubject));
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Per-block variant of {@link stampSnapshotAuthors} for the server-authoritative
|
|
77
|
+
* persist path (Collab T9). When the SERVER persists one converged snapshot that
|
|
78
|
+
* merges edits from several principals, a single `authorSubject` would misattribute
|
|
79
|
+
* every changed block to one writer. Instead each **changed** block is attributed
|
|
80
|
+
* to `authorByBlock.get(blockId)` — the *verified* subject of the principal whose
|
|
81
|
+
* ingested update last changed that block (`''`/absent ⇒ a guest/unverified change,
|
|
82
|
+
* left unattributed). Unchanged blocks keep their prior author. So attribution
|
|
83
|
+
* reflects who actually made each change, never "the server" and never a forged
|
|
84
|
+
* writer. Idempotent when the document is unchanged.
|
|
85
|
+
*/
|
|
86
|
+
export function stampSnapshotAuthorsPerBlock(prev, next, authorByBlock) {
|
|
87
|
+
return withAuthors(next, computeBlockAuthorsBy(prev, next, (id) => authorByBlock.get(id)));
|
|
88
|
+
}
|
|
59
89
|
/**
|
|
60
90
|
* The verified author of a snapshot's most-recently-changed attributed block —
|
|
61
91
|
* the snapshot's "last verified editor", read on the receiving instance to
|
package/dist/authors.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"authors.js","sourceRoot":"","sources":["../src/authors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,EAAC,cAAc,EAAC,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"authors.js","sourceRoot":"","sources":["../src/authors.ts"],"names":[],"mappings":"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"}
|
package/dist/backup.d.ts
CHANGED
|
@@ -86,9 +86,11 @@ export interface BackupStatus {
|
|
|
86
86
|
/**
|
|
87
87
|
* Pure: re-key a bundle for copy-mode import. Mints a fresh id for every page and
|
|
88
88
|
* database, remaps every internal reference (`parentId`, `databaseId`,
|
|
89
|
-
* `hostedDatabaseId`, a database's `pageId`, and `@`-
|
|
90
|
-
*
|
|
91
|
-
*
|
|
89
|
+
* `hostedDatabaseId`, a database's `pageId`, and `@`-mentions — both the EditorJS
|
|
90
|
+
* HTML form (`data-page-id`) and the block-doc run form (an `m` attr, the shape
|
|
91
|
+
* the block-native editor and importers emit)), and returns the rewritten
|
|
92
|
+
* pages/databases plus the `oldId → newId` map. References to pages outside the
|
|
93
|
+
* bundle are left as-is.
|
|
92
94
|
* Unit-tested; the store layer adds DB-aware name de-duplication on top.
|
|
93
95
|
*/
|
|
94
96
|
export declare function remapBundle(pages: StoredPage[], databases: StoredDatabase[], newId: () => string): {
|
package/dist/backup.js
CHANGED
|
@@ -17,9 +17,11 @@ export const DEFAULT_BACKUP_CONFIG = {
|
|
|
17
17
|
/**
|
|
18
18
|
* Pure: re-key a bundle for copy-mode import. Mints a fresh id for every page and
|
|
19
19
|
* database, remaps every internal reference (`parentId`, `databaseId`,
|
|
20
|
-
* `hostedDatabaseId`, a database's `pageId`, and `@`-
|
|
21
|
-
*
|
|
22
|
-
*
|
|
20
|
+
* `hostedDatabaseId`, a database's `pageId`, and `@`-mentions — both the EditorJS
|
|
21
|
+
* HTML form (`data-page-id`) and the block-doc run form (an `m` attr, the shape
|
|
22
|
+
* the block-native editor and importers emit)), and returns the rewritten
|
|
23
|
+
* pages/databases plus the `oldId → newId` map. References to pages outside the
|
|
24
|
+
* bundle are left as-is.
|
|
23
25
|
* Unit-tested; the store layer adds DB-aware name de-duplication on top.
|
|
24
26
|
*/
|
|
25
27
|
export function remapBundle(pages, databases, newId) {
|
|
@@ -32,7 +34,13 @@ export function remapBundle(pages, databases, newId) {
|
|
|
32
34
|
const remapMentions = (data) => {
|
|
33
35
|
let json = JSON.stringify(data);
|
|
34
36
|
for (const [oldId, nid] of Object.entries(idMap)) {
|
|
37
|
+
// EditorJS HTML mention: `data-page-id=\"id\"` (the inner quotes are escaped
|
|
38
|
+
// because the HTML lives inside a JSON string value once serialised).
|
|
35
39
|
json = json.split(`data-page-id=\\"${oldId}\\"`).join(`data-page-id=\\"${nid}\\"`);
|
|
40
|
+
// Block-doc mention run: an `m` attr (`{"a":{"m":"id"}}`) — structured JSON,
|
|
41
|
+
// so the quotes are plain. Anchored on the exact bundle id (a unique token),
|
|
42
|
+
// so it never rewrites an unrelated value.
|
|
43
|
+
json = json.split(`"m":"${oldId}"`).join(`"m":"${nid}"`);
|
|
36
44
|
}
|
|
37
45
|
return JSON.parse(json);
|
|
38
46
|
};
|
package/dist/backup.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"backup.js","sourceRoot":"","sources":["../src/backup.ts"],"names":[],"mappings":"AAcA,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,CAAC;AAgDhC,MAAM,CAAC,MAAM,eAAe,GAA6B,CAAC,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,CAAU,CAAC;AAE3G,iDAAiD;AACjD,MAAM,CAAC,MAAM,iBAAiB,GAAkC;IAC9D,KAAK,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI;IAC1B,MAAM,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI;IAC/B,OAAO,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI;IACjC,MAAM,EAAE,GAAG,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI;CAClC,CAAC;AAgBF,MAAM,CAAC,MAAM,qBAAqB,GAAiB;IACjD,OAAO,EAAE,KAAK;IACd,GAAG,EAAE,IAAI;IACT,QAAQ,EAAE,EAAC,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAC;IAClE,IAAI,EAAE,EAAC,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,EAAC;IACnD,OAAO,EAAE,EAAE;CACZ,CAAC;AAmBF
|
|
1
|
+
{"version":3,"file":"backup.js","sourceRoot":"","sources":["../src/backup.ts"],"names":[],"mappings":"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"}
|
package/dist/client.d.ts
CHANGED
|
@@ -115,6 +115,79 @@ export interface DataClient {
|
|
|
115
115
|
subscribePage(id: string, handlers: PageSubscription): () => void;
|
|
116
116
|
/** Subscribe to live page-list updates. Returns an unsubscribe fn. */
|
|
117
117
|
subscribePages(onList: (pages: PageMeta[]) => void): () => void;
|
|
118
|
+
/**
|
|
119
|
+
* Subscribe to the live stream's *reconnect* signal (Collab T7): fires after the SSE
|
|
120
|
+
* stream drops and successfully **reopens** (the OB-132/OB-283 resync signal), so a
|
|
121
|
+
* caller can run a tight catch-up — the relay re-does its state-vector `/sync`
|
|
122
|
+
* handshake, the awareness provider re-announces presence — instead of waiting out the
|
|
123
|
+
* coarser page-*snapshot* resync (≤ snapshot-rate). Trailing-debounced against a
|
|
124
|
+
* flapping connection. It does NOT fire on the FIRST connect (the one-shot handshakes
|
|
125
|
+
* cover that) nor in poll-mode (no live SSE ⇒ convergence stays at snapshot-rate, the
|
|
126
|
+
* existing graceful degrade). Returns an unsubscribe fn; a transport with no live
|
|
127
|
+
* stream (the in-webview client) never fires it.
|
|
128
|
+
*/
|
|
129
|
+
subscribeReconnect(onReconnect: () => void): () => void;
|
|
130
|
+
/**
|
|
131
|
+
* Relay one incremental Yjs update for a page to other open editors. `update` is
|
|
132
|
+
* the base64 CRDT bytes; `clientId` is the author's `Y.Doc` id so the author's
|
|
133
|
+
* own echo can be dropped. Ephemeral — never persisted (durability stays with
|
|
134
|
+
* {@link savePage}'s debounced snapshot).
|
|
135
|
+
*/
|
|
136
|
+
postPageUpdate(id: string, update: string, clientId: number): Promise<void>;
|
|
137
|
+
/**
|
|
138
|
+
* Subscribe to a page's incremental Yjs updates. `onUpdate` fires with the base64
|
|
139
|
+
* CRDT bytes + the author's `clientId`. Returns an unsubscribe fn.
|
|
140
|
+
*/
|
|
141
|
+
subscribePageUpdates(id: string, onUpdate: (update: string, clientId: number) => void): () => void;
|
|
142
|
+
/**
|
|
143
|
+
* Late-joiner handshake: send the local doc's base64 state vector, receive the
|
|
144
|
+
* base64 update carrying exactly the ops this client is missing (or `null` when
|
|
145
|
+
* the server has nothing newer than the snapshot the client already loaded). This
|
|
146
|
+
* is how a client joining mid-session converges to the CURRENT doc.
|
|
147
|
+
*/
|
|
148
|
+
syncPageUpdates(id: string, stateVector: string): Promise<string | null>;
|
|
149
|
+
/**
|
|
150
|
+
* Publish this client's presence (cursor / selection) as a base64
|
|
151
|
+
* `y-protocols/awareness` update. **Read-gated** (a viewer appears present), and
|
|
152
|
+
* the server **re-stamps the identity** (name/colour) from the verified principal
|
|
153
|
+
* — what's in the body is never trusted for who-you-are. Ephemeral: never
|
|
154
|
+
* persisted, never in the edit log.
|
|
155
|
+
*/
|
|
156
|
+
postPageAwareness(id: string, update: string, clientId: number): Promise<void>;
|
|
157
|
+
/**
|
|
158
|
+
* Subscribe to a page's awareness updates (other clients' presence). `onUpdate`
|
|
159
|
+
* fires with the base64 awareness bytes + the author's `clientId` (so the author
|
|
160
|
+
* drops its own echo). Returns an unsubscribe fn. Ephemeral — not resynced on
|
|
161
|
+
* reconnect; the periodic awareness refresh + the on-connect snapshot recover it.
|
|
162
|
+
*/
|
|
163
|
+
subscribePageAwareness(id: string, onUpdate: (update: string, clientId: number) => void): () => void;
|
|
164
|
+
/**
|
|
165
|
+
* Current presence snapshot for a late joiner (Collab T4): the base64 awareness
|
|
166
|
+
* updates of everyone currently present (already identity-stamped), so a client
|
|
167
|
+
* connecting mid-session sees who's here at once rather than waiting out the next
|
|
168
|
+
* awareness refresh. Read-gated. Empty when nobody else is present.
|
|
169
|
+
*/
|
|
170
|
+
syncPageAwareness(id: string): Promise<string[]>;
|
|
171
|
+
/**
|
|
172
|
+
* Upload binary `bytes` (e.g. an image's file bytes) to the content-addressed
|
|
173
|
+
* asset store, ref'd to `pageId` — a page the caller can write, whose read-gate
|
|
174
|
+
* the asset inherits so it's immediately reachable. Resolves `{id}`, the
|
|
175
|
+
* SHA-256 content hash; a byte-identical re-upload dedups to the same id. The
|
|
176
|
+
* image block persists only this `id`, never the bytes, so the CRDT stays small.
|
|
177
|
+
*/
|
|
178
|
+
putAsset(bytes: Uint8Array, mime: string, pageId: string): Promise<{
|
|
179
|
+
id: string;
|
|
180
|
+
}>;
|
|
181
|
+
/**
|
|
182
|
+
* Fetch an asset's bytes + mime by content-hash `id`, or `null` when it's
|
|
183
|
+
* missing or the caller can read no page that references it (read-gated — an
|
|
184
|
+
* absent and an unreadable asset answer alike, so there's no existence oracle).
|
|
185
|
+
* The image block resolves this to an object URL for `<img src>`.
|
|
186
|
+
*/
|
|
187
|
+
getAsset(id: string): Promise<{
|
|
188
|
+
bytes: Uint8Array;
|
|
189
|
+
mime: string;
|
|
190
|
+
} | null>;
|
|
118
191
|
/** Create a database for a host page. */
|
|
119
192
|
createDatabase(input: DatabaseInput): Promise<StoredDatabase>;
|
|
120
193
|
/** Fetch a database by id, or `null` if it does not exist. */
|
|
@@ -232,6 +305,36 @@ export interface LiveSourceLike {
|
|
|
232
305
|
}) => void): void;
|
|
233
306
|
close(): void;
|
|
234
307
|
}
|
|
308
|
+
/**
|
|
309
|
+
* How long to wait for the `EventSource`'s first `open` before deciding the
|
|
310
|
+
* stream is structurally dead and falling back to polling. The *.book.pub
|
|
311
|
+
* forwarding tunnel buffers the never-ending SSE body in release builds and
|
|
312
|
+
* forwards nothing, so a tunneled browser sees neither `open` nor any event;
|
|
313
|
+
* this bound caps how long it stays dark before polling takes over. Loopback
|
|
314
|
+
* (dev) and any future-fixed transport open well inside this window and so
|
|
315
|
+
* never poll. Exported for tests; not re-exported from the package index.
|
|
316
|
+
*/
|
|
317
|
+
export declare const LIVE_OPEN_GRACE_MS = 8000;
|
|
318
|
+
/**
|
|
319
|
+
* How often poll-mode re-fetches every open subscription once the SSE stream is
|
|
320
|
+
* deemed dead — the interval within which a tunneled client sees writes.
|
|
321
|
+
*/
|
|
322
|
+
export declare const LIVE_POLL_INTERVAL_MS = 4000;
|
|
323
|
+
/**
|
|
324
|
+
* Number of `error`s (with no intervening `open`) that trip poll-mode early,
|
|
325
|
+
* before {@link LIVE_OPEN_GRACE_MS} elapses — e.g. a connection that is refused
|
|
326
|
+
* or fails immediately rather than hanging.
|
|
327
|
+
*/
|
|
328
|
+
export declare const LIVE_POLL_AFTER_ERRORS = 3;
|
|
329
|
+
/**
|
|
330
|
+
* Trailing-debounce window for the {@link LiveStream} reconnect signal (Collab T7). A
|
|
331
|
+
* flapping connection can `error`/`open` repeatedly; coalescing the reopens into a single
|
|
332
|
+
* notification — fired once the stream has stayed open this long — keeps a caller's
|
|
333
|
+
* re-handshake from storming the relay. Short relative to a snapshot save, so the
|
|
334
|
+
* post-reconnect catch-up is still far tighter than the snapshot-rate fallback. Exported
|
|
335
|
+
* for tests; not re-exported from the package index.
|
|
336
|
+
*/
|
|
337
|
+
export declare const LIVE_RECONNECT_DEBOUNCE_MS = 300;
|
|
235
338
|
/** Options for swapping {@link HttpDataClient}'s transport (desktop IPC). */
|
|
236
339
|
export interface HttpDataClientOptions {
|
|
237
340
|
/** Replacement for the global `fetch` (e.g. tunnel requests over host IPC). */
|
|
@@ -302,6 +405,52 @@ export declare class HttpDataClient implements DataClient {
|
|
|
302
405
|
compact(): Promise<CompactResult>;
|
|
303
406
|
subscribePage(id: string, handlers: PageSubscription): () => void;
|
|
304
407
|
subscribePages(onList: (pages: PageMeta[]) => void): () => void;
|
|
408
|
+
/** Reopen-after-drop reconnect signal (Collab T7) — tight post-reconnect catch-up. */
|
|
409
|
+
subscribeReconnect(onReconnect: () => void): () => void;
|
|
410
|
+
/** Relay one incremental Yjs update (Collab T1); ephemeral, no store write. */
|
|
411
|
+
postPageUpdate(id: string, update: string, clientId: number): Promise<void>;
|
|
412
|
+
subscribePageUpdates(id: string, onUpdate: (update: string, clientId: number) => void): () => void;
|
|
413
|
+
/** Late-joiner sync handshake (Collab T1): state vector in, missing ops out. */
|
|
414
|
+
syncPageUpdates(id: string, stateVector: string): Promise<string | null>;
|
|
415
|
+
/** Publish ephemeral presence (Collab T4); read-gated, identity server-stamped. */
|
|
416
|
+
postPageAwareness(id: string, update: string, clientId: number): Promise<void>;
|
|
417
|
+
subscribePageAwareness(id: string, onUpdate: (update: string, clientId: number) => void): () => void;
|
|
418
|
+
/** Current presence snapshot for a late joiner (Collab T4). */
|
|
419
|
+
syncPageAwareness(id: string): Promise<string[]>;
|
|
420
|
+
/**
|
|
421
|
+
* Upload asset bytes and ref them to `pageId`. The body is base64-JSON
|
|
422
|
+
* (`{data, mime}`) rather than raw binary DELIBERATELY: the desktop IPC bridge
|
|
423
|
+
* (`tauriFetch`) corrupts raw binary / stream request bodies, so base64 keeps
|
|
424
|
+
* the upload byte-exact on BOTH the web-http and desktop-IPC transports.
|
|
425
|
+
*/
|
|
426
|
+
putAsset(bytes: Uint8Array, mime: string, pageId: string): Promise<{
|
|
427
|
+
id: string;
|
|
428
|
+
}>;
|
|
429
|
+
/**
|
|
430
|
+
* Fetch an asset by content-hash id, decoding the base64-JSON variant
|
|
431
|
+
* (`?encoding=base64`) — again to stay byte-safe over the desktop IPC bridge,
|
|
432
|
+
* which corrupts raw binary responses. `null` on 404 (missing or read-gated).
|
|
433
|
+
*
|
|
434
|
+
* A5 decision — base64 single-shot over the desktop's `tauriFetch`, NOT the
|
|
435
|
+
* streaming `tauriStreamFetch` (which stays tunnel-only): assets are capped at
|
|
436
|
+
* 10 MiB, and `getAsset` must materialize the FULL bytes anyway (its consumer
|
|
437
|
+
* wraps them in a `Blob`/object-URL), so streaming buys no client-side memory
|
|
438
|
+
* win — it would only spare the server a whole-asset base64 pass. Wiring it would
|
|
439
|
+
* mean threading a second transport through this one `fetchImpl` abstraction for a
|
|
440
|
+
* bounded (~13 MiB transient) payload — cost > benefit. Buffered base64-JSON is
|
|
441
|
+
* the right call at this cap; revisit only if the cap is ever raised materially.
|
|
442
|
+
*
|
|
443
|
+
* `cache: 'no-store'` keeps this byte-exact across all three transports (IPC
|
|
444
|
+
* base64, web, tunnel) — it never relies on the browser HTTP cache, so it holds
|
|
445
|
+
* the object-URL in-app instead. The server's content-addressed `ETag`/304 (A5)
|
|
446
|
+
* still shortcuts a browser's OWN cache-revalidation for any DIRECT `<img src>`
|
|
447
|
+
* fetch of the asset URL (notably through a *.book.pub tunnel, where the browser
|
|
448
|
+
* caches the first response), which is a separate, non-`no-store` code path.
|
|
449
|
+
*/
|
|
450
|
+
getAsset(id: string): Promise<{
|
|
451
|
+
bytes: Uint8Array;
|
|
452
|
+
mime: string;
|
|
453
|
+
} | null>;
|
|
305
454
|
createDatabase(input: DatabaseInput): Promise<StoredDatabase>;
|
|
306
455
|
getDatabase(id: string): Promise<StoredDatabase | null>;
|
|
307
456
|
getPageDatabase(pageId: string): Promise<StoredDatabase | null>;
|