reflectdb 0.1.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/LICENSE +21 -0
- package/README.md +1260 -0
- package/dist/cjs/client/index.cjs +1252 -0
- package/dist/cjs/client/index.d.cts +629 -0
- package/dist/cjs/client/storage/indexeddb.cjs +253 -0
- package/dist/cjs/client/storage/indexeddb.d.cts +85 -0
- package/dist/cjs/core/index.cjs +202 -0
- package/dist/cjs/core/index.d.cts +473 -0
- package/dist/cjs/react/index.cjs +1512 -0
- package/dist/cjs/react/index.d.cts +748 -0
- package/dist/cjs/server/drizzle.cjs +413 -0
- package/dist/cjs/server/drizzle.d.cts +233 -0
- package/dist/cjs/server/index.cjs +4486 -0
- package/dist/cjs/server/index.d.cts +1988 -0
- package/dist/cjs/svelte/index.cjs +1414 -0
- package/dist/cjs/svelte/index.d.cts +645 -0
- package/dist/cjs/transport/bun-ws.cjs +244 -0
- package/dist/cjs/transport/bun-ws.d.cts +215 -0
- package/dist/cjs/transport/polling.cjs +285 -0
- package/dist/cjs/transport/polling.d.cts +210 -0
- package/dist/cjs/transport/sse.cjs +312 -0
- package/dist/cjs/transport/sse.d.cts +205 -0
- package/dist/cjs/transport/ws.cjs +330 -0
- package/dist/cjs/transport/ws.d.cts +236 -0
- package/dist/cjs/vanilla/index.cjs +1430 -0
- package/dist/cjs/vanilla/index.d.cts +657 -0
- package/dist/client/index.d.ts +629 -0
- package/dist/client/index.js +106 -0
- package/dist/client/storage/indexeddb.d.ts +85 -0
- package/dist/client/storage/indexeddb.js +213 -0
- package/dist/core/index.d.ts +473 -0
- package/dist/core/index.js +56 -0
- package/dist/react/index.d.ts +748 -0
- package/dist/react/index.js +366 -0
- package/dist/server/drizzle.d.ts +233 -0
- package/dist/server/drizzle.js +9 -0
- package/dist/server/index.d.ts +1988 -0
- package/dist/server/index.js +3959 -0
- package/dist/shared/esm-3tkwvysa.js +54 -0
- package/dist/shared/esm-b7xs9cde.js +4 -0
- package/dist/shared/esm-rw7jjtrv.js +58 -0
- package/dist/shared/esm-wkwx6bd9.js +25 -0
- package/dist/shared/esm-ytrd3hbq.js +1007 -0
- package/dist/shared/esm-z1xse19c.js +369 -0
- package/dist/svelte/index.d.ts +645 -0
- package/dist/svelte/index.js +262 -0
- package/dist/transport/bun-ws.d.ts +215 -0
- package/dist/transport/bun-ws.js +140 -0
- package/dist/transport/polling.d.ts +210 -0
- package/dist/transport/polling.js +181 -0
- package/dist/transport/sse.d.ts +205 -0
- package/dist/transport/sse.js +208 -0
- package/dist/transport/ws.d.ts +236 -0
- package/dist/transport/ws.js +226 -0
- package/dist/vanilla/index.d.ts +657 -0
- package/dist/vanilla/index.js +278 -0
- package/package.json +253 -0
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
var import_node_module = require("node:module");
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
function __accessProp(key) {
|
|
7
|
+
return this[key];
|
|
8
|
+
}
|
|
9
|
+
var __toCommonJS = (from) => {
|
|
10
|
+
var entry = (__moduleCache ??= new WeakMap).get(from), desc;
|
|
11
|
+
if (entry)
|
|
12
|
+
return entry;
|
|
13
|
+
entry = __defProp({}, "__esModule", { value: true });
|
|
14
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
15
|
+
for (var key of __getOwnPropNames(from))
|
|
16
|
+
if (!__hasOwnProp.call(entry, key))
|
|
17
|
+
__defProp(entry, key, {
|
|
18
|
+
get: __accessProp.bind(from, key),
|
|
19
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
__moduleCache.set(from, entry);
|
|
23
|
+
return entry;
|
|
24
|
+
};
|
|
25
|
+
var __moduleCache;
|
|
26
|
+
var __returnValue = (v) => v;
|
|
27
|
+
function __exportSetter(name, newValue) {
|
|
28
|
+
this[name] = __returnValue.bind(null, newValue);
|
|
29
|
+
}
|
|
30
|
+
var __export = (target, all) => {
|
|
31
|
+
for (var name in all)
|
|
32
|
+
__defProp(target, name, {
|
|
33
|
+
get: all[name],
|
|
34
|
+
enumerable: true,
|
|
35
|
+
configurable: true,
|
|
36
|
+
set: __exportSetter.bind(all, name)
|
|
37
|
+
});
|
|
38
|
+
};
|
|
39
|
+
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
40
|
+
|
|
41
|
+
// src/client/storage/indexeddb.ts
|
|
42
|
+
var exports_indexeddb = {};
|
|
43
|
+
__export(exports_indexeddb, {
|
|
44
|
+
createIndexedDBStorage: () => createIndexedDBStorage
|
|
45
|
+
});
|
|
46
|
+
module.exports = __toCommonJS(exports_indexeddb);
|
|
47
|
+
function createIndexedDBStorage(config) {
|
|
48
|
+
let dbPromise = null;
|
|
49
|
+
let schemaChecked = false;
|
|
50
|
+
function openDB() {
|
|
51
|
+
if (dbPromise)
|
|
52
|
+
return dbPromise;
|
|
53
|
+
dbPromise = new Promise((resolve, reject) => {
|
|
54
|
+
const request = indexedDB.open(config.dbName, config.version ?? 1);
|
|
55
|
+
request.onupgradeneeded = (event) => {
|
|
56
|
+
const db = request.result;
|
|
57
|
+
const transaction = request.transaction;
|
|
58
|
+
if (!db.objectStoreNames.contains("rows")) {
|
|
59
|
+
const rowStore = db.createObjectStore("rows", { keyPath: ["table", "rowId"] });
|
|
60
|
+
rowStore.createIndex("table", "table", { unique: false });
|
|
61
|
+
}
|
|
62
|
+
if (!db.objectStoreNames.contains("pendingOps")) {
|
|
63
|
+
db.createObjectStore("pendingOps", { keyPath: "op.id" });
|
|
64
|
+
}
|
|
65
|
+
if (!db.objectStoreNames.contains("meta")) {
|
|
66
|
+
db.createObjectStore("meta", { keyPath: "key" });
|
|
67
|
+
}
|
|
68
|
+
if (config.migrate && transaction) {
|
|
69
|
+
config.migrate({
|
|
70
|
+
db,
|
|
71
|
+
transaction,
|
|
72
|
+
oldVersion: event.oldVersion,
|
|
73
|
+
newVersion: event.newVersion ?? (config.version ?? 1)
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
request.onsuccess = () => resolve(request.result);
|
|
78
|
+
request.onerror = () => reject(request.error);
|
|
79
|
+
});
|
|
80
|
+
return dbPromise;
|
|
81
|
+
}
|
|
82
|
+
function tx(storeNames, mode) {
|
|
83
|
+
return openDB().then((db) => {
|
|
84
|
+
const names = Array.isArray(storeNames) ? storeNames : [storeNames];
|
|
85
|
+
const transaction = db.transaction(names, mode);
|
|
86
|
+
const stores = {};
|
|
87
|
+
for (const name of names) {
|
|
88
|
+
stores[name] = transaction.objectStore(name);
|
|
89
|
+
}
|
|
90
|
+
return { tx: transaction, stores };
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
function reqToPromise(request) {
|
|
94
|
+
return new Promise((resolve, reject) => {
|
|
95
|
+
request.onsuccess = () => resolve(request.result);
|
|
96
|
+
request.onerror = () => reject(request.error);
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
function txComplete(transaction) {
|
|
100
|
+
return new Promise((resolve, reject) => {
|
|
101
|
+
transaction.oncomplete = () => resolve();
|
|
102
|
+
transaction.onerror = () => reject(transaction.error);
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
async function readMetaRaw(key) {
|
|
106
|
+
const { stores } = await tx("meta", "readonly");
|
|
107
|
+
const result = await reqToPromise(stores.meta.get(key));
|
|
108
|
+
return result?.value ?? null;
|
|
109
|
+
}
|
|
110
|
+
async function writeMetaRaw(key, value) {
|
|
111
|
+
const { tx: transaction, stores } = await tx("meta", "readwrite");
|
|
112
|
+
stores.meta.put({ key, value });
|
|
113
|
+
await txComplete(transaction);
|
|
114
|
+
}
|
|
115
|
+
let schemaCheckPromise = null;
|
|
116
|
+
async function ensureSchemaChecked() {
|
|
117
|
+
if (schemaChecked)
|
|
118
|
+
return;
|
|
119
|
+
if (schemaCheckPromise)
|
|
120
|
+
return schemaCheckPromise;
|
|
121
|
+
schemaCheckPromise = (async () => {
|
|
122
|
+
if (config.appSchemaVersion === undefined) {
|
|
123
|
+
schemaChecked = true;
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
const storedRaw = await readMetaRaw("__reflectdb_appSchemaVersion");
|
|
127
|
+
const stored = storedRaw == null ? null : Number.parseInt(storedRaw, 10);
|
|
128
|
+
if (stored === null) {
|
|
129
|
+
await writeMetaRaw("__reflectdb_appSchemaVersion", String(config.appSchemaVersion));
|
|
130
|
+
schemaChecked = true;
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
if (stored !== config.appSchemaVersion) {
|
|
134
|
+
if (config.onSchemaChange) {
|
|
135
|
+
await config.onSchemaChange({ storedVersion: stored, configVersion: config.appSchemaVersion }, adapter);
|
|
136
|
+
} else {
|
|
137
|
+
console.warn(`[reflectdb] IndexedDB appSchemaVersion mismatch: stored=${stored} config=${config.appSchemaVersion}. ` + `Pass onSchemaChange to handle (e.g. await storage.clear()).`);
|
|
138
|
+
}
|
|
139
|
+
await writeMetaRaw("__reflectdb_appSchemaVersion", String(config.appSchemaVersion));
|
|
140
|
+
}
|
|
141
|
+
schemaChecked = true;
|
|
142
|
+
})().catch((err) => {
|
|
143
|
+
schemaCheckPromise = null;
|
|
144
|
+
throw err;
|
|
145
|
+
});
|
|
146
|
+
return schemaCheckPromise;
|
|
147
|
+
}
|
|
148
|
+
const adapter = {
|
|
149
|
+
async getRows(table) {
|
|
150
|
+
await ensureSchemaChecked();
|
|
151
|
+
const { stores } = await tx("rows", "readonly");
|
|
152
|
+
const index = stores.rows.index("table");
|
|
153
|
+
const results = await reqToPromise(index.getAll(table));
|
|
154
|
+
return results;
|
|
155
|
+
},
|
|
156
|
+
async getAllRows() {
|
|
157
|
+
const { stores } = await tx("rows", "readonly");
|
|
158
|
+
const results = await reqToPromise(stores.rows.getAll());
|
|
159
|
+
return results;
|
|
160
|
+
},
|
|
161
|
+
async putRow(table, rowId, row) {
|
|
162
|
+
const { tx: transaction, stores } = await tx("rows", "readwrite");
|
|
163
|
+
stores.rows.put(row);
|
|
164
|
+
await txComplete(transaction);
|
|
165
|
+
},
|
|
166
|
+
async deleteRow(table, rowId) {
|
|
167
|
+
const { tx: transaction, stores } = await tx("rows", "readwrite");
|
|
168
|
+
stores.rows.delete([table, rowId]);
|
|
169
|
+
await txComplete(transaction);
|
|
170
|
+
},
|
|
171
|
+
async clearTable(table) {
|
|
172
|
+
const { tx: transaction, stores } = await tx("rows", "readwrite");
|
|
173
|
+
const index = stores.rows.index("table");
|
|
174
|
+
const keys = await reqToPromise(index.getAllKeys(table));
|
|
175
|
+
const deletes = keys.map((key) => reqToPromise(stores.rows.delete(key)));
|
|
176
|
+
await Promise.all(deletes);
|
|
177
|
+
await txComplete(transaction);
|
|
178
|
+
},
|
|
179
|
+
async getPendingOps() {
|
|
180
|
+
const { stores } = await tx("pendingOps", "readonly");
|
|
181
|
+
const results = await reqToPromise(stores.pendingOps.getAll());
|
|
182
|
+
return results;
|
|
183
|
+
},
|
|
184
|
+
async putPendingOps(ops) {
|
|
185
|
+
const { tx: transaction, stores } = await tx("pendingOps", "readwrite");
|
|
186
|
+
stores.pendingOps.clear();
|
|
187
|
+
for (const op of ops) {
|
|
188
|
+
stores.pendingOps.put(op);
|
|
189
|
+
}
|
|
190
|
+
await txComplete(transaction);
|
|
191
|
+
},
|
|
192
|
+
async appendPendingOps(ops) {
|
|
193
|
+
const { tx: transaction, stores } = await tx("pendingOps", "readwrite");
|
|
194
|
+
for (const op of ops) {
|
|
195
|
+
stores.pendingOps.put(op);
|
|
196
|
+
}
|
|
197
|
+
await txComplete(transaction);
|
|
198
|
+
},
|
|
199
|
+
async updatePendingOps(ops) {
|
|
200
|
+
const { tx: transaction, stores } = await tx("pendingOps", "readwrite");
|
|
201
|
+
for (const op of ops) {
|
|
202
|
+
stores.pendingOps.put(op);
|
|
203
|
+
}
|
|
204
|
+
await txComplete(transaction);
|
|
205
|
+
},
|
|
206
|
+
async removePendingOps(opIds) {
|
|
207
|
+
const { tx: transaction, stores } = await tx("pendingOps", "readwrite");
|
|
208
|
+
for (const id of opIds) {
|
|
209
|
+
stores.pendingOps.delete(id);
|
|
210
|
+
}
|
|
211
|
+
await txComplete(transaction);
|
|
212
|
+
},
|
|
213
|
+
async clearPendingOps() {
|
|
214
|
+
const { tx: transaction, stores } = await tx("pendingOps", "readwrite");
|
|
215
|
+
stores.pendingOps.clear();
|
|
216
|
+
await txComplete(transaction);
|
|
217
|
+
},
|
|
218
|
+
async getMeta(key) {
|
|
219
|
+
const { stores } = await tx("meta", "readonly");
|
|
220
|
+
const result = await reqToPromise(stores.meta.get(key));
|
|
221
|
+
return result?.value ?? null;
|
|
222
|
+
},
|
|
223
|
+
async setMeta(key, value) {
|
|
224
|
+
const { tx: transaction, stores } = await tx("meta", "readwrite");
|
|
225
|
+
stores.meta.put({ key, value });
|
|
226
|
+
await txComplete(transaction);
|
|
227
|
+
},
|
|
228
|
+
async deleteMeta(key) {
|
|
229
|
+
const { tx: transaction, stores } = await tx("meta", "readwrite");
|
|
230
|
+
stores.meta.delete(key);
|
|
231
|
+
await txComplete(transaction);
|
|
232
|
+
},
|
|
233
|
+
async clear() {
|
|
234
|
+
const { tx: transaction, stores } = await tx(["rows", "pendingOps", "meta"], "readwrite");
|
|
235
|
+
stores.rows.clear();
|
|
236
|
+
stores.pendingOps.clear();
|
|
237
|
+
stores.meta.clear();
|
|
238
|
+
await txComplete(transaction);
|
|
239
|
+
dbPromise = null;
|
|
240
|
+
}
|
|
241
|
+
};
|
|
242
|
+
const _getAllRows = adapter.getAllRows;
|
|
243
|
+
adapter.getAllRows = async () => {
|
|
244
|
+
await ensureSchemaChecked();
|
|
245
|
+
return _getAllRows();
|
|
246
|
+
};
|
|
247
|
+
const _getPendingOps = adapter.getPendingOps;
|
|
248
|
+
adapter.getPendingOps = async () => {
|
|
249
|
+
await ensureSchemaChecked();
|
|
250
|
+
return _getPendingOps();
|
|
251
|
+
};
|
|
252
|
+
return adapter;
|
|
253
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
type OpType = "insert" | "update" | "delete";
|
|
2
|
+
type OpStatus = "pending" | "synced" | "rejected";
|
|
3
|
+
type ErrorReason = "outside_shape" | "readonly_query" | "rate_limited" | "buffer_full" | "server_conflict" | "custom_conflict" | "merge_stale" | "clock_drift" | "replay" | "batch_too_large" | "schema_outdated" | "auth_revoked" | "compacted" | "mutation_rejected" | "server_error" | "unknown_query";
|
|
4
|
+
interface ClientOp {
|
|
5
|
+
id: string;
|
|
6
|
+
table: string;
|
|
7
|
+
op: OpType;
|
|
8
|
+
rowId: string;
|
|
9
|
+
payload: Record<string, unknown> | null;
|
|
10
|
+
hlc: string;
|
|
11
|
+
batchId?: string;
|
|
12
|
+
batchSize?: number;
|
|
13
|
+
batchSeq?: number;
|
|
14
|
+
}
|
|
15
|
+
interface PendingOp {
|
|
16
|
+
op: ClientOp;
|
|
17
|
+
status: OpStatus;
|
|
18
|
+
rejectedReason: ErrorReason | null;
|
|
19
|
+
createdAt: number;
|
|
20
|
+
/**
|
|
21
|
+
* Row state captured just before the optimistic apply. Restored on reject
|
|
22
|
+
* so a rejected optimistic insert collapses back to no-row (instead of
|
|
23
|
+
* leaving a tombstone), and a rejected update reverts to the merged row
|
|
24
|
+
* the client had before touching it.
|
|
25
|
+
*/
|
|
26
|
+
preState?: {
|
|
27
|
+
data: Record<string, unknown> | null;
|
|
28
|
+
colClocks: Record<string, string>;
|
|
29
|
+
serverHlc: string | null;
|
|
30
|
+
} | null;
|
|
31
|
+
}
|
|
32
|
+
interface LocalRow {
|
|
33
|
+
table: string;
|
|
34
|
+
rowId: string;
|
|
35
|
+
data: Record<string, unknown> | null;
|
|
36
|
+
colClocks: Record<string, string>;
|
|
37
|
+
serverHlc: string | null;
|
|
38
|
+
}
|
|
39
|
+
interface ClientStorageAdapter {
|
|
40
|
+
getRows(table: string): Promise<LocalRow[]>;
|
|
41
|
+
getAllRows(): Promise<LocalRow[]>;
|
|
42
|
+
putRow(table: string, rowId: string, row: LocalRow): Promise<void>;
|
|
43
|
+
deleteRow(table: string, rowId: string): Promise<void>;
|
|
44
|
+
clearTable(table: string): Promise<void>;
|
|
45
|
+
getPendingOps(): Promise<PendingOp[]>;
|
|
46
|
+
putPendingOps(ops: PendingOp[]): Promise<void>;
|
|
47
|
+
appendPendingOps(ops: PendingOp[]): Promise<void>;
|
|
48
|
+
updatePendingOps(ops: PendingOp[]): Promise<void>;
|
|
49
|
+
removePendingOps(opIds: string[]): Promise<void>;
|
|
50
|
+
clearPendingOps(): Promise<void>;
|
|
51
|
+
getMeta(key: string): Promise<string | null>;
|
|
52
|
+
setMeta(key: string, value: string): Promise<void>;
|
|
53
|
+
deleteMeta(key: string): Promise<void>;
|
|
54
|
+
clear(): Promise<void>;
|
|
55
|
+
}
|
|
56
|
+
interface IndexedDBMigrationContext {
|
|
57
|
+
db: IDBDatabase;
|
|
58
|
+
transaction: IDBTransaction;
|
|
59
|
+
oldVersion: number;
|
|
60
|
+
newVersion: number;
|
|
61
|
+
}
|
|
62
|
+
declare function createIndexedDBStorage(config: {
|
|
63
|
+
dbName: string;
|
|
64
|
+
version?: number;
|
|
65
|
+
/**
|
|
66
|
+
* Called during onupgradeneeded after the built-in stores are ensured.
|
|
67
|
+
* Bump `version` and handle old→new schema changes here. Without this,
|
|
68
|
+
* raising `version` in app code with no migration wipes user data.
|
|
69
|
+
*/
|
|
70
|
+
migrate?: (ctx: IndexedDBMigrationContext) => void;
|
|
71
|
+
/**
|
|
72
|
+
* Application-level schema version (separate from IDB `version`).
|
|
73
|
+
* Persisted to meta on first open. On subsequent opens, mismatch fires
|
|
74
|
+
* `onSchemaChange` so the app can clear or migrate row data whose shape
|
|
75
|
+
* changed without an IDB version bump (e.g. new required field added to
|
|
76
|
+
* a Drizzle table).
|
|
77
|
+
*/
|
|
78
|
+
appSchemaVersion?: number;
|
|
79
|
+
/** Invoked when stored appSchemaVersion differs from config. Default: warn. */
|
|
80
|
+
onSchemaChange?: (ctx: {
|
|
81
|
+
storedVersion: number;
|
|
82
|
+
configVersion: number;
|
|
83
|
+
}, storage: ClientStorageAdapter) => void | Promise<void>;
|
|
84
|
+
}): ClientStorageAdapter;
|
|
85
|
+
export { createIndexedDBStorage, IndexedDBMigrationContext };
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
var import_node_module = require("node:module");
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
function __accessProp(key) {
|
|
7
|
+
return this[key];
|
|
8
|
+
}
|
|
9
|
+
var __toCommonJS = (from) => {
|
|
10
|
+
var entry = (__moduleCache ??= new WeakMap).get(from), desc;
|
|
11
|
+
if (entry)
|
|
12
|
+
return entry;
|
|
13
|
+
entry = __defProp({}, "__esModule", { value: true });
|
|
14
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
15
|
+
for (var key of __getOwnPropNames(from))
|
|
16
|
+
if (!__hasOwnProp.call(entry, key))
|
|
17
|
+
__defProp(entry, key, {
|
|
18
|
+
get: __accessProp.bind(from, key),
|
|
19
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
__moduleCache.set(from, entry);
|
|
23
|
+
return entry;
|
|
24
|
+
};
|
|
25
|
+
var __moduleCache;
|
|
26
|
+
var __returnValue = (v) => v;
|
|
27
|
+
function __exportSetter(name, newValue) {
|
|
28
|
+
this[name] = __returnValue.bind(null, newValue);
|
|
29
|
+
}
|
|
30
|
+
var __export = (target, all) => {
|
|
31
|
+
for (var name in all)
|
|
32
|
+
__defProp(target, name, {
|
|
33
|
+
get: all[name],
|
|
34
|
+
enumerable: true,
|
|
35
|
+
configurable: true,
|
|
36
|
+
set: __exportSetter.bind(all, name)
|
|
37
|
+
});
|
|
38
|
+
};
|
|
39
|
+
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
40
|
+
|
|
41
|
+
// src/core/types.ts
|
|
42
|
+
var exports_types = {};
|
|
43
|
+
__export(exports_types, {
|
|
44
|
+
reasonFromError: () => reasonFromError,
|
|
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,
|
|
52
|
+
MAX_CLOCK_DRIFT_MS: () => MAX_CLOCK_DRIFT_MS,
|
|
53
|
+
MAX_BATCH_SIZE: () => MAX_BATCH_SIZE
|
|
54
|
+
});
|
|
55
|
+
function isErrorReason(value) {
|
|
56
|
+
return typeof value === "string" && VALID_ERROR_REASONS.has(value);
|
|
57
|
+
}
|
|
58
|
+
function reasonFromError(err) {
|
|
59
|
+
if (err instanceof MutationError && isErrorReason(err.reason)) {
|
|
60
|
+
return err.reason;
|
|
61
|
+
}
|
|
62
|
+
return "server_error";
|
|
63
|
+
}
|
|
64
|
+
var TransportSendError, PROTOCOL_VERSION = 1, SUPPORTED_PROTOCOL_VERSIONS, MAX_CLOCK_DRIFT_MS, MAX_BATCH_SIZE = 100, TOMBSTONE_RETENTION_MS, SERVER_TOMBSTONE_RETENTION_MS, MutationError, VALID_ERROR_REASONS;
|
|
65
|
+
var init_types = __esm(() => {
|
|
66
|
+
TransportSendError = class TransportSendError extends Error {
|
|
67
|
+
clientId;
|
|
68
|
+
cause;
|
|
69
|
+
constructor(clientId, message, cause) {
|
|
70
|
+
super(message);
|
|
71
|
+
this.clientId = clientId;
|
|
72
|
+
this.cause = cause;
|
|
73
|
+
this.name = "TransportSendError";
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
SUPPORTED_PROTOCOL_VERSIONS = [1];
|
|
77
|
+
MAX_CLOCK_DRIFT_MS = 5 * 60 * 1000;
|
|
78
|
+
TOMBSTONE_RETENTION_MS = 7 * 24 * 60 * 60 * 1000;
|
|
79
|
+
SERVER_TOMBSTONE_RETENTION_MS = 90 * 24 * 60 * 60 * 1000;
|
|
80
|
+
MutationError = class MutationError extends Error {
|
|
81
|
+
reason;
|
|
82
|
+
constructor(reason, message) {
|
|
83
|
+
super(message ?? reason);
|
|
84
|
+
this.reason = reason;
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
VALID_ERROR_REASONS = new Set([
|
|
88
|
+
"outside_shape",
|
|
89
|
+
"readonly_query",
|
|
90
|
+
"rate_limited",
|
|
91
|
+
"buffer_full",
|
|
92
|
+
"server_conflict",
|
|
93
|
+
"custom_conflict",
|
|
94
|
+
"merge_stale",
|
|
95
|
+
"clock_drift",
|
|
96
|
+
"replay",
|
|
97
|
+
"batch_too_large",
|
|
98
|
+
"schema_outdated",
|
|
99
|
+
"auth_revoked",
|
|
100
|
+
"compacted",
|
|
101
|
+
"mutation_rejected",
|
|
102
|
+
"server_error",
|
|
103
|
+
"unknown_query"
|
|
104
|
+
]);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
// src/core/index.ts
|
|
108
|
+
var exports_core = {};
|
|
109
|
+
__export(exports_core, {
|
|
110
|
+
view: () => view,
|
|
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,
|
|
128
|
+
MAX_CLOCK_DRIFT_MS: () => MAX_CLOCK_DRIFT_MS,
|
|
129
|
+
MAX_BATCH_SIZE: () => MAX_BATCH_SIZE
|
|
130
|
+
});
|
|
131
|
+
module.exports = __toCommonJS(exports_core);
|
|
132
|
+
|
|
133
|
+
// src/core/hlc.ts
|
|
134
|
+
init_types();
|
|
135
|
+
var MS_PAD = 19;
|
|
136
|
+
var COUNTER_PAD = 4;
|
|
137
|
+
var COUNTER_MAX = 9999;
|
|
138
|
+
function createHlc(nodeId) {
|
|
139
|
+
return { ms: 0, counter: 0, nodeId };
|
|
140
|
+
}
|
|
141
|
+
function normalize(ms, counter, nodeId) {
|
|
142
|
+
if (counter > COUNTER_MAX) {
|
|
143
|
+
return { ms: ms + 1, counter: 0, nodeId };
|
|
144
|
+
}
|
|
145
|
+
return { ms, counter, nodeId };
|
|
146
|
+
}
|
|
147
|
+
function sendHlc(local) {
|
|
148
|
+
const wall = Date.now();
|
|
149
|
+
const ms = Math.max(wall, local.ms);
|
|
150
|
+
const counter = ms === local.ms ? local.counter + 1 : 0;
|
|
151
|
+
return normalize(ms, counter, local.nodeId);
|
|
152
|
+
}
|
|
153
|
+
function receiveHlc(local, remote) {
|
|
154
|
+
const wall = Date.now();
|
|
155
|
+
const clampedRemoteMs = Math.min(remote.ms, wall + MAX_CLOCK_DRIFT_MS);
|
|
156
|
+
const ms = Math.max(wall, local.ms, clampedRemoteMs);
|
|
157
|
+
const counter = ms === local.ms && ms === clampedRemoteMs ? Math.max(local.counter, remote.counter) + 1 : ms === local.ms ? local.counter + 1 : ms === clampedRemoteMs ? remote.counter + 1 : 0;
|
|
158
|
+
return normalize(ms, counter, local.nodeId);
|
|
159
|
+
}
|
|
160
|
+
function packHlc(hlc) {
|
|
161
|
+
const ms = String(hlc.ms).padStart(MS_PAD, "0");
|
|
162
|
+
const counter = String(hlc.counter).padStart(COUNTER_PAD, "0");
|
|
163
|
+
return `${ms}.${counter}.${hlc.nodeId}`;
|
|
164
|
+
}
|
|
165
|
+
function unpackHlc(packed) {
|
|
166
|
+
const firstDot = packed.indexOf(".");
|
|
167
|
+
const secondDot = firstDot < 0 ? -1 : packed.indexOf(".", firstDot + 1);
|
|
168
|
+
if (firstDot < 0 || secondDot < 0) {
|
|
169
|
+
throw new Error(`Malformed HLC: ${packed}`);
|
|
170
|
+
}
|
|
171
|
+
const ms = Number(packed.slice(0, firstDot));
|
|
172
|
+
const counter = Number(packed.slice(firstDot + 1, secondDot));
|
|
173
|
+
const nodeId = packed.slice(secondDot + 1);
|
|
174
|
+
if (!Number.isFinite(ms) || !Number.isFinite(counter) || nodeId.length === 0) {
|
|
175
|
+
throw new Error(`Malformed HLC: ${packed}`);
|
|
176
|
+
}
|
|
177
|
+
return { ms, counter, nodeId };
|
|
178
|
+
}
|
|
179
|
+
function compareHlc(a, b) {
|
|
180
|
+
if (a < b)
|
|
181
|
+
return -1;
|
|
182
|
+
if (a > b)
|
|
183
|
+
return 1;
|
|
184
|
+
return 0;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// src/core/index.ts
|
|
188
|
+
init_types();
|
|
189
|
+
|
|
190
|
+
// src/core/schema.ts
|
|
191
|
+
function view(opts) {
|
|
192
|
+
return { __view: true, ...opts };
|
|
193
|
+
}
|
|
194
|
+
function presence(opts) {
|
|
195
|
+
return { __presence: true, ...opts };
|
|
196
|
+
}
|
|
197
|
+
function defineSyncQueries(queries) {
|
|
198
|
+
return queries;
|
|
199
|
+
}
|
|
200
|
+
function t() {
|
|
201
|
+
return;
|
|
202
|
+
}
|