@trestleinc/replicate 1.1.0 → 1.1.2-preview.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 +446 -260
- package/dist/client/index.d.ts +311 -19
- package/dist/client/index.js +4027 -0
- package/dist/component/_generated/api.d.ts +13 -17
- package/dist/component/_generated/api.js +24 -4
- package/dist/component/_generated/component.d.ts +79 -77
- package/dist/component/_generated/component.js +1 -0
- package/dist/component/_generated/dataModel.d.ts +12 -15
- package/dist/component/_generated/dataModel.js +1 -0
- package/dist/component/_generated/server.d.ts +19 -22
- package/dist/component/_generated/server.js +65 -1
- package/dist/component/_virtual/rolldown_runtime.js +18 -0
- package/dist/component/convex.config.d.ts +6 -2
- package/dist/component/convex.config.js +7 -3
- package/dist/component/logger.d.ts +10 -6
- package/dist/component/logger.js +25 -28
- package/dist/component/public.d.ts +70 -61
- package/dist/component/public.js +311 -295
- package/dist/component/schema.d.ts +53 -45
- package/dist/component/schema.js +26 -32
- package/dist/component/shared/types.d.ts +9 -0
- package/dist/component/shared/types.js +15 -0
- package/dist/server/index.d.ts +134 -13
- package/dist/server/index.js +368 -0
- package/dist/shared/index.d.ts +27 -3
- package/dist/shared/index.js +1 -2
- package/package.json +34 -29
- package/src/client/collection.ts +339 -306
- package/src/client/errors.ts +9 -9
- package/src/client/index.ts +13 -32
- package/src/client/logger.ts +2 -2
- package/src/client/merge.ts +37 -34
- package/src/client/persistence/custom.ts +84 -0
- package/src/client/persistence/index.ts +9 -46
- package/src/client/persistence/indexeddb.ts +111 -84
- package/src/client/persistence/memory.ts +3 -3
- package/src/client/persistence/sqlite/browser.ts +168 -0
- package/src/client/persistence/sqlite/native.ts +29 -0
- package/src/client/persistence/sqlite/schema.ts +124 -0
- package/src/client/persistence/types.ts +32 -28
- package/src/client/prose-schema.ts +55 -0
- package/src/client/prose.ts +28 -25
- package/src/client/replicate.ts +5 -5
- package/src/client/services/cursor.ts +109 -0
- package/src/component/_generated/component.ts +31 -29
- package/src/component/convex.config.ts +2 -2
- package/src/component/logger.ts +7 -7
- package/src/component/public.ts +225 -237
- package/src/component/schema.ts +18 -15
- package/src/server/builder.ts +20 -7
- package/src/server/index.ts +3 -5
- package/src/server/schema.ts +5 -5
- package/src/server/storage.ts +113 -59
- package/src/shared/index.ts +5 -5
- package/src/shared/types.ts +51 -14
- package/dist/client/collection.d.ts +0 -96
- package/dist/client/errors.d.ts +0 -59
- package/dist/client/logger.d.ts +0 -2
- package/dist/client/merge.d.ts +0 -77
- package/dist/client/persistence/adapters/index.d.ts +0 -8
- package/dist/client/persistence/adapters/opsqlite.d.ts +0 -46
- package/dist/client/persistence/adapters/sqljs.d.ts +0 -83
- package/dist/client/persistence/index.d.ts +0 -49
- package/dist/client/persistence/indexeddb.d.ts +0 -17
- package/dist/client/persistence/memory.d.ts +0 -16
- package/dist/client/persistence/sqlite-browser.d.ts +0 -51
- package/dist/client/persistence/sqlite-level.d.ts +0 -63
- package/dist/client/persistence/sqlite-rn.d.ts +0 -36
- package/dist/client/persistence/sqlite.d.ts +0 -47
- package/dist/client/persistence/types.d.ts +0 -42
- package/dist/client/prose.d.ts +0 -56
- package/dist/client/replicate.d.ts +0 -40
- package/dist/client/services/checkpoint.d.ts +0 -18
- package/dist/client/services/reconciliation.d.ts +0 -24
- package/dist/index.js +0 -1620
- package/dist/server/builder.d.ts +0 -94
- package/dist/server/schema.d.ts +0 -27
- package/dist/server/storage.d.ts +0 -80
- package/dist/server.js +0 -281
- package/dist/shared/types.d.ts +0 -50
- package/dist/shared/types.js +0 -6
- package/dist/shared.js +0 -6
- package/src/client/persistence/adapters/index.ts +0 -8
- package/src/client/persistence/adapters/opsqlite.ts +0 -54
- package/src/client/persistence/adapters/sqljs.ts +0 -128
- package/src/client/persistence/sqlite-browser.ts +0 -107
- package/src/client/persistence/sqlite-level.ts +0 -407
- package/src/client/persistence/sqlite-rn.ts +0 -44
- package/src/client/persistence/sqlite.ts +0 -161
- package/src/client/services/checkpoint.ts +0 -86
- package/src/client/services/reconciliation.ts +0 -108
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { ProseValue } from "$/shared/types";
|
|
3
|
+
|
|
4
|
+
const PROSE_MARKER = Symbol.for("replicate:prose");
|
|
5
|
+
|
|
6
|
+
function createProseSchema(): z.ZodType<ProseValue> {
|
|
7
|
+
const schema = z.custom<ProseValue>(
|
|
8
|
+
(val) => {
|
|
9
|
+
if (val == null) return true;
|
|
10
|
+
if (typeof val !== "object") return false;
|
|
11
|
+
return (val as { type?: string }).type === "doc";
|
|
12
|
+
},
|
|
13
|
+
{ message: "Expected prose document with type \"doc\"" },
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
Object.defineProperty(schema, PROSE_MARKER, { value: true, writable: false });
|
|
17
|
+
|
|
18
|
+
return schema;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function emptyProse(): ProseValue {
|
|
22
|
+
return { type: "doc", content: [] } as unknown as ProseValue;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function prose(): z.ZodType<ProseValue> {
|
|
26
|
+
return createProseSchema();
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
prose.empty = emptyProse;
|
|
30
|
+
|
|
31
|
+
export function isProseSchema(schema: unknown): boolean {
|
|
32
|
+
return (
|
|
33
|
+
schema != null
|
|
34
|
+
&& typeof schema === "object"
|
|
35
|
+
&& PROSE_MARKER in schema
|
|
36
|
+
&& (schema as Record<symbol, unknown>)[PROSE_MARKER] === true
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function extractProseFields(schema: z.ZodObject<z.ZodRawShape>): string[] {
|
|
41
|
+
const fields: string[] = [];
|
|
42
|
+
|
|
43
|
+
for (const [key, fieldSchema] of Object.entries(schema.shape)) {
|
|
44
|
+
let unwrapped = fieldSchema;
|
|
45
|
+
while (unwrapped instanceof z.ZodOptional || unwrapped instanceof z.ZodNullable) {
|
|
46
|
+
unwrapped = unwrapped.unwrap();
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (isProseSchema(unwrapped)) {
|
|
50
|
+
fields.push(key);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return fields;
|
|
55
|
+
}
|
package/src/client/prose.ts
CHANGED
|
@@ -5,15 +5,15 @@
|
|
|
5
5
|
* Uses document-level tracking to prevent race conditions.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import * as Y from
|
|
9
|
-
import type { Collection } from
|
|
10
|
-
import { getLogger } from
|
|
11
|
-
import { serializeYMapValue } from
|
|
8
|
+
import * as Y from "yjs";
|
|
9
|
+
import type { Collection } from "@tanstack/db";
|
|
10
|
+
import { getLogger } from "$/client/logger";
|
|
11
|
+
import { serializeYMapValue } from "$/client/merge";
|
|
12
12
|
|
|
13
13
|
/** Server origin - changes from server should not trigger local sync */
|
|
14
|
-
const SERVER_ORIGIN =
|
|
14
|
+
const SERVER_ORIGIN = "server";
|
|
15
15
|
|
|
16
|
-
const logger = getLogger([
|
|
16
|
+
const logger = getLogger(["replicate", "prose"]);
|
|
17
17
|
|
|
18
18
|
// Default debounce time for prose sync
|
|
19
19
|
const DEFAULT_DEBOUNCE_MS = 1000;
|
|
@@ -62,12 +62,13 @@ export function isApplyingFromServer(collection: string, documentId: string): bo
|
|
|
62
62
|
export function setApplyingFromServer(
|
|
63
63
|
collection: string,
|
|
64
64
|
documentId: string,
|
|
65
|
-
value: boolean
|
|
65
|
+
value: boolean,
|
|
66
66
|
): void {
|
|
67
67
|
const key = `${collection}:${documentId}`;
|
|
68
68
|
if (value) {
|
|
69
69
|
applyingFromServer.set(key, true);
|
|
70
|
-
}
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
71
72
|
applyingFromServer.delete(key);
|
|
72
73
|
}
|
|
73
74
|
}
|
|
@@ -89,8 +90,9 @@ function setPendingInternal(key: string, value: boolean): void {
|
|
|
89
90
|
for (const cb of listeners) {
|
|
90
91
|
try {
|
|
91
92
|
cb(value);
|
|
92
|
-
}
|
|
93
|
-
|
|
93
|
+
}
|
|
94
|
+
catch (err) {
|
|
95
|
+
logger.error("Pending listener error", { key, error: String(err) });
|
|
94
96
|
}
|
|
95
97
|
}
|
|
96
98
|
}
|
|
@@ -110,7 +112,7 @@ export function isPending(collection: string, documentId: string): boolean {
|
|
|
110
112
|
export function subscribePending(
|
|
111
113
|
collection: string,
|
|
112
114
|
documentId: string,
|
|
113
|
-
callback: (pending: boolean) => void
|
|
115
|
+
callback: (pending: boolean) => void,
|
|
114
116
|
): () => void {
|
|
115
117
|
const key = `${collection}:${documentId}`;
|
|
116
118
|
|
|
@@ -145,7 +147,7 @@ export function cancelPending(collection: string, documentId: string): void {
|
|
|
145
147
|
clearTimeout(timer);
|
|
146
148
|
debounceTimers.delete(key);
|
|
147
149
|
setPendingInternal(key, false);
|
|
148
|
-
logger.debug(
|
|
150
|
+
logger.debug("Cancelled pending sync due to remote update", { collection, documentId });
|
|
149
151
|
}
|
|
150
152
|
}
|
|
151
153
|
|
|
@@ -162,7 +164,7 @@ export function cancelAllPending(collection: string): void {
|
|
|
162
164
|
setPendingInternal(key, false);
|
|
163
165
|
}
|
|
164
166
|
}
|
|
165
|
-
logger.debug(
|
|
167
|
+
logger.debug("Cancelled all pending syncs", { collection });
|
|
166
168
|
}
|
|
167
169
|
|
|
168
170
|
// ============================================================================
|
|
@@ -201,7 +203,7 @@ export function observeFragment(config: ProseObserverConfig): () => void {
|
|
|
201
203
|
// Skip if already observing this document
|
|
202
204
|
const existingCleanup = fragmentObservers.get(key);
|
|
203
205
|
if (existingCleanup) {
|
|
204
|
-
logger.debug(
|
|
206
|
+
logger.debug("Fragment already being observed", { collection, documentId, field });
|
|
205
207
|
return existingCleanup;
|
|
206
208
|
}
|
|
207
209
|
|
|
@@ -224,7 +226,7 @@ export function observeFragment(config: ProseObserverConfig): () => void {
|
|
|
224
226
|
|
|
225
227
|
const itemYMap = ymap.get(documentId) as Y.Map<unknown> | undefined;
|
|
226
228
|
if (!itemYMap) {
|
|
227
|
-
logger.error(
|
|
229
|
+
logger.error("Document not found", { collection, documentId });
|
|
228
230
|
setPendingInternal(key, false);
|
|
229
231
|
return;
|
|
230
232
|
}
|
|
@@ -237,7 +239,7 @@ export function observeFragment(config: ProseObserverConfig): () => void {
|
|
|
237
239
|
: Y.encodeStateAsUpdateV2(ydoc);
|
|
238
240
|
|
|
239
241
|
if (delta.length <= 2) {
|
|
240
|
-
logger.debug(
|
|
242
|
+
logger.debug("No changes to sync", { collection, documentId });
|
|
241
243
|
setPendingInternal(key, false);
|
|
242
244
|
return;
|
|
243
245
|
}
|
|
@@ -245,7 +247,7 @@ export function observeFragment(config: ProseObserverConfig): () => void {
|
|
|
245
247
|
const crdtBytes = delta.buffer as ArrayBuffer;
|
|
246
248
|
const currentVector = Y.encodeStateVector(ydoc);
|
|
247
249
|
|
|
248
|
-
logger.debug(
|
|
250
|
+
logger.debug("Syncing prose delta", {
|
|
249
251
|
collection,
|
|
250
252
|
documentId,
|
|
251
253
|
deltaSize: delta.byteLength,
|
|
@@ -259,7 +261,7 @@ export function observeFragment(config: ProseObserverConfig): () => void {
|
|
|
259
261
|
{ metadata: { contentSync: { crdtBytes, materializedDoc } } },
|
|
260
262
|
(draft: any) => {
|
|
261
263
|
draft.updatedAt = Date.now();
|
|
262
|
-
}
|
|
264
|
+
},
|
|
263
265
|
);
|
|
264
266
|
await result.isPersisted.promise;
|
|
265
267
|
|
|
@@ -267,9 +269,10 @@ export function observeFragment(config: ProseObserverConfig): () => void {
|
|
|
267
269
|
lastSyncedVectors.set(key, currentVector);
|
|
268
270
|
failedSyncQueue.delete(key);
|
|
269
271
|
setPendingInternal(key, false);
|
|
270
|
-
logger.debug(
|
|
271
|
-
}
|
|
272
|
-
|
|
272
|
+
logger.debug("Prose sync completed", { collection, documentId });
|
|
273
|
+
}
|
|
274
|
+
catch (err) {
|
|
275
|
+
logger.error("Prose sync failed, queued for retry", {
|
|
273
276
|
collection,
|
|
274
277
|
documentId,
|
|
275
278
|
error: String(err),
|
|
@@ -284,7 +287,7 @@ export function observeFragment(config: ProseObserverConfig): () => void {
|
|
|
284
287
|
// Also retry any failed syncs for this document
|
|
285
288
|
if (failedSyncQueue.has(key)) {
|
|
286
289
|
failedSyncQueue.delete(key);
|
|
287
|
-
logger.debug(
|
|
290
|
+
logger.debug("Retrying failed sync", { collection, documentId });
|
|
288
291
|
}
|
|
289
292
|
};
|
|
290
293
|
|
|
@@ -296,11 +299,11 @@ export function observeFragment(config: ProseObserverConfig): () => void {
|
|
|
296
299
|
cancelPending(collection, documentId);
|
|
297
300
|
fragmentObservers.delete(key);
|
|
298
301
|
lastSyncedVectors.delete(key);
|
|
299
|
-
logger.debug(
|
|
302
|
+
logger.debug("Fragment observer cleaned up", { collection, documentId, field });
|
|
300
303
|
};
|
|
301
304
|
|
|
302
305
|
fragmentObservers.set(key, cleanup);
|
|
303
|
-
logger.debug(
|
|
306
|
+
logger.debug("Fragment observer registered", { collection, documentId, field });
|
|
304
307
|
|
|
305
308
|
return cleanup;
|
|
306
309
|
}
|
|
@@ -365,5 +368,5 @@ export function cleanup(collection: string): void {
|
|
|
365
368
|
}
|
|
366
369
|
}
|
|
367
370
|
|
|
368
|
-
logger.debug(
|
|
371
|
+
logger.debug("Prose cleanup complete", { collection });
|
|
369
372
|
}
|
package/src/client/replicate.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
export interface ReplicateParams {
|
|
9
9
|
readonly begin: () => void;
|
|
10
|
-
readonly write: (message: { type:
|
|
10
|
+
readonly write: (message: { type: "insert" | "update" | "delete"; value: unknown }) => void;
|
|
11
11
|
readonly commit: () => void;
|
|
12
12
|
readonly truncate: () => void;
|
|
13
13
|
}
|
|
@@ -41,7 +41,7 @@ export function createReplicateOps<T>(params: ReplicateParams): BoundReplicateOp
|
|
|
41
41
|
insert(items: T[]): void {
|
|
42
42
|
params.begin();
|
|
43
43
|
for (const item of items) {
|
|
44
|
-
params.write({ type:
|
|
44
|
+
params.write({ type: "insert", value: item });
|
|
45
45
|
}
|
|
46
46
|
params.commit();
|
|
47
47
|
},
|
|
@@ -49,7 +49,7 @@ export function createReplicateOps<T>(params: ReplicateParams): BoundReplicateOp
|
|
|
49
49
|
delete(items: T[]): void {
|
|
50
50
|
params.begin();
|
|
51
51
|
for (const item of items) {
|
|
52
|
-
params.write({ type:
|
|
52
|
+
params.write({ type: "delete", value: item });
|
|
53
53
|
}
|
|
54
54
|
params.commit();
|
|
55
55
|
},
|
|
@@ -58,7 +58,7 @@ export function createReplicateOps<T>(params: ReplicateParams): BoundReplicateOp
|
|
|
58
58
|
upsert(items: T[]): void {
|
|
59
59
|
params.begin();
|
|
60
60
|
for (const item of items) {
|
|
61
|
-
params.write({ type:
|
|
61
|
+
params.write({ type: "update", value: item });
|
|
62
62
|
}
|
|
63
63
|
params.commit();
|
|
64
64
|
},
|
|
@@ -67,7 +67,7 @@ export function createReplicateOps<T>(params: ReplicateParams): BoundReplicateOp
|
|
|
67
67
|
params.begin();
|
|
68
68
|
params.truncate();
|
|
69
69
|
for (const item of items) {
|
|
70
|
-
params.write({ type:
|
|
70
|
+
params.write({ type: "insert", value: item });
|
|
71
71
|
}
|
|
72
72
|
params.commit();
|
|
73
73
|
},
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { Effect, Context, Layer } from "effect";
|
|
2
|
+
import { IDBError, IDBWriteError } from "$/client/errors";
|
|
3
|
+
import type { KeyValueStore } from "$/client/persistence/types";
|
|
4
|
+
|
|
5
|
+
export type Cursor = number;
|
|
6
|
+
|
|
7
|
+
export class CursorService extends Context.Tag("CursorService")<
|
|
8
|
+
CursorService,
|
|
9
|
+
{
|
|
10
|
+
readonly loadCursor: (collection: string) => Effect.Effect<Cursor, IDBError>;
|
|
11
|
+
readonly saveCursor: (collection: string, cursor: Cursor) => Effect.Effect<void, IDBWriteError>;
|
|
12
|
+
readonly clearCursor: (collection: string) => Effect.Effect<void, IDBError>;
|
|
13
|
+
readonly loadPeerId: (collection: string) => Effect.Effect<string, IDBError | IDBWriteError>;
|
|
14
|
+
}
|
|
15
|
+
>() {}
|
|
16
|
+
|
|
17
|
+
function generatePeerId(): string {
|
|
18
|
+
return crypto.randomUUID();
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function createCursorLayer(kv: KeyValueStore) {
|
|
22
|
+
return Layer.succeed(
|
|
23
|
+
CursorService,
|
|
24
|
+
CursorService.of({
|
|
25
|
+
loadCursor: collection =>
|
|
26
|
+
Effect.gen(function* (_) {
|
|
27
|
+
const key = `cursor:${collection}`;
|
|
28
|
+
const stored = yield* _(
|
|
29
|
+
Effect.tryPromise({
|
|
30
|
+
try: () => kv.get<Cursor>(key),
|
|
31
|
+
catch: cause => new IDBError({ operation: "get", key, cause }),
|
|
32
|
+
}),
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
if (stored !== undefined) {
|
|
36
|
+
yield* _(
|
|
37
|
+
Effect.logDebug("Loaded cursor from storage", {
|
|
38
|
+
collection,
|
|
39
|
+
cursor: stored,
|
|
40
|
+
}),
|
|
41
|
+
);
|
|
42
|
+
return stored;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
yield* _(
|
|
46
|
+
Effect.logDebug("No stored cursor, using default", {
|
|
47
|
+
collection,
|
|
48
|
+
}),
|
|
49
|
+
);
|
|
50
|
+
return 0;
|
|
51
|
+
}),
|
|
52
|
+
|
|
53
|
+
saveCursor: (collection, cursor) =>
|
|
54
|
+
Effect.gen(function* (_) {
|
|
55
|
+
const key = `cursor:${collection}`;
|
|
56
|
+
yield* _(
|
|
57
|
+
Effect.tryPromise({
|
|
58
|
+
try: () => kv.set(key, cursor),
|
|
59
|
+
catch: cause => new IDBWriteError({ key, value: cursor, cause }),
|
|
60
|
+
}),
|
|
61
|
+
);
|
|
62
|
+
yield* _(
|
|
63
|
+
Effect.logDebug("Cursor saved", {
|
|
64
|
+
collection,
|
|
65
|
+
cursor,
|
|
66
|
+
}),
|
|
67
|
+
);
|
|
68
|
+
}),
|
|
69
|
+
|
|
70
|
+
clearCursor: collection =>
|
|
71
|
+
Effect.gen(function* (_) {
|
|
72
|
+
const key = `cursor:${collection}`;
|
|
73
|
+
yield* _(
|
|
74
|
+
Effect.tryPromise({
|
|
75
|
+
try: () => kv.del(key),
|
|
76
|
+
catch: cause => new IDBError({ operation: "delete", key, cause }),
|
|
77
|
+
}),
|
|
78
|
+
);
|
|
79
|
+
yield* _(Effect.logDebug("Cursor cleared", { collection }));
|
|
80
|
+
}),
|
|
81
|
+
|
|
82
|
+
loadPeerId: collection =>
|
|
83
|
+
Effect.gen(function* (_) {
|
|
84
|
+
const key = `peerId:${collection}`;
|
|
85
|
+
const stored = yield* _(
|
|
86
|
+
Effect.tryPromise({
|
|
87
|
+
try: () => kv.get<string>(key),
|
|
88
|
+
catch: cause => new IDBError({ operation: "get", key, cause }),
|
|
89
|
+
}),
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
if (stored) {
|
|
93
|
+
yield* _(Effect.logDebug("Loaded peerId from storage", { collection, peerId: stored }));
|
|
94
|
+
return stored;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const newPeerId = generatePeerId();
|
|
98
|
+
yield* _(
|
|
99
|
+
Effect.tryPromise({
|
|
100
|
+
try: () => kv.set(key, newPeerId),
|
|
101
|
+
catch: cause => new IDBWriteError({ key, value: newPeerId, cause }),
|
|
102
|
+
}),
|
|
103
|
+
);
|
|
104
|
+
yield* _(Effect.logDebug("Generated new peerId", { collection, peerId: newPeerId }));
|
|
105
|
+
return newPeerId;
|
|
106
|
+
}),
|
|
107
|
+
}),
|
|
108
|
+
);
|
|
109
|
+
}
|
|
@@ -24,64 +24,72 @@ import type { FunctionReference } from "convex/server";
|
|
|
24
24
|
export type ComponentApi<Name extends string | undefined = string | undefined> =
|
|
25
25
|
{
|
|
26
26
|
public: {
|
|
27
|
-
|
|
27
|
+
compact: FunctionReference<
|
|
28
28
|
"mutation",
|
|
29
29
|
"internal",
|
|
30
30
|
{
|
|
31
31
|
collection: string;
|
|
32
|
-
crdtBytes: ArrayBuffer;
|
|
33
32
|
documentId: string;
|
|
34
|
-
|
|
35
|
-
|
|
33
|
+
peerTimeout?: number;
|
|
34
|
+
snapshotBytes: ArrayBuffer;
|
|
35
|
+
stateVector: ArrayBuffer;
|
|
36
36
|
},
|
|
37
|
-
{
|
|
37
|
+
{ removed: number; retained: number; success: boolean },
|
|
38
|
+
Name
|
|
39
|
+
>;
|
|
40
|
+
deleteDocument: FunctionReference<
|
|
41
|
+
"mutation",
|
|
42
|
+
"internal",
|
|
43
|
+
{ collection: string; crdtBytes: ArrayBuffer; documentId: string },
|
|
44
|
+
{ seq: number; success: boolean },
|
|
38
45
|
Name
|
|
39
46
|
>;
|
|
40
47
|
getInitialState: FunctionReference<
|
|
41
48
|
"query",
|
|
42
49
|
"internal",
|
|
43
50
|
{ collection: string },
|
|
44
|
-
{
|
|
51
|
+
{ crdtBytes: ArrayBuffer; cursor: number } | null,
|
|
45
52
|
Name
|
|
46
53
|
>;
|
|
47
54
|
insertDocument: FunctionReference<
|
|
48
55
|
"mutation",
|
|
49
56
|
"internal",
|
|
50
|
-
{
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
{
|
|
57
|
+
{ collection: string; crdtBytes: ArrayBuffer; documentId: string },
|
|
58
|
+
{ seq: number; success: boolean },
|
|
59
|
+
Name
|
|
60
|
+
>;
|
|
61
|
+
mark: FunctionReference<
|
|
62
|
+
"mutation",
|
|
63
|
+
"internal",
|
|
64
|
+
{ collection: string; peerId: string; syncedSeq: number },
|
|
65
|
+
null,
|
|
58
66
|
Name
|
|
59
67
|
>;
|
|
60
68
|
recovery: FunctionReference<
|
|
61
69
|
"query",
|
|
62
70
|
"internal",
|
|
63
71
|
{ clientStateVector: ArrayBuffer; collection: string },
|
|
64
|
-
{ diff?: ArrayBuffer; serverStateVector: ArrayBuffer },
|
|
72
|
+
{ cursor: number; diff?: ArrayBuffer; serverStateVector: ArrayBuffer },
|
|
65
73
|
Name
|
|
66
74
|
>;
|
|
67
75
|
stream: FunctionReference<
|
|
68
76
|
"query",
|
|
69
77
|
"internal",
|
|
70
78
|
{
|
|
71
|
-
checkpoint: { lastModified: number };
|
|
72
79
|
collection: string;
|
|
80
|
+
cursor: number;
|
|
73
81
|
limit?: number;
|
|
74
|
-
|
|
82
|
+
sizeThreshold?: number;
|
|
75
83
|
},
|
|
76
84
|
{
|
|
77
85
|
changes: Array<{
|
|
78
86
|
crdtBytes: ArrayBuffer;
|
|
79
|
-
documentId
|
|
87
|
+
documentId: string;
|
|
80
88
|
operationType: string;
|
|
81
|
-
|
|
82
|
-
version: number;
|
|
89
|
+
seq: number;
|
|
83
90
|
}>;
|
|
84
|
-
|
|
91
|
+
compact?: string;
|
|
92
|
+
cursor: number;
|
|
85
93
|
hasMore: boolean;
|
|
86
94
|
},
|
|
87
95
|
Name
|
|
@@ -89,14 +97,8 @@ export type ComponentApi<Name extends string | undefined = string | undefined> =
|
|
|
89
97
|
updateDocument: FunctionReference<
|
|
90
98
|
"mutation",
|
|
91
99
|
"internal",
|
|
92
|
-
{
|
|
93
|
-
|
|
94
|
-
crdtBytes: ArrayBuffer;
|
|
95
|
-
documentId: string;
|
|
96
|
-
threshold?: number;
|
|
97
|
-
version: number;
|
|
98
|
-
},
|
|
99
|
-
{ compacted?: boolean; success: boolean },
|
|
100
|
+
{ collection: string; crdtBytes: ArrayBuffer; documentId: string },
|
|
101
|
+
{ seq: number; success: boolean },
|
|
100
102
|
Name
|
|
101
103
|
>;
|
|
102
104
|
};
|
package/src/component/logger.ts
CHANGED
|
@@ -9,28 +9,28 @@ class ComponentLogger implements Logger {
|
|
|
9
9
|
constructor(private category: string[]) {}
|
|
10
10
|
|
|
11
11
|
private format(level: string, message: string, context?: Record<string, any>): string {
|
|
12
|
-
const prefix = `[${this.category.join(
|
|
13
|
-
const contextStr = context ? ` ${JSON.stringify(context)}` :
|
|
12
|
+
const prefix = `[${this.category.join(":")}]`;
|
|
13
|
+
const contextStr = context ? ` ${JSON.stringify(context)}` : "";
|
|
14
14
|
return `${prefix} ${level}: ${message}${contextStr}`;
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
debug(message: string, context?: Record<string, any>): void {
|
|
18
|
-
console.log(this.format(
|
|
18
|
+
console.log(this.format("DEBUG", message, context));
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
info(message: string, context?: Record<string, any>): void {
|
|
22
|
-
console.log(this.format(
|
|
22
|
+
console.log(this.format("INFO", message, context));
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
warn(message: string, context?: Record<string, any>): void {
|
|
26
|
-
console.warn(this.format(
|
|
26
|
+
console.warn(this.format("WARN", message, context));
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
error(message: string, context?: Record<string, any>): void {
|
|
30
|
-
console.error(this.format(
|
|
30
|
+
console.error(this.format("ERROR", message, context));
|
|
31
31
|
}
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
export function getLogger(category: string[]): Logger {
|
|
35
|
-
return new ComponentLogger([
|
|
35
|
+
return new ComponentLogger(["component", ...category]);
|
|
36
36
|
}
|