@loro-dev/streams-crdt 0.1.1 → 0.2.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/README.md +27 -4
- package/dist/flock.d.ts +4 -29
- package/dist/flock.js +39 -81
- package/dist/flock.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/loro.d.ts +2 -2
- package/dist/loro.js +1 -1
- package/dist/{stream-id-B9n-uFFB.d.ts → stream-id-BxGVitUa.d.ts} +35 -11
- package/dist/{stream-id-YOFZ4I6Y.js → stream-id-kM9JM1F7.js} +78 -244
- package/dist/stream-id-kM9JM1F7.js.map +1 -0
- package/package.json +4 -3
- package/dist/stream-id-YOFZ4I6Y.js.map +0 -1
package/README.md
CHANGED
|
@@ -184,8 +184,31 @@ the transport also clears the stored replay cursor for that stream.
|
|
|
184
184
|
- a sync callback returning a string
|
|
185
185
|
- an async callback returning a string
|
|
186
186
|
|
|
187
|
-
|
|
188
|
-
|
|
187
|
+
`StreamsCrdt` asks for a token before each request. If a request comes back
|
|
188
|
+
with `401` or `403`, it calls `auth` one more time with
|
|
189
|
+
`{ reason: "unauthorized", status, previousToken }` and retries that request
|
|
190
|
+
once.
|
|
191
|
+
|
|
192
|
+
This lets the caller keep a cached token in the normal path, and only refresh
|
|
193
|
+
after the server rejects it:
|
|
194
|
+
|
|
195
|
+
```ts
|
|
196
|
+
let token = readCachedGatewayJwt();
|
|
197
|
+
|
|
198
|
+
const transport = new StreamsCrdt({
|
|
199
|
+
streamUrl,
|
|
200
|
+
adapter,
|
|
201
|
+
auth: async (context) => {
|
|
202
|
+
if (context?.reason === "unauthorized") {
|
|
203
|
+
token = await refreshGatewayJwt();
|
|
204
|
+
}
|
|
205
|
+
return token;
|
|
206
|
+
},
|
|
207
|
+
});
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
If your callback already returns a fresh token every time, you can ignore the
|
|
211
|
+
`context` argument.
|
|
189
212
|
|
|
190
213
|
## Remote Cursor Store
|
|
191
214
|
|
|
@@ -474,7 +497,7 @@ const transport = new StreamsCrdt({
|
|
|
474
497
|
`@loro-dev/streams-crdt/flock` re-exports everything from the root plus:
|
|
475
498
|
|
|
476
499
|
- `createFlockAdapter(flock)` — creates a `CrdtAdapter` for one `Flock` replica
|
|
477
|
-
- `
|
|
500
|
+
- `VersionVector`, `ExportBundle` — re-exported from `@loro-dev/flock-wasm`
|
|
478
501
|
|
|
479
502
|
### Zstd Entry Point
|
|
480
503
|
|
|
@@ -491,7 +514,7 @@ const transport = new StreamsCrdt({
|
|
|
491
514
|
- `createStreamIfMissing` defaults to `false` and only affects the initial sync/join bootstrap
|
|
492
515
|
- `deleteStream()` returns `{ deleted: false }` when the target stream is already missing
|
|
493
516
|
- `sync()` and `join()` return `Result` objects instead of implicitly creating missing streams
|
|
494
|
-
- `join()` resolves only after the initial replay has succeeded; without a stored remote cursor it prefers
|
|
517
|
+
- `join()` resolves only after the initial replay has succeeded; without a stored remote cursor it bootstraps once, then prefers ordinary live SSE and falls back sticky to long-poll
|
|
495
518
|
- One transport instance maps to one DS stream
|
|
496
519
|
- One adapter instance maps to one local CRDT instance
|
|
497
520
|
- Built-in remote cursor stores implement `delete(streamUrl)` so `deleteStream()` can reset replay state cleanly
|
package/dist/flock.d.ts
CHANGED
|
@@ -1,36 +1,11 @@
|
|
|
1
|
-
import { A as
|
|
1
|
+
import { A as RemoteCursorStore, C as BeforeRemoteCursorSaveContext, D as IndexedDbRemoteCursorStoreOptions, E as IndexedDbRemoteCursorStore, O as RemoteCursor, S as TransportSyncSuccess, T as InMemoryRemoteCursorStore, _ as TransportDeleteStreamSuccess, a as CrdtAdapter, b as TransportRoomStatus, c as JsonValue, d as SnapshotTransformHook, f as SnapshotUploadOptions, g as TransportCreateStreamSuccess, h as StreamsCrdtOptions, i as StreamsCrdt, j as createInitialRemoteCursor, k as RemoteCursorSaveSource, l as Result, m as StreamsAuthProvider, n as isValidBucketId, o as CrdtUpdateBatch, p as StreamsAuthContext, r as isValidRillId, s as JsonObject, t as createStreamUrl, u as SnapshotCodec, v as TransportError, w as BeforeRemoteCursorSaveHook, x as TransportSubscription, y as TransportJoinParams } from "./stream-id-BxGVitUa.js";
|
|
2
|
+
import { ExportBundle, Flock, VersionVector, VersionVector as VersionVector$1 } from "@loro-dev/flock-wasm";
|
|
2
3
|
|
|
3
4
|
//#region src/flock.d.ts
|
|
4
|
-
type FlockVersionEntry = {
|
|
5
|
-
logicalCounter: number;
|
|
6
|
-
physicalTime?: number;
|
|
7
|
-
};
|
|
8
|
-
/**
|
|
9
|
-
* Flock version vector shape used by the built-in Flock adapter.
|
|
10
|
-
*/
|
|
11
|
-
type FlockVersionVector = Record<string, FlockVersionEntry>;
|
|
12
|
-
type FlockExportBundle = {
|
|
13
|
-
readonly version?: number;
|
|
14
|
-
readonly entries: Record<string, unknown>;
|
|
15
|
-
};
|
|
16
|
-
type FlockLike = {
|
|
17
|
-
exportJson(options?: {
|
|
18
|
-
from?: FlockVersionVector;
|
|
19
|
-
peerId?: string;
|
|
20
|
-
}): FlockExportBundle;
|
|
21
|
-
importJson(bundle: FlockExportBundle): unknown;
|
|
22
|
-
merge?(replica: unknown): unknown;
|
|
23
|
-
peerId?(): string;
|
|
24
|
-
version(): unknown;
|
|
25
|
-
exportFile?(): Uint8Array;
|
|
26
|
-
subscribe?(listener: (batch: {
|
|
27
|
-
source?: string;
|
|
28
|
-
}) => void): () => void;
|
|
29
|
-
};
|
|
30
5
|
/**
|
|
31
6
|
* Creates a `CrdtAdapter` for one Flock replica.
|
|
32
7
|
*/
|
|
33
|
-
declare function createFlockAdapter(flock:
|
|
8
|
+
declare function createFlockAdapter(flock: Flock): CrdtAdapter<VersionVector$1>;
|
|
34
9
|
//#endregion
|
|
35
|
-
export { BeforeRemoteCursorSaveContext, BeforeRemoteCursorSaveHook, CrdtAdapter, CrdtUpdateBatch,
|
|
10
|
+
export { BeforeRemoteCursorSaveContext, BeforeRemoteCursorSaveHook, CrdtAdapter, CrdtUpdateBatch, type ExportBundle, InMemoryRemoteCursorStore, IndexedDbRemoteCursorStore, IndexedDbRemoteCursorStoreOptions, JsonObject, JsonValue, RemoteCursor, RemoteCursorSaveSource, RemoteCursorStore, Result, SnapshotCodec, SnapshotTransformHook, SnapshotUploadOptions, StreamsAuthContext, StreamsAuthProvider, StreamsCrdt, StreamsCrdtOptions, TransportCreateStreamSuccess, TransportDeleteStreamSuccess, TransportError, TransportJoinParams, TransportRoomStatus, TransportSubscription, TransportSyncSuccess, type VersionVector, createFlockAdapter, createInitialRemoteCursor, createStreamUrl, isValidBucketId, isValidRillId };
|
|
36
11
|
//# sourceMappingURL=flock.d.ts.map
|
package/dist/flock.js
CHANGED
|
@@ -1,74 +1,45 @@
|
|
|
1
|
-
import { a as InMemoryRemoteCursorStore, i as StreamsCrdt, n as isValidBucketId, o as IndexedDbRemoteCursorStore, r as isValidRillId, s as createInitialRemoteCursor, t as createStreamUrl } from "./stream-id-
|
|
1
|
+
import { a as InMemoryRemoteCursorStore, i as StreamsCrdt, n as isValidBucketId, o as IndexedDbRemoteCursorStore, r as isValidRillId, s as createInitialRemoteCursor, t as createStreamUrl } from "./stream-id-kM9JM1F7.js";
|
|
2
2
|
//#region src/flock.ts
|
|
3
|
-
function
|
|
4
|
-
|
|
5
|
-
for (const [peer, raw] of Object.entries(version)) {
|
|
6
|
-
if (typeof raw !== "object" || raw == null || Array.isArray(raw)) continue;
|
|
7
|
-
const logicalCounter = typeof raw.logicalCounter === "number" ? raw.logicalCounter : void 0;
|
|
8
|
-
if (logicalCounter == null || !Number.isFinite(logicalCounter)) continue;
|
|
9
|
-
out[peer] = typeof raw.physicalTime === "number" && Number.isFinite(raw.physicalTime) ? {
|
|
10
|
-
logicalCounter,
|
|
11
|
-
physicalTime: raw.physicalTime
|
|
12
|
-
} : { logicalCounter };
|
|
13
|
-
}
|
|
14
|
-
return out;
|
|
15
|
-
}
|
|
16
|
-
function fromVersionVector(version) {
|
|
17
|
-
const out = {};
|
|
18
|
-
for (const [peer, entry] of Object.entries(version)) out[peer] = entry.physicalTime === void 0 ? { logicalCounter: entry.logicalCounter } : {
|
|
19
|
-
logicalCounter: entry.logicalCounter,
|
|
20
|
-
physicalTime: entry.physicalTime
|
|
21
|
-
};
|
|
22
|
-
return out;
|
|
3
|
+
function isAfter(entry, current) {
|
|
4
|
+
return entry.physicalTime > current.physicalTime || entry.physicalTime === current.physicalTime && entry.logicalCounter > current.logicalCounter;
|
|
23
5
|
}
|
|
24
6
|
function mergeVersions(base, incoming) {
|
|
25
7
|
const merged = { ...base };
|
|
26
8
|
for (const [peer, entry] of Object.entries(incoming)) {
|
|
9
|
+
if (entry == null) continue;
|
|
27
10
|
const current = merged[peer];
|
|
28
|
-
if (current == null || entry
|
|
29
|
-
merged[peer] = { ...entry };
|
|
30
|
-
continue;
|
|
31
|
-
}
|
|
32
|
-
if (entry.logicalCounter < current.logicalCounter) continue;
|
|
33
|
-
const physicalTime = Math.max(current.physicalTime ?? Number.NEGATIVE_INFINITY, entry.physicalTime ?? Number.NEGATIVE_INFINITY);
|
|
34
|
-
merged[peer] = physicalTime === Number.NEGATIVE_INFINITY ? { logicalCounter: current.logicalCounter } : {
|
|
35
|
-
logicalCounter: current.logicalCounter,
|
|
36
|
-
physicalTime
|
|
37
|
-
};
|
|
11
|
+
if (current == null || isAfter(entry, current)) merged[peer] = { ...entry };
|
|
38
12
|
}
|
|
39
13
|
return merged;
|
|
40
14
|
}
|
|
15
|
+
function parseClock(record) {
|
|
16
|
+
const firstComma = record.c.indexOf(",");
|
|
17
|
+
const secondComma = record.c.indexOf(",", firstComma + 1);
|
|
18
|
+
if (firstComma < 0 || secondComma < 0) return null;
|
|
19
|
+
const physicalTime = Number(record.c.slice(0, firstComma));
|
|
20
|
+
const logicalCounter = Number(record.c.slice(firstComma + 1, secondComma));
|
|
21
|
+
if (!Number.isFinite(physicalTime) || !Number.isFinite(logicalCounter)) return null;
|
|
22
|
+
return {
|
|
23
|
+
peerId: record.c.slice(secondComma + 1),
|
|
24
|
+
entry: {
|
|
25
|
+
physicalTime,
|
|
26
|
+
logicalCounter
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
}
|
|
41
30
|
function extractVersionFromBundle(bundle) {
|
|
42
31
|
const out = {};
|
|
43
|
-
for (const
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
if (logicalCounter == null || !Number.isFinite(logicalCounter)) continue;
|
|
49
|
-
out[entry.peerId] = typeof entry.physicalTime === "number" && Number.isFinite(entry.physicalTime) ? {
|
|
50
|
-
logicalCounter,
|
|
51
|
-
physicalTime: entry.physicalTime
|
|
52
|
-
} : { logicalCounter };
|
|
32
|
+
for (const record of Object.values(bundle.entries)) {
|
|
33
|
+
const parsed = parseClock(record);
|
|
34
|
+
if (parsed == null) continue;
|
|
35
|
+
const current = out[parsed.peerId];
|
|
36
|
+
if (current == null || isAfter(parsed.entry, current)) out[parsed.peerId] = parsed.entry;
|
|
53
37
|
}
|
|
54
38
|
return out;
|
|
55
39
|
}
|
|
56
40
|
function hasEntries(bundle) {
|
|
57
41
|
return Object.keys(bundle.entries).length > 0;
|
|
58
42
|
}
|
|
59
|
-
function tryMergeSnapshotFromFile(flock, snapshot) {
|
|
60
|
-
if (typeof flock.merge !== "function") return null;
|
|
61
|
-
const ctor = flock.constructor;
|
|
62
|
-
if (ctor == null || typeof ctor.fromFile !== "function") return null;
|
|
63
|
-
try {
|
|
64
|
-
const peerId = typeof flock.peerId === "function" ? flock.peerId() : void 0;
|
|
65
|
-
const replica = ctor.fromFile(snapshot, peerId);
|
|
66
|
-
flock.merge(replica);
|
|
67
|
-
return toVersionVector(flock.version() ?? {});
|
|
68
|
-
} catch {
|
|
69
|
-
return null;
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
43
|
/**
|
|
73
44
|
* Creates a `CrdtAdapter` for one Flock replica.
|
|
74
45
|
*/
|
|
@@ -80,59 +51,46 @@ function createFlockAdapter(flock) {
|
|
|
80
51
|
};
|
|
81
52
|
return {
|
|
82
53
|
emptyVersion: () => ({}),
|
|
83
|
-
mergeVersions
|
|
84
|
-
exportSnapshot: () =>
|
|
85
|
-
if (typeof flock.exportFile === "function") return flock.exportFile();
|
|
86
|
-
return new TextEncoder().encode(JSON.stringify({
|
|
87
|
-
version: 0,
|
|
88
|
-
entries: {}
|
|
89
|
-
}));
|
|
90
|
-
},
|
|
54
|
+
mergeVersions,
|
|
55
|
+
exportSnapshot: () => flock.exportFile(),
|
|
91
56
|
applySnapshot: (snapshot) => {
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
if (mergedVersion != null) return fromVersionVector(mergedVersion);
|
|
95
|
-
const bundle = JSON.parse(new TextDecoder().decode(snapshot));
|
|
96
|
-
if (hasEntries(bundle)) flock.importJson(bundle);
|
|
97
|
-
return fromVersionVector(extractVersionFromBundle(bundle));
|
|
57
|
+
flock.importFile(snapshot);
|
|
58
|
+
return flock.version();
|
|
98
59
|
},
|
|
99
60
|
exportUpdates: (fromVersion) => {
|
|
100
|
-
const
|
|
101
|
-
|
|
102
|
-
recordExportFrontier(from);
|
|
61
|
+
const bundle = flock.exportJson(fromVersion);
|
|
62
|
+
recordExportFrontier(fromVersion);
|
|
103
63
|
if (!hasEntries(bundle)) return;
|
|
104
64
|
const exportedVersion = extractVersionFromBundle(bundle);
|
|
105
65
|
recordExportFrontier(exportedVersion);
|
|
106
66
|
return {
|
|
107
67
|
updates: [new TextEncoder().encode(JSON.stringify(bundle))],
|
|
108
|
-
version:
|
|
68
|
+
version: exportedVersion
|
|
109
69
|
};
|
|
110
70
|
},
|
|
111
71
|
applyRemoteUpdates: (updates, remoterVersion) => {
|
|
112
|
-
let merged =
|
|
72
|
+
let merged = remoterVersion;
|
|
113
73
|
for (const update of updates) {
|
|
114
74
|
const bundle = JSON.parse(new TextDecoder().decode(update));
|
|
115
75
|
if (!hasEntries(bundle)) continue;
|
|
116
76
|
flock.importJson(bundle);
|
|
117
77
|
merged = mergeVersions(merged, extractVersionFromBundle(bundle));
|
|
118
78
|
}
|
|
119
|
-
return
|
|
79
|
+
return merged;
|
|
120
80
|
},
|
|
121
81
|
subscribeLocalUpdates: (listener) => {
|
|
122
|
-
if (typeof flock.subscribe !== "function") return () => void 0;
|
|
123
82
|
return flock.subscribe((batch) => {
|
|
124
83
|
if (batch.source !== "local") return;
|
|
125
|
-
const drain = () => {
|
|
126
|
-
const
|
|
127
|
-
const batchPayload = flock.exportJson({
|
|
84
|
+
const drain = async () => {
|
|
85
|
+
const batchPayload = await flock.exportJson({
|
|
128
86
|
from: lastExportedVersion,
|
|
129
|
-
peerId
|
|
87
|
+
peerId: flock.peerId()
|
|
130
88
|
});
|
|
131
89
|
if (!hasEntries(batchPayload)) return;
|
|
132
|
-
recordExportFrontier(
|
|
90
|
+
recordExportFrontier(flock.version());
|
|
133
91
|
listener({
|
|
134
92
|
updates: [new TextEncoder().encode(JSON.stringify(batchPayload))],
|
|
135
|
-
version:
|
|
93
|
+
version: extractVersionFromBundle(batchPayload)
|
|
136
94
|
});
|
|
137
95
|
};
|
|
138
96
|
localExportQueue = localExportQueue.then(drain).catch(() => {});
|
package/dist/flock.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"flock.js","names":[],"sources":["../src/flock.ts"],"sourcesContent":["import type { JsonObject, CrdtAdapter } from \"./types\";\n\nexport { StreamsCrdt } from \"./transport\";\nexport * from \"./shared\";\n\ntype FlockVersionEntry = {\n logicalCounter: number;\n physicalTime?: number;\n};\n\n/**\n * Flock version vector shape used by the built-in Flock adapter.\n */\nexport type FlockVersionVector = Record<string, FlockVersionEntry>;\n\ntype FlockExportBundle = {\n readonly version?: number;\n readonly entries: Record<string, unknown>;\n};\n\ntype FlockLike = {\n exportJson(options?: {\n from?: FlockVersionVector;\n peerId?: string;\n }): FlockExportBundle;\n importJson(bundle: FlockExportBundle): unknown;\n merge?(replica: unknown): unknown;\n peerId?(): string;\n version(): unknown;\n exportFile?(): Uint8Array;\n subscribe?(listener: (batch: { source?: string }) => void): () => void;\n};\n\nfunction toVersionVector(version: JsonObject): FlockVersionVector {\n const out: FlockVersionVector = {};\n for (const [peer, raw] of Object.entries(version)) {\n if (typeof raw !== \"object\" || raw == null || Array.isArray(raw)) {\n continue;\n }\n const logicalCounter =\n typeof raw.logicalCounter === \"number\" ? raw.logicalCounter : undefined;\n if (logicalCounter == null || !Number.isFinite(logicalCounter)) {\n continue;\n }\n out[peer] =\n typeof raw.physicalTime === \"number\" && Number.isFinite(raw.physicalTime)\n ? { logicalCounter, physicalTime: raw.physicalTime }\n : { logicalCounter };\n }\n return out;\n}\n\nfunction fromVersionVector(version: FlockVersionVector): JsonObject {\n const out: Record<string, JsonObject> = {};\n for (const [peer, entry] of Object.entries(version)) {\n out[peer] =\n entry.physicalTime === undefined\n ? { logicalCounter: entry.logicalCounter }\n : {\n logicalCounter: entry.logicalCounter,\n physicalTime: entry.physicalTime,\n };\n }\n return out;\n}\n\nfunction mergeVersions(\n base: FlockVersionVector,\n incoming: FlockVersionVector,\n): FlockVersionVector {\n const merged: FlockVersionVector = { ...base };\n for (const [peer, entry] of Object.entries(incoming)) {\n const current = merged[peer];\n if (current == null || entry.logicalCounter > current.logicalCounter) {\n merged[peer] = { ...entry };\n continue;\n }\n if (entry.logicalCounter < current.logicalCounter) {\n continue;\n }\n const physicalTime = Math.max(\n current.physicalTime ?? Number.NEGATIVE_INFINITY,\n entry.physicalTime ?? Number.NEGATIVE_INFINITY,\n );\n merged[peer] =\n physicalTime === Number.NEGATIVE_INFINITY\n ? { logicalCounter: current.logicalCounter }\n : { logicalCounter: current.logicalCounter, physicalTime };\n }\n return merged;\n}\n\nfunction extractVersionFromBundle(\n bundle: FlockExportBundle,\n): FlockVersionVector {\n const out: FlockVersionVector = {};\n for (const raw of Object.values(bundle.entries)) {\n if (typeof raw !== \"object\" || raw == null || Array.isArray(raw)) {\n continue;\n }\n const entry = raw as {\n peerId?: unknown;\n logicalCounter?: unknown;\n counter?: unknown;\n physicalTime?: unknown;\n };\n if (typeof entry.peerId !== \"string\") {\n continue;\n }\n const logicalCounter =\n typeof entry.logicalCounter === \"number\"\n ? entry.logicalCounter\n : typeof entry.counter === \"number\"\n ? entry.counter\n : undefined;\n if (logicalCounter == null || !Number.isFinite(logicalCounter)) {\n continue;\n }\n out[entry.peerId] =\n typeof entry.physicalTime === \"number\" &&\n Number.isFinite(entry.physicalTime)\n ? { logicalCounter, physicalTime: entry.physicalTime }\n : { logicalCounter };\n }\n return out;\n}\n\nfunction hasEntries(bundle: FlockExportBundle): boolean {\n return Object.keys(bundle.entries).length > 0;\n}\n\nfunction tryMergeSnapshotFromFile(\n flock: FlockLike,\n snapshot: Uint8Array,\n): FlockVersionVector | null {\n if (typeof flock.merge !== \"function\") {\n return null;\n }\n const ctor = (\n flock as unknown as {\n readonly constructor?: {\n fromFile?: (bytes: Uint8Array, peerId?: string) => unknown;\n };\n }\n ).constructor;\n if (ctor == null || typeof ctor.fromFile !== \"function\") {\n return null;\n }\n try {\n const peerId =\n typeof flock.peerId === \"function\" ? flock.peerId() : undefined;\n const replica = ctor.fromFile(snapshot, peerId);\n flock.merge(replica);\n return toVersionVector((flock.version() as JsonObject) ?? {});\n } catch {\n return null;\n }\n}\n\n/**\n * Creates a `CrdtAdapter` for one Flock replica.\n */\nexport function createFlockAdapter(flock: FlockLike): CrdtAdapter<JsonObject> {\n let lastExportedVersion: FlockVersionVector = {};\n let localExportQueue = Promise.resolve();\n\n const recordExportFrontier = (version: FlockVersionVector): void => {\n lastExportedVersion = mergeVersions(lastExportedVersion, version);\n };\n\n return {\n emptyVersion: () => ({}),\n mergeVersions: (base, incoming) =>\n fromVersionVector(\n mergeVersions(toVersionVector(base), toVersionVector(incoming)),\n ),\n exportSnapshot: () => {\n if (typeof flock.exportFile === \"function\") {\n return flock.exportFile();\n }\n return new TextEncoder().encode(\n JSON.stringify({ version: 0, entries: {} }),\n );\n },\n applySnapshot: (snapshot) => {\n if (snapshot.byteLength === 0) {\n return {};\n }\n const mergedVersion = tryMergeSnapshotFromFile(flock, snapshot);\n if (mergedVersion != null) {\n return fromVersionVector(mergedVersion);\n }\n const bundle = JSON.parse(\n new TextDecoder().decode(snapshot),\n ) as FlockExportBundle;\n if (hasEntries(bundle)) {\n flock.importJson(bundle);\n }\n return fromVersionVector(extractVersionFromBundle(bundle));\n },\n exportUpdates: (fromVersion) => {\n const from = toVersionVector(fromVersion);\n const bundle = flock.exportJson({ from });\n recordExportFrontier(from);\n if (!hasEntries(bundle)) {\n return undefined;\n }\n const exportedVersion = extractVersionFromBundle(bundle);\n recordExportFrontier(exportedVersion);\n return {\n updates: [new TextEncoder().encode(JSON.stringify(bundle))],\n version: fromVersionVector(exportedVersion),\n };\n },\n applyRemoteUpdates: (updates, remoterVersion) => {\n let merged = toVersionVector(remoterVersion);\n for (const update of updates) {\n const bundle = JSON.parse(\n new TextDecoder().decode(update),\n ) as FlockExportBundle;\n if (!hasEntries(bundle)) {\n continue;\n }\n flock.importJson(bundle);\n merged = mergeVersions(merged, extractVersionFromBundle(bundle));\n }\n return fromVersionVector(merged);\n },\n subscribeLocalUpdates: (listener) => {\n if (typeof flock.subscribe !== \"function\") {\n return () => undefined;\n }\n const unsubscribe = flock.subscribe((batch) => {\n if (batch.source !== \"local\") {\n return;\n }\n const drain = () => {\n const peerId =\n typeof flock.peerId === \"function\" ? flock.peerId() : undefined;\n const batchPayload = flock.exportJson({\n from: lastExportedVersion,\n peerId,\n });\n if (!hasEntries(batchPayload)) {\n return;\n }\n const currentVersion = toVersionVector(\n fromVersionVector((flock.version() as FlockVersionVector) ?? {}),\n );\n recordExportFrontier(currentVersion);\n listener({\n updates: [new TextEncoder().encode(JSON.stringify(batchPayload))],\n version: fromVersionVector(extractVersionFromBundle(batchPayload)),\n });\n };\n\n localExportQueue = localExportQueue.then(drain).catch(() => {\n /* swallow to keep queue alive */\n });\n });\n return unsubscribe;\n },\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"flock.js","names":[],"sources":["../src/flock.ts"],"sourcesContent":["import { Flock } from \"@loro-dev/flock-wasm\";\nimport type {\n EventBatch,\n ExportBundle,\n ExportRecord,\n VersionVector,\n VersionVectorEntry,\n} from \"@loro-dev/flock-wasm\";\nimport type { CrdtAdapter } from \"./types\";\n\nexport { StreamsCrdt } from \"./transport\";\nexport * from \"./shared\";\nexport type { ExportBundle, VersionVector } from \"@loro-dev/flock-wasm\";\n\nfunction isAfter(\n entry: VersionVectorEntry,\n current: VersionVectorEntry,\n): boolean {\n return (\n entry.physicalTime > current.physicalTime ||\n (entry.physicalTime === current.physicalTime &&\n entry.logicalCounter > current.logicalCounter)\n );\n}\n\nfunction mergeVersions(\n base: VersionVector,\n incoming: VersionVector,\n): VersionVector {\n const merged: VersionVector = { ...base };\n for (const [peer, entry] of Object.entries(incoming)) {\n if (entry == null) {\n continue;\n }\n const current = merged[peer];\n if (current == null || isAfter(entry, current)) {\n merged[peer] = { ...entry };\n }\n }\n return merged;\n}\n\nfunction parseClock(\n record: ExportRecord,\n): { peerId: string; entry: VersionVectorEntry } | null {\n const firstComma = record.c.indexOf(\",\");\n const secondComma = record.c.indexOf(\",\", firstComma + 1);\n if (firstComma < 0 || secondComma < 0) {\n return null;\n }\n\n const physicalTime = Number(record.c.slice(0, firstComma));\n const logicalCounter = Number(record.c.slice(firstComma + 1, secondComma));\n if (!Number.isFinite(physicalTime) || !Number.isFinite(logicalCounter)) {\n return null;\n }\n\n return {\n peerId: record.c.slice(secondComma + 1),\n entry: { physicalTime, logicalCounter },\n };\n}\n\nfunction extractVersionFromBundle(bundle: ExportBundle): VersionVector {\n const out: VersionVector = {};\n for (const record of Object.values(bundle.entries)) {\n const parsed = parseClock(record);\n if (parsed == null) {\n continue;\n }\n const current = out[parsed.peerId];\n if (current == null || isAfter(parsed.entry, current)) {\n out[parsed.peerId] = parsed.entry;\n }\n }\n return out;\n}\n\nfunction hasEntries(bundle: ExportBundle): boolean {\n return Object.keys(bundle.entries).length > 0;\n}\n\n/**\n * Creates a `CrdtAdapter` for one Flock replica.\n */\nexport function createFlockAdapter(flock: Flock): CrdtAdapter<VersionVector> {\n let lastExportedVersion: VersionVector = {};\n let localExportQueue = Promise.resolve();\n\n const recordExportFrontier = (version: VersionVector): void => {\n lastExportedVersion = mergeVersions(lastExportedVersion, version);\n };\n\n return {\n emptyVersion: () => ({}),\n mergeVersions,\n exportSnapshot: () => flock.exportFile(),\n applySnapshot: (snapshot) => {\n flock.importFile(snapshot);\n return flock.version();\n },\n exportUpdates: (fromVersion) => {\n const bundle = flock.exportJson(fromVersion);\n recordExportFrontier(fromVersion);\n if (!hasEntries(bundle)) {\n return undefined;\n }\n const exportedVersion = extractVersionFromBundle(bundle);\n recordExportFrontier(exportedVersion);\n return {\n updates: [new TextEncoder().encode(JSON.stringify(bundle))],\n version: exportedVersion,\n };\n },\n applyRemoteUpdates: (updates, remoterVersion) => {\n let merged = remoterVersion;\n for (const update of updates) {\n const bundle = JSON.parse(\n new TextDecoder().decode(update),\n ) as ExportBundle;\n if (!hasEntries(bundle)) {\n continue;\n }\n flock.importJson(bundle);\n merged = mergeVersions(merged, extractVersionFromBundle(bundle));\n }\n return merged;\n },\n subscribeLocalUpdates: (listener) => {\n const unsubscribe = flock.subscribe((batch) => {\n if (batch.source !== \"local\") {\n return;\n }\n const drain = async () => {\n const batchPayload = await flock.exportJson({\n from: lastExportedVersion,\n peerId: flock.peerId(),\n });\n if (!hasEntries(batchPayload)) {\n return;\n }\n recordExportFrontier(flock.version());\n listener({\n updates: [new TextEncoder().encode(JSON.stringify(batchPayload))],\n version: extractVersionFromBundle(batchPayload),\n });\n };\n\n localExportQueue = localExportQueue.then(drain).catch(() => {\n /* swallow to keep queue alive */\n });\n });\n return unsubscribe;\n },\n };\n}\n"],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { A as
|
|
2
|
-
export { BeforeRemoteCursorSaveContext, BeforeRemoteCursorSaveHook, CrdtAdapter, CrdtUpdateBatch, InMemoryRemoteCursorStore, IndexedDbRemoteCursorStore, IndexedDbRemoteCursorStoreOptions, JsonObject, JsonValue, RemoteCursor, RemoteCursorSaveSource, RemoteCursorStore, Result, SnapshotCodec, SnapshotTransformHook, SnapshotUploadOptions, StreamsAuthProvider, StreamsCrdt, StreamsCrdtOptions, TransportCreateStreamSuccess, TransportDeleteStreamSuccess, TransportError, TransportJoinParams, TransportRoomStatus, TransportSubscription, TransportSyncSuccess, createInitialRemoteCursor, createStreamUrl, isValidBucketId, isValidRillId };
|
|
1
|
+
import { A as RemoteCursorStore, C as BeforeRemoteCursorSaveContext, D as IndexedDbRemoteCursorStoreOptions, E as IndexedDbRemoteCursorStore, O as RemoteCursor, S as TransportSyncSuccess, T as InMemoryRemoteCursorStore, _ as TransportDeleteStreamSuccess, a as CrdtAdapter, b as TransportRoomStatus, c as JsonValue, d as SnapshotTransformHook, f as SnapshotUploadOptions, g as TransportCreateStreamSuccess, h as StreamsCrdtOptions, i as StreamsCrdt, j as createInitialRemoteCursor, k as RemoteCursorSaveSource, l as Result, m as StreamsAuthProvider, n as isValidBucketId, o as CrdtUpdateBatch, p as StreamsAuthContext, r as isValidRillId, s as JsonObject, t as createStreamUrl, u as SnapshotCodec, v as TransportError, w as BeforeRemoteCursorSaveHook, x as TransportSubscription, y as TransportJoinParams } from "./stream-id-BxGVitUa.js";
|
|
2
|
+
export { BeforeRemoteCursorSaveContext, BeforeRemoteCursorSaveHook, CrdtAdapter, CrdtUpdateBatch, InMemoryRemoteCursorStore, IndexedDbRemoteCursorStore, IndexedDbRemoteCursorStoreOptions, JsonObject, JsonValue, RemoteCursor, RemoteCursorSaveSource, RemoteCursorStore, Result, SnapshotCodec, SnapshotTransformHook, SnapshotUploadOptions, StreamsAuthContext, StreamsAuthProvider, StreamsCrdt, StreamsCrdtOptions, TransportCreateStreamSuccess, TransportDeleteStreamSuccess, TransportError, TransportJoinParams, TransportRoomStatus, TransportSubscription, TransportSyncSuccess, createInitialRemoteCursor, createStreamUrl, isValidBucketId, isValidRillId };
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as InMemoryRemoteCursorStore, i as StreamsCrdt, n as isValidBucketId, o as IndexedDbRemoteCursorStore, r as isValidRillId, s as createInitialRemoteCursor, t as createStreamUrl } from "./stream-id-
|
|
1
|
+
import { a as InMemoryRemoteCursorStore, i as StreamsCrdt, n as isValidBucketId, o as IndexedDbRemoteCursorStore, r as isValidRillId, s as createInitialRemoteCursor, t as createStreamUrl } from "./stream-id-kM9JM1F7.js";
|
|
2
2
|
export { InMemoryRemoteCursorStore, IndexedDbRemoteCursorStore, StreamsCrdt, createInitialRemoteCursor, createStreamUrl, isValidBucketId, isValidRillId };
|
package/dist/loro.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { A as
|
|
1
|
+
import { A as RemoteCursorStore, C as BeforeRemoteCursorSaveContext, D as IndexedDbRemoteCursorStoreOptions, E as IndexedDbRemoteCursorStore, O as RemoteCursor, S as TransportSyncSuccess, T as InMemoryRemoteCursorStore, _ as TransportDeleteStreamSuccess, a as CrdtAdapter, b as TransportRoomStatus, c as JsonValue, d as SnapshotTransformHook, f as SnapshotUploadOptions, g as TransportCreateStreamSuccess, h as StreamsCrdtOptions, i as StreamsCrdt, j as createInitialRemoteCursor, k as RemoteCursorSaveSource, l as Result, m as StreamsAuthProvider, n as isValidBucketId, o as CrdtUpdateBatch, p as StreamsAuthContext, r as isValidRillId, s as JsonObject, t as createStreamUrl, u as SnapshotCodec, v as TransportError, w as BeforeRemoteCursorSaveHook, x as TransportSubscription, y as TransportJoinParams } from "./stream-id-BxGVitUa.js";
|
|
2
2
|
import { LoroDoc } from "loro-crdt";
|
|
3
3
|
|
|
4
4
|
//#region src/loro.d.ts
|
|
@@ -18,5 +18,5 @@ import { LoroDoc } from "loro-crdt";
|
|
|
18
18
|
*/
|
|
19
19
|
declare function createLoroDocAdapter(doc: LoroDoc): CrdtAdapter<JsonObject>;
|
|
20
20
|
//#endregion
|
|
21
|
-
export { BeforeRemoteCursorSaveContext, BeforeRemoteCursorSaveHook, CrdtAdapter, CrdtUpdateBatch, InMemoryRemoteCursorStore, IndexedDbRemoteCursorStore, IndexedDbRemoteCursorStoreOptions, JsonObject, JsonValue, RemoteCursor, RemoteCursorSaveSource, RemoteCursorStore, Result, SnapshotCodec, SnapshotTransformHook, SnapshotUploadOptions, StreamsAuthProvider, StreamsCrdt, StreamsCrdtOptions, TransportCreateStreamSuccess, TransportDeleteStreamSuccess, TransportError, TransportJoinParams, TransportRoomStatus, TransportSubscription, TransportSyncSuccess, createInitialRemoteCursor, createLoroDocAdapter, createStreamUrl, isValidBucketId, isValidRillId };
|
|
21
|
+
export { BeforeRemoteCursorSaveContext, BeforeRemoteCursorSaveHook, CrdtAdapter, CrdtUpdateBatch, InMemoryRemoteCursorStore, IndexedDbRemoteCursorStore, IndexedDbRemoteCursorStoreOptions, JsonObject, JsonValue, RemoteCursor, RemoteCursorSaveSource, RemoteCursorStore, Result, SnapshotCodec, SnapshotTransformHook, SnapshotUploadOptions, StreamsAuthContext, StreamsAuthProvider, StreamsCrdt, StreamsCrdtOptions, TransportCreateStreamSuccess, TransportDeleteStreamSuccess, TransportError, TransportJoinParams, TransportRoomStatus, TransportSubscription, TransportSyncSuccess, createInitialRemoteCursor, createLoroDocAdapter, createStreamUrl, isValidBucketId, isValidRillId };
|
|
22
22
|
//# sourceMappingURL=loro.d.ts.map
|
package/dist/loro.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as InMemoryRemoteCursorStore, i as StreamsCrdt, n as isValidBucketId, o as IndexedDbRemoteCursorStore, r as isValidRillId, s as createInitialRemoteCursor, t as createStreamUrl } from "./stream-id-
|
|
1
|
+
import { a as InMemoryRemoteCursorStore, i as StreamsCrdt, n as isValidBucketId, o as IndexedDbRemoteCursorStore, r as isValidRillId, s as createInitialRemoteCursor, t as createStreamUrl } from "./stream-id-kM9JM1F7.js";
|
|
2
2
|
import { VersionVector, decodeImportBlobMeta } from "loro-crdt";
|
|
3
3
|
//#region src/loro.ts
|
|
4
4
|
function toDocVersionRecord(version) {
|
|
@@ -119,15 +119,38 @@ type JsonPrimitive = string | number | boolean | null;
|
|
|
119
119
|
*/
|
|
120
120
|
type JsonValue = JsonPrimitive | JsonObject | JsonValue[];
|
|
121
121
|
/**
|
|
122
|
-
* JSON object shape used by public transport types.
|
|
122
|
+
* JSON-like object shape used by public transport types.
|
|
123
|
+
*
|
|
124
|
+
* Sparse records may expose `undefined` for omitted keys at runtime (for
|
|
125
|
+
* example Flock's `VersionVector` index signature), so object fields allow it.
|
|
123
126
|
*/
|
|
124
127
|
type JsonObject = {
|
|
125
|
-
readonly [key: string]: JsonValue;
|
|
128
|
+
readonly [key: string]: JsonValue | undefined;
|
|
126
129
|
};
|
|
127
130
|
/**
|
|
128
131
|
* Authorization source for gateway requests.
|
|
129
132
|
*/
|
|
130
|
-
type
|
|
133
|
+
type StreamsAuthContext = {
|
|
134
|
+
/** Default path before sending a request. */readonly reason: "request";
|
|
135
|
+
} | {
|
|
136
|
+
/**
|
|
137
|
+
* The previous request was rejected by the server with 401/403.
|
|
138
|
+
*
|
|
139
|
+
* Return a freshly refreshed token here when the caller keeps its own
|
|
140
|
+
* token cache.
|
|
141
|
+
*/
|
|
142
|
+
readonly reason: "unauthorized";
|
|
143
|
+
readonly status: 401 | 403;
|
|
144
|
+
readonly previousToken?: string;
|
|
145
|
+
};
|
|
146
|
+
/**
|
|
147
|
+
* Authorization source for gateway requests.
|
|
148
|
+
*
|
|
149
|
+
* The callback is invoked before each request. When a request comes back with
|
|
150
|
+
* 401/403, transport invokes it one more time with `reason: "unauthorized"`
|
|
151
|
+
* and retries that request once.
|
|
152
|
+
*/
|
|
153
|
+
type StreamsAuthProvider = string | ((context?: StreamsAuthContext) => MaybePromise<string | null | undefined>);
|
|
131
154
|
/**
|
|
132
155
|
* Rust-style result for transport operations that may fail for expected reasons.
|
|
133
156
|
*/
|
|
@@ -330,6 +353,13 @@ interface StreamsCrdtOptions<TVersion extends JsonObject> {
|
|
|
330
353
|
* Defaults to false so missing streams are surfaced explicitly.
|
|
331
354
|
*/
|
|
332
355
|
readonly createStreamIfMissing?: boolean;
|
|
356
|
+
/**
|
|
357
|
+
* Auth token source.
|
|
358
|
+
*
|
|
359
|
+
* String and zero-arg callback forms keep the old behavior. Callbacks may
|
|
360
|
+
* also inspect `context.reason` to refresh a cached token only after the
|
|
361
|
+
* server rejects the current one.
|
|
362
|
+
*/
|
|
333
363
|
readonly auth?: StreamsAuthProvider;
|
|
334
364
|
readonly fetch?: (input: string, init?: RequestInit) => Promise<Response>;
|
|
335
365
|
/**
|
|
@@ -433,10 +463,6 @@ declare class StreamsCrdt<TVersion extends JsonObject> implements StreamsCrdtLik
|
|
|
433
463
|
private syncOnce;
|
|
434
464
|
private performInitialJoinSync;
|
|
435
465
|
private bootstrapIntoState;
|
|
436
|
-
private bootstrapIntoJoinedState;
|
|
437
|
-
private bootstrapIntoJoinedStateViaSse;
|
|
438
|
-
private continueJoinedSseSessionUntilCaughtUp;
|
|
439
|
-
private bootstrapIntoJoinedStateViaLongPoll;
|
|
440
466
|
private catchup;
|
|
441
467
|
private appendLocalBatch;
|
|
442
468
|
private exportUpdates;
|
|
@@ -458,8 +484,6 @@ declare class StreamsCrdt<TVersion extends JsonObject> implements StreamsCrdtLik
|
|
|
458
484
|
private createStreamRequest;
|
|
459
485
|
private deleteStreamRequest;
|
|
460
486
|
private readFromOffsetSseItems;
|
|
461
|
-
private openBootstrapSseSession;
|
|
462
|
-
private readBootstrapLongPoll;
|
|
463
487
|
private readFromOffset;
|
|
464
488
|
private bootstrap;
|
|
465
489
|
private readSnapshotOffsetValue;
|
|
@@ -488,5 +512,5 @@ declare function createStreamUrl(input: {
|
|
|
488
512
|
baseUrl?: string;
|
|
489
513
|
}): string;
|
|
490
514
|
//#endregion
|
|
491
|
-
export {
|
|
492
|
-
//# sourceMappingURL=stream-id-
|
|
515
|
+
export { RemoteCursorStore as A, BeforeRemoteCursorSaveContext as C, IndexedDbRemoteCursorStoreOptions as D, IndexedDbRemoteCursorStore as E, RemoteCursor as O, TransportSyncSuccess as S, InMemoryRemoteCursorStore as T, TransportDeleteStreamSuccess as _, CrdtAdapter as a, TransportRoomStatus as b, JsonValue as c, SnapshotTransformHook as d, SnapshotUploadOptions as f, TransportCreateStreamSuccess as g, StreamsCrdtOptions as h, StreamsCrdt as i, createInitialRemoteCursor as j, RemoteCursorSaveSource as k, Result as l, StreamsAuthProvider as m, isValidBucketId as n, CrdtUpdateBatch as o, StreamsAuthContext as p, isValidRillId as r, JsonObject as s, createStreamUrl as t, SnapshotCodec as u, TransportError as v, BeforeRemoteCursorSaveHook as w, TransportSubscription as x, TransportJoinParams as y };
|
|
516
|
+
//# sourceMappingURL=stream-id-BxGVitUa.d.ts.map
|