reflectdb 0.1.0 → 0.1.2
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 +500 -40
- package/dist/cjs/client/index.cjs +32 -17
- package/dist/cjs/client/index.d.cts +18 -3
- package/dist/cjs/client/storage/indexeddb.d.cts +1 -1
- package/dist/cjs/core/index.cjs +28 -28
- package/dist/cjs/core/index.d.cts +21 -9
- package/dist/cjs/react/index.cjs +48 -33
- package/dist/cjs/react/index.d.cts +23 -5
- package/dist/cjs/server/drizzle.cjs +2 -2
- package/dist/cjs/server/drizzle.d.cts +1 -1
- package/dist/cjs/server/ephemeral/index.cjs +180 -0
- package/dist/cjs/server/ephemeral/index.d.cts +102 -0
- package/dist/cjs/server/ephemeral/redis.cjs +226 -0
- package/dist/cjs/server/ephemeral/redis.d.cts +136 -0
- package/dist/cjs/server/index.cjs +238 -87
- package/dist/cjs/server/index.d.cts +196 -5
- package/dist/cjs/svelte/index.cjs +34 -19
- package/dist/cjs/svelte/index.d.cts +18 -3
- package/dist/cjs/transport/bun-ws.cjs +9 -9
- package/dist/cjs/transport/bun-ws.d.cts +1 -1
- package/dist/cjs/transport/polling.cjs +11 -11
- package/dist/cjs/transport/polling.d.cts +1 -1
- package/dist/cjs/transport/sse.cjs +11 -11
- package/dist/cjs/transport/sse.d.cts +1 -1
- package/dist/cjs/transport/ws.cjs +11 -11
- package/dist/cjs/transport/ws.d.cts +1 -1
- package/dist/cjs/vanilla/index.cjs +34 -19
- package/dist/cjs/vanilla/index.d.cts +18 -3
- package/dist/client/index.d.ts +18 -3
- package/dist/client/index.js +7 -7
- package/dist/client/storage/indexeddb.d.ts +1 -1
- package/dist/client/storage/indexeddb.js +1 -1
- package/dist/core/index.d.ts +21 -9
- package/dist/core/index.js +20 -20
- package/dist/react/index.d.ts +23 -5
- package/dist/react/index.js +23 -23
- package/dist/server/drizzle.d.ts +1 -1
- package/dist/server/drizzle.js +3 -3
- package/dist/server/ephemeral/index.d.ts +102 -0
- package/dist/server/ephemeral/index.js +9 -0
- package/dist/server/ephemeral/redis.d.ts +136 -0
- package/dist/server/ephemeral/redis.js +186 -0
- package/dist/server/index.d.ts +196 -5
- package/dist/server/index.js +184 -163
- package/dist/shared/{esm-ytrd3hbq.js → esm-8qbr4y0d.js} +18 -3
- package/dist/shared/{esm-wkwx6bd9.js → esm-ck88h30s.js} +10 -10
- package/dist/shared/esm-g0marxk7.js +134 -0
- package/dist/svelte/index.d.ts +18 -3
- package/dist/svelte/index.js +9 -9
- package/dist/transport/bun-ws.d.ts +1 -1
- package/dist/transport/bun-ws.js +1 -1
- package/dist/transport/polling.d.ts +1 -1
- package/dist/transport/polling.js +3 -3
- package/dist/transport/sse.d.ts +1 -1
- package/dist/transport/sse.js +3 -3
- package/dist/transport/ws.d.ts +1 -1
- package/dist/transport/ws.js +3 -3
- package/dist/vanilla/index.d.ts +18 -3
- package/dist/vanilla/index.js +9 -9
- package/package.json +66 -44
- /package/dist/shared/{esm-b7xs9cde.js → esm-k7kedp3y.js} +0 -0
|
@@ -41,16 +41,16 @@ var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
|
41
41
|
// src/core/types.ts
|
|
42
42
|
var exports_types = {};
|
|
43
43
|
__export(exports_types, {
|
|
44
|
-
|
|
45
|
-
isErrorReason: () => isErrorReason,
|
|
46
|
-
TransportSendError: () => TransportSendError,
|
|
47
|
-
TOMBSTONE_RETENTION_MS: () => TOMBSTONE_RETENTION_MS,
|
|
48
|
-
SUPPORTED_PROTOCOL_VERSIONS: () => SUPPORTED_PROTOCOL_VERSIONS,
|
|
49
|
-
SERVER_TOMBSTONE_RETENTION_MS: () => SERVER_TOMBSTONE_RETENTION_MS,
|
|
50
|
-
PROTOCOL_VERSION: () => PROTOCOL_VERSION,
|
|
51
|
-
MutationError: () => MutationError,
|
|
44
|
+
MAX_BATCH_SIZE: () => MAX_BATCH_SIZE,
|
|
52
45
|
MAX_CLOCK_DRIFT_MS: () => MAX_CLOCK_DRIFT_MS,
|
|
53
|
-
|
|
46
|
+
MutationError: () => MutationError,
|
|
47
|
+
PROTOCOL_VERSION: () => PROTOCOL_VERSION,
|
|
48
|
+
SERVER_TOMBSTONE_RETENTION_MS: () => SERVER_TOMBSTONE_RETENTION_MS,
|
|
49
|
+
SUPPORTED_PROTOCOL_VERSIONS: () => SUPPORTED_PROTOCOL_VERSIONS,
|
|
50
|
+
TOMBSTONE_RETENTION_MS: () => TOMBSTONE_RETENTION_MS,
|
|
51
|
+
TransportSendError: () => TransportSendError,
|
|
52
|
+
isErrorReason: () => isErrorReason,
|
|
53
|
+
reasonFromError: () => reasonFromError
|
|
54
54
|
});
|
|
55
55
|
function isErrorReason(value) {
|
|
56
56
|
return typeof value === "string" && VALID_ERROR_REASONS.has(value);
|
|
@@ -107,12 +107,12 @@ var init_types = __esm(() => {
|
|
|
107
107
|
// src/client/index.ts
|
|
108
108
|
var exports_client = {};
|
|
109
109
|
__export(exports_client, {
|
|
110
|
-
|
|
111
|
-
createSyncClient: () => createSyncClient,
|
|
112
|
-
createOpCreator: () => createOpCreator,
|
|
113
|
-
createMemoryStorage: () => createMemoryStorage,
|
|
110
|
+
ClientStore: () => ClientStore,
|
|
114
111
|
SyncClient: () => SyncClient,
|
|
115
|
-
|
|
112
|
+
createMemoryStorage: () => createMemoryStorage,
|
|
113
|
+
createOpCreator: () => createOpCreator,
|
|
114
|
+
createSyncClient: () => createSyncClient,
|
|
115
|
+
pushSafely: () => pushSafely
|
|
116
116
|
});
|
|
117
117
|
module.exports = __toCommonJS(exports_client);
|
|
118
118
|
|
|
@@ -414,7 +414,7 @@ class ClientStore {
|
|
|
414
414
|
if (existing?.serverHlc && compareHlc(hlc, existing.serverHlc) <= 0) {
|
|
415
415
|
return;
|
|
416
416
|
}
|
|
417
|
-
this.setRow(table, rowId, payload ?? {}, colClocks ?? { _row: hlc }, hlc);
|
|
417
|
+
this.setRow(table, rowId, this.withPk(table, rowId, payload ?? {}), colClocks ?? { _row: hlc }, hlc);
|
|
418
418
|
return;
|
|
419
419
|
}
|
|
420
420
|
const incomingClocks = colClocks ?? {};
|
|
@@ -435,7 +435,13 @@ class ClientStore {
|
|
|
435
435
|
}
|
|
436
436
|
const newRowHlc = existing.serverHlc && compareHlc(existing.serverHlc, hlc) >= 0 ? existing.serverHlc : hlc;
|
|
437
437
|
mergedClocks._row = newRowHlc;
|
|
438
|
-
this.setRow(table, rowId, mergedData, mergedClocks, newRowHlc);
|
|
438
|
+
this.setRow(table, rowId, this.withPk(table, rowId, mergedData), mergedClocks, newRowHlc);
|
|
439
|
+
}
|
|
440
|
+
withPk(table, rowId, data) {
|
|
441
|
+
const pk = this.tableMeta.get(table)?.pk ?? "id";
|
|
442
|
+
if (data[pk] !== undefined)
|
|
443
|
+
return data;
|
|
444
|
+
return { ...data, [pk]: rowId };
|
|
439
445
|
}
|
|
440
446
|
revertOp(opId, serverRow) {
|
|
441
447
|
const pending = this.pendingOps.find((p) => p.op.id === opId);
|
|
@@ -480,10 +486,19 @@ class ClientStore {
|
|
|
480
486
|
delete payload[field];
|
|
481
487
|
}
|
|
482
488
|
}
|
|
489
|
+
if (op.op === "insert" && payload) {
|
|
490
|
+
payload = this.withPk(op.table, op.rowId, payload);
|
|
491
|
+
}
|
|
483
492
|
if (op.op === "delete") {
|
|
484
493
|
this.setRow(op.table, op.rowId, null, { _row: op.hlc }, op.hlc);
|
|
485
494
|
} else if (op.op === "insert") {
|
|
486
|
-
this.
|
|
495
|
+
const existing = this.getRow(op.table, op.rowId);
|
|
496
|
+
if (existing?.data) {
|
|
497
|
+
const merged = { ...existing.data, ...payload };
|
|
498
|
+
this.setRow(op.table, op.rowId, merged, existing.colClocks, existing.serverHlc);
|
|
499
|
+
} else {
|
|
500
|
+
this.setRow(op.table, op.rowId, payload ?? {}, { _row: op.hlc }, op.hlc);
|
|
501
|
+
}
|
|
487
502
|
} else {
|
|
488
503
|
const existing = this.getRow(op.table, op.rowId);
|
|
489
504
|
if (existing?.data) {
|
|
@@ -285,6 +285,17 @@ declare class ClientStore {
|
|
|
285
285
|
clearTable(table: string): void;
|
|
286
286
|
applySnapshot(table: string, rows: Record<string, unknown>[], colClocks: Record<string, Record<string, string>>, append?: boolean, pk?: string): void;
|
|
287
287
|
applyDelta(table: string, op: string, rowId: string, payload: Record<string, unknown> | null, hlc: string, colClocks?: Record<string, string>): void;
|
|
288
|
+
/**
|
|
289
|
+
* Guarantee a materialized row carries its own primary key.
|
|
290
|
+
*
|
|
291
|
+
* A delta's payload is not always a whole row: eager broadcasts forward the
|
|
292
|
+
* writer's payload verbatim, and the typed API omits the pk from what a
|
|
293
|
+
* client may write — so an eagerly-broadcast insert describes a row with no
|
|
294
|
+
* id in it. Rows are addressed by `rowId` everywhere in the protocol, so the
|
|
295
|
+
* key is never in doubt; only the materialized object was missing it, and
|
|
296
|
+
* `rows.map(r => r.id)` came back undefined.
|
|
297
|
+
*/
|
|
298
|
+
private withPk;
|
|
288
299
|
revertOp(opId: string, serverRow: Record<string, unknown> | null | undefined): void;
|
|
289
300
|
setTableMeta(meta: Record<string, {
|
|
290
301
|
serverSet: string[];
|
|
@@ -475,11 +486,15 @@ interface DrizzleTableLike {
|
|
|
475
486
|
/**
|
|
476
487
|
* Value supplied per serverSet field in the schema's object form.
|
|
477
488
|
* Either a static value or a function that receives the request context.
|
|
489
|
+
*
|
|
490
|
+
* The static arm is enumerated rather than written as `unknown`: a union with
|
|
491
|
+
* `unknown` collapses to `unknown`, which strips the contextual type from the
|
|
492
|
+
* callback arm and makes every `(ctx) => …` an implicit `any` under `strict`.
|
|
478
493
|
*/
|
|
479
|
-
type ServerSetSchemaValue =
|
|
494
|
+
type ServerSetSchemaValue = ((ctx: {
|
|
480
495
|
auth: unknown;
|
|
481
496
|
params: unknown;
|
|
482
|
-
}) => unknown)
|
|
497
|
+
}) => unknown) | string | number | bigint | boolean | symbol | null | undefined | Date | readonly unknown[] | Record<string, unknown>;
|
|
483
498
|
/**
|
|
484
499
|
* Schema-side `serverSet` declaration. Two shapes:
|
|
485
500
|
* - `string[]` — keys only; values are supplied at `implement(...)` time.
|
|
@@ -626,4 +641,4 @@ interface TypedSyncClient<TQueries extends SyncQueryMap> {
|
|
|
626
641
|
subscribeEphemeral(key: string, listener: (event: EphemeralEvent) => void): () => void;
|
|
627
642
|
}
|
|
628
643
|
declare function createSyncClient<TQueries extends SyncQueryMap>(config: TypedSyncClientConfig<TQueries>): TypedSyncClient<TQueries>;
|
|
629
|
-
export {
|
|
644
|
+
export { ClientStorageAdapter, ClientStore, LocalRow, OpCreator, PendingOp, SyncClient, SyncClientConfig, SyncClientState, SyncOptions, TypedSyncClient, TypedSyncClientConfig, createMemoryStorage, createOpCreator, createSyncClient, pushSafely };
|
|
@@ -82,4 +82,4 @@ declare function createIndexedDBStorage(config: {
|
|
|
82
82
|
configVersion: number;
|
|
83
83
|
}, storage: ClientStorageAdapter) => void | Promise<void>;
|
|
84
84
|
}): ClientStorageAdapter;
|
|
85
|
-
export {
|
|
85
|
+
export { IndexedDBMigrationContext, createIndexedDBStorage };
|
package/dist/cjs/core/index.cjs
CHANGED
|
@@ -41,16 +41,16 @@ var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
|
41
41
|
// src/core/types.ts
|
|
42
42
|
var exports_types = {};
|
|
43
43
|
__export(exports_types, {
|
|
44
|
-
|
|
45
|
-
isErrorReason: () => isErrorReason,
|
|
46
|
-
TransportSendError: () => TransportSendError,
|
|
47
|
-
TOMBSTONE_RETENTION_MS: () => TOMBSTONE_RETENTION_MS,
|
|
48
|
-
SUPPORTED_PROTOCOL_VERSIONS: () => SUPPORTED_PROTOCOL_VERSIONS,
|
|
49
|
-
SERVER_TOMBSTONE_RETENTION_MS: () => SERVER_TOMBSTONE_RETENTION_MS,
|
|
50
|
-
PROTOCOL_VERSION: () => PROTOCOL_VERSION,
|
|
51
|
-
MutationError: () => MutationError,
|
|
44
|
+
MAX_BATCH_SIZE: () => MAX_BATCH_SIZE,
|
|
52
45
|
MAX_CLOCK_DRIFT_MS: () => MAX_CLOCK_DRIFT_MS,
|
|
53
|
-
|
|
46
|
+
MutationError: () => MutationError,
|
|
47
|
+
PROTOCOL_VERSION: () => PROTOCOL_VERSION,
|
|
48
|
+
SERVER_TOMBSTONE_RETENTION_MS: () => SERVER_TOMBSTONE_RETENTION_MS,
|
|
49
|
+
SUPPORTED_PROTOCOL_VERSIONS: () => SUPPORTED_PROTOCOL_VERSIONS,
|
|
50
|
+
TOMBSTONE_RETENTION_MS: () => TOMBSTONE_RETENTION_MS,
|
|
51
|
+
TransportSendError: () => TransportSendError,
|
|
52
|
+
isErrorReason: () => isErrorReason,
|
|
53
|
+
reasonFromError: () => reasonFromError
|
|
54
54
|
});
|
|
55
55
|
function isErrorReason(value) {
|
|
56
56
|
return typeof value === "string" && VALID_ERROR_REASONS.has(value);
|
|
@@ -107,26 +107,26 @@ var init_types = __esm(() => {
|
|
|
107
107
|
// src/core/index.ts
|
|
108
108
|
var exports_core = {};
|
|
109
109
|
__export(exports_core, {
|
|
110
|
-
|
|
111
|
-
unpackHlc: () => unpackHlc,
|
|
112
|
-
t: () => t,
|
|
113
|
-
sendHlc: () => sendHlc,
|
|
114
|
-
receiveHlc: () => receiveHlc,
|
|
115
|
-
reasonFromError: () => reasonFromError,
|
|
116
|
-
presence: () => presence,
|
|
117
|
-
packHlc: () => packHlc,
|
|
118
|
-
isErrorReason: () => isErrorReason,
|
|
119
|
-
defineSyncQueries: () => defineSyncQueries,
|
|
120
|
-
createHlc: () => createHlc,
|
|
121
|
-
compareHlc: () => compareHlc,
|
|
122
|
-
TransportSendError: () => TransportSendError,
|
|
123
|
-
TOMBSTONE_RETENTION_MS: () => TOMBSTONE_RETENTION_MS,
|
|
124
|
-
SUPPORTED_PROTOCOL_VERSIONS: () => SUPPORTED_PROTOCOL_VERSIONS,
|
|
125
|
-
SERVER_TOMBSTONE_RETENTION_MS: () => SERVER_TOMBSTONE_RETENTION_MS,
|
|
126
|
-
PROTOCOL_VERSION: () => PROTOCOL_VERSION,
|
|
127
|
-
MutationError: () => MutationError,
|
|
110
|
+
MAX_BATCH_SIZE: () => MAX_BATCH_SIZE,
|
|
128
111
|
MAX_CLOCK_DRIFT_MS: () => MAX_CLOCK_DRIFT_MS,
|
|
129
|
-
|
|
112
|
+
MutationError: () => MutationError,
|
|
113
|
+
PROTOCOL_VERSION: () => PROTOCOL_VERSION,
|
|
114
|
+
SERVER_TOMBSTONE_RETENTION_MS: () => SERVER_TOMBSTONE_RETENTION_MS,
|
|
115
|
+
SUPPORTED_PROTOCOL_VERSIONS: () => SUPPORTED_PROTOCOL_VERSIONS,
|
|
116
|
+
TOMBSTONE_RETENTION_MS: () => TOMBSTONE_RETENTION_MS,
|
|
117
|
+
TransportSendError: () => TransportSendError,
|
|
118
|
+
compareHlc: () => compareHlc,
|
|
119
|
+
createHlc: () => createHlc,
|
|
120
|
+
defineSyncQueries: () => defineSyncQueries,
|
|
121
|
+
isErrorReason: () => isErrorReason,
|
|
122
|
+
packHlc: () => packHlc,
|
|
123
|
+
presence: () => presence,
|
|
124
|
+
reasonFromError: () => reasonFromError,
|
|
125
|
+
receiveHlc: () => receiveHlc,
|
|
126
|
+
sendHlc: () => sendHlc,
|
|
127
|
+
t: () => t,
|
|
128
|
+
unpackHlc: () => unpackHlc,
|
|
129
|
+
view: () => view
|
|
130
130
|
});
|
|
131
131
|
module.exports = __toCommonJS(exports_core);
|
|
132
132
|
|
|
@@ -321,11 +321,15 @@ interface DrizzleTableLike {
|
|
|
321
321
|
/**
|
|
322
322
|
* Value supplied per serverSet field in the schema's object form.
|
|
323
323
|
* Either a static value or a function that receives the request context.
|
|
324
|
+
*
|
|
325
|
+
* The static arm is enumerated rather than written as `unknown`: a union with
|
|
326
|
+
* `unknown` collapses to `unknown`, which strips the contextual type from the
|
|
327
|
+
* callback arm and makes every `(ctx) => …` an implicit `any` under `strict`.
|
|
324
328
|
*/
|
|
325
|
-
type ServerSetSchemaValue =
|
|
329
|
+
type ServerSetSchemaValue = ((ctx: {
|
|
326
330
|
auth: unknown;
|
|
327
331
|
params: unknown;
|
|
328
|
-
}) => unknown)
|
|
332
|
+
}) => unknown) | string | number | bigint | boolean | symbol | null | undefined | Date | readonly unknown[] | Record<string, unknown>;
|
|
329
333
|
/**
|
|
330
334
|
* Schema-side `serverSet` declaration. Two shapes:
|
|
331
335
|
* - `string[]` — keys only; values are supplied at `implement(...)` time.
|
|
@@ -370,8 +374,8 @@ declare function view<
|
|
|
370
374
|
deps?: string[];
|
|
371
375
|
tables?: string[];
|
|
372
376
|
}): SyncViewDef & {
|
|
373
|
-
row
|
|
374
|
-
params
|
|
377
|
+
row: TRow;
|
|
378
|
+
params: TParams;
|
|
375
379
|
};
|
|
376
380
|
/**
|
|
377
381
|
* Typed ephemeral channel. Sugar over the runtime `useEphemeral` hook —
|
|
@@ -392,8 +396,8 @@ declare function presence<
|
|
|
392
396
|
params?: TParams;
|
|
393
397
|
ttlMs?: number;
|
|
394
398
|
}): SyncPresenceDef & {
|
|
395
|
-
state
|
|
396
|
-
params
|
|
399
|
+
state: TState;
|
|
400
|
+
params: TParams;
|
|
397
401
|
};
|
|
398
402
|
type SyncQueryEntry = SyncQueryDef | SyncViewDef | SyncPresenceDef;
|
|
399
403
|
type SyncQueryMap = Record<string, SyncQueryEntry>;
|
|
@@ -403,12 +407,20 @@ type ColumnOf<TDef> = TDef extends {
|
|
|
403
407
|
} ? keyof TDef["table"]["$inferSelect"] & string : TDef extends {
|
|
404
408
|
row: infer R extends Record<string, unknown>;
|
|
405
409
|
} ? keyof R & string : string;
|
|
406
|
-
/**
|
|
410
|
+
/**
|
|
411
|
+
* Constrain serverSet and readonly to valid column names. Accepts either array
|
|
412
|
+
* or object form for serverSet.
|
|
413
|
+
*
|
|
414
|
+
* View/presence entries carry neither field, so they get `unknown` — the
|
|
415
|
+
* identity of intersection. `Record<string, never>` reads like "no constraint"
|
|
416
|
+
* but means "an object with no properties", which every view and presence entry
|
|
417
|
+
* fails, making both helpers unusable inside `defineSyncQueries`.
|
|
418
|
+
*/
|
|
407
419
|
type FieldsConstraint<TDef> = TDef extends {
|
|
408
420
|
__view: true;
|
|
409
421
|
} | {
|
|
410
422
|
__presence: true;
|
|
411
|
-
} ?
|
|
423
|
+
} ? unknown : {
|
|
412
424
|
serverSet?: readonly ColumnOf<TDef>[] | Readonly<Partial<Record<ColumnOf<TDef>, ServerSetSchemaValue>>>;
|
|
413
425
|
readonly?: readonly ColumnOf<TDef>[];
|
|
414
426
|
};
|
|
@@ -470,4 +482,4 @@ type InferWritableRow<
|
|
|
470
482
|
} ? never : Omit<InferRow<TQueries, K>, (TQueries[K] extends {
|
|
471
483
|
readonly: readonly (infer R extends string)[];
|
|
472
484
|
} ? R : never) | InferServerSetKeys<TQueries[K]> | PkOf<TQueries[K]>>;
|
|
473
|
-
export {
|
|
485
|
+
export { AckMessage, AuthContext, AuthMessage, BootstrapCompleteMessage, BootstrapMessage, ClientMessage, ClientOp, ClientTransport, CompactionConfig, ConflictPolicy, ConflictResolver, CountChangedMessage, CustomConflictPolicy, DeltaMessage, Dialect, DisconnectMessage, DrizzleTableLike, EphemeralEvent, EphemeralMessage, ErrorReason, HLC, HelloAckMessage, HelloMessage, HelloRejectMessage, InferParams, InferRow, InferState, InferWritableRow, LoadMoreMessage, MAX_BATCH_SIZE, MAX_CLOCK_DRIFT_MS, MutationError, OpStatus, OpType, OpsMessage, PROTOCOL_VERSION, RateLimitConfig, ReauthMessage, RejectMessage, RequiresParams, ResumeCompleteMessage, ResumeMessage, ResumeRejectedMessage, SERVER_TOMBSTONE_RETENTION_MS, SUPPORTED_PROTOCOL_VERSIONS, ServerMessage, ServerTransport, ShapeChangedMessage, ShapeConfig, SnapshotMessage, SyncDeclareMessage, SyncError, SyncMessage, SyncOp, SyncPresenceDef, SyncQueryDef, SyncQueryEntry, SyncQueryMap, SyncViewDef, TOMBSTONE_RETENTION_MS, TableMeta, TransportSendError, UnsyncMessage, compareHlc, createHlc, defineSyncQueries, isErrorReason, packHlc, presence, reasonFromError, receiveHlc, sendHlc, t, unpackHlc, view };
|
package/dist/cjs/react/index.cjs
CHANGED
|
@@ -41,16 +41,16 @@ var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
|
41
41
|
// src/core/types.ts
|
|
42
42
|
var exports_types = {};
|
|
43
43
|
__export(exports_types, {
|
|
44
|
-
|
|
45
|
-
isErrorReason: () => isErrorReason,
|
|
46
|
-
TransportSendError: () => TransportSendError,
|
|
47
|
-
TOMBSTONE_RETENTION_MS: () => TOMBSTONE_RETENTION_MS,
|
|
48
|
-
SUPPORTED_PROTOCOL_VERSIONS: () => SUPPORTED_PROTOCOL_VERSIONS,
|
|
49
|
-
SERVER_TOMBSTONE_RETENTION_MS: () => SERVER_TOMBSTONE_RETENTION_MS,
|
|
50
|
-
PROTOCOL_VERSION: () => PROTOCOL_VERSION,
|
|
51
|
-
MutationError: () => MutationError,
|
|
44
|
+
MAX_BATCH_SIZE: () => MAX_BATCH_SIZE,
|
|
52
45
|
MAX_CLOCK_DRIFT_MS: () => MAX_CLOCK_DRIFT_MS,
|
|
53
|
-
|
|
46
|
+
MutationError: () => MutationError,
|
|
47
|
+
PROTOCOL_VERSION: () => PROTOCOL_VERSION,
|
|
48
|
+
SERVER_TOMBSTONE_RETENTION_MS: () => SERVER_TOMBSTONE_RETENTION_MS,
|
|
49
|
+
SUPPORTED_PROTOCOL_VERSIONS: () => SUPPORTED_PROTOCOL_VERSIONS,
|
|
50
|
+
TOMBSTONE_RETENTION_MS: () => TOMBSTONE_RETENTION_MS,
|
|
51
|
+
TransportSendError: () => TransportSendError,
|
|
52
|
+
isErrorReason: () => isErrorReason,
|
|
53
|
+
reasonFromError: () => reasonFromError
|
|
54
54
|
});
|
|
55
55
|
function isErrorReason(value) {
|
|
56
56
|
return typeof value === "string" && VALID_ERROR_REASONS.has(value);
|
|
@@ -107,18 +107,18 @@ var init_types = __esm(() => {
|
|
|
107
107
|
// src/react/index.ts
|
|
108
108
|
var exports_react = {};
|
|
109
109
|
__export(exports_react, {
|
|
110
|
-
|
|
111
|
-
useSyncStatus: () => useSyncStatus,
|
|
112
|
-
useSyncClient: () => useSyncClient,
|
|
113
|
-
useSync: () => useSync,
|
|
114
|
-
useRow: () => useRow,
|
|
115
|
-
usePendingCount: () => usePendingCount,
|
|
116
|
-
useLoadMore: () => useLoadMore,
|
|
117
|
-
useEphemeral: () => useEphemeral,
|
|
118
|
-
derivePresenceKey: () => derivePresenceKey,
|
|
119
|
-
createSyncReact: () => createSyncReact,
|
|
110
|
+
SyncContext: () => SyncContext,
|
|
120
111
|
SyncProvider: () => SyncProvider,
|
|
121
|
-
|
|
112
|
+
createSyncReact: () => createSyncReact,
|
|
113
|
+
derivePresenceKey: () => derivePresenceKey,
|
|
114
|
+
useEphemeral: () => useEphemeral,
|
|
115
|
+
useLoadMore: () => useLoadMore,
|
|
116
|
+
usePendingCount: () => usePendingCount,
|
|
117
|
+
useRow: () => useRow,
|
|
118
|
+
useSync: () => useSync,
|
|
119
|
+
useSyncClient: () => useSyncClient,
|
|
120
|
+
useSyncStatus: () => useSyncStatus,
|
|
121
|
+
useTotalCount: () => useTotalCount
|
|
122
122
|
});
|
|
123
123
|
module.exports = __toCommonJS(exports_react);
|
|
124
124
|
|
|
@@ -427,7 +427,7 @@ class ClientStore {
|
|
|
427
427
|
if (existing?.serverHlc && compareHlc(hlc, existing.serverHlc) <= 0) {
|
|
428
428
|
return;
|
|
429
429
|
}
|
|
430
|
-
this.setRow(table, rowId, payload ?? {}, colClocks ?? { _row: hlc }, hlc);
|
|
430
|
+
this.setRow(table, rowId, this.withPk(table, rowId, payload ?? {}), colClocks ?? { _row: hlc }, hlc);
|
|
431
431
|
return;
|
|
432
432
|
}
|
|
433
433
|
const incomingClocks = colClocks ?? {};
|
|
@@ -448,7 +448,13 @@ class ClientStore {
|
|
|
448
448
|
}
|
|
449
449
|
const newRowHlc = existing.serverHlc && compareHlc(existing.serverHlc, hlc) >= 0 ? existing.serverHlc : hlc;
|
|
450
450
|
mergedClocks._row = newRowHlc;
|
|
451
|
-
this.setRow(table, rowId, mergedData, mergedClocks, newRowHlc);
|
|
451
|
+
this.setRow(table, rowId, this.withPk(table, rowId, mergedData), mergedClocks, newRowHlc);
|
|
452
|
+
}
|
|
453
|
+
withPk(table, rowId, data) {
|
|
454
|
+
const pk = this.tableMeta.get(table)?.pk ?? "id";
|
|
455
|
+
if (data[pk] !== undefined)
|
|
456
|
+
return data;
|
|
457
|
+
return { ...data, [pk]: rowId };
|
|
452
458
|
}
|
|
453
459
|
revertOp(opId, serverRow) {
|
|
454
460
|
const pending = this.pendingOps.find((p) => p.op.id === opId);
|
|
@@ -493,10 +499,19 @@ class ClientStore {
|
|
|
493
499
|
delete payload[field];
|
|
494
500
|
}
|
|
495
501
|
}
|
|
502
|
+
if (op.op === "insert" && payload) {
|
|
503
|
+
payload = this.withPk(op.table, op.rowId, payload);
|
|
504
|
+
}
|
|
496
505
|
if (op.op === "delete") {
|
|
497
506
|
this.setRow(op.table, op.rowId, null, { _row: op.hlc }, op.hlc);
|
|
498
507
|
} else if (op.op === "insert") {
|
|
499
|
-
this.
|
|
508
|
+
const existing = this.getRow(op.table, op.rowId);
|
|
509
|
+
if (existing?.data) {
|
|
510
|
+
const merged = { ...existing.data, ...payload };
|
|
511
|
+
this.setRow(op.table, op.rowId, merged, existing.colClocks, existing.serverHlc);
|
|
512
|
+
} else {
|
|
513
|
+
this.setRow(op.table, op.rowId, payload ?? {}, { _row: op.hlc }, op.hlc);
|
|
514
|
+
}
|
|
500
515
|
} else {
|
|
501
516
|
const existing = this.getRow(op.table, op.rowId);
|
|
502
517
|
if (existing?.data) {
|
|
@@ -1176,7 +1191,7 @@ function pushSafely(client) {
|
|
|
1176
1191
|
}
|
|
1177
1192
|
|
|
1178
1193
|
// src/react/context.tsx
|
|
1179
|
-
var
|
|
1194
|
+
var jsx_runtime = require("react/jsx-runtime");
|
|
1180
1195
|
var SyncContext = import_react.createContext(null);
|
|
1181
1196
|
function createBrowserWsTransport(url) {
|
|
1182
1197
|
let ws = null;
|
|
@@ -1292,10 +1307,10 @@ function SyncProvider({
|
|
|
1292
1307
|
}, [url, clientId, storage, managedTables]);
|
|
1293
1308
|
if (!ctx)
|
|
1294
1309
|
return null;
|
|
1295
|
-
return /* @__PURE__ */
|
|
1310
|
+
return /* @__PURE__ */ jsx_runtime.jsx(SyncContext.Provider, {
|
|
1296
1311
|
value: ctx,
|
|
1297
1312
|
children
|
|
1298
|
-
}
|
|
1313
|
+
});
|
|
1299
1314
|
}
|
|
1300
1315
|
function useSyncClient() {
|
|
1301
1316
|
const ctx = import_react.useContext(SyncContext);
|
|
@@ -1361,21 +1376,21 @@ function useEphemeral(config) {
|
|
|
1361
1376
|
const timersRef = import_react2.useRef(new Map);
|
|
1362
1377
|
import_react2.useEffect(() => {
|
|
1363
1378
|
const unsub = client.subscribeEphemeral(config.key, (event) => {
|
|
1364
|
-
setEvents((prev) => ({ ...prev, [event.
|
|
1379
|
+
setEvents((prev) => ({ ...prev, [event.clientId]: event.data }));
|
|
1365
1380
|
if (config.ttlMs) {
|
|
1366
|
-
const existing = timersRef.current.get(event.
|
|
1381
|
+
const existing = timersRef.current.get(event.clientId);
|
|
1367
1382
|
if (existing) {
|
|
1368
1383
|
clearTimeout(existing);
|
|
1369
1384
|
}
|
|
1370
1385
|
const timer = setTimeout(() => {
|
|
1371
1386
|
setEvents((prev) => {
|
|
1372
1387
|
const next = { ...prev };
|
|
1373
|
-
delete next[event.
|
|
1388
|
+
delete next[event.clientId];
|
|
1374
1389
|
return next;
|
|
1375
1390
|
});
|
|
1376
|
-
timersRef.current.delete(event.
|
|
1391
|
+
timersRef.current.delete(event.clientId);
|
|
1377
1392
|
}, config.ttlMs);
|
|
1378
|
-
timersRef.current.set(event.
|
|
1393
|
+
timersRef.current.set(event.clientId, timer);
|
|
1379
1394
|
}
|
|
1380
1395
|
});
|
|
1381
1396
|
return () => {
|
|
@@ -1492,8 +1507,8 @@ function createSyncReact(queries) {
|
|
|
1492
1507
|
userId,
|
|
1493
1508
|
ttlMs
|
|
1494
1509
|
});
|
|
1495
|
-
const peers = import_react3.useMemo(() => Object.entries(events).map(([
|
|
1496
|
-
userId:
|
|
1510
|
+
const peers = import_react3.useMemo(() => Object.entries(events).map(([peerId, state]) => ({
|
|
1511
|
+
userId: peerId,
|
|
1497
1512
|
state
|
|
1498
1513
|
})), [events]);
|
|
1499
1514
|
return { peers, set: broadcast };
|
|
@@ -268,6 +268,17 @@ declare class ClientStore {
|
|
|
268
268
|
clearTable(table: string): void;
|
|
269
269
|
applySnapshot(table: string, rows: Record<string, unknown>[], colClocks: Record<string, Record<string, string>>, append?: boolean, pk?: string): void;
|
|
270
270
|
applyDelta(table: string, op: string, rowId: string, payload: Record<string, unknown> | null, hlc: string, colClocks?: Record<string, string>): void;
|
|
271
|
+
/**
|
|
272
|
+
* Guarantee a materialized row carries its own primary key.
|
|
273
|
+
*
|
|
274
|
+
* A delta's payload is not always a whole row: eager broadcasts forward the
|
|
275
|
+
* writer's payload verbatim, and the typed API omits the pk from what a
|
|
276
|
+
* client may write — so an eagerly-broadcast insert describes a row with no
|
|
277
|
+
* id in it. Rows are addressed by `rowId` everywhere in the protocol, so the
|
|
278
|
+
* key is never in doubt; only the materialized object was missing it, and
|
|
279
|
+
* `rows.map(r => r.id)` came back undefined.
|
|
280
|
+
*/
|
|
281
|
+
private withPk;
|
|
271
282
|
revertOp(opId: string, serverRow: Record<string, unknown> | null | undefined): void;
|
|
272
283
|
setTableMeta(meta: Record<string, {
|
|
273
284
|
serverSet: string[];
|
|
@@ -531,6 +542,9 @@ declare function usePendingCount2(): number;
|
|
|
531
542
|
*
|
|
532
543
|
* ```tsx
|
|
533
544
|
* function CursorTracker({ userId }: { userId: string }) {
|
|
545
|
+
* `events` is keyed by the peer's `clientId`, so two tabs from one account
|
|
546
|
+
* appear as two peers.
|
|
547
|
+
*
|
|
534
548
|
* const { events, broadcast } = useEphemeral({
|
|
535
549
|
* key: "cursor",
|
|
536
550
|
* userId,
|
|
@@ -546,8 +560,8 @@ declare function usePendingCount2(): number;
|
|
|
546
560
|
*
|
|
547
561
|
* return (
|
|
548
562
|
* <div>
|
|
549
|
-
* {Object.entries(events).map(([
|
|
550
|
-
* <div key={
|
|
563
|
+
* {Object.entries(events).map(([peerId, data]) => (
|
|
564
|
+
* <div key={peerId}>Peer {peerId}: {JSON.stringify(data)}</div>
|
|
551
565
|
* ))}
|
|
552
566
|
* </div>
|
|
553
567
|
* );
|
|
@@ -579,11 +593,15 @@ interface DrizzleTableLike {
|
|
|
579
593
|
/**
|
|
580
594
|
* Value supplied per serverSet field in the schema's object form.
|
|
581
595
|
* Either a static value or a function that receives the request context.
|
|
596
|
+
*
|
|
597
|
+
* The static arm is enumerated rather than written as `unknown`: a union with
|
|
598
|
+
* `unknown` collapses to `unknown`, which strips the contextual type from the
|
|
599
|
+
* callback arm and makes every `(ctx) => …` an implicit `any` under `strict`.
|
|
582
600
|
*/
|
|
583
|
-
type ServerSetSchemaValue =
|
|
601
|
+
type ServerSetSchemaValue = ((ctx: {
|
|
584
602
|
auth: unknown;
|
|
585
603
|
params: unknown;
|
|
586
|
-
}) => unknown)
|
|
604
|
+
}) => unknown) | string | number | bigint | boolean | symbol | null | undefined | Date | readonly unknown[] | Record<string, unknown>;
|
|
587
605
|
/**
|
|
588
606
|
* Schema-side `serverSet` declaration. Two shapes:
|
|
589
607
|
* - `string[]` — keys only; values are supplied at `implement(...)` time.
|
|
@@ -745,4 +763,4 @@ type UseSyncOptions<
|
|
|
745
763
|
window?: number;
|
|
746
764
|
};
|
|
747
765
|
declare function createSyncReact<TQueries extends SyncQueryMap>(queries?: TQueries): SyncReactHooks<TQueries>;
|
|
748
|
-
export {
|
|
766
|
+
export { SyncContext, SyncProvider2 as SyncProvider, SyncProviderProps, createSyncReact, derivePresenceKey, useEphemeral2 as useEphemeral, useLoadMore2 as useLoadMore, usePendingCount2 as usePendingCount, useRow2 as useRow, useSync2 as useSync, useSyncClient, useSyncStatus2 as useSyncStatus, useTotalCount2 as useTotalCount };
|
|
@@ -41,8 +41,8 @@ var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
|
41
41
|
// src/server/drizzle.ts
|
|
42
42
|
var exports_drizzle = {};
|
|
43
43
|
__export(exports_drizzle, {
|
|
44
|
-
|
|
45
|
-
|
|
44
|
+
drizzleTable: () => drizzleTable,
|
|
45
|
+
drizzleTxAtomic: () => drizzleTxAtomic
|
|
46
46
|
});
|
|
47
47
|
module.exports = __toCommonJS(exports_drizzle);
|
|
48
48
|
var import_node_module2 = require("node:module");
|