korajs 0.3.5 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/config.cjs.map +1 -1
- package/dist/config.js.map +1 -1
- package/dist/index.cjs +138 -28
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +123 -6
- package/dist/index.d.ts +123 -6
- package/dist/index.js +135 -24
- package/dist/index.js.map +1 -1
- package/package.json +6 -6
package/dist/config.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/config.ts"],"sourcesContent":["/**\n * Kora CLI/runtime configuration shape loaded from `kora.config.*`.\n */\nexport interface KoraUserConfig {\n\t/** Path to the schema file. Defaults to auto-detection in CLI. */\n\tschema?: string\n\tdev?: {\n\t\t/** Vite development server port. */\n\t\tport?: number\n\t\tsync?:\n\t\t\t| boolean\n\t\t\t| {\n\t\t\t\t/** Enable or disable sync server startup in `kora dev`. */\n\t\t\t\tenabled?: boolean\n\t\t\t\t/** Sync server port (also exposed as PORT/KORA_SYNC_PORT env). */\n\t\t\t\tport?: number\n\t\t\t\t/** Sync server store backend for managed mode (without server.ts). */\n\t\t\t\tstore?:\n\t\t\t\t\t| 'memory'\n\t\t\t\t\t| 'sqlite'\n\t\t\t\t\t| 'postgres'\n\t\t\t\t\t| {\n\t\t\t\t\t\ttype: 'memory'\n\t\t\t\t\t}\n\t\t\t\t\t| {\n\t\t\t\t\t\ttype: 'sqlite'\n\t\t\t\t\t\tfilename?: string\n\t\t\t\t\t}\n\t\t\t\t\t| {\n\t\t\t\t\t\ttype: 'postgres'\n\t\t\t\t\t\tconnectionString: string\n\t\t\t\t\t}\n\t\t\t}\n\t\twatch?:\n\t\t\t| boolean\n\t\t\t| {\n\t\t\t\t/** Enable or disable schema watching. */\n\t\t\t\tenabled?: boolean\n\t\t\t\t/** Debounce duration for schema regeneration. */\n\t\t\t\tdebounceMs?: number\n\t\t\t}\n\t}\n}\n\n/**\n * Defines a typed Kora config.\n */\nexport function defineConfig(config: KoraUserConfig): KoraUserConfig {\n\treturn config\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AA+CO,SAAS,aAAa,QAAwC;AACpE,SAAO;AACR;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/config.ts"],"sourcesContent":["/**\n * Kora CLI/runtime configuration shape loaded from `kora.config.*`.\n */\nexport interface KoraUserConfig {\n\t/** Path to the schema file. Defaults to auto-detection in CLI. */\n\tschema?: string\n\tdev?: {\n\t\t/** Vite development server port. */\n\t\tport?: number\n\t\tsync?:\n\t\t\t| boolean\n\t\t\t| {\n\t\t\t\t\t/** Enable or disable sync server startup in `kora dev`. */\n\t\t\t\t\tenabled?: boolean\n\t\t\t\t\t/** Sync server port (also exposed as PORT/KORA_SYNC_PORT env). */\n\t\t\t\t\tport?: number\n\t\t\t\t\t/** Sync server store backend for managed mode (without server.ts). */\n\t\t\t\t\tstore?:\n\t\t\t\t\t\t| 'memory'\n\t\t\t\t\t\t| 'sqlite'\n\t\t\t\t\t\t| 'postgres'\n\t\t\t\t\t\t| {\n\t\t\t\t\t\t\t\ttype: 'memory'\n\t\t\t\t\t\t }\n\t\t\t\t\t\t| {\n\t\t\t\t\t\t\t\ttype: 'sqlite'\n\t\t\t\t\t\t\t\tfilename?: string\n\t\t\t\t\t\t }\n\t\t\t\t\t\t| {\n\t\t\t\t\t\t\t\ttype: 'postgres'\n\t\t\t\t\t\t\t\tconnectionString: string\n\t\t\t\t\t\t }\n\t\t\t }\n\t\twatch?:\n\t\t\t| boolean\n\t\t\t| {\n\t\t\t\t\t/** Enable or disable schema watching. */\n\t\t\t\t\tenabled?: boolean\n\t\t\t\t\t/** Debounce duration for schema regeneration. */\n\t\t\t\t\tdebounceMs?: number\n\t\t\t }\n\t}\n}\n\n/**\n * Defines a typed Kora config.\n */\nexport function defineConfig(config: KoraUserConfig): KoraUserConfig {\n\treturn config\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AA+CO,SAAS,aAAa,QAAwC;AACpE,SAAO;AACR;","names":[]}
|
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/config.ts"],"sourcesContent":["/**\n * Kora CLI/runtime configuration shape loaded from `kora.config.*`.\n */\nexport interface KoraUserConfig {\n\t/** Path to the schema file. Defaults to auto-detection in CLI. */\n\tschema?: string\n\tdev?: {\n\t\t/** Vite development server port. */\n\t\tport?: number\n\t\tsync?:\n\t\t\t| boolean\n\t\t\t| {\n\t\t\t\t/** Enable or disable sync server startup in `kora dev`. */\n\t\t\t\tenabled?: boolean\n\t\t\t\t/** Sync server port (also exposed as PORT/KORA_SYNC_PORT env). */\n\t\t\t\tport?: number\n\t\t\t\t/** Sync server store backend for managed mode (without server.ts). */\n\t\t\t\tstore?:\n\t\t\t\t\t| 'memory'\n\t\t\t\t\t| 'sqlite'\n\t\t\t\t\t| 'postgres'\n\t\t\t\t\t| {\n\t\t\t\t\t\ttype: 'memory'\n\t\t\t\t\t}\n\t\t\t\t\t| {\n\t\t\t\t\t\ttype: 'sqlite'\n\t\t\t\t\t\tfilename?: string\n\t\t\t\t\t}\n\t\t\t\t\t| {\n\t\t\t\t\t\ttype: 'postgres'\n\t\t\t\t\t\tconnectionString: string\n\t\t\t\t\t}\n\t\t\t}\n\t\twatch?:\n\t\t\t| boolean\n\t\t\t| {\n\t\t\t\t/** Enable or disable schema watching. */\n\t\t\t\tenabled?: boolean\n\t\t\t\t/** Debounce duration for schema regeneration. */\n\t\t\t\tdebounceMs?: number\n\t\t\t}\n\t}\n}\n\n/**\n * Defines a typed Kora config.\n */\nexport function defineConfig(config: KoraUserConfig): KoraUserConfig {\n\treturn config\n}\n"],"mappings":";AA+CO,SAAS,aAAa,QAAwC;AACpE,SAAO;AACR;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/config.ts"],"sourcesContent":["/**\n * Kora CLI/runtime configuration shape loaded from `kora.config.*`.\n */\nexport interface KoraUserConfig {\n\t/** Path to the schema file. Defaults to auto-detection in CLI. */\n\tschema?: string\n\tdev?: {\n\t\t/** Vite development server port. */\n\t\tport?: number\n\t\tsync?:\n\t\t\t| boolean\n\t\t\t| {\n\t\t\t\t\t/** Enable or disable sync server startup in `kora dev`. */\n\t\t\t\t\tenabled?: boolean\n\t\t\t\t\t/** Sync server port (also exposed as PORT/KORA_SYNC_PORT env). */\n\t\t\t\t\tport?: number\n\t\t\t\t\t/** Sync server store backend for managed mode (without server.ts). */\n\t\t\t\t\tstore?:\n\t\t\t\t\t\t| 'memory'\n\t\t\t\t\t\t| 'sqlite'\n\t\t\t\t\t\t| 'postgres'\n\t\t\t\t\t\t| {\n\t\t\t\t\t\t\t\ttype: 'memory'\n\t\t\t\t\t\t }\n\t\t\t\t\t\t| {\n\t\t\t\t\t\t\t\ttype: 'sqlite'\n\t\t\t\t\t\t\t\tfilename?: string\n\t\t\t\t\t\t }\n\t\t\t\t\t\t| {\n\t\t\t\t\t\t\t\ttype: 'postgres'\n\t\t\t\t\t\t\t\tconnectionString: string\n\t\t\t\t\t\t }\n\t\t\t }\n\t\twatch?:\n\t\t\t| boolean\n\t\t\t| {\n\t\t\t\t\t/** Enable or disable schema watching. */\n\t\t\t\t\tenabled?: boolean\n\t\t\t\t\t/** Debounce duration for schema regeneration. */\n\t\t\t\t\tdebounceMs?: number\n\t\t\t }\n\t}\n}\n\n/**\n * Defines a typed Kora config.\n */\nexport function defineConfig(config: KoraUserConfig): KoraUserConfig {\n\treturn config\n}\n"],"mappings":";AA+CO,SAAS,aAAa,QAAwC;AACpE,SAAO;AACR;","names":[]}
|
package/dist/index.cjs
CHANGED
|
@@ -30,21 +30,26 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
30
30
|
// src/index.ts
|
|
31
31
|
var index_exports = {};
|
|
32
32
|
__export(index_exports, {
|
|
33
|
-
HybridLogicalClock: () =>
|
|
34
|
-
KoraError: () =>
|
|
33
|
+
HybridLogicalClock: () => import_core3.HybridLogicalClock,
|
|
34
|
+
KoraError: () => import_core6.KoraError,
|
|
35
35
|
MergeEngine: () => import_merge2.MergeEngine,
|
|
36
|
+
SequenceManager: () => import_store2.SequenceManager,
|
|
36
37
|
Store: () => import_store2.Store,
|
|
37
38
|
SyncEngine: () => import_sync2.SyncEngine,
|
|
39
|
+
TransactionContext: () => import_store3.TransactionContext,
|
|
38
40
|
WebSocketTransport: () => import_sync2.WebSocketTransport,
|
|
39
41
|
createApp: () => createApp,
|
|
40
|
-
createOperation: () =>
|
|
41
|
-
defineSchema: () =>
|
|
42
|
-
generateUUIDv7: () =>
|
|
43
|
-
|
|
42
|
+
createOperation: () => import_core5.createOperation,
|
|
43
|
+
defineSchema: () => import_core2.defineSchema,
|
|
44
|
+
generateUUIDv7: () => import_core4.generateUUIDv7,
|
|
45
|
+
migrate: () => import_core2.migrate,
|
|
46
|
+
op: () => import_core7.op,
|
|
47
|
+
t: () => import_core2.t
|
|
44
48
|
});
|
|
45
49
|
module.exports = __toCommonJS(index_exports);
|
|
46
50
|
|
|
47
51
|
// src/create-app.ts
|
|
52
|
+
var import_core = require("@korajs/core");
|
|
48
53
|
var import_internal = require("@korajs/core/internal");
|
|
49
54
|
var import_devtools = require("@korajs/devtools");
|
|
50
55
|
var import_merge = require("@korajs/merge");
|
|
@@ -117,23 +122,23 @@ var MergeAwareSyncStore = class {
|
|
|
117
122
|
async getOperationRange(nodeId, fromSeq, toSeq) {
|
|
118
123
|
return this.store.getOperationRange(nodeId, fromSeq, toSeq);
|
|
119
124
|
}
|
|
120
|
-
async applyRemoteOperation(
|
|
121
|
-
if (
|
|
122
|
-
return this.store.applyRemoteOperation(
|
|
125
|
+
async applyRemoteOperation(op2) {
|
|
126
|
+
if (op2.type !== "update" || !op2.data || !op2.previousData) {
|
|
127
|
+
return this.store.applyRemoteOperation(op2);
|
|
123
128
|
}
|
|
124
129
|
const schema = this.store.getSchema();
|
|
125
|
-
const collectionDef = schema.collections[
|
|
130
|
+
const collectionDef = schema.collections[op2.collection];
|
|
126
131
|
if (!collectionDef) {
|
|
127
|
-
return this.store.applyRemoteOperation(
|
|
132
|
+
return this.store.applyRemoteOperation(op2);
|
|
128
133
|
}
|
|
129
|
-
const accessor = this.store.collection(
|
|
130
|
-
const currentRecord = await accessor.findById(
|
|
134
|
+
const accessor = this.store.collection(op2.collection);
|
|
135
|
+
const currentRecord = await accessor.findById(op2.recordId);
|
|
131
136
|
if (!currentRecord) {
|
|
132
|
-
return this.store.applyRemoteOperation(
|
|
137
|
+
return this.store.applyRemoteOperation(op2);
|
|
133
138
|
}
|
|
134
139
|
let hasConflict = false;
|
|
135
|
-
for (const field of Object.keys(
|
|
136
|
-
const expectedBase =
|
|
140
|
+
for (const field of Object.keys(op2.data)) {
|
|
141
|
+
const expectedBase = op2.previousData[field];
|
|
137
142
|
const currentLocal = currentRecord[field];
|
|
138
143
|
if (!deepEqual(expectedBase, currentLocal)) {
|
|
139
144
|
hasConflict = true;
|
|
@@ -141,24 +146,24 @@ var MergeAwareSyncStore = class {
|
|
|
141
146
|
}
|
|
142
147
|
}
|
|
143
148
|
if (!hasConflict) {
|
|
144
|
-
return this.store.applyRemoteOperation(
|
|
149
|
+
return this.store.applyRemoteOperation(op2);
|
|
145
150
|
}
|
|
146
151
|
this.emitter?.emit({
|
|
147
152
|
type: "merge:started",
|
|
148
|
-
operationA:
|
|
149
|
-
operationB:
|
|
153
|
+
operationA: op2,
|
|
154
|
+
operationB: op2
|
|
150
155
|
});
|
|
151
|
-
const baseState = { ...
|
|
156
|
+
const baseState = { ...op2.previousData };
|
|
152
157
|
const localOp = {
|
|
153
|
-
...
|
|
158
|
+
...op2,
|
|
154
159
|
// The "local" operation's data is the diff between base and current local state
|
|
155
|
-
data: buildLocalDiff(
|
|
156
|
-
previousData:
|
|
160
|
+
data: buildLocalDiff(op2.previousData, currentRecord, Object.keys(op2.data)),
|
|
161
|
+
previousData: op2.previousData,
|
|
157
162
|
nodeId: this.store.getNodeId()
|
|
158
163
|
};
|
|
159
164
|
const input = {
|
|
160
165
|
local: localOp,
|
|
161
|
-
remote:
|
|
166
|
+
remote: op2,
|
|
162
167
|
baseState,
|
|
163
168
|
collectionDef
|
|
164
169
|
};
|
|
@@ -171,7 +176,7 @@ var MergeAwareSyncStore = class {
|
|
|
171
176
|
this.emitter?.emit({ type: "merge:completed", trace: firstTrace });
|
|
172
177
|
}
|
|
173
178
|
const mergedOp = {
|
|
174
|
-
...
|
|
179
|
+
...op2,
|
|
175
180
|
data: result.mergedData
|
|
176
181
|
};
|
|
177
182
|
return this.store.applyRemoteOperation(mergedOp);
|
|
@@ -293,13 +298,104 @@ function createApp(config) {
|
|
|
293
298
|
if (syncEngine) {
|
|
294
299
|
return syncEngine.getStatus();
|
|
295
300
|
}
|
|
296
|
-
return {
|
|
301
|
+
return {
|
|
302
|
+
status: "offline",
|
|
303
|
+
pendingOperations: 0,
|
|
304
|
+
lastSyncedAt: null,
|
|
305
|
+
lastSuccessfulPush: null,
|
|
306
|
+
lastSuccessfulPull: null,
|
|
307
|
+
conflicts: 0
|
|
308
|
+
};
|
|
309
|
+
},
|
|
310
|
+
async retryNow() {
|
|
311
|
+
await ready;
|
|
312
|
+
if (syncEngine) {
|
|
313
|
+
await syncEngine.retryNow();
|
|
314
|
+
}
|
|
315
|
+
},
|
|
316
|
+
exportDiagnostics() {
|
|
317
|
+
if (syncEngine) {
|
|
318
|
+
return syncEngine.exportDiagnostics();
|
|
319
|
+
}
|
|
320
|
+
return {
|
|
321
|
+
state: "disconnected",
|
|
322
|
+
status: {
|
|
323
|
+
status: "offline",
|
|
324
|
+
pendingOperations: 0,
|
|
325
|
+
lastSyncedAt: null,
|
|
326
|
+
lastSuccessfulPush: null,
|
|
327
|
+
lastSuccessfulPull: null,
|
|
328
|
+
conflicts: 0
|
|
329
|
+
},
|
|
330
|
+
nodeId: "",
|
|
331
|
+
url: config.sync?.url ?? "",
|
|
332
|
+
schemaVersion: config.schema.version,
|
|
333
|
+
lastSyncedAt: null,
|
|
334
|
+
lastSuccessfulPush: null,
|
|
335
|
+
lastSuccessfulPull: null,
|
|
336
|
+
conflicts: 0,
|
|
337
|
+
pendingOperations: 0,
|
|
338
|
+
hasInFlightBatch: false,
|
|
339
|
+
reconnecting: false,
|
|
340
|
+
timestamp: Date.now()
|
|
341
|
+
};
|
|
297
342
|
}
|
|
298
343
|
} : null;
|
|
344
|
+
async function executeTransaction(fn, mutationName) {
|
|
345
|
+
await ready;
|
|
346
|
+
if (!store) {
|
|
347
|
+
throw new Error("Store not initialized. Await app.ready before using transactions.");
|
|
348
|
+
}
|
|
349
|
+
const txContext = store.createTransaction();
|
|
350
|
+
if (mutationName !== void 0) {
|
|
351
|
+
txContext.setMutationName(mutationName);
|
|
352
|
+
}
|
|
353
|
+
const collectionNames = Object.keys(config.schema.collections);
|
|
354
|
+
const proxy = {};
|
|
355
|
+
for (const name of collectionNames) {
|
|
356
|
+
Object.defineProperty(proxy, name, {
|
|
357
|
+
get() {
|
|
358
|
+
return txContext.collection(name);
|
|
359
|
+
},
|
|
360
|
+
enumerable: true,
|
|
361
|
+
configurable: false
|
|
362
|
+
});
|
|
363
|
+
}
|
|
364
|
+
try {
|
|
365
|
+
await fn(proxy);
|
|
366
|
+
const { operations } = await txContext.commit();
|
|
367
|
+
for (const op2 of operations) {
|
|
368
|
+
store.getSubscriptionManager().notify(op2.collection, op2);
|
|
369
|
+
emitter.emit({ type: "operation:created", operation: op2 });
|
|
370
|
+
}
|
|
371
|
+
return operations;
|
|
372
|
+
} catch (error) {
|
|
373
|
+
txContext.rollback();
|
|
374
|
+
throw error;
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
const sequences = {
|
|
378
|
+
async next(name, config2) {
|
|
379
|
+
await ready;
|
|
380
|
+
if (!store) throw new Error("Store not initialized. Await app.ready before using sequences.");
|
|
381
|
+
return store.getSequenceManager().next(name, config2);
|
|
382
|
+
},
|
|
383
|
+
async current(name, config2) {
|
|
384
|
+
await ready;
|
|
385
|
+
if (!store) throw new Error("Store not initialized. Await app.ready before using sequences.");
|
|
386
|
+
return store.getSequenceManager().current(name, config2);
|
|
387
|
+
},
|
|
388
|
+
async reset(name, config2) {
|
|
389
|
+
await ready;
|
|
390
|
+
if (!store) throw new Error("Store not initialized. Await app.ready before using sequences.");
|
|
391
|
+
return store.getSequenceManager().reset(name, config2);
|
|
392
|
+
}
|
|
393
|
+
};
|
|
299
394
|
const app = {
|
|
300
395
|
ready,
|
|
301
396
|
events: emitter,
|
|
302
397
|
sync: syncControl,
|
|
398
|
+
sequences,
|
|
303
399
|
getStore() {
|
|
304
400
|
if (!store) {
|
|
305
401
|
throw new Error("Store not initialized. Await app.ready before accessing the store.");
|
|
@@ -309,6 +405,12 @@ function createApp(config) {
|
|
|
309
405
|
getSyncEngine() {
|
|
310
406
|
return syncEngine;
|
|
311
407
|
},
|
|
408
|
+
async transaction(fn) {
|
|
409
|
+
return executeTransaction(fn);
|
|
410
|
+
},
|
|
411
|
+
async mutation(name, fn) {
|
|
412
|
+
return executeTransaction(fn, name);
|
|
413
|
+
},
|
|
312
414
|
async close() {
|
|
313
415
|
await ready;
|
|
314
416
|
intentionalDisconnect = true;
|
|
@@ -362,6 +464,7 @@ async function initializeAsync(config, emitter, mergeEngine) {
|
|
|
362
464
|
if (config.sync) {
|
|
363
465
|
const transport = new import_sync.WebSocketTransport();
|
|
364
466
|
const mergeAwareStore = new MergeAwareSyncStore(store, mergeEngine, emitter);
|
|
467
|
+
const scopeMap = config.sync.scope ? (0, import_core.buildScopeMap)(config.schema, config.sync.scope) : void 0;
|
|
365
468
|
syncEngine = new import_sync.SyncEngine({
|
|
366
469
|
transport,
|
|
367
470
|
store: mergeAwareStore,
|
|
@@ -370,7 +473,8 @@ async function initializeAsync(config, emitter, mergeEngine) {
|
|
|
370
473
|
transport: config.sync.transport,
|
|
371
474
|
auth: config.sync.auth,
|
|
372
475
|
batchSize: config.sync.batchSize,
|
|
373
|
-
schemaVersion: config.sync.schemaVersion ?? config.schema.version
|
|
476
|
+
schemaVersion: config.sync.schemaVersion ?? config.schema.version,
|
|
477
|
+
scopeMap
|
|
374
478
|
},
|
|
375
479
|
emitter
|
|
376
480
|
});
|
|
@@ -463,12 +567,14 @@ function createPendingQueryBuilder(initialWhere) {
|
|
|
463
567
|
}
|
|
464
568
|
|
|
465
569
|
// src/index.ts
|
|
466
|
-
var import_core = require("@korajs/core");
|
|
467
570
|
var import_core2 = require("@korajs/core");
|
|
468
571
|
var import_core3 = require("@korajs/core");
|
|
469
572
|
var import_core4 = require("@korajs/core");
|
|
470
573
|
var import_core5 = require("@korajs/core");
|
|
574
|
+
var import_core6 = require("@korajs/core");
|
|
575
|
+
var import_core7 = require("@korajs/core");
|
|
471
576
|
var import_store2 = require("@korajs/store");
|
|
577
|
+
var import_store3 = require("@korajs/store");
|
|
472
578
|
var import_merge2 = require("@korajs/merge");
|
|
473
579
|
var import_sync2 = require("@korajs/sync");
|
|
474
580
|
// Annotate the CommonJS export names for ESM import in node:
|
|
@@ -476,13 +582,17 @@ var import_sync2 = require("@korajs/sync");
|
|
|
476
582
|
HybridLogicalClock,
|
|
477
583
|
KoraError,
|
|
478
584
|
MergeEngine,
|
|
585
|
+
SequenceManager,
|
|
479
586
|
Store,
|
|
480
587
|
SyncEngine,
|
|
588
|
+
TransactionContext,
|
|
481
589
|
WebSocketTransport,
|
|
482
590
|
createApp,
|
|
483
591
|
createOperation,
|
|
484
592
|
defineSchema,
|
|
485
593
|
generateUUIDv7,
|
|
594
|
+
migrate,
|
|
595
|
+
op,
|
|
486
596
|
t
|
|
487
597
|
});
|
|
488
598
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/create-app.ts","../src/adapter-resolver.ts","../src/merge-aware-sync-store.ts"],"sourcesContent":["// kora — meta-package re-exporting core, store, merge, sync\n// This is the primary entry point for `import { createApp, defineSchema, t } from 'korajs'`\n\n// === createApp factory ===\nexport { createApp } from './create-app'\n\n// === App types ===\nexport type {\n\tAdapterType,\n\tKoraApp,\n\tKoraConfig,\n\tStoreOptions,\n\tSyncControl,\n\tSyncOptions,\n\tTypedCollectionAccessor,\n\tTypedKoraApp,\n\tTypedKoraConfig,\n} from './types'\n\n// === @korajs/core re-exports ===\nexport { defineSchema, t } from '@korajs/core'\nexport { HybridLogicalClock } from '@korajs/core'\nexport { generateUUIDv7 } from '@korajs/core'\nexport { createOperation } from '@korajs/core'\nexport { KoraError } from '@korajs/core'\nexport type {\n\tCollectionDefinition,\n\tConnectionQuality,\n\tConstraint,\n\tFieldDescriptor,\n\tFieldKindToType,\n\tHLCTimestamp,\n\tInferFieldType,\n\tInferInsertInput,\n\tInferRecord,\n\tInferUpdateInput,\n\tKoraEvent,\n\tKoraEventEmitter,\n\tKoraEventListener,\n\tKoraEventType,\n\tMergeStrategy,\n\tMergeTrace,\n\tOperation,\n\tSchemaDefinition,\n\tSchemaInput,\n\tTypedSchemaDefinition,\n\tVersionVector,\n} from '@korajs/core'\n\n// === @korajs/store re-exports ===\nexport { Store } from '@korajs/store'\nexport type {\n\tCollectionAccessor,\n\tCollectionRecord,\n\tStorageAdapter,\n\tStoreConfig,\n} from '@korajs/store'\n\n// === @korajs/merge re-exports ===\nexport { MergeEngine } from '@korajs/merge'\nexport type { MergeInput, MergeResult } from '@korajs/merge'\n\n// === @korajs/sync re-exports ===\nexport { SyncEngine, WebSocketTransport } from '@korajs/sync'\nexport type {\n\tSyncConfig,\n\tSyncState,\n\tSyncStatus,\n\tSyncStatusInfo,\n\tSyncStore,\n} from '@korajs/sync'\n","import type { KoraEventEmitter, Operation, SchemaInput } from '@korajs/core'\nimport { SimpleEventEmitter } from '@korajs/core/internal'\nimport { Instrumenter } from '@korajs/devtools'\nimport { MergeEngine } from '@korajs/merge'\nimport { Store } from '@korajs/store'\nimport type { CollectionAccessor, StorageAdapter } from '@korajs/store'\nimport type { QueryBuilder } from '@korajs/store'\nimport { ConnectionMonitor, ReconnectionManager, SyncEngine, WebSocketTransport } from '@korajs/sync'\nimport type { SyncStatusInfo } from '@korajs/sync'\nimport { createAdapter, detectAdapterType } from './adapter-resolver'\nimport { MergeAwareSyncStore } from './merge-aware-sync-store'\nimport type { KoraApp, KoraConfig, SyncControl, TypedKoraApp, TypedKoraConfig } from './types'\n\n/**\n * Creates a new Kora application instance.\n *\n * Wires together store, merge engine, event emitter, and optionally sync\n * into a single developer-facing `KoraApp` object. Collection accessors\n * (e.g. `app.todos`) are defined as properties for immediate use after `await app.ready`.\n *\n * @param config - Application configuration including schema and optional sync settings\n * @returns A KoraApp instance with reactive collections ready for use\n *\n * @example\n * ```typescript\n * const app = createApp({\n * schema: defineSchema({\n * version: 1,\n * collections: {\n * todos: {\n * fields: {\n * title: t.string(),\n * completed: t.boolean().default(false)\n * }\n * }\n * }\n * })\n * })\n *\n * await app.ready\n * const todo = await app.todos.insert({ title: 'Hello' })\n * ```\n */\n/**\n * Creates a new typed Kora application instance.\n * When the schema is created with `defineSchema()`, full type inference flows through\n * to collection accessors, providing autocomplete and type checking for all CRUD operations.\n */\nexport function createApp<const S extends SchemaInput>(config: TypedKoraConfig<S>): TypedKoraApp<S>\n/**\n * Creates a new Kora application instance (untyped fallback).\n */\nexport function createApp(config: KoraConfig): KoraApp\nexport function createApp(config: KoraConfig): KoraApp {\n\tconst emitter: KoraEventEmitter & { clear(): void } = new SimpleEventEmitter()\n\tconst mergeEngine = new MergeEngine()\n\n\tlet store: Store | null = null\n\tlet syncEngine: SyncEngine | null = null\n\tlet unsubscribeSync: (() => void) | null = null\n\tlet reconnectionManager: ReconnectionManager | null = null\n\tlet connectionMonitor: ConnectionMonitor | null = null\n\tlet instrumenter: Instrumenter | null = null\n\tlet intentionalDisconnect = false\n\tlet qualityInterval: ReturnType<typeof setInterval> | null = null\n\n\t// Wire DevTools instrumentation immediately (emitter exists synchronously)\n\tif (config.devtools) {\n\t\tinstrumenter = new Instrumenter(emitter, {\n\t\t\tbridgeEnabled: typeof globalThis !== 'undefined' && 'window' in globalThis,\n\t\t})\n\t}\n\n\t// Build the ready promise — resolves when the store is open and wired\n\tconst ready = initializeAsync(config, emitter, mergeEngine).then((result) => {\n\t\tstore = result.store\n\t\tsyncEngine = result.syncEngine\n\t\tunsubscribeSync = result.unsubscribeSync\n\n\t\t// Wire reconnection and connection quality after sync engine is ready\n\t\tif (config.sync && syncEngine) {\n\t\t\tconnectionMonitor = new ConnectionMonitor()\n\t\t\treconnectionManager = new ReconnectionManager({\n\t\t\t\tinitialDelay: config.sync.reconnectInterval,\n\t\t\t\tmaxDelay: config.sync.maxReconnectInterval,\n\t\t\t})\n\n\t\t\t// Track activity for connection quality\n\t\t\temitter.on('sync:sent', () => connectionMonitor?.recordActivity())\n\t\t\temitter.on('sync:received', () => connectionMonitor?.recordActivity())\n\t\t\temitter.on('sync:acknowledged', () => connectionMonitor?.recordActivity())\n\n\t\t\t// Emit quality on timer while connected\n\t\t\temitter.on('sync:connected', () => {\n\t\t\t\tif (qualityInterval !== null) clearInterval(qualityInterval)\n\t\t\t\tqualityInterval = setInterval(() => {\n\t\t\t\t\tif (connectionMonitor) {\n\t\t\t\t\t\temitter.emit({ type: 'connection:quality', quality: connectionMonitor.getQuality() })\n\t\t\t\t\t}\n\t\t\t\t}, 5000)\n\t\t\t})\n\n\t\t\t// Reset monitor and clear timer on disconnect\n\t\t\temitter.on('sync:disconnected', () => {\n\t\t\t\tconnectionMonitor?.reset()\n\t\t\t\tif (qualityInterval !== null) {\n\t\t\t\t\tclearInterval(qualityInterval)\n\t\t\t\t\tqualityInterval = null\n\t\t\t\t}\n\t\t\t})\n\n\t\t\t// Auto-reconnect on unexpected disconnect\n\t\t\tif (config.sync.autoReconnect !== false) {\n\t\t\t\tconst engine = syncEngine\n\t\t\t\temitter.on('sync:disconnected', () => {\n\t\t\t\t\tif (intentionalDisconnect) return\n\t\t\t\t\t// Ignore cascading disconnect events from failed reconnection attempts.\n\t\t\t\t\t// The reconnection manager is already retrying — don't restart it.\n\t\t\t\t\tif (reconnectionManager?.isRunning()) return\n\n\t\t\t\t\tengine.setReconnecting(true)\n\t\t\t\t\treconnectionManager?.stop()\n\t\t\t\t\treconnectionManager?.start(async () => {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tawait engine.start()\n\t\t\t\t\t\t\tengine.setReconnecting(false)\n\t\t\t\t\t\t\treturn true\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\treturn false\n\t\t\t\t\t\t}\n\t\t\t\t\t}).then(() => {\n\t\t\t\t\t\t// If reconnection exhausted max attempts without success, clear flag\n\t\t\t\t\t\tengine.setReconnecting(false)\n\t\t\t\t\t})\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\t})\n\n\t// Build sync control\n\tconst syncControl: SyncControl | null = config.sync\n\t\t? {\n\t\t\t\tasync connect(): Promise<void> {\n\t\t\t\t\tawait ready\n\t\t\t\t\tif (syncEngine) {\n\t\t\t\t\t\tintentionalDisconnect = false\n\t\t\t\t\t\treconnectionManager?.stop()\n\t\t\t\t\t\treconnectionManager?.reset()\n\t\t\t\t\t\tawait syncEngine.start()\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tasync disconnect(): Promise<void> {\n\t\t\t\t\tawait ready\n\t\t\t\t\tif (syncEngine) {\n\t\t\t\t\t\tintentionalDisconnect = true\n\t\t\t\t\t\treconnectionManager?.stop()\n\t\t\t\t\t\tawait syncEngine.stop()\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tgetStatus(): SyncStatusInfo {\n\t\t\t\t\tif (syncEngine) {\n\t\t\t\t\t\treturn syncEngine.getStatus()\n\t\t\t\t\t}\n\t\t\t\t\treturn { status: 'offline', pendingOperations: 0, lastSyncedAt: null }\n\t\t\t\t},\n\t\t\t}\n\t\t: null\n\n\t// Build the KoraApp object\n\tconst app: KoraApp = {\n\t\tready,\n\t\tevents: emitter,\n\t\tsync: syncControl,\n\t\tgetStore(): Store {\n\t\t\tif (!store) {\n\t\t\t\tthrow new Error('Store not initialized. Await app.ready before accessing the store.')\n\t\t\t}\n\t\t\treturn store\n\t\t},\n\t\tgetSyncEngine(): SyncEngine | null {\n\t\t\treturn syncEngine\n\t\t},\n\t\tasync close(): Promise<void> {\n\t\t\tawait ready\n\t\t\tintentionalDisconnect = true\n\t\t\tif (qualityInterval !== null) {\n\t\t\t\tclearInterval(qualityInterval)\n\t\t\t\tqualityInterval = null\n\t\t\t}\n\t\t\treconnectionManager?.stop()\n\t\t\tif (instrumenter) {\n\t\t\t\tinstrumenter.destroy()\n\t\t\t\tinstrumenter = null\n\t\t\t}\n\t\t\tif (unsubscribeSync) {\n\t\t\t\tunsubscribeSync()\n\t\t\t\tunsubscribeSync = null\n\t\t\t}\n\t\t\tif (syncEngine) {\n\t\t\t\tawait syncEngine.stop()\n\t\t\t\tsyncEngine = null\n\t\t\t}\n\t\t\tif (store) {\n\t\t\t\tawait store.close()\n\t\t\t\tstore = null\n\t\t\t}\n\t\t\temitter.clear()\n\t\t},\n\t}\n\n\t// Define collection accessors via Object.defineProperty.\n\t// Before ready resolves, query methods return empty results.\n\tfor (const collectionName of Object.keys(config.schema.collections)) {\n\t\tObject.defineProperty(app, collectionName, {\n\t\t\tget(): CollectionAccessor {\n\t\t\t\treturn createCollectionAccessor(collectionName, () => store)\n\t\t\t},\n\t\t\tenumerable: true,\n\t\t\tconfigurable: false,\n\t\t})\n\t}\n\n\treturn app\n}\n\n/**\n * Asynchronous initialization: create adapter, open store, wire sync.\n */\nasync function initializeAsync(\n\tconfig: KoraConfig,\n\temitter: KoraEventEmitter,\n\tmergeEngine: MergeEngine,\n): Promise<{\n\tstore: Store\n\tsyncEngine: SyncEngine | null\n\tunsubscribeSync: (() => void) | null\n}> {\n\t// Resolve adapter\n\tconst adapterType = config.store?.adapter ?? detectAdapterType()\n\tconst dbName = config.store?.name ?? 'kora-db'\n\tconst adapter: StorageAdapter = await createAdapter(adapterType, dbName, config.store?.workerUrl)\n\n\t// Create and open the store\n\tconst store = new Store({\n\t\tschema: config.schema,\n\t\tadapter,\n\t\temitter,\n\t})\n\tawait store.open()\n\n\t// Wire sync if configured\n\tlet syncEngine: SyncEngine | null = null\n\tlet unsubscribeSync: (() => void) | null = null\n\n\tif (config.sync) {\n\t\tconst transport = new WebSocketTransport()\n\t\tconst mergeAwareStore = new MergeAwareSyncStore(store, mergeEngine, emitter)\n\n\t\tsyncEngine = new SyncEngine({\n\t\t\ttransport,\n\t\t\tstore: mergeAwareStore,\n\t\t\tconfig: {\n\t\t\t\turl: config.sync.url,\n\t\t\t\ttransport: config.sync.transport,\n\t\t\t\tauth: config.sync.auth,\n\t\t\t\tbatchSize: config.sync.batchSize,\n\t\t\t\tschemaVersion: config.sync.schemaVersion ?? config.schema.version,\n\t\t\t},\n\t\t\temitter,\n\t\t})\n\n\t\t// Wire local mutations → sync outbound queue\n\t\tunsubscribeSync = emitter.on('operation:created', (event) => {\n\t\t\tif (syncEngine) {\n\t\t\t\tsyncEngine.pushOperation(event.operation)\n\t\t\t}\n\t\t})\n\t}\n\n\treturn { store, syncEngine, unsubscribeSync }\n}\n\nfunction createCollectionAccessor(\n\tcollectionName: string,\n\tgetStore: () => Store | null,\n): CollectionAccessor {\n\treturn {\n\t\tasync insert(data: Record<string, unknown>) {\n\t\t\tconst currentStore = getStore()\n\t\t\tif (!currentStore) {\n\t\t\t\tthrow new Error(`Cannot mutate collection \"${collectionName}\" before app.ready resolves.`)\n\t\t\t}\n\t\t\treturn currentStore.collection(collectionName).insert(data)\n\t\t},\n\t\tasync findById(id: string) {\n\t\t\tconst currentStore = getStore()\n\t\t\tif (!currentStore) return null\n\t\t\treturn currentStore.collection(collectionName).findById(id)\n\t\t},\n\t\tasync update(id: string, data: Record<string, unknown>) {\n\t\t\tconst currentStore = getStore()\n\t\t\tif (!currentStore) {\n\t\t\t\tthrow new Error(`Cannot mutate collection \"${collectionName}\" before app.ready resolves.`)\n\t\t\t}\n\t\t\treturn currentStore.collection(collectionName).update(id, data)\n\t\t},\n\t\tasync delete(id: string) {\n\t\t\tconst currentStore = getStore()\n\t\t\tif (!currentStore) {\n\t\t\t\tthrow new Error(`Cannot mutate collection \"${collectionName}\" before app.ready resolves.`)\n\t\t\t}\n\t\t\treturn currentStore.collection(collectionName).delete(id)\n\t\t},\n\t\twhere(conditions: Record<string, unknown>) {\n\t\t\tconst currentStore = getStore()\n\t\t\tif (!currentStore) {\n\t\t\t\treturn createPendingQueryBuilder(conditions)\n\t\t\t}\n\t\t\treturn currentStore.collection(collectionName).where(conditions)\n\t\t},\n\t}\n}\n\nfunction createPendingQueryBuilder(initialWhere: Record<string, unknown>): QueryBuilder {\n\tconst descriptor = {\n\t\tcollection: '__pending__',\n\t\twhere: { ...initialWhere },\n\t\torderBy: [] as Array<{ field: string; direction: 'asc' | 'desc' }>,\n\t\tlimit: undefined as number | undefined,\n\t\toffset: undefined as number | undefined,\n\t}\n\n\tconst builder = {\n\t\twhere(conditions: Record<string, unknown>) {\n\t\t\tdescriptor.where = { ...descriptor.where, ...conditions }\n\t\t\treturn this\n\t\t},\n\t\torderBy(field: string, direction: 'asc' | 'desc' = 'asc') {\n\t\t\tdescriptor.orderBy.push({ field, direction })\n\t\t\treturn this\n\t\t},\n\t\tlimit(n: number) {\n\t\t\tdescriptor.limit = n\n\t\t\treturn this\n\t\t},\n\t\toffset(n: number) {\n\t\t\tdescriptor.offset = n\n\t\t\treturn this\n\t\t},\n\t\tasync exec() {\n\t\t\treturn []\n\t\t},\n\t\tasync count() {\n\t\t\treturn 0\n\t\t},\n\t\tsubscribe(callback: (results: Array<Record<string, unknown>>) => void) {\n\t\t\tvoid callback([])\n\t\t\treturn () => {}\n\t\t},\n\t\tgetDescriptor() {\n\t\t\treturn { ...descriptor, where: { ...descriptor.where }, orderBy: [...descriptor.orderBy] }\n\t\t},\n\t}\n\n\treturn builder as unknown as QueryBuilder\n}\n","import type { StorageAdapter } from '@korajs/store'\nimport type { AdapterType } from './types'\n\n/**\n * Detect the best storage adapter for the current environment.\n *\n * - Tauri app: 'tauri-sqlite' (native SQLite via Tauri plugin)\n * - Node.js: 'better-sqlite3'\n * - Browser with OPFS: 'sqlite-wasm'\n * - Browser without OPFS: 'indexeddb'\n */\nexport function detectAdapterType(): AdapterType {\n\t// Tauri environment — detected via __TAURI_INTERNALS__ injected by the Tauri runtime\n\tif (\n\t\ttypeof globalThis !== 'undefined' &&\n\t\ttypeof (globalThis as Record<string, unknown>).__TAURI_INTERNALS__ !== 'undefined'\n\t) {\n\t\treturn 'tauri-sqlite'\n\t}\n\n\t// Node.js environment\n\tif (typeof process !== 'undefined' && process.versions?.node) {\n\t\treturn 'better-sqlite3'\n\t}\n\n\t// Browser environment\n\tif (typeof globalThis.navigator !== 'undefined') {\n\t\t// Check for OPFS support (FileSystemHandle indicates OPFS availability)\n\t\tif (typeof (globalThis as Record<string, unknown>).FileSystemHandle !== 'undefined') {\n\t\t\treturn 'sqlite-wasm'\n\t\t}\n\t\treturn 'indexeddb'\n\t}\n\n\t// Default fallback (e.g., Deno, Bun, or other runtimes)\n\treturn 'better-sqlite3'\n}\n\n/**\n * Create a StorageAdapter for the given adapter type.\n * Uses dynamic imports so unused adapters are not bundled.\n *\n * @param type - The adapter type to create\n * @param dbName - Database name (used by all adapters)\n * @returns A configured StorageAdapter instance\n */\nexport async function createAdapter(\n\ttype: AdapterType,\n\tdbName: string,\n\tworkerUrl?: string | URL,\n): Promise<StorageAdapter> {\n\tswitch (type) {\n\t\tcase 'tauri-sqlite': {\n\t\t\t// @korajs/tauri is only installed in Tauri projects (optional peer dep).\n\t\t\t// This code path only runs when __TAURI_INTERNALS__ is detected.\n\t\t\t// Using @vite-ignore so Vite doesn't statically analyze this import —\n\t\t\t// it will still resolve it at runtime through Vite's dev server.\n\t\t\tconst { TauriSqliteAdapter } = await import(\n\t\t\t\t/* @vite-ignore */ '@korajs/tauri'\n\t\t\t)\n\t\t\treturn new TauriSqliteAdapter({ path: `${dbName}.db` })\n\t\t}\n\t\tcase 'better-sqlite3': {\n\t\t\tconst { BetterSqlite3Adapter } = await import(\n\t\t\t\t/* @vite-ignore */ '@korajs/store/better-sqlite3'\n\t\t\t)\n\t\t\treturn new BetterSqlite3Adapter(dbName)\n\t\t}\n\t\tcase 'sqlite-wasm': {\n\t\t\tconst { SqliteWasmAdapter } = await import('@korajs/store/sqlite-wasm')\n\t\t\treturn new SqliteWasmAdapter({ dbName, workerUrl })\n\t\t}\n\t\tcase 'indexeddb': {\n\t\t\tconst { IndexedDbAdapter } = await import('@korajs/store/indexeddb')\n\t\t\treturn new IndexedDbAdapter({ dbName, workerUrl })\n\t\t}\n\t\tdefault: {\n\t\t\tconst _exhaustive: never = type\n\t\t\tthrow new Error(`Unknown adapter type: ${_exhaustive}`)\n\t\t}\n\t}\n}\n","import type { KoraEventEmitter, Operation, VersionVector } from '@korajs/core'\nimport type { MergeEngine, MergeInput } from '@korajs/merge'\nimport type { Store } from '@korajs/store'\nimport type { ApplyResult, SyncStore } from '@korajs/sync'\n\n/**\n * Wraps a Store to interpose merge resolution before applying remote operations.\n *\n * For inserts and deletes, delegates directly to the underlying Store.\n * For updates, checks whether the remote operation's previousData conflicts\n * with the current local state. If so, runs MergeEngine to resolve and\n * applies the merged result instead.\n *\n * This keeps MergeEngine integration out of Store and SyncEngine internals.\n */\nexport class MergeAwareSyncStore implements SyncStore {\n\tconstructor(\n\t\tprivate readonly store: Store,\n\t\tprivate readonly mergeEngine: MergeEngine,\n\t\tprivate readonly emitter: KoraEventEmitter | null,\n\t) {}\n\n\tgetVersionVector(): VersionVector {\n\t\treturn this.store.getVersionVector()\n\t}\n\n\tgetNodeId(): string {\n\t\treturn this.store.getNodeId()\n\t}\n\n\tasync getOperationRange(nodeId: string, fromSeq: number, toSeq: number): Promise<Operation[]> {\n\t\treturn this.store.getOperationRange(nodeId, fromSeq, toSeq)\n\t}\n\n\tasync applyRemoteOperation(op: Operation): Promise<ApplyResult> {\n\t\t// Only intercept updates that have previousData (needed for 3-way merge)\n\t\tif (op.type !== 'update' || !op.data || !op.previousData) {\n\t\t\treturn this.store.applyRemoteOperation(op)\n\t\t}\n\n\t\t// Look up current local record to detect conflicts\n\t\tconst schema = this.store.getSchema()\n\t\tconst collectionDef = schema.collections[op.collection]\n\t\tif (!collectionDef) {\n\t\t\treturn this.store.applyRemoteOperation(op)\n\t\t}\n\n\t\tconst accessor = this.store.collection(op.collection)\n\t\tconst currentRecord = await accessor.findById(op.recordId)\n\n\t\t// If record doesn't exist locally, delegate directly\n\t\tif (!currentRecord) {\n\t\t\treturn this.store.applyRemoteOperation(op)\n\t\t}\n\n\t\t// Check for conflicts: do any of the remote op's changed fields differ\n\t\t// from what the remote op expected them to be (previousData)?\n\t\tlet hasConflict = false\n\t\tfor (const field of Object.keys(op.data)) {\n\t\t\tconst expectedBase = op.previousData[field]\n\t\t\tconst currentLocal = currentRecord[field]\n\n\t\t\t// If the local state doesn't match what the remote expected,\n\t\t\t// it means the local side also changed this field — conflict.\n\t\t\tif (!deepEqual(expectedBase, currentLocal)) {\n\t\t\t\thasConflict = true\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\t// No conflict: safe to apply directly\n\t\tif (!hasConflict) {\n\t\t\treturn this.store.applyRemoteOperation(op)\n\t\t}\n\n\t\t// Conflict detected — run merge engine\n\t\t// Build a synthetic \"local operation\" representing the current local state changes\n\t\t// relative to the same base the remote operation used.\n\t\tthis.emitter?.emit({\n\t\t\ttype: 'merge:started',\n\t\t\toperationA: op,\n\t\t\toperationB: op,\n\t\t})\n\n\t\tconst baseState: Record<string, unknown> = { ...op.previousData }\n\t\tconst localOp: Operation = {\n\t\t\t...op,\n\t\t\t// The \"local\" operation's data is the diff between base and current local state\n\t\t\tdata: buildLocalDiff(op.previousData, currentRecord, Object.keys(op.data)),\n\t\t\tpreviousData: op.previousData,\n\t\t\tnodeId: this.store.getNodeId(),\n\t\t}\n\n\t\tconst input: MergeInput = {\n\t\t\tlocal: localOp,\n\t\t\tremote: op,\n\t\t\tbaseState,\n\t\t\tcollectionDef,\n\t\t}\n\n\t\tconst result = this.mergeEngine.mergeFields(input)\n\n\t\t// Emit merge traces\n\t\tfor (const trace of result.traces) {\n\t\t\tthis.emitter?.emit({ type: 'merge:conflict', trace })\n\t\t}\n\t\tconst firstTrace = result.traces[0]\n\t\tif (firstTrace) {\n\t\t\tthis.emitter?.emit({ type: 'merge:completed', trace: firstTrace })\n\t\t}\n\n\t\t// Create a modified operation with the merged data to apply\n\t\tconst mergedOp: Operation = {\n\t\t\t...op,\n\t\t\tdata: result.mergedData,\n\t\t}\n\n\t\treturn this.store.applyRemoteOperation(mergedOp)\n\t}\n}\n\n/**\n * Build the local diff: for each field the remote op changed,\n * extract the current local value (which may differ from both base and remote).\n */\nfunction buildLocalDiff(\n\tbaseState: Record<string, unknown>,\n\tcurrentRecord: Record<string, unknown>,\n\tfields: string[],\n): Record<string, unknown> {\n\tconst diff: Record<string, unknown> = {}\n\tfor (const field of fields) {\n\t\tdiff[field] = currentRecord[field]\n\t}\n\treturn diff\n}\n\n/**\n * Simple deep equality check for comparing field values.\n * Handles primitives, arrays, and plain objects.\n */\nfunction deepEqual(a: unknown, b: unknown): boolean {\n\tif (a === b) return true\n\tif (a === null || b === null) return false\n\tif (a === undefined || b === undefined) return false\n\tif (typeof a !== typeof b) return false\n\n\tif (Array.isArray(a) && Array.isArray(b)) {\n\t\tif (a.length !== b.length) return false\n\t\treturn a.every((val, i) => deepEqual(val, b[i]))\n\t}\n\n\tif (typeof a === 'object' && typeof b === 'object') {\n\t\tconst keysA = Object.keys(a as Record<string, unknown>)\n\t\tconst keysB = Object.keys(b as Record<string, unknown>)\n\t\tif (keysA.length !== keysB.length) return false\n\t\treturn keysA.every((key) =>\n\t\t\tdeepEqual((a as Record<string, unknown>)[key], (b as Record<string, unknown>)[key]),\n\t\t)\n\t}\n\n\treturn false\n}\n"],"mappings":"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","names":["import_core","import_store","import_merge","import_sync"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/create-app.ts","../src/adapter-resolver.ts","../src/merge-aware-sync-store.ts"],"sourcesContent":["// kora — meta-package re-exporting core, store, merge, sync\n// This is the primary entry point for `import { createApp, defineSchema, t } from 'korajs'`\n\n// === createApp factory ===\nexport { createApp } from './create-app'\n\n// === App types ===\nexport type {\n\tAdapterType,\n\tKoraApp,\n\tKoraConfig,\n\tStoreOptions,\n\tSyncControl,\n\tSyncOptions,\n\tSequenceAccessor,\n\tTransactionCollectionProxy,\n\tTransactionProxy,\n\tTypedCollectionAccessor,\n\tTypedKoraApp,\n\tTypedKoraConfig,\n} from './types'\n\n// === @korajs/core re-exports ===\nexport { defineSchema, migrate, t } from '@korajs/core'\nexport { HybridLogicalClock } from '@korajs/core'\nexport { generateUUIDv7 } from '@korajs/core'\nexport { createOperation } from '@korajs/core'\nexport { KoraError } from '@korajs/core'\nexport { op } from '@korajs/core'\nexport type {\n\tAtomicOp,\n\tAtomicOpType,\n\tCollectionDefinition,\n\tConnectionQuality,\n\tConstraint,\n\tFieldDescriptor,\n\tFieldKindToType,\n\tHLCTimestamp,\n\tInferFieldType,\n\tInferInsertInput,\n\tInferRecord,\n\tInferUpdateInput,\n\tKoraEvent,\n\tKoraEventEmitter,\n\tKoraEventListener,\n\tKoraEventType,\n\tMergeStrategy,\n\tMergeTrace,\n\tMigrationDefinition,\n\tMigrationStep,\n\tOperation,\n\tSchemaDefinition,\n\tSchemaInput,\n\tSequenceConfig,\n\tTypedSchemaDefinition,\n\tVersionVector,\n} from '@korajs/core'\n\n// === @korajs/store re-exports ===\nexport { SequenceManager, Store } from '@korajs/store'\nexport { TransactionContext } from '@korajs/store'\nexport type {\n\tCollectionAccessor,\n\tCollectionRecord,\n\tStorageAdapter,\n\tStoreConfig,\n\tTransactionCollectionAccessor,\n\tTransactionContextConfig,\n} from '@korajs/store'\n\n// === @korajs/merge re-exports ===\nexport { MergeEngine } from '@korajs/merge'\nexport type { MergeInput, MergeResult } from '@korajs/merge'\n\n// === @korajs/sync re-exports ===\nexport { SyncEngine, WebSocketTransport } from '@korajs/sync'\nexport type {\n\tSyncConfig,\n\tSyncDiagnostics,\n\tSyncState,\n\tSyncStatus,\n\tSyncStatusInfo,\n\tSyncStore,\n} from '@korajs/sync'\n","import type { KoraEventEmitter, Operation, SchemaInput } from '@korajs/core'\nimport { buildScopeMap } from '@korajs/core'\nimport { SimpleEventEmitter } from '@korajs/core/internal'\nimport { Instrumenter } from '@korajs/devtools'\nimport { MergeEngine } from '@korajs/merge'\nimport { Store } from '@korajs/store'\nimport type { CollectionAccessor, StorageAdapter } from '@korajs/store'\nimport type { QueryBuilder } from '@korajs/store'\nimport {\n\tConnectionMonitor,\n\tReconnectionManager,\n\tSyncEngine,\n\tWebSocketTransport,\n} from '@korajs/sync'\nimport type { SyncStatusInfo } from '@korajs/sync'\nimport { createAdapter, detectAdapterType } from './adapter-resolver'\nimport { MergeAwareSyncStore } from './merge-aware-sync-store'\nimport type {\n\tKoraApp,\n\tKoraConfig,\n\tSequenceAccessor,\n\tSyncControl,\n\tTransactionProxy,\n\tTypedKoraApp,\n\tTypedKoraConfig,\n} from './types'\n\n/**\n * Creates a new Kora application instance.\n *\n * Wires together store, merge engine, event emitter, and optionally sync\n * into a single developer-facing `KoraApp` object. Collection accessors\n * (e.g. `app.todos`) are defined as properties for immediate use after `await app.ready`.\n *\n * @param config - Application configuration including schema and optional sync settings\n * @returns A KoraApp instance with reactive collections ready for use\n *\n * @example\n * ```typescript\n * const app = createApp({\n * schema: defineSchema({\n * version: 1,\n * collections: {\n * todos: {\n * fields: {\n * title: t.string(),\n * completed: t.boolean().default(false)\n * }\n * }\n * }\n * })\n * })\n *\n * await app.ready\n * const todo = await app.todos.insert({ title: 'Hello' })\n * ```\n */\n/**\n * Creates a new typed Kora application instance.\n * When the schema is created with `defineSchema()`, full type inference flows through\n * to collection accessors, providing autocomplete and type checking for all CRUD operations.\n */\nexport function createApp<const S extends SchemaInput>(config: TypedKoraConfig<S>): TypedKoraApp<S>\n/**\n * Creates a new Kora application instance (untyped fallback).\n */\nexport function createApp(config: KoraConfig): KoraApp\nexport function createApp(config: KoraConfig): KoraApp {\n\tconst emitter: KoraEventEmitter & { clear(): void } = new SimpleEventEmitter()\n\tconst mergeEngine = new MergeEngine()\n\n\tlet store: Store | null = null\n\tlet syncEngine: SyncEngine | null = null\n\tlet unsubscribeSync: (() => void) | null = null\n\tlet reconnectionManager: ReconnectionManager | null = null\n\tlet connectionMonitor: ConnectionMonitor | null = null\n\tlet instrumenter: Instrumenter | null = null\n\tlet intentionalDisconnect = false\n\tlet qualityInterval: ReturnType<typeof setInterval> | null = null\n\n\t// Wire DevTools instrumentation immediately (emitter exists synchronously)\n\tif (config.devtools) {\n\t\tinstrumenter = new Instrumenter(emitter, {\n\t\t\tbridgeEnabled: typeof globalThis !== 'undefined' && 'window' in globalThis,\n\t\t})\n\t}\n\n\t// Build the ready promise — resolves when the store is open and wired\n\tconst ready = initializeAsync(config, emitter, mergeEngine).then((result) => {\n\t\tstore = result.store\n\t\tsyncEngine = result.syncEngine\n\t\tunsubscribeSync = result.unsubscribeSync\n\n\t\t// Wire reconnection and connection quality after sync engine is ready\n\t\tif (config.sync && syncEngine) {\n\t\t\tconnectionMonitor = new ConnectionMonitor()\n\t\t\treconnectionManager = new ReconnectionManager({\n\t\t\t\tinitialDelay: config.sync.reconnectInterval,\n\t\t\t\tmaxDelay: config.sync.maxReconnectInterval,\n\t\t\t})\n\n\t\t\t// Track activity for connection quality\n\t\t\temitter.on('sync:sent', () => connectionMonitor?.recordActivity())\n\t\t\temitter.on('sync:received', () => connectionMonitor?.recordActivity())\n\t\t\temitter.on('sync:acknowledged', () => connectionMonitor?.recordActivity())\n\n\t\t\t// Emit quality on timer while connected\n\t\t\temitter.on('sync:connected', () => {\n\t\t\t\tif (qualityInterval !== null) clearInterval(qualityInterval)\n\t\t\t\tqualityInterval = setInterval(() => {\n\t\t\t\t\tif (connectionMonitor) {\n\t\t\t\t\t\temitter.emit({ type: 'connection:quality', quality: connectionMonitor.getQuality() })\n\t\t\t\t\t}\n\t\t\t\t}, 5000)\n\t\t\t})\n\n\t\t\t// Reset monitor and clear timer on disconnect\n\t\t\temitter.on('sync:disconnected', () => {\n\t\t\t\tconnectionMonitor?.reset()\n\t\t\t\tif (qualityInterval !== null) {\n\t\t\t\t\tclearInterval(qualityInterval)\n\t\t\t\t\tqualityInterval = null\n\t\t\t\t}\n\t\t\t})\n\n\t\t\t// Auto-reconnect on unexpected disconnect\n\t\t\tif (config.sync.autoReconnect !== false) {\n\t\t\t\tconst engine = syncEngine\n\t\t\t\temitter.on('sync:disconnected', () => {\n\t\t\t\t\tif (intentionalDisconnect) return\n\t\t\t\t\t// Ignore cascading disconnect events from failed reconnection attempts.\n\t\t\t\t\t// The reconnection manager is already retrying — don't restart it.\n\t\t\t\t\tif (reconnectionManager?.isRunning()) return\n\n\t\t\t\t\tengine.setReconnecting(true)\n\t\t\t\t\treconnectionManager?.stop()\n\t\t\t\t\treconnectionManager\n\t\t\t\t\t\t?.start(async () => {\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tawait engine.start()\n\t\t\t\t\t\t\t\tengine.setReconnecting(false)\n\t\t\t\t\t\t\t\treturn true\n\t\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t\treturn false\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t})\n\t\t\t\t\t\t.then(() => {\n\t\t\t\t\t\t\t// If reconnection exhausted max attempts without success, clear flag\n\t\t\t\t\t\t\tengine.setReconnecting(false)\n\t\t\t\t\t\t})\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\t})\n\n\t// Build sync control\n\tconst syncControl: SyncControl | null = config.sync\n\t\t? {\n\t\t\t\tasync connect(): Promise<void> {\n\t\t\t\t\tawait ready\n\t\t\t\t\tif (syncEngine) {\n\t\t\t\t\t\tintentionalDisconnect = false\n\t\t\t\t\t\treconnectionManager?.stop()\n\t\t\t\t\t\treconnectionManager?.reset()\n\t\t\t\t\t\tawait syncEngine.start()\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tasync disconnect(): Promise<void> {\n\t\t\t\t\tawait ready\n\t\t\t\t\tif (syncEngine) {\n\t\t\t\t\t\tintentionalDisconnect = true\n\t\t\t\t\t\treconnectionManager?.stop()\n\t\t\t\t\t\tawait syncEngine.stop()\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tgetStatus(): SyncStatusInfo {\n\t\t\t\t\tif (syncEngine) {\n\t\t\t\t\t\treturn syncEngine.getStatus()\n\t\t\t\t\t}\n\t\t\t\t\treturn {\n\t\t\t\t\t\tstatus: 'offline',\n\t\t\t\t\t\tpendingOperations: 0,\n\t\t\t\t\t\tlastSyncedAt: null,\n\t\t\t\t\t\tlastSuccessfulPush: null,\n\t\t\t\t\t\tlastSuccessfulPull: null,\n\t\t\t\t\t\tconflicts: 0,\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tasync retryNow(): Promise<void> {\n\t\t\t\t\tawait ready\n\t\t\t\t\tif (syncEngine) {\n\t\t\t\t\t\tawait syncEngine.retryNow()\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\texportDiagnostics() {\n\t\t\t\t\tif (syncEngine) {\n\t\t\t\t\t\treturn syncEngine.exportDiagnostics()\n\t\t\t\t\t}\n\t\t\t\t\treturn {\n\t\t\t\t\t\tstate: 'disconnected' as const,\n\t\t\t\t\t\tstatus: {\n\t\t\t\t\t\t\tstatus: 'offline' as const,\n\t\t\t\t\t\t\tpendingOperations: 0,\n\t\t\t\t\t\t\tlastSyncedAt: null,\n\t\t\t\t\t\t\tlastSuccessfulPush: null,\n\t\t\t\t\t\t\tlastSuccessfulPull: null,\n\t\t\t\t\t\t\tconflicts: 0,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tnodeId: '',\n\t\t\t\t\t\turl: config.sync?.url ?? '',\n\t\t\t\t\t\tschemaVersion: config.schema.version,\n\t\t\t\t\t\tlastSyncedAt: null,\n\t\t\t\t\t\tlastSuccessfulPush: null,\n\t\t\t\t\t\tlastSuccessfulPull: null,\n\t\t\t\t\t\tconflicts: 0,\n\t\t\t\t\t\tpendingOperations: 0,\n\t\t\t\t\t\thasInFlightBatch: false,\n\t\t\t\t\t\treconnecting: false,\n\t\t\t\t\t\ttimestamp: Date.now(),\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t}\n\t\t: null\n\n\t// Shared transaction executor for both transaction() and mutation()\n\tasync function executeTransaction(\n\t\tfn: (tx: TransactionProxy) => Promise<void>,\n\t\tmutationName?: string,\n\t): Promise<Operation[]> {\n\t\tawait ready\n\t\tif (!store) {\n\t\t\tthrow new Error('Store not initialized. Await app.ready before using transactions.')\n\t\t}\n\t\tconst txContext = store.createTransaction()\n\t\tif (mutationName !== undefined) {\n\t\t\ttxContext.setMutationName(mutationName)\n\t\t}\n\t\tconst collectionNames = Object.keys(config.schema.collections)\n\n\t\t// Build proxy with collection accessors as direct properties\n\t\tconst proxy: TransactionProxy = {} as TransactionProxy\n\t\tfor (const name of collectionNames) {\n\t\t\tObject.defineProperty(proxy, name, {\n\t\t\t\tget() {\n\t\t\t\t\treturn txContext.collection(name)\n\t\t\t\t},\n\t\t\t\tenumerable: true,\n\t\t\t\tconfigurable: false,\n\t\t\t})\n\t\t}\n\n\t\ttry {\n\t\t\tawait fn(proxy)\n\t\t\tconst { operations } = await txContext.commit()\n\n\t\t\t// Notify subscriptions and emit events after commit\n\t\t\tfor (const op of operations) {\n\t\t\t\tstore.getSubscriptionManager().notify(op.collection, op)\n\t\t\t\temitter.emit({ type: 'operation:created', operation: op })\n\t\t\t}\n\n\t\t\treturn operations\n\t\t} catch (error) {\n\t\t\ttxContext.rollback()\n\t\t\tthrow error\n\t\t}\n\t}\n\n\t// Build sequences accessor (delegates to SequenceManager after ready)\n\tconst sequences: SequenceAccessor = {\n\t\tasync next(name, config) {\n\t\t\tawait ready\n\t\t\tif (!store) throw new Error('Store not initialized. Await app.ready before using sequences.')\n\t\t\treturn store.getSequenceManager().next(name, config)\n\t\t},\n\t\tasync current(name, config) {\n\t\t\tawait ready\n\t\t\tif (!store) throw new Error('Store not initialized. Await app.ready before using sequences.')\n\t\t\treturn store.getSequenceManager().current(name, config)\n\t\t},\n\t\tasync reset(name, config) {\n\t\t\tawait ready\n\t\t\tif (!store) throw new Error('Store not initialized. Await app.ready before using sequences.')\n\t\t\treturn store.getSequenceManager().reset(name, config)\n\t\t},\n\t}\n\n\t// Build the KoraApp object\n\tconst app: KoraApp = {\n\t\tready,\n\t\tevents: emitter,\n\t\tsync: syncControl,\n\t\tsequences,\n\t\tgetStore(): Store {\n\t\t\tif (!store) {\n\t\t\t\tthrow new Error('Store not initialized. Await app.ready before accessing the store.')\n\t\t\t}\n\t\t\treturn store\n\t\t},\n\t\tgetSyncEngine(): SyncEngine | null {\n\t\t\treturn syncEngine\n\t\t},\n\t\tasync transaction(fn: (tx: TransactionProxy) => Promise<void>): Promise<Operation[]> {\n\t\t\treturn executeTransaction(fn)\n\t\t},\n\t\tasync mutation(\n\t\t\tname: string,\n\t\t\tfn: (tx: TransactionProxy) => Promise<void>,\n\t\t): Promise<Operation[]> {\n\t\t\treturn executeTransaction(fn, name)\n\t\t},\n\t\tasync close(): Promise<void> {\n\t\t\tawait ready\n\t\t\tintentionalDisconnect = true\n\t\t\tif (qualityInterval !== null) {\n\t\t\t\tclearInterval(qualityInterval)\n\t\t\t\tqualityInterval = null\n\t\t\t}\n\t\t\treconnectionManager?.stop()\n\t\t\tif (instrumenter) {\n\t\t\t\tinstrumenter.destroy()\n\t\t\t\tinstrumenter = null\n\t\t\t}\n\t\t\tif (unsubscribeSync) {\n\t\t\t\tunsubscribeSync()\n\t\t\t\tunsubscribeSync = null\n\t\t\t}\n\t\t\tif (syncEngine) {\n\t\t\t\tawait syncEngine.stop()\n\t\t\t\tsyncEngine = null\n\t\t\t}\n\t\t\tif (store) {\n\t\t\t\tawait store.close()\n\t\t\t\tstore = null\n\t\t\t}\n\t\t\temitter.clear()\n\t\t},\n\t}\n\n\t// Define collection accessors via Object.defineProperty.\n\t// Before ready resolves, query methods return empty results.\n\tfor (const collectionName of Object.keys(config.schema.collections)) {\n\t\tObject.defineProperty(app, collectionName, {\n\t\t\tget(): CollectionAccessor {\n\t\t\t\treturn createCollectionAccessor(collectionName, () => store)\n\t\t\t},\n\t\t\tenumerable: true,\n\t\t\tconfigurable: false,\n\t\t})\n\t}\n\n\treturn app\n}\n\n/**\n * Asynchronous initialization: create adapter, open store, wire sync.\n */\nasync function initializeAsync(\n\tconfig: KoraConfig,\n\temitter: KoraEventEmitter,\n\tmergeEngine: MergeEngine,\n): Promise<{\n\tstore: Store\n\tsyncEngine: SyncEngine | null\n\tunsubscribeSync: (() => void) | null\n}> {\n\t// Resolve adapter\n\tconst adapterType = config.store?.adapter ?? detectAdapterType()\n\tconst dbName = config.store?.name ?? 'kora-db'\n\tconst adapter: StorageAdapter = await createAdapter(adapterType, dbName, config.store?.workerUrl)\n\n\t// Create and open the store\n\tconst store = new Store({\n\t\tschema: config.schema,\n\t\tadapter,\n\t\temitter,\n\t})\n\tawait store.open()\n\n\t// Wire sync if configured\n\tlet syncEngine: SyncEngine | null = null\n\tlet unsubscribeSync: (() => void) | null = null\n\n\tif (config.sync) {\n\t\tconst transport = new WebSocketTransport()\n\t\tconst mergeAwareStore = new MergeAwareSyncStore(store, mergeEngine, emitter)\n\n\t\t// Build scope map from schema scope declarations + flat scope values\n\t\tconst scopeMap = config.sync.scope ? buildScopeMap(config.schema, config.sync.scope) : undefined\n\n\t\tsyncEngine = new SyncEngine({\n\t\t\ttransport,\n\t\t\tstore: mergeAwareStore,\n\t\t\tconfig: {\n\t\t\t\turl: config.sync.url,\n\t\t\t\ttransport: config.sync.transport,\n\t\t\t\tauth: config.sync.auth,\n\t\t\t\tbatchSize: config.sync.batchSize,\n\t\t\t\tschemaVersion: config.sync.schemaVersion ?? config.schema.version,\n\t\t\t\tscopeMap,\n\t\t\t},\n\t\t\temitter,\n\t\t})\n\n\t\t// Wire local mutations → sync outbound queue\n\t\tunsubscribeSync = emitter.on('operation:created', (event) => {\n\t\t\tif (syncEngine) {\n\t\t\t\tsyncEngine.pushOperation(event.operation)\n\t\t\t}\n\t\t})\n\t}\n\n\treturn { store, syncEngine, unsubscribeSync }\n}\n\nfunction createCollectionAccessor(\n\tcollectionName: string,\n\tgetStore: () => Store | null,\n): CollectionAccessor {\n\treturn {\n\t\tasync insert(data: Record<string, unknown>) {\n\t\t\tconst currentStore = getStore()\n\t\t\tif (!currentStore) {\n\t\t\t\tthrow new Error(`Cannot mutate collection \"${collectionName}\" before app.ready resolves.`)\n\t\t\t}\n\t\t\treturn currentStore.collection(collectionName).insert(data)\n\t\t},\n\t\tasync findById(id: string) {\n\t\t\tconst currentStore = getStore()\n\t\t\tif (!currentStore) return null\n\t\t\treturn currentStore.collection(collectionName).findById(id)\n\t\t},\n\t\tasync update(id: string, data: Record<string, unknown>) {\n\t\t\tconst currentStore = getStore()\n\t\t\tif (!currentStore) {\n\t\t\t\tthrow new Error(`Cannot mutate collection \"${collectionName}\" before app.ready resolves.`)\n\t\t\t}\n\t\t\treturn currentStore.collection(collectionName).update(id, data)\n\t\t},\n\t\tasync delete(id: string) {\n\t\t\tconst currentStore = getStore()\n\t\t\tif (!currentStore) {\n\t\t\t\tthrow new Error(`Cannot mutate collection \"${collectionName}\" before app.ready resolves.`)\n\t\t\t}\n\t\t\treturn currentStore.collection(collectionName).delete(id)\n\t\t},\n\t\twhere(conditions: Record<string, unknown>) {\n\t\t\tconst currentStore = getStore()\n\t\t\tif (!currentStore) {\n\t\t\t\treturn createPendingQueryBuilder(conditions)\n\t\t\t}\n\t\t\treturn currentStore.collection(collectionName).where(conditions)\n\t\t},\n\t}\n}\n\nfunction createPendingQueryBuilder(initialWhere: Record<string, unknown>): QueryBuilder {\n\tconst descriptor = {\n\t\tcollection: '__pending__',\n\t\twhere: { ...initialWhere },\n\t\torderBy: [] as Array<{ field: string; direction: 'asc' | 'desc' }>,\n\t\tlimit: undefined as number | undefined,\n\t\toffset: undefined as number | undefined,\n\t}\n\n\tconst builder = {\n\t\twhere(conditions: Record<string, unknown>) {\n\t\t\tdescriptor.where = { ...descriptor.where, ...conditions }\n\t\t\treturn this\n\t\t},\n\t\torderBy(field: string, direction: 'asc' | 'desc' = 'asc') {\n\t\t\tdescriptor.orderBy.push({ field, direction })\n\t\t\treturn this\n\t\t},\n\t\tlimit(n: number) {\n\t\t\tdescriptor.limit = n\n\t\t\treturn this\n\t\t},\n\t\toffset(n: number) {\n\t\t\tdescriptor.offset = n\n\t\t\treturn this\n\t\t},\n\t\tasync exec() {\n\t\t\treturn []\n\t\t},\n\t\tasync count() {\n\t\t\treturn 0\n\t\t},\n\t\tsubscribe(callback: (results: Array<Record<string, unknown>>) => void) {\n\t\t\tvoid callback([])\n\t\t\treturn () => {}\n\t\t},\n\t\tgetDescriptor() {\n\t\t\treturn { ...descriptor, where: { ...descriptor.where }, orderBy: [...descriptor.orderBy] }\n\t\t},\n\t}\n\n\treturn builder as unknown as QueryBuilder\n}\n","import type { StorageAdapter } from '@korajs/store'\nimport type { AdapterType } from './types'\n\n/**\n * Detect the best storage adapter for the current environment.\n *\n * - Tauri app: 'tauri-sqlite' (native SQLite via Tauri plugin)\n * - Node.js: 'better-sqlite3'\n * - Browser with OPFS: 'sqlite-wasm'\n * - Browser without OPFS: 'indexeddb'\n */\nexport function detectAdapterType(): AdapterType {\n\t// Tauri environment — detected via __TAURI_INTERNALS__ injected by the Tauri runtime\n\tif (\n\t\ttypeof globalThis !== 'undefined' &&\n\t\ttypeof (globalThis as Record<string, unknown>).__TAURI_INTERNALS__ !== 'undefined'\n\t) {\n\t\treturn 'tauri-sqlite'\n\t}\n\n\t// Node.js environment\n\tif (typeof process !== 'undefined' && process.versions?.node) {\n\t\treturn 'better-sqlite3'\n\t}\n\n\t// Browser environment\n\tif (typeof globalThis.navigator !== 'undefined') {\n\t\t// Check for OPFS support (FileSystemHandle indicates OPFS availability)\n\t\tif (typeof (globalThis as Record<string, unknown>).FileSystemHandle !== 'undefined') {\n\t\t\treturn 'sqlite-wasm'\n\t\t}\n\t\treturn 'indexeddb'\n\t}\n\n\t// Default fallback (e.g., Deno, Bun, or other runtimes)\n\treturn 'better-sqlite3'\n}\n\n/**\n * Create a StorageAdapter for the given adapter type.\n * Uses dynamic imports so unused adapters are not bundled.\n *\n * @param type - The adapter type to create\n * @param dbName - Database name (used by all adapters)\n * @returns A configured StorageAdapter instance\n */\nexport async function createAdapter(\n\ttype: AdapterType,\n\tdbName: string,\n\tworkerUrl?: string | URL,\n): Promise<StorageAdapter> {\n\tswitch (type) {\n\t\tcase 'tauri-sqlite': {\n\t\t\t// @korajs/tauri is only installed in Tauri projects (optional peer dep).\n\t\t\t// This code path only runs when __TAURI_INTERNALS__ is detected.\n\t\t\t// Using @vite-ignore so Vite doesn't statically analyze this import —\n\t\t\t// it will still resolve it at runtime through Vite's dev server.\n\t\t\tconst { TauriSqliteAdapter } = await import(/* @vite-ignore */ '@korajs/tauri')\n\t\t\treturn new TauriSqliteAdapter({ path: `${dbName}.db` })\n\t\t}\n\t\tcase 'better-sqlite3': {\n\t\t\tconst { BetterSqlite3Adapter } = await import(\n\t\t\t\t/* @vite-ignore */ '@korajs/store/better-sqlite3'\n\t\t\t)\n\t\t\treturn new BetterSqlite3Adapter(dbName)\n\t\t}\n\t\tcase 'sqlite-wasm': {\n\t\t\tconst { SqliteWasmAdapter } = await import('@korajs/store/sqlite-wasm')\n\t\t\treturn new SqliteWasmAdapter({ dbName, workerUrl })\n\t\t}\n\t\tcase 'indexeddb': {\n\t\t\tconst { IndexedDbAdapter } = await import('@korajs/store/indexeddb')\n\t\t\treturn new IndexedDbAdapter({ dbName, workerUrl })\n\t\t}\n\t\tdefault: {\n\t\t\tconst _exhaustive: never = type\n\t\t\tthrow new Error(`Unknown adapter type: ${_exhaustive}`)\n\t\t}\n\t}\n}\n","import type { KoraEventEmitter, Operation, VersionVector } from '@korajs/core'\nimport type { MergeEngine, MergeInput } from '@korajs/merge'\nimport type { Store } from '@korajs/store'\nimport type { ApplyResult, SyncStore } from '@korajs/sync'\n\n/**\n * Wraps a Store to interpose merge resolution before applying remote operations.\n *\n * For inserts and deletes, delegates directly to the underlying Store.\n * For updates, checks whether the remote operation's previousData conflicts\n * with the current local state. If so, runs MergeEngine to resolve and\n * applies the merged result instead.\n *\n * This keeps MergeEngine integration out of Store and SyncEngine internals.\n */\nexport class MergeAwareSyncStore implements SyncStore {\n\tconstructor(\n\t\tprivate readonly store: Store,\n\t\tprivate readonly mergeEngine: MergeEngine,\n\t\tprivate readonly emitter: KoraEventEmitter | null,\n\t) {}\n\n\tgetVersionVector(): VersionVector {\n\t\treturn this.store.getVersionVector()\n\t}\n\n\tgetNodeId(): string {\n\t\treturn this.store.getNodeId()\n\t}\n\n\tasync getOperationRange(nodeId: string, fromSeq: number, toSeq: number): Promise<Operation[]> {\n\t\treturn this.store.getOperationRange(nodeId, fromSeq, toSeq)\n\t}\n\n\tasync applyRemoteOperation(op: Operation): Promise<ApplyResult> {\n\t\t// Only intercept updates that have previousData (needed for 3-way merge)\n\t\tif (op.type !== 'update' || !op.data || !op.previousData) {\n\t\t\treturn this.store.applyRemoteOperation(op)\n\t\t}\n\n\t\t// Look up current local record to detect conflicts\n\t\tconst schema = this.store.getSchema()\n\t\tconst collectionDef = schema.collections[op.collection]\n\t\tif (!collectionDef) {\n\t\t\treturn this.store.applyRemoteOperation(op)\n\t\t}\n\n\t\tconst accessor = this.store.collection(op.collection)\n\t\tconst currentRecord = await accessor.findById(op.recordId)\n\n\t\t// If record doesn't exist locally, delegate directly\n\t\tif (!currentRecord) {\n\t\t\treturn this.store.applyRemoteOperation(op)\n\t\t}\n\n\t\t// Check for conflicts: do any of the remote op's changed fields differ\n\t\t// from what the remote op expected them to be (previousData)?\n\t\tlet hasConflict = false\n\t\tfor (const field of Object.keys(op.data)) {\n\t\t\tconst expectedBase = op.previousData[field]\n\t\t\tconst currentLocal = currentRecord[field]\n\n\t\t\t// If the local state doesn't match what the remote expected,\n\t\t\t// it means the local side also changed this field — conflict.\n\t\t\tif (!deepEqual(expectedBase, currentLocal)) {\n\t\t\t\thasConflict = true\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\t// No conflict: safe to apply directly\n\t\tif (!hasConflict) {\n\t\t\treturn this.store.applyRemoteOperation(op)\n\t\t}\n\n\t\t// Conflict detected — run merge engine\n\t\t// Build a synthetic \"local operation\" representing the current local state changes\n\t\t// relative to the same base the remote operation used.\n\t\tthis.emitter?.emit({\n\t\t\ttype: 'merge:started',\n\t\t\toperationA: op,\n\t\t\toperationB: op,\n\t\t})\n\n\t\tconst baseState: Record<string, unknown> = { ...op.previousData }\n\t\tconst localOp: Operation = {\n\t\t\t...op,\n\t\t\t// The \"local\" operation's data is the diff between base and current local state\n\t\t\tdata: buildLocalDiff(op.previousData, currentRecord, Object.keys(op.data)),\n\t\t\tpreviousData: op.previousData,\n\t\t\tnodeId: this.store.getNodeId(),\n\t\t}\n\n\t\tconst input: MergeInput = {\n\t\t\tlocal: localOp,\n\t\t\tremote: op,\n\t\t\tbaseState,\n\t\t\tcollectionDef,\n\t\t}\n\n\t\tconst result = this.mergeEngine.mergeFields(input)\n\n\t\t// Emit merge traces\n\t\tfor (const trace of result.traces) {\n\t\t\tthis.emitter?.emit({ type: 'merge:conflict', trace })\n\t\t}\n\t\tconst firstTrace = result.traces[0]\n\t\tif (firstTrace) {\n\t\t\tthis.emitter?.emit({ type: 'merge:completed', trace: firstTrace })\n\t\t}\n\n\t\t// Create a modified operation with the merged data to apply\n\t\tconst mergedOp: Operation = {\n\t\t\t...op,\n\t\t\tdata: result.mergedData,\n\t\t}\n\n\t\treturn this.store.applyRemoteOperation(mergedOp)\n\t}\n}\n\n/**\n * Build the local diff: for each field the remote op changed,\n * extract the current local value (which may differ from both base and remote).\n */\nfunction buildLocalDiff(\n\tbaseState: Record<string, unknown>,\n\tcurrentRecord: Record<string, unknown>,\n\tfields: string[],\n): Record<string, unknown> {\n\tconst diff: Record<string, unknown> = {}\n\tfor (const field of fields) {\n\t\tdiff[field] = currentRecord[field]\n\t}\n\treturn diff\n}\n\n/**\n * Simple deep equality check for comparing field values.\n * Handles primitives, arrays, and plain objects.\n */\nfunction deepEqual(a: unknown, b: unknown): boolean {\n\tif (a === b) return true\n\tif (a === null || b === null) return false\n\tif (a === undefined || b === undefined) return false\n\tif (typeof a !== typeof b) return false\n\n\tif (Array.isArray(a) && Array.isArray(b)) {\n\t\tif (a.length !== b.length) return false\n\t\treturn a.every((val, i) => deepEqual(val, b[i]))\n\t}\n\n\tif (typeof a === 'object' && typeof b === 'object') {\n\t\tconst keysA = Object.keys(a as Record<string, unknown>)\n\t\tconst keysB = Object.keys(b as Record<string, unknown>)\n\t\tif (keysA.length !== keysB.length) return false\n\t\treturn keysA.every((key) =>\n\t\t\tdeepEqual((a as Record<string, unknown>)[key], (b as Record<string, unknown>)[key]),\n\t\t)\n\t}\n\n\treturn false\n}\n"],"mappings":"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","names":["op","op","config","import_core","import_store","import_merge","import_sync"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import { KoraEventEmitter, SchemaDefinition, SchemaInput, FieldBuilder, InferRecord, InferInsertInput, InferUpdateInput } from '@korajs/core';
|
|
2
|
-
export { CollectionDefinition, ConnectionQuality, Constraint, FieldDescriptor, FieldKindToType, HLCTimestamp, HybridLogicalClock, InferFieldType, InferInsertInput, InferRecord, InferUpdateInput, KoraError, KoraEvent, KoraEventEmitter, KoraEventListener, KoraEventType, MergeStrategy, MergeTrace, Operation, SchemaDefinition, SchemaInput, TypedSchemaDefinition, VersionVector, createOperation, defineSchema, generateUUIDv7, t } from '@korajs/core';
|
|
1
|
+
import { KoraEventEmitter, SequenceConfig, Operation, SchemaDefinition, SchemaInput, FieldBuilder, InferRecord, InferInsertInput, InferUpdateInput } from '@korajs/core';
|
|
2
|
+
export { AtomicOp, AtomicOpType, CollectionDefinition, ConnectionQuality, Constraint, FieldDescriptor, FieldKindToType, HLCTimestamp, HybridLogicalClock, InferFieldType, InferInsertInput, InferRecord, InferUpdateInput, KoraError, KoraEvent, KoraEventEmitter, KoraEventListener, KoraEventType, MergeStrategy, MergeTrace, MigrationDefinition, MigrationStep, Operation, SchemaDefinition, SchemaInput, SequenceConfig, TypedSchemaDefinition, VersionVector, createOperation, defineSchema, generateUUIDv7, migrate, op, t } from '@korajs/core';
|
|
3
3
|
import * as _korajs_store from '@korajs/store';
|
|
4
|
-
import { QueryBuilder, CollectionAccessor } from '@korajs/store';
|
|
5
|
-
export { CollectionAccessor, CollectionRecord, StorageAdapter, Store, StoreConfig } from '@korajs/store';
|
|
4
|
+
import { CollectionRecord, QueryBuilder, CollectionAccessor } from '@korajs/store';
|
|
5
|
+
export { CollectionAccessor, CollectionRecord, SequenceManager, StorageAdapter, Store, StoreConfig, TransactionCollectionAccessor, TransactionContext, TransactionContextConfig } from '@korajs/store';
|
|
6
|
+
import * as _korajs_sync from '@korajs/sync';
|
|
6
7
|
import { SyncStatusInfo, SyncEngine } from '@korajs/sync';
|
|
7
|
-
export { SyncConfig, SyncEngine, SyncState, SyncStatus, SyncStatusInfo, SyncStore, WebSocketTransport } from '@korajs/sync';
|
|
8
|
+
export { SyncConfig, SyncDiagnostics, SyncEngine, SyncState, SyncStatus, SyncStatusInfo, SyncStore, WebSocketTransport } from '@korajs/sync';
|
|
8
9
|
export { MergeEngine, MergeInput, MergeResult } from '@korajs/merge';
|
|
9
10
|
|
|
10
11
|
/**
|
|
@@ -40,6 +41,22 @@ interface SyncOptions {
|
|
|
40
41
|
}>;
|
|
41
42
|
/** Sync scopes per collection. */
|
|
42
43
|
scopes?: Record<string, (ctx: Record<string, unknown>) => Record<string, unknown>>;
|
|
44
|
+
/**
|
|
45
|
+
* Flat scope values. Combined with schema scope declarations to build
|
|
46
|
+
* per-collection scope filters sent to the server during handshake.
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* ```typescript
|
|
50
|
+
* createApp({
|
|
51
|
+
* schema,
|
|
52
|
+
* sync: {
|
|
53
|
+
* url: 'wss://server/kora',
|
|
54
|
+
* scope: { orgId: 'org-123', storeId: 'store-456' },
|
|
55
|
+
* },
|
|
56
|
+
* })
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
59
|
+
scope?: Record<string, unknown>;
|
|
43
60
|
/** Number of operations per batch. Defaults to 100. */
|
|
44
61
|
batchSize?: number;
|
|
45
62
|
/** Schema version of this client. */
|
|
@@ -89,6 +106,71 @@ interface SyncControl {
|
|
|
89
106
|
disconnect(): Promise<void>;
|
|
90
107
|
/** Get the current developer-facing sync status. */
|
|
91
108
|
getStatus(): SyncStatusInfo;
|
|
109
|
+
/** Force an immediate reconnection attempt. No-op if already connected. */
|
|
110
|
+
retryNow(): Promise<void>;
|
|
111
|
+
/** Export a diagnostics snapshot for debugging and support tickets. */
|
|
112
|
+
exportDiagnostics(): _korajs_sync.SyncDiagnostics;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* A transaction collection accessor providing insert, update, delete, and findById.
|
|
116
|
+
*/
|
|
117
|
+
interface TransactionCollectionProxy {
|
|
118
|
+
insert(data: Record<string, unknown>): Promise<CollectionRecord>;
|
|
119
|
+
update(id: string, data: Record<string, unknown>): Promise<CollectionRecord>;
|
|
120
|
+
delete(id: string): Promise<void>;
|
|
121
|
+
findById(id: string): Promise<CollectionRecord | null>;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Transaction proxy passed to the transaction callback.
|
|
125
|
+
* Provides collection accessors as direct properties (e.g., tx.todos.insert(...)).
|
|
126
|
+
*/
|
|
127
|
+
interface TransactionProxy {
|
|
128
|
+
/** Dynamic collection accessors for transaction operations. */
|
|
129
|
+
[collection: string]: TransactionCollectionProxy;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Accessor for offline-safe sequences.
|
|
133
|
+
* Generates monotonically increasing, collision-free identifiers
|
|
134
|
+
* that work across offline devices.
|
|
135
|
+
*/
|
|
136
|
+
interface SequenceAccessor {
|
|
137
|
+
/**
|
|
138
|
+
* Get the next value in a sequence, atomically incrementing the counter.
|
|
139
|
+
*
|
|
140
|
+
* @param name - The sequence name (e.g., 'receipt', 'invoice')
|
|
141
|
+
* @param config - Optional configuration for scope, format, and starting value
|
|
142
|
+
* @returns The formatted sequence value
|
|
143
|
+
*
|
|
144
|
+
* @example
|
|
145
|
+
* ```typescript
|
|
146
|
+
* const receiptNo = await app.sequences.next('receipt', {
|
|
147
|
+
* scope: storeId,
|
|
148
|
+
* format: 'S-{date}-{node4}-{seq}',
|
|
149
|
+
* })
|
|
150
|
+
* // → "S-20260508-a1b2-0042"
|
|
151
|
+
* ```
|
|
152
|
+
*/
|
|
153
|
+
next(name: string, config?: SequenceConfig): Promise<string>;
|
|
154
|
+
/**
|
|
155
|
+
* Get the current counter value without incrementing.
|
|
156
|
+
*
|
|
157
|
+
* @param name - The sequence name
|
|
158
|
+
* @param config - Optional scope
|
|
159
|
+
* @returns The current counter value, or 0 if never used
|
|
160
|
+
*/
|
|
161
|
+
current(name: string, config?: {
|
|
162
|
+
scope?: string;
|
|
163
|
+
}): Promise<number>;
|
|
164
|
+
/**
|
|
165
|
+
* Reset a sequence counter.
|
|
166
|
+
*
|
|
167
|
+
* @param name - The sequence name
|
|
168
|
+
* @param config - Optional scope and target value
|
|
169
|
+
*/
|
|
170
|
+
reset(name: string, config?: {
|
|
171
|
+
scope?: string;
|
|
172
|
+
to?: number;
|
|
173
|
+
}): Promise<void>;
|
|
92
174
|
}
|
|
93
175
|
/**
|
|
94
176
|
* The main application object returned by createApp().
|
|
@@ -101,12 +183,41 @@ interface KoraApp {
|
|
|
101
183
|
events: KoraEventEmitter;
|
|
102
184
|
/** Sync control (connect/disconnect/status). Null if sync not configured. */
|
|
103
185
|
sync: SyncControl | null;
|
|
186
|
+
/** Offline-safe sequence generation. */
|
|
187
|
+
sequences: SequenceAccessor;
|
|
104
188
|
/** Get the underlying Store instance (for advanced use / React integration). */
|
|
105
189
|
getStore(): _korajs_store.Store;
|
|
106
190
|
/** Get the underlying SyncEngine instance. Null if sync not configured. */
|
|
107
191
|
getSyncEngine(): SyncEngine | null;
|
|
108
192
|
/** Gracefully close the app: stop sync, close store. */
|
|
109
193
|
close(): Promise<void>;
|
|
194
|
+
/**
|
|
195
|
+
* Execute multiple mutations atomically within a transaction.
|
|
196
|
+
* All operations are committed together or rolled back on error.
|
|
197
|
+
* Subscription notifications are batched after commit.
|
|
198
|
+
*
|
|
199
|
+
* @example
|
|
200
|
+
* ```typescript
|
|
201
|
+
* await app.transaction(async (tx) => {
|
|
202
|
+
* await tx.sales.update(saleId, { status: 'completed' })
|
|
203
|
+
* await tx.payments.insert({ saleId, method: 'cash', amount: total })
|
|
204
|
+
* })
|
|
205
|
+
* ```
|
|
206
|
+
*/
|
|
207
|
+
transaction(fn: (tx: TransactionProxy) => Promise<void>): Promise<Operation[]>;
|
|
208
|
+
/**
|
|
209
|
+
* Execute a named mutation — a transaction with a human-readable name.
|
|
210
|
+
* The mutation name is attached to all operations and visible in DevTools.
|
|
211
|
+
*
|
|
212
|
+
* @example
|
|
213
|
+
* ```typescript
|
|
214
|
+
* await app.mutation('complete-sale', async (tx) => {
|
|
215
|
+
* await tx.sales.update(saleId, { status: 'completed' })
|
|
216
|
+
* await tx.payments.insert({ saleId, method: 'cash', amount: total })
|
|
217
|
+
* })
|
|
218
|
+
* ```
|
|
219
|
+
*/
|
|
220
|
+
mutation(name: string, fn: (tx: TransactionProxy) => Promise<void>): Promise<Operation[]>;
|
|
110
221
|
/** Dynamic collection accessors (e.g., app.todos). Typed via Object.defineProperty. */
|
|
111
222
|
[collection: string]: unknown;
|
|
112
223
|
}
|
|
@@ -137,12 +248,18 @@ type TypedKoraApp<S extends SchemaInput> = {
|
|
|
137
248
|
events: KoraEventEmitter;
|
|
138
249
|
/** Sync control (connect/disconnect/status). Null if sync not configured. */
|
|
139
250
|
sync: SyncControl | null;
|
|
251
|
+
/** Offline-safe sequence generation. */
|
|
252
|
+
sequences: SequenceAccessor;
|
|
140
253
|
/** Get the underlying Store instance (for advanced use / React integration). */
|
|
141
254
|
getStore(): _korajs_store.Store;
|
|
142
255
|
/** Get the underlying SyncEngine instance. Null if sync not configured. */
|
|
143
256
|
getSyncEngine(): SyncEngine | null;
|
|
144
257
|
/** Gracefully close the app: stop sync, close store. */
|
|
145
258
|
close(): Promise<void>;
|
|
259
|
+
/** Execute multiple mutations atomically within a transaction. */
|
|
260
|
+
transaction(fn: (tx: TransactionProxy) => Promise<void>): Promise<Operation[]>;
|
|
261
|
+
/** Execute a named mutation — a transaction with a DevTools-visible name. */
|
|
262
|
+
mutation(name: string, fn: (tx: TransactionProxy) => Promise<void>): Promise<Operation[]>;
|
|
146
263
|
} & {
|
|
147
264
|
readonly [C in keyof S['collections'] & string]: S['collections'][C] extends {
|
|
148
265
|
fields: infer F extends Record<string, FieldBuilder<any, any, any>>;
|
|
@@ -190,4 +307,4 @@ declare function createApp<const S extends SchemaInput>(config: TypedKoraConfig<
|
|
|
190
307
|
*/
|
|
191
308
|
declare function createApp(config: KoraConfig): KoraApp;
|
|
192
309
|
|
|
193
|
-
export { type AdapterType, type KoraApp, type KoraConfig, type StoreOptions, type SyncControl, type SyncOptions, type TypedCollectionAccessor, type TypedKoraApp, type TypedKoraConfig, createApp };
|
|
310
|
+
export { type AdapterType, type KoraApp, type KoraConfig, type SequenceAccessor, type StoreOptions, type SyncControl, type SyncOptions, type TransactionCollectionProxy, type TransactionProxy, type TypedCollectionAccessor, type TypedKoraApp, type TypedKoraConfig, createApp };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import { KoraEventEmitter, SchemaDefinition, SchemaInput, FieldBuilder, InferRecord, InferInsertInput, InferUpdateInput } from '@korajs/core';
|
|
2
|
-
export { CollectionDefinition, ConnectionQuality, Constraint, FieldDescriptor, FieldKindToType, HLCTimestamp, HybridLogicalClock, InferFieldType, InferInsertInput, InferRecord, InferUpdateInput, KoraError, KoraEvent, KoraEventEmitter, KoraEventListener, KoraEventType, MergeStrategy, MergeTrace, Operation, SchemaDefinition, SchemaInput, TypedSchemaDefinition, VersionVector, createOperation, defineSchema, generateUUIDv7, t } from '@korajs/core';
|
|
1
|
+
import { KoraEventEmitter, SequenceConfig, Operation, SchemaDefinition, SchemaInput, FieldBuilder, InferRecord, InferInsertInput, InferUpdateInput } from '@korajs/core';
|
|
2
|
+
export { AtomicOp, AtomicOpType, CollectionDefinition, ConnectionQuality, Constraint, FieldDescriptor, FieldKindToType, HLCTimestamp, HybridLogicalClock, InferFieldType, InferInsertInput, InferRecord, InferUpdateInput, KoraError, KoraEvent, KoraEventEmitter, KoraEventListener, KoraEventType, MergeStrategy, MergeTrace, MigrationDefinition, MigrationStep, Operation, SchemaDefinition, SchemaInput, SequenceConfig, TypedSchemaDefinition, VersionVector, createOperation, defineSchema, generateUUIDv7, migrate, op, t } from '@korajs/core';
|
|
3
3
|
import * as _korajs_store from '@korajs/store';
|
|
4
|
-
import { QueryBuilder, CollectionAccessor } from '@korajs/store';
|
|
5
|
-
export { CollectionAccessor, CollectionRecord, StorageAdapter, Store, StoreConfig } from '@korajs/store';
|
|
4
|
+
import { CollectionRecord, QueryBuilder, CollectionAccessor } from '@korajs/store';
|
|
5
|
+
export { CollectionAccessor, CollectionRecord, SequenceManager, StorageAdapter, Store, StoreConfig, TransactionCollectionAccessor, TransactionContext, TransactionContextConfig } from '@korajs/store';
|
|
6
|
+
import * as _korajs_sync from '@korajs/sync';
|
|
6
7
|
import { SyncStatusInfo, SyncEngine } from '@korajs/sync';
|
|
7
|
-
export { SyncConfig, SyncEngine, SyncState, SyncStatus, SyncStatusInfo, SyncStore, WebSocketTransport } from '@korajs/sync';
|
|
8
|
+
export { SyncConfig, SyncDiagnostics, SyncEngine, SyncState, SyncStatus, SyncStatusInfo, SyncStore, WebSocketTransport } from '@korajs/sync';
|
|
8
9
|
export { MergeEngine, MergeInput, MergeResult } from '@korajs/merge';
|
|
9
10
|
|
|
10
11
|
/**
|
|
@@ -40,6 +41,22 @@ interface SyncOptions {
|
|
|
40
41
|
}>;
|
|
41
42
|
/** Sync scopes per collection. */
|
|
42
43
|
scopes?: Record<string, (ctx: Record<string, unknown>) => Record<string, unknown>>;
|
|
44
|
+
/**
|
|
45
|
+
* Flat scope values. Combined with schema scope declarations to build
|
|
46
|
+
* per-collection scope filters sent to the server during handshake.
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* ```typescript
|
|
50
|
+
* createApp({
|
|
51
|
+
* schema,
|
|
52
|
+
* sync: {
|
|
53
|
+
* url: 'wss://server/kora',
|
|
54
|
+
* scope: { orgId: 'org-123', storeId: 'store-456' },
|
|
55
|
+
* },
|
|
56
|
+
* })
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
59
|
+
scope?: Record<string, unknown>;
|
|
43
60
|
/** Number of operations per batch. Defaults to 100. */
|
|
44
61
|
batchSize?: number;
|
|
45
62
|
/** Schema version of this client. */
|
|
@@ -89,6 +106,71 @@ interface SyncControl {
|
|
|
89
106
|
disconnect(): Promise<void>;
|
|
90
107
|
/** Get the current developer-facing sync status. */
|
|
91
108
|
getStatus(): SyncStatusInfo;
|
|
109
|
+
/** Force an immediate reconnection attempt. No-op if already connected. */
|
|
110
|
+
retryNow(): Promise<void>;
|
|
111
|
+
/** Export a diagnostics snapshot for debugging and support tickets. */
|
|
112
|
+
exportDiagnostics(): _korajs_sync.SyncDiagnostics;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* A transaction collection accessor providing insert, update, delete, and findById.
|
|
116
|
+
*/
|
|
117
|
+
interface TransactionCollectionProxy {
|
|
118
|
+
insert(data: Record<string, unknown>): Promise<CollectionRecord>;
|
|
119
|
+
update(id: string, data: Record<string, unknown>): Promise<CollectionRecord>;
|
|
120
|
+
delete(id: string): Promise<void>;
|
|
121
|
+
findById(id: string): Promise<CollectionRecord | null>;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Transaction proxy passed to the transaction callback.
|
|
125
|
+
* Provides collection accessors as direct properties (e.g., tx.todos.insert(...)).
|
|
126
|
+
*/
|
|
127
|
+
interface TransactionProxy {
|
|
128
|
+
/** Dynamic collection accessors for transaction operations. */
|
|
129
|
+
[collection: string]: TransactionCollectionProxy;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Accessor for offline-safe sequences.
|
|
133
|
+
* Generates monotonically increasing, collision-free identifiers
|
|
134
|
+
* that work across offline devices.
|
|
135
|
+
*/
|
|
136
|
+
interface SequenceAccessor {
|
|
137
|
+
/**
|
|
138
|
+
* Get the next value in a sequence, atomically incrementing the counter.
|
|
139
|
+
*
|
|
140
|
+
* @param name - The sequence name (e.g., 'receipt', 'invoice')
|
|
141
|
+
* @param config - Optional configuration for scope, format, and starting value
|
|
142
|
+
* @returns The formatted sequence value
|
|
143
|
+
*
|
|
144
|
+
* @example
|
|
145
|
+
* ```typescript
|
|
146
|
+
* const receiptNo = await app.sequences.next('receipt', {
|
|
147
|
+
* scope: storeId,
|
|
148
|
+
* format: 'S-{date}-{node4}-{seq}',
|
|
149
|
+
* })
|
|
150
|
+
* // → "S-20260508-a1b2-0042"
|
|
151
|
+
* ```
|
|
152
|
+
*/
|
|
153
|
+
next(name: string, config?: SequenceConfig): Promise<string>;
|
|
154
|
+
/**
|
|
155
|
+
* Get the current counter value without incrementing.
|
|
156
|
+
*
|
|
157
|
+
* @param name - The sequence name
|
|
158
|
+
* @param config - Optional scope
|
|
159
|
+
* @returns The current counter value, or 0 if never used
|
|
160
|
+
*/
|
|
161
|
+
current(name: string, config?: {
|
|
162
|
+
scope?: string;
|
|
163
|
+
}): Promise<number>;
|
|
164
|
+
/**
|
|
165
|
+
* Reset a sequence counter.
|
|
166
|
+
*
|
|
167
|
+
* @param name - The sequence name
|
|
168
|
+
* @param config - Optional scope and target value
|
|
169
|
+
*/
|
|
170
|
+
reset(name: string, config?: {
|
|
171
|
+
scope?: string;
|
|
172
|
+
to?: number;
|
|
173
|
+
}): Promise<void>;
|
|
92
174
|
}
|
|
93
175
|
/**
|
|
94
176
|
* The main application object returned by createApp().
|
|
@@ -101,12 +183,41 @@ interface KoraApp {
|
|
|
101
183
|
events: KoraEventEmitter;
|
|
102
184
|
/** Sync control (connect/disconnect/status). Null if sync not configured. */
|
|
103
185
|
sync: SyncControl | null;
|
|
186
|
+
/** Offline-safe sequence generation. */
|
|
187
|
+
sequences: SequenceAccessor;
|
|
104
188
|
/** Get the underlying Store instance (for advanced use / React integration). */
|
|
105
189
|
getStore(): _korajs_store.Store;
|
|
106
190
|
/** Get the underlying SyncEngine instance. Null if sync not configured. */
|
|
107
191
|
getSyncEngine(): SyncEngine | null;
|
|
108
192
|
/** Gracefully close the app: stop sync, close store. */
|
|
109
193
|
close(): Promise<void>;
|
|
194
|
+
/**
|
|
195
|
+
* Execute multiple mutations atomically within a transaction.
|
|
196
|
+
* All operations are committed together or rolled back on error.
|
|
197
|
+
* Subscription notifications are batched after commit.
|
|
198
|
+
*
|
|
199
|
+
* @example
|
|
200
|
+
* ```typescript
|
|
201
|
+
* await app.transaction(async (tx) => {
|
|
202
|
+
* await tx.sales.update(saleId, { status: 'completed' })
|
|
203
|
+
* await tx.payments.insert({ saleId, method: 'cash', amount: total })
|
|
204
|
+
* })
|
|
205
|
+
* ```
|
|
206
|
+
*/
|
|
207
|
+
transaction(fn: (tx: TransactionProxy) => Promise<void>): Promise<Operation[]>;
|
|
208
|
+
/**
|
|
209
|
+
* Execute a named mutation — a transaction with a human-readable name.
|
|
210
|
+
* The mutation name is attached to all operations and visible in DevTools.
|
|
211
|
+
*
|
|
212
|
+
* @example
|
|
213
|
+
* ```typescript
|
|
214
|
+
* await app.mutation('complete-sale', async (tx) => {
|
|
215
|
+
* await tx.sales.update(saleId, { status: 'completed' })
|
|
216
|
+
* await tx.payments.insert({ saleId, method: 'cash', amount: total })
|
|
217
|
+
* })
|
|
218
|
+
* ```
|
|
219
|
+
*/
|
|
220
|
+
mutation(name: string, fn: (tx: TransactionProxy) => Promise<void>): Promise<Operation[]>;
|
|
110
221
|
/** Dynamic collection accessors (e.g., app.todos). Typed via Object.defineProperty. */
|
|
111
222
|
[collection: string]: unknown;
|
|
112
223
|
}
|
|
@@ -137,12 +248,18 @@ type TypedKoraApp<S extends SchemaInput> = {
|
|
|
137
248
|
events: KoraEventEmitter;
|
|
138
249
|
/** Sync control (connect/disconnect/status). Null if sync not configured. */
|
|
139
250
|
sync: SyncControl | null;
|
|
251
|
+
/** Offline-safe sequence generation. */
|
|
252
|
+
sequences: SequenceAccessor;
|
|
140
253
|
/** Get the underlying Store instance (for advanced use / React integration). */
|
|
141
254
|
getStore(): _korajs_store.Store;
|
|
142
255
|
/** Get the underlying SyncEngine instance. Null if sync not configured. */
|
|
143
256
|
getSyncEngine(): SyncEngine | null;
|
|
144
257
|
/** Gracefully close the app: stop sync, close store. */
|
|
145
258
|
close(): Promise<void>;
|
|
259
|
+
/** Execute multiple mutations atomically within a transaction. */
|
|
260
|
+
transaction(fn: (tx: TransactionProxy) => Promise<void>): Promise<Operation[]>;
|
|
261
|
+
/** Execute a named mutation — a transaction with a DevTools-visible name. */
|
|
262
|
+
mutation(name: string, fn: (tx: TransactionProxy) => Promise<void>): Promise<Operation[]>;
|
|
146
263
|
} & {
|
|
147
264
|
readonly [C in keyof S['collections'] & string]: S['collections'][C] extends {
|
|
148
265
|
fields: infer F extends Record<string, FieldBuilder<any, any, any>>;
|
|
@@ -190,4 +307,4 @@ declare function createApp<const S extends SchemaInput>(config: TypedKoraConfig<
|
|
|
190
307
|
*/
|
|
191
308
|
declare function createApp(config: KoraConfig): KoraApp;
|
|
192
309
|
|
|
193
|
-
export { type AdapterType, type KoraApp, type KoraConfig, type StoreOptions, type SyncControl, type SyncOptions, type TypedCollectionAccessor, type TypedKoraApp, type TypedKoraConfig, createApp };
|
|
310
|
+
export { type AdapterType, type KoraApp, type KoraConfig, type SequenceAccessor, type StoreOptions, type SyncControl, type SyncOptions, type TransactionCollectionProxy, type TransactionProxy, type TypedCollectionAccessor, type TypedKoraApp, type TypedKoraConfig, createApp };
|
package/dist/index.js
CHANGED
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
// src/create-app.ts
|
|
2
|
+
import { buildScopeMap } from "@korajs/core";
|
|
2
3
|
import { SimpleEventEmitter } from "@korajs/core/internal";
|
|
3
4
|
import { Instrumenter } from "@korajs/devtools";
|
|
4
5
|
import { MergeEngine } from "@korajs/merge";
|
|
5
6
|
import { Store } from "@korajs/store";
|
|
6
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
ConnectionMonitor,
|
|
9
|
+
ReconnectionManager,
|
|
10
|
+
SyncEngine,
|
|
11
|
+
WebSocketTransport
|
|
12
|
+
} from "@korajs/sync";
|
|
7
13
|
|
|
8
14
|
// src/adapter-resolver.ts
|
|
9
15
|
function detectAdapterType() {
|
|
@@ -71,23 +77,23 @@ var MergeAwareSyncStore = class {
|
|
|
71
77
|
async getOperationRange(nodeId, fromSeq, toSeq) {
|
|
72
78
|
return this.store.getOperationRange(nodeId, fromSeq, toSeq);
|
|
73
79
|
}
|
|
74
|
-
async applyRemoteOperation(
|
|
75
|
-
if (
|
|
76
|
-
return this.store.applyRemoteOperation(
|
|
80
|
+
async applyRemoteOperation(op2) {
|
|
81
|
+
if (op2.type !== "update" || !op2.data || !op2.previousData) {
|
|
82
|
+
return this.store.applyRemoteOperation(op2);
|
|
77
83
|
}
|
|
78
84
|
const schema = this.store.getSchema();
|
|
79
|
-
const collectionDef = schema.collections[
|
|
85
|
+
const collectionDef = schema.collections[op2.collection];
|
|
80
86
|
if (!collectionDef) {
|
|
81
|
-
return this.store.applyRemoteOperation(
|
|
87
|
+
return this.store.applyRemoteOperation(op2);
|
|
82
88
|
}
|
|
83
|
-
const accessor = this.store.collection(
|
|
84
|
-
const currentRecord = await accessor.findById(
|
|
89
|
+
const accessor = this.store.collection(op2.collection);
|
|
90
|
+
const currentRecord = await accessor.findById(op2.recordId);
|
|
85
91
|
if (!currentRecord) {
|
|
86
|
-
return this.store.applyRemoteOperation(
|
|
92
|
+
return this.store.applyRemoteOperation(op2);
|
|
87
93
|
}
|
|
88
94
|
let hasConflict = false;
|
|
89
|
-
for (const field of Object.keys(
|
|
90
|
-
const expectedBase =
|
|
95
|
+
for (const field of Object.keys(op2.data)) {
|
|
96
|
+
const expectedBase = op2.previousData[field];
|
|
91
97
|
const currentLocal = currentRecord[field];
|
|
92
98
|
if (!deepEqual(expectedBase, currentLocal)) {
|
|
93
99
|
hasConflict = true;
|
|
@@ -95,24 +101,24 @@ var MergeAwareSyncStore = class {
|
|
|
95
101
|
}
|
|
96
102
|
}
|
|
97
103
|
if (!hasConflict) {
|
|
98
|
-
return this.store.applyRemoteOperation(
|
|
104
|
+
return this.store.applyRemoteOperation(op2);
|
|
99
105
|
}
|
|
100
106
|
this.emitter?.emit({
|
|
101
107
|
type: "merge:started",
|
|
102
|
-
operationA:
|
|
103
|
-
operationB:
|
|
108
|
+
operationA: op2,
|
|
109
|
+
operationB: op2
|
|
104
110
|
});
|
|
105
|
-
const baseState = { ...
|
|
111
|
+
const baseState = { ...op2.previousData };
|
|
106
112
|
const localOp = {
|
|
107
|
-
...
|
|
113
|
+
...op2,
|
|
108
114
|
// The "local" operation's data is the diff between base and current local state
|
|
109
|
-
data: buildLocalDiff(
|
|
110
|
-
previousData:
|
|
115
|
+
data: buildLocalDiff(op2.previousData, currentRecord, Object.keys(op2.data)),
|
|
116
|
+
previousData: op2.previousData,
|
|
111
117
|
nodeId: this.store.getNodeId()
|
|
112
118
|
};
|
|
113
119
|
const input = {
|
|
114
120
|
local: localOp,
|
|
115
|
-
remote:
|
|
121
|
+
remote: op2,
|
|
116
122
|
baseState,
|
|
117
123
|
collectionDef
|
|
118
124
|
};
|
|
@@ -125,7 +131,7 @@ var MergeAwareSyncStore = class {
|
|
|
125
131
|
this.emitter?.emit({ type: "merge:completed", trace: firstTrace });
|
|
126
132
|
}
|
|
127
133
|
const mergedOp = {
|
|
128
|
-
...
|
|
134
|
+
...op2,
|
|
129
135
|
data: result.mergedData
|
|
130
136
|
};
|
|
131
137
|
return this.store.applyRemoteOperation(mergedOp);
|
|
@@ -247,13 +253,104 @@ function createApp(config) {
|
|
|
247
253
|
if (syncEngine) {
|
|
248
254
|
return syncEngine.getStatus();
|
|
249
255
|
}
|
|
250
|
-
return {
|
|
256
|
+
return {
|
|
257
|
+
status: "offline",
|
|
258
|
+
pendingOperations: 0,
|
|
259
|
+
lastSyncedAt: null,
|
|
260
|
+
lastSuccessfulPush: null,
|
|
261
|
+
lastSuccessfulPull: null,
|
|
262
|
+
conflicts: 0
|
|
263
|
+
};
|
|
264
|
+
},
|
|
265
|
+
async retryNow() {
|
|
266
|
+
await ready;
|
|
267
|
+
if (syncEngine) {
|
|
268
|
+
await syncEngine.retryNow();
|
|
269
|
+
}
|
|
270
|
+
},
|
|
271
|
+
exportDiagnostics() {
|
|
272
|
+
if (syncEngine) {
|
|
273
|
+
return syncEngine.exportDiagnostics();
|
|
274
|
+
}
|
|
275
|
+
return {
|
|
276
|
+
state: "disconnected",
|
|
277
|
+
status: {
|
|
278
|
+
status: "offline",
|
|
279
|
+
pendingOperations: 0,
|
|
280
|
+
lastSyncedAt: null,
|
|
281
|
+
lastSuccessfulPush: null,
|
|
282
|
+
lastSuccessfulPull: null,
|
|
283
|
+
conflicts: 0
|
|
284
|
+
},
|
|
285
|
+
nodeId: "",
|
|
286
|
+
url: config.sync?.url ?? "",
|
|
287
|
+
schemaVersion: config.schema.version,
|
|
288
|
+
lastSyncedAt: null,
|
|
289
|
+
lastSuccessfulPush: null,
|
|
290
|
+
lastSuccessfulPull: null,
|
|
291
|
+
conflicts: 0,
|
|
292
|
+
pendingOperations: 0,
|
|
293
|
+
hasInFlightBatch: false,
|
|
294
|
+
reconnecting: false,
|
|
295
|
+
timestamp: Date.now()
|
|
296
|
+
};
|
|
251
297
|
}
|
|
252
298
|
} : null;
|
|
299
|
+
async function executeTransaction(fn, mutationName) {
|
|
300
|
+
await ready;
|
|
301
|
+
if (!store) {
|
|
302
|
+
throw new Error("Store not initialized. Await app.ready before using transactions.");
|
|
303
|
+
}
|
|
304
|
+
const txContext = store.createTransaction();
|
|
305
|
+
if (mutationName !== void 0) {
|
|
306
|
+
txContext.setMutationName(mutationName);
|
|
307
|
+
}
|
|
308
|
+
const collectionNames = Object.keys(config.schema.collections);
|
|
309
|
+
const proxy = {};
|
|
310
|
+
for (const name of collectionNames) {
|
|
311
|
+
Object.defineProperty(proxy, name, {
|
|
312
|
+
get() {
|
|
313
|
+
return txContext.collection(name);
|
|
314
|
+
},
|
|
315
|
+
enumerable: true,
|
|
316
|
+
configurable: false
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
try {
|
|
320
|
+
await fn(proxy);
|
|
321
|
+
const { operations } = await txContext.commit();
|
|
322
|
+
for (const op2 of operations) {
|
|
323
|
+
store.getSubscriptionManager().notify(op2.collection, op2);
|
|
324
|
+
emitter.emit({ type: "operation:created", operation: op2 });
|
|
325
|
+
}
|
|
326
|
+
return operations;
|
|
327
|
+
} catch (error) {
|
|
328
|
+
txContext.rollback();
|
|
329
|
+
throw error;
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
const sequences = {
|
|
333
|
+
async next(name, config2) {
|
|
334
|
+
await ready;
|
|
335
|
+
if (!store) throw new Error("Store not initialized. Await app.ready before using sequences.");
|
|
336
|
+
return store.getSequenceManager().next(name, config2);
|
|
337
|
+
},
|
|
338
|
+
async current(name, config2) {
|
|
339
|
+
await ready;
|
|
340
|
+
if (!store) throw new Error("Store not initialized. Await app.ready before using sequences.");
|
|
341
|
+
return store.getSequenceManager().current(name, config2);
|
|
342
|
+
},
|
|
343
|
+
async reset(name, config2) {
|
|
344
|
+
await ready;
|
|
345
|
+
if (!store) throw new Error("Store not initialized. Await app.ready before using sequences.");
|
|
346
|
+
return store.getSequenceManager().reset(name, config2);
|
|
347
|
+
}
|
|
348
|
+
};
|
|
253
349
|
const app = {
|
|
254
350
|
ready,
|
|
255
351
|
events: emitter,
|
|
256
352
|
sync: syncControl,
|
|
353
|
+
sequences,
|
|
257
354
|
getStore() {
|
|
258
355
|
if (!store) {
|
|
259
356
|
throw new Error("Store not initialized. Await app.ready before accessing the store.");
|
|
@@ -263,6 +360,12 @@ function createApp(config) {
|
|
|
263
360
|
getSyncEngine() {
|
|
264
361
|
return syncEngine;
|
|
265
362
|
},
|
|
363
|
+
async transaction(fn) {
|
|
364
|
+
return executeTransaction(fn);
|
|
365
|
+
},
|
|
366
|
+
async mutation(name, fn) {
|
|
367
|
+
return executeTransaction(fn, name);
|
|
368
|
+
},
|
|
266
369
|
async close() {
|
|
267
370
|
await ready;
|
|
268
371
|
intentionalDisconnect = true;
|
|
@@ -316,6 +419,7 @@ async function initializeAsync(config, emitter, mergeEngine) {
|
|
|
316
419
|
if (config.sync) {
|
|
317
420
|
const transport = new WebSocketTransport();
|
|
318
421
|
const mergeAwareStore = new MergeAwareSyncStore(store, mergeEngine, emitter);
|
|
422
|
+
const scopeMap = config.sync.scope ? buildScopeMap(config.schema, config.sync.scope) : void 0;
|
|
319
423
|
syncEngine = new SyncEngine({
|
|
320
424
|
transport,
|
|
321
425
|
store: mergeAwareStore,
|
|
@@ -324,7 +428,8 @@ async function initializeAsync(config, emitter, mergeEngine) {
|
|
|
324
428
|
transport: config.sync.transport,
|
|
325
429
|
auth: config.sync.auth,
|
|
326
430
|
batchSize: config.sync.batchSize,
|
|
327
|
-
schemaVersion: config.sync.schemaVersion ?? config.schema.version
|
|
431
|
+
schemaVersion: config.sync.schemaVersion ?? config.schema.version,
|
|
432
|
+
scopeMap
|
|
328
433
|
},
|
|
329
434
|
emitter
|
|
330
435
|
});
|
|
@@ -417,25 +522,31 @@ function createPendingQueryBuilder(initialWhere) {
|
|
|
417
522
|
}
|
|
418
523
|
|
|
419
524
|
// src/index.ts
|
|
420
|
-
import { defineSchema, t } from "@korajs/core";
|
|
525
|
+
import { defineSchema, migrate, t } from "@korajs/core";
|
|
421
526
|
import { HybridLogicalClock } from "@korajs/core";
|
|
422
527
|
import { generateUUIDv7 } from "@korajs/core";
|
|
423
528
|
import { createOperation } from "@korajs/core";
|
|
424
529
|
import { KoraError } from "@korajs/core";
|
|
425
|
-
import {
|
|
530
|
+
import { op } from "@korajs/core";
|
|
531
|
+
import { SequenceManager, Store as Store2 } from "@korajs/store";
|
|
532
|
+
import { TransactionContext } from "@korajs/store";
|
|
426
533
|
import { MergeEngine as MergeEngine2 } from "@korajs/merge";
|
|
427
534
|
import { SyncEngine as SyncEngine2, WebSocketTransport as WebSocketTransport2 } from "@korajs/sync";
|
|
428
535
|
export {
|
|
429
536
|
HybridLogicalClock,
|
|
430
537
|
KoraError,
|
|
431
538
|
MergeEngine2 as MergeEngine,
|
|
539
|
+
SequenceManager,
|
|
432
540
|
Store2 as Store,
|
|
433
541
|
SyncEngine2 as SyncEngine,
|
|
542
|
+
TransactionContext,
|
|
434
543
|
WebSocketTransport2 as WebSocketTransport,
|
|
435
544
|
createApp,
|
|
436
545
|
createOperation,
|
|
437
546
|
defineSchema,
|
|
438
547
|
generateUUIDv7,
|
|
548
|
+
migrate,
|
|
549
|
+
op,
|
|
439
550
|
t
|
|
440
551
|
};
|
|
441
552
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/create-app.ts","../src/adapter-resolver.ts","../src/merge-aware-sync-store.ts","../src/index.ts"],"sourcesContent":["import type { KoraEventEmitter, Operation, SchemaInput } from '@korajs/core'\nimport { SimpleEventEmitter } from '@korajs/core/internal'\nimport { Instrumenter } from '@korajs/devtools'\nimport { MergeEngine } from '@korajs/merge'\nimport { Store } from '@korajs/store'\nimport type { CollectionAccessor, StorageAdapter } from '@korajs/store'\nimport type { QueryBuilder } from '@korajs/store'\nimport { ConnectionMonitor, ReconnectionManager, SyncEngine, WebSocketTransport } from '@korajs/sync'\nimport type { SyncStatusInfo } from '@korajs/sync'\nimport { createAdapter, detectAdapterType } from './adapter-resolver'\nimport { MergeAwareSyncStore } from './merge-aware-sync-store'\nimport type { KoraApp, KoraConfig, SyncControl, TypedKoraApp, TypedKoraConfig } from './types'\n\n/**\n * Creates a new Kora application instance.\n *\n * Wires together store, merge engine, event emitter, and optionally sync\n * into a single developer-facing `KoraApp` object. Collection accessors\n * (e.g. `app.todos`) are defined as properties for immediate use after `await app.ready`.\n *\n * @param config - Application configuration including schema and optional sync settings\n * @returns A KoraApp instance with reactive collections ready for use\n *\n * @example\n * ```typescript\n * const app = createApp({\n * schema: defineSchema({\n * version: 1,\n * collections: {\n * todos: {\n * fields: {\n * title: t.string(),\n * completed: t.boolean().default(false)\n * }\n * }\n * }\n * })\n * })\n *\n * await app.ready\n * const todo = await app.todos.insert({ title: 'Hello' })\n * ```\n */\n/**\n * Creates a new typed Kora application instance.\n * When the schema is created with `defineSchema()`, full type inference flows through\n * to collection accessors, providing autocomplete and type checking for all CRUD operations.\n */\nexport function createApp<const S extends SchemaInput>(config: TypedKoraConfig<S>): TypedKoraApp<S>\n/**\n * Creates a new Kora application instance (untyped fallback).\n */\nexport function createApp(config: KoraConfig): KoraApp\nexport function createApp(config: KoraConfig): KoraApp {\n\tconst emitter: KoraEventEmitter & { clear(): void } = new SimpleEventEmitter()\n\tconst mergeEngine = new MergeEngine()\n\n\tlet store: Store | null = null\n\tlet syncEngine: SyncEngine | null = null\n\tlet unsubscribeSync: (() => void) | null = null\n\tlet reconnectionManager: ReconnectionManager | null = null\n\tlet connectionMonitor: ConnectionMonitor | null = null\n\tlet instrumenter: Instrumenter | null = null\n\tlet intentionalDisconnect = false\n\tlet qualityInterval: ReturnType<typeof setInterval> | null = null\n\n\t// Wire DevTools instrumentation immediately (emitter exists synchronously)\n\tif (config.devtools) {\n\t\tinstrumenter = new Instrumenter(emitter, {\n\t\t\tbridgeEnabled: typeof globalThis !== 'undefined' && 'window' in globalThis,\n\t\t})\n\t}\n\n\t// Build the ready promise — resolves when the store is open and wired\n\tconst ready = initializeAsync(config, emitter, mergeEngine).then((result) => {\n\t\tstore = result.store\n\t\tsyncEngine = result.syncEngine\n\t\tunsubscribeSync = result.unsubscribeSync\n\n\t\t// Wire reconnection and connection quality after sync engine is ready\n\t\tif (config.sync && syncEngine) {\n\t\t\tconnectionMonitor = new ConnectionMonitor()\n\t\t\treconnectionManager = new ReconnectionManager({\n\t\t\t\tinitialDelay: config.sync.reconnectInterval,\n\t\t\t\tmaxDelay: config.sync.maxReconnectInterval,\n\t\t\t})\n\n\t\t\t// Track activity for connection quality\n\t\t\temitter.on('sync:sent', () => connectionMonitor?.recordActivity())\n\t\t\temitter.on('sync:received', () => connectionMonitor?.recordActivity())\n\t\t\temitter.on('sync:acknowledged', () => connectionMonitor?.recordActivity())\n\n\t\t\t// Emit quality on timer while connected\n\t\t\temitter.on('sync:connected', () => {\n\t\t\t\tif (qualityInterval !== null) clearInterval(qualityInterval)\n\t\t\t\tqualityInterval = setInterval(() => {\n\t\t\t\t\tif (connectionMonitor) {\n\t\t\t\t\t\temitter.emit({ type: 'connection:quality', quality: connectionMonitor.getQuality() })\n\t\t\t\t\t}\n\t\t\t\t}, 5000)\n\t\t\t})\n\n\t\t\t// Reset monitor and clear timer on disconnect\n\t\t\temitter.on('sync:disconnected', () => {\n\t\t\t\tconnectionMonitor?.reset()\n\t\t\t\tif (qualityInterval !== null) {\n\t\t\t\t\tclearInterval(qualityInterval)\n\t\t\t\t\tqualityInterval = null\n\t\t\t\t}\n\t\t\t})\n\n\t\t\t// Auto-reconnect on unexpected disconnect\n\t\t\tif (config.sync.autoReconnect !== false) {\n\t\t\t\tconst engine = syncEngine\n\t\t\t\temitter.on('sync:disconnected', () => {\n\t\t\t\t\tif (intentionalDisconnect) return\n\t\t\t\t\t// Ignore cascading disconnect events from failed reconnection attempts.\n\t\t\t\t\t// The reconnection manager is already retrying — don't restart it.\n\t\t\t\t\tif (reconnectionManager?.isRunning()) return\n\n\t\t\t\t\tengine.setReconnecting(true)\n\t\t\t\t\treconnectionManager?.stop()\n\t\t\t\t\treconnectionManager?.start(async () => {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tawait engine.start()\n\t\t\t\t\t\t\tengine.setReconnecting(false)\n\t\t\t\t\t\t\treturn true\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\treturn false\n\t\t\t\t\t\t}\n\t\t\t\t\t}).then(() => {\n\t\t\t\t\t\t// If reconnection exhausted max attempts without success, clear flag\n\t\t\t\t\t\tengine.setReconnecting(false)\n\t\t\t\t\t})\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\t})\n\n\t// Build sync control\n\tconst syncControl: SyncControl | null = config.sync\n\t\t? {\n\t\t\t\tasync connect(): Promise<void> {\n\t\t\t\t\tawait ready\n\t\t\t\t\tif (syncEngine) {\n\t\t\t\t\t\tintentionalDisconnect = false\n\t\t\t\t\t\treconnectionManager?.stop()\n\t\t\t\t\t\treconnectionManager?.reset()\n\t\t\t\t\t\tawait syncEngine.start()\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tasync disconnect(): Promise<void> {\n\t\t\t\t\tawait ready\n\t\t\t\t\tif (syncEngine) {\n\t\t\t\t\t\tintentionalDisconnect = true\n\t\t\t\t\t\treconnectionManager?.stop()\n\t\t\t\t\t\tawait syncEngine.stop()\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tgetStatus(): SyncStatusInfo {\n\t\t\t\t\tif (syncEngine) {\n\t\t\t\t\t\treturn syncEngine.getStatus()\n\t\t\t\t\t}\n\t\t\t\t\treturn { status: 'offline', pendingOperations: 0, lastSyncedAt: null }\n\t\t\t\t},\n\t\t\t}\n\t\t: null\n\n\t// Build the KoraApp object\n\tconst app: KoraApp = {\n\t\tready,\n\t\tevents: emitter,\n\t\tsync: syncControl,\n\t\tgetStore(): Store {\n\t\t\tif (!store) {\n\t\t\t\tthrow new Error('Store not initialized. Await app.ready before accessing the store.')\n\t\t\t}\n\t\t\treturn store\n\t\t},\n\t\tgetSyncEngine(): SyncEngine | null {\n\t\t\treturn syncEngine\n\t\t},\n\t\tasync close(): Promise<void> {\n\t\t\tawait ready\n\t\t\tintentionalDisconnect = true\n\t\t\tif (qualityInterval !== null) {\n\t\t\t\tclearInterval(qualityInterval)\n\t\t\t\tqualityInterval = null\n\t\t\t}\n\t\t\treconnectionManager?.stop()\n\t\t\tif (instrumenter) {\n\t\t\t\tinstrumenter.destroy()\n\t\t\t\tinstrumenter = null\n\t\t\t}\n\t\t\tif (unsubscribeSync) {\n\t\t\t\tunsubscribeSync()\n\t\t\t\tunsubscribeSync = null\n\t\t\t}\n\t\t\tif (syncEngine) {\n\t\t\t\tawait syncEngine.stop()\n\t\t\t\tsyncEngine = null\n\t\t\t}\n\t\t\tif (store) {\n\t\t\t\tawait store.close()\n\t\t\t\tstore = null\n\t\t\t}\n\t\t\temitter.clear()\n\t\t},\n\t}\n\n\t// Define collection accessors via Object.defineProperty.\n\t// Before ready resolves, query methods return empty results.\n\tfor (const collectionName of Object.keys(config.schema.collections)) {\n\t\tObject.defineProperty(app, collectionName, {\n\t\t\tget(): CollectionAccessor {\n\t\t\t\treturn createCollectionAccessor(collectionName, () => store)\n\t\t\t},\n\t\t\tenumerable: true,\n\t\t\tconfigurable: false,\n\t\t})\n\t}\n\n\treturn app\n}\n\n/**\n * Asynchronous initialization: create adapter, open store, wire sync.\n */\nasync function initializeAsync(\n\tconfig: KoraConfig,\n\temitter: KoraEventEmitter,\n\tmergeEngine: MergeEngine,\n): Promise<{\n\tstore: Store\n\tsyncEngine: SyncEngine | null\n\tunsubscribeSync: (() => void) | null\n}> {\n\t// Resolve adapter\n\tconst adapterType = config.store?.adapter ?? detectAdapterType()\n\tconst dbName = config.store?.name ?? 'kora-db'\n\tconst adapter: StorageAdapter = await createAdapter(adapterType, dbName, config.store?.workerUrl)\n\n\t// Create and open the store\n\tconst store = new Store({\n\t\tschema: config.schema,\n\t\tadapter,\n\t\temitter,\n\t})\n\tawait store.open()\n\n\t// Wire sync if configured\n\tlet syncEngine: SyncEngine | null = null\n\tlet unsubscribeSync: (() => void) | null = null\n\n\tif (config.sync) {\n\t\tconst transport = new WebSocketTransport()\n\t\tconst mergeAwareStore = new MergeAwareSyncStore(store, mergeEngine, emitter)\n\n\t\tsyncEngine = new SyncEngine({\n\t\t\ttransport,\n\t\t\tstore: mergeAwareStore,\n\t\t\tconfig: {\n\t\t\t\turl: config.sync.url,\n\t\t\t\ttransport: config.sync.transport,\n\t\t\t\tauth: config.sync.auth,\n\t\t\t\tbatchSize: config.sync.batchSize,\n\t\t\t\tschemaVersion: config.sync.schemaVersion ?? config.schema.version,\n\t\t\t},\n\t\t\temitter,\n\t\t})\n\n\t\t// Wire local mutations → sync outbound queue\n\t\tunsubscribeSync = emitter.on('operation:created', (event) => {\n\t\t\tif (syncEngine) {\n\t\t\t\tsyncEngine.pushOperation(event.operation)\n\t\t\t}\n\t\t})\n\t}\n\n\treturn { store, syncEngine, unsubscribeSync }\n}\n\nfunction createCollectionAccessor(\n\tcollectionName: string,\n\tgetStore: () => Store | null,\n): CollectionAccessor {\n\treturn {\n\t\tasync insert(data: Record<string, unknown>) {\n\t\t\tconst currentStore = getStore()\n\t\t\tif (!currentStore) {\n\t\t\t\tthrow new Error(`Cannot mutate collection \"${collectionName}\" before app.ready resolves.`)\n\t\t\t}\n\t\t\treturn currentStore.collection(collectionName).insert(data)\n\t\t},\n\t\tasync findById(id: string) {\n\t\t\tconst currentStore = getStore()\n\t\t\tif (!currentStore) return null\n\t\t\treturn currentStore.collection(collectionName).findById(id)\n\t\t},\n\t\tasync update(id: string, data: Record<string, unknown>) {\n\t\t\tconst currentStore = getStore()\n\t\t\tif (!currentStore) {\n\t\t\t\tthrow new Error(`Cannot mutate collection \"${collectionName}\" before app.ready resolves.`)\n\t\t\t}\n\t\t\treturn currentStore.collection(collectionName).update(id, data)\n\t\t},\n\t\tasync delete(id: string) {\n\t\t\tconst currentStore = getStore()\n\t\t\tif (!currentStore) {\n\t\t\t\tthrow new Error(`Cannot mutate collection \"${collectionName}\" before app.ready resolves.`)\n\t\t\t}\n\t\t\treturn currentStore.collection(collectionName).delete(id)\n\t\t},\n\t\twhere(conditions: Record<string, unknown>) {\n\t\t\tconst currentStore = getStore()\n\t\t\tif (!currentStore) {\n\t\t\t\treturn createPendingQueryBuilder(conditions)\n\t\t\t}\n\t\t\treturn currentStore.collection(collectionName).where(conditions)\n\t\t},\n\t}\n}\n\nfunction createPendingQueryBuilder(initialWhere: Record<string, unknown>): QueryBuilder {\n\tconst descriptor = {\n\t\tcollection: '__pending__',\n\t\twhere: { ...initialWhere },\n\t\torderBy: [] as Array<{ field: string; direction: 'asc' | 'desc' }>,\n\t\tlimit: undefined as number | undefined,\n\t\toffset: undefined as number | undefined,\n\t}\n\n\tconst builder = {\n\t\twhere(conditions: Record<string, unknown>) {\n\t\t\tdescriptor.where = { ...descriptor.where, ...conditions }\n\t\t\treturn this\n\t\t},\n\t\torderBy(field: string, direction: 'asc' | 'desc' = 'asc') {\n\t\t\tdescriptor.orderBy.push({ field, direction })\n\t\t\treturn this\n\t\t},\n\t\tlimit(n: number) {\n\t\t\tdescriptor.limit = n\n\t\t\treturn this\n\t\t},\n\t\toffset(n: number) {\n\t\t\tdescriptor.offset = n\n\t\t\treturn this\n\t\t},\n\t\tasync exec() {\n\t\t\treturn []\n\t\t},\n\t\tasync count() {\n\t\t\treturn 0\n\t\t},\n\t\tsubscribe(callback: (results: Array<Record<string, unknown>>) => void) {\n\t\t\tvoid callback([])\n\t\t\treturn () => {}\n\t\t},\n\t\tgetDescriptor() {\n\t\t\treturn { ...descriptor, where: { ...descriptor.where }, orderBy: [...descriptor.orderBy] }\n\t\t},\n\t}\n\n\treturn builder as unknown as QueryBuilder\n}\n","import type { StorageAdapter } from '@korajs/store'\nimport type { AdapterType } from './types'\n\n/**\n * Detect the best storage adapter for the current environment.\n *\n * - Tauri app: 'tauri-sqlite' (native SQLite via Tauri plugin)\n * - Node.js: 'better-sqlite3'\n * - Browser with OPFS: 'sqlite-wasm'\n * - Browser without OPFS: 'indexeddb'\n */\nexport function detectAdapterType(): AdapterType {\n\t// Tauri environment — detected via __TAURI_INTERNALS__ injected by the Tauri runtime\n\tif (\n\t\ttypeof globalThis !== 'undefined' &&\n\t\ttypeof (globalThis as Record<string, unknown>).__TAURI_INTERNALS__ !== 'undefined'\n\t) {\n\t\treturn 'tauri-sqlite'\n\t}\n\n\t// Node.js environment\n\tif (typeof process !== 'undefined' && process.versions?.node) {\n\t\treturn 'better-sqlite3'\n\t}\n\n\t// Browser environment\n\tif (typeof globalThis.navigator !== 'undefined') {\n\t\t// Check for OPFS support (FileSystemHandle indicates OPFS availability)\n\t\tif (typeof (globalThis as Record<string, unknown>).FileSystemHandle !== 'undefined') {\n\t\t\treturn 'sqlite-wasm'\n\t\t}\n\t\treturn 'indexeddb'\n\t}\n\n\t// Default fallback (e.g., Deno, Bun, or other runtimes)\n\treturn 'better-sqlite3'\n}\n\n/**\n * Create a StorageAdapter for the given adapter type.\n * Uses dynamic imports so unused adapters are not bundled.\n *\n * @param type - The adapter type to create\n * @param dbName - Database name (used by all adapters)\n * @returns A configured StorageAdapter instance\n */\nexport async function createAdapter(\n\ttype: AdapterType,\n\tdbName: string,\n\tworkerUrl?: string | URL,\n): Promise<StorageAdapter> {\n\tswitch (type) {\n\t\tcase 'tauri-sqlite': {\n\t\t\t// @korajs/tauri is only installed in Tauri projects (optional peer dep).\n\t\t\t// This code path only runs when __TAURI_INTERNALS__ is detected.\n\t\t\t// Using @vite-ignore so Vite doesn't statically analyze this import —\n\t\t\t// it will still resolve it at runtime through Vite's dev server.\n\t\t\tconst { TauriSqliteAdapter } = await import(\n\t\t\t\t/* @vite-ignore */ '@korajs/tauri'\n\t\t\t)\n\t\t\treturn new TauriSqliteAdapter({ path: `${dbName}.db` })\n\t\t}\n\t\tcase 'better-sqlite3': {\n\t\t\tconst { BetterSqlite3Adapter } = await import(\n\t\t\t\t/* @vite-ignore */ '@korajs/store/better-sqlite3'\n\t\t\t)\n\t\t\treturn new BetterSqlite3Adapter(dbName)\n\t\t}\n\t\tcase 'sqlite-wasm': {\n\t\t\tconst { SqliteWasmAdapter } = await import('@korajs/store/sqlite-wasm')\n\t\t\treturn new SqliteWasmAdapter({ dbName, workerUrl })\n\t\t}\n\t\tcase 'indexeddb': {\n\t\t\tconst { IndexedDbAdapter } = await import('@korajs/store/indexeddb')\n\t\t\treturn new IndexedDbAdapter({ dbName, workerUrl })\n\t\t}\n\t\tdefault: {\n\t\t\tconst _exhaustive: never = type\n\t\t\tthrow new Error(`Unknown adapter type: ${_exhaustive}`)\n\t\t}\n\t}\n}\n","import type { KoraEventEmitter, Operation, VersionVector } from '@korajs/core'\nimport type { MergeEngine, MergeInput } from '@korajs/merge'\nimport type { Store } from '@korajs/store'\nimport type { ApplyResult, SyncStore } from '@korajs/sync'\n\n/**\n * Wraps a Store to interpose merge resolution before applying remote operations.\n *\n * For inserts and deletes, delegates directly to the underlying Store.\n * For updates, checks whether the remote operation's previousData conflicts\n * with the current local state. If so, runs MergeEngine to resolve and\n * applies the merged result instead.\n *\n * This keeps MergeEngine integration out of Store and SyncEngine internals.\n */\nexport class MergeAwareSyncStore implements SyncStore {\n\tconstructor(\n\t\tprivate readonly store: Store,\n\t\tprivate readonly mergeEngine: MergeEngine,\n\t\tprivate readonly emitter: KoraEventEmitter | null,\n\t) {}\n\n\tgetVersionVector(): VersionVector {\n\t\treturn this.store.getVersionVector()\n\t}\n\n\tgetNodeId(): string {\n\t\treturn this.store.getNodeId()\n\t}\n\n\tasync getOperationRange(nodeId: string, fromSeq: number, toSeq: number): Promise<Operation[]> {\n\t\treturn this.store.getOperationRange(nodeId, fromSeq, toSeq)\n\t}\n\n\tasync applyRemoteOperation(op: Operation): Promise<ApplyResult> {\n\t\t// Only intercept updates that have previousData (needed for 3-way merge)\n\t\tif (op.type !== 'update' || !op.data || !op.previousData) {\n\t\t\treturn this.store.applyRemoteOperation(op)\n\t\t}\n\n\t\t// Look up current local record to detect conflicts\n\t\tconst schema = this.store.getSchema()\n\t\tconst collectionDef = schema.collections[op.collection]\n\t\tif (!collectionDef) {\n\t\t\treturn this.store.applyRemoteOperation(op)\n\t\t}\n\n\t\tconst accessor = this.store.collection(op.collection)\n\t\tconst currentRecord = await accessor.findById(op.recordId)\n\n\t\t// If record doesn't exist locally, delegate directly\n\t\tif (!currentRecord) {\n\t\t\treturn this.store.applyRemoteOperation(op)\n\t\t}\n\n\t\t// Check for conflicts: do any of the remote op's changed fields differ\n\t\t// from what the remote op expected them to be (previousData)?\n\t\tlet hasConflict = false\n\t\tfor (const field of Object.keys(op.data)) {\n\t\t\tconst expectedBase = op.previousData[field]\n\t\t\tconst currentLocal = currentRecord[field]\n\n\t\t\t// If the local state doesn't match what the remote expected,\n\t\t\t// it means the local side also changed this field — conflict.\n\t\t\tif (!deepEqual(expectedBase, currentLocal)) {\n\t\t\t\thasConflict = true\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\t// No conflict: safe to apply directly\n\t\tif (!hasConflict) {\n\t\t\treturn this.store.applyRemoteOperation(op)\n\t\t}\n\n\t\t// Conflict detected — run merge engine\n\t\t// Build a synthetic \"local operation\" representing the current local state changes\n\t\t// relative to the same base the remote operation used.\n\t\tthis.emitter?.emit({\n\t\t\ttype: 'merge:started',\n\t\t\toperationA: op,\n\t\t\toperationB: op,\n\t\t})\n\n\t\tconst baseState: Record<string, unknown> = { ...op.previousData }\n\t\tconst localOp: Operation = {\n\t\t\t...op,\n\t\t\t// The \"local\" operation's data is the diff between base and current local state\n\t\t\tdata: buildLocalDiff(op.previousData, currentRecord, Object.keys(op.data)),\n\t\t\tpreviousData: op.previousData,\n\t\t\tnodeId: this.store.getNodeId(),\n\t\t}\n\n\t\tconst input: MergeInput = {\n\t\t\tlocal: localOp,\n\t\t\tremote: op,\n\t\t\tbaseState,\n\t\t\tcollectionDef,\n\t\t}\n\n\t\tconst result = this.mergeEngine.mergeFields(input)\n\n\t\t// Emit merge traces\n\t\tfor (const trace of result.traces) {\n\t\t\tthis.emitter?.emit({ type: 'merge:conflict', trace })\n\t\t}\n\t\tconst firstTrace = result.traces[0]\n\t\tif (firstTrace) {\n\t\t\tthis.emitter?.emit({ type: 'merge:completed', trace: firstTrace })\n\t\t}\n\n\t\t// Create a modified operation with the merged data to apply\n\t\tconst mergedOp: Operation = {\n\t\t\t...op,\n\t\t\tdata: result.mergedData,\n\t\t}\n\n\t\treturn this.store.applyRemoteOperation(mergedOp)\n\t}\n}\n\n/**\n * Build the local diff: for each field the remote op changed,\n * extract the current local value (which may differ from both base and remote).\n */\nfunction buildLocalDiff(\n\tbaseState: Record<string, unknown>,\n\tcurrentRecord: Record<string, unknown>,\n\tfields: string[],\n): Record<string, unknown> {\n\tconst diff: Record<string, unknown> = {}\n\tfor (const field of fields) {\n\t\tdiff[field] = currentRecord[field]\n\t}\n\treturn diff\n}\n\n/**\n * Simple deep equality check for comparing field values.\n * Handles primitives, arrays, and plain objects.\n */\nfunction deepEqual(a: unknown, b: unknown): boolean {\n\tif (a === b) return true\n\tif (a === null || b === null) return false\n\tif (a === undefined || b === undefined) return false\n\tif (typeof a !== typeof b) return false\n\n\tif (Array.isArray(a) && Array.isArray(b)) {\n\t\tif (a.length !== b.length) return false\n\t\treturn a.every((val, i) => deepEqual(val, b[i]))\n\t}\n\n\tif (typeof a === 'object' && typeof b === 'object') {\n\t\tconst keysA = Object.keys(a as Record<string, unknown>)\n\t\tconst keysB = Object.keys(b as Record<string, unknown>)\n\t\tif (keysA.length !== keysB.length) return false\n\t\treturn keysA.every((key) =>\n\t\t\tdeepEqual((a as Record<string, unknown>)[key], (b as Record<string, unknown>)[key]),\n\t\t)\n\t}\n\n\treturn false\n}\n","// kora — meta-package re-exporting core, store, merge, sync\n// This is the primary entry point for `import { createApp, defineSchema, t } from 'korajs'`\n\n// === createApp factory ===\nexport { createApp } from './create-app'\n\n// === App types ===\nexport type {\n\tAdapterType,\n\tKoraApp,\n\tKoraConfig,\n\tStoreOptions,\n\tSyncControl,\n\tSyncOptions,\n\tTypedCollectionAccessor,\n\tTypedKoraApp,\n\tTypedKoraConfig,\n} from './types'\n\n// === @korajs/core re-exports ===\nexport { defineSchema, t } from '@korajs/core'\nexport { HybridLogicalClock } from '@korajs/core'\nexport { generateUUIDv7 } from '@korajs/core'\nexport { createOperation } from '@korajs/core'\nexport { KoraError } from '@korajs/core'\nexport type {\n\tCollectionDefinition,\n\tConnectionQuality,\n\tConstraint,\n\tFieldDescriptor,\n\tFieldKindToType,\n\tHLCTimestamp,\n\tInferFieldType,\n\tInferInsertInput,\n\tInferRecord,\n\tInferUpdateInput,\n\tKoraEvent,\n\tKoraEventEmitter,\n\tKoraEventListener,\n\tKoraEventType,\n\tMergeStrategy,\n\tMergeTrace,\n\tOperation,\n\tSchemaDefinition,\n\tSchemaInput,\n\tTypedSchemaDefinition,\n\tVersionVector,\n} from '@korajs/core'\n\n// === @korajs/store re-exports ===\nexport { Store } from '@korajs/store'\nexport type {\n\tCollectionAccessor,\n\tCollectionRecord,\n\tStorageAdapter,\n\tStoreConfig,\n} from '@korajs/store'\n\n// === @korajs/merge re-exports ===\nexport { MergeEngine } from '@korajs/merge'\nexport type { MergeInput, MergeResult } from '@korajs/merge'\n\n// === @korajs/sync re-exports ===\nexport { SyncEngine, WebSocketTransport } from '@korajs/sync'\nexport type {\n\tSyncConfig,\n\tSyncState,\n\tSyncStatus,\n\tSyncStatusInfo,\n\tSyncStore,\n} from '@korajs/sync'\n"],"mappings":"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","names":["Store","MergeEngine","SyncEngine","WebSocketTransport"]}
|
|
1
|
+
{"version":3,"sources":["../src/create-app.ts","../src/adapter-resolver.ts","../src/merge-aware-sync-store.ts","../src/index.ts"],"sourcesContent":["import type { KoraEventEmitter, Operation, SchemaInput } from '@korajs/core'\nimport { buildScopeMap } from '@korajs/core'\nimport { SimpleEventEmitter } from '@korajs/core/internal'\nimport { Instrumenter } from '@korajs/devtools'\nimport { MergeEngine } from '@korajs/merge'\nimport { Store } from '@korajs/store'\nimport type { CollectionAccessor, StorageAdapter } from '@korajs/store'\nimport type { QueryBuilder } from '@korajs/store'\nimport {\n\tConnectionMonitor,\n\tReconnectionManager,\n\tSyncEngine,\n\tWebSocketTransport,\n} from '@korajs/sync'\nimport type { SyncStatusInfo } from '@korajs/sync'\nimport { createAdapter, detectAdapterType } from './adapter-resolver'\nimport { MergeAwareSyncStore } from './merge-aware-sync-store'\nimport type {\n\tKoraApp,\n\tKoraConfig,\n\tSequenceAccessor,\n\tSyncControl,\n\tTransactionProxy,\n\tTypedKoraApp,\n\tTypedKoraConfig,\n} from './types'\n\n/**\n * Creates a new Kora application instance.\n *\n * Wires together store, merge engine, event emitter, and optionally sync\n * into a single developer-facing `KoraApp` object. Collection accessors\n * (e.g. `app.todos`) are defined as properties for immediate use after `await app.ready`.\n *\n * @param config - Application configuration including schema and optional sync settings\n * @returns A KoraApp instance with reactive collections ready for use\n *\n * @example\n * ```typescript\n * const app = createApp({\n * schema: defineSchema({\n * version: 1,\n * collections: {\n * todos: {\n * fields: {\n * title: t.string(),\n * completed: t.boolean().default(false)\n * }\n * }\n * }\n * })\n * })\n *\n * await app.ready\n * const todo = await app.todos.insert({ title: 'Hello' })\n * ```\n */\n/**\n * Creates a new typed Kora application instance.\n * When the schema is created with `defineSchema()`, full type inference flows through\n * to collection accessors, providing autocomplete and type checking for all CRUD operations.\n */\nexport function createApp<const S extends SchemaInput>(config: TypedKoraConfig<S>): TypedKoraApp<S>\n/**\n * Creates a new Kora application instance (untyped fallback).\n */\nexport function createApp(config: KoraConfig): KoraApp\nexport function createApp(config: KoraConfig): KoraApp {\n\tconst emitter: KoraEventEmitter & { clear(): void } = new SimpleEventEmitter()\n\tconst mergeEngine = new MergeEngine()\n\n\tlet store: Store | null = null\n\tlet syncEngine: SyncEngine | null = null\n\tlet unsubscribeSync: (() => void) | null = null\n\tlet reconnectionManager: ReconnectionManager | null = null\n\tlet connectionMonitor: ConnectionMonitor | null = null\n\tlet instrumenter: Instrumenter | null = null\n\tlet intentionalDisconnect = false\n\tlet qualityInterval: ReturnType<typeof setInterval> | null = null\n\n\t// Wire DevTools instrumentation immediately (emitter exists synchronously)\n\tif (config.devtools) {\n\t\tinstrumenter = new Instrumenter(emitter, {\n\t\t\tbridgeEnabled: typeof globalThis !== 'undefined' && 'window' in globalThis,\n\t\t})\n\t}\n\n\t// Build the ready promise — resolves when the store is open and wired\n\tconst ready = initializeAsync(config, emitter, mergeEngine).then((result) => {\n\t\tstore = result.store\n\t\tsyncEngine = result.syncEngine\n\t\tunsubscribeSync = result.unsubscribeSync\n\n\t\t// Wire reconnection and connection quality after sync engine is ready\n\t\tif (config.sync && syncEngine) {\n\t\t\tconnectionMonitor = new ConnectionMonitor()\n\t\t\treconnectionManager = new ReconnectionManager({\n\t\t\t\tinitialDelay: config.sync.reconnectInterval,\n\t\t\t\tmaxDelay: config.sync.maxReconnectInterval,\n\t\t\t})\n\n\t\t\t// Track activity for connection quality\n\t\t\temitter.on('sync:sent', () => connectionMonitor?.recordActivity())\n\t\t\temitter.on('sync:received', () => connectionMonitor?.recordActivity())\n\t\t\temitter.on('sync:acknowledged', () => connectionMonitor?.recordActivity())\n\n\t\t\t// Emit quality on timer while connected\n\t\t\temitter.on('sync:connected', () => {\n\t\t\t\tif (qualityInterval !== null) clearInterval(qualityInterval)\n\t\t\t\tqualityInterval = setInterval(() => {\n\t\t\t\t\tif (connectionMonitor) {\n\t\t\t\t\t\temitter.emit({ type: 'connection:quality', quality: connectionMonitor.getQuality() })\n\t\t\t\t\t}\n\t\t\t\t}, 5000)\n\t\t\t})\n\n\t\t\t// Reset monitor and clear timer on disconnect\n\t\t\temitter.on('sync:disconnected', () => {\n\t\t\t\tconnectionMonitor?.reset()\n\t\t\t\tif (qualityInterval !== null) {\n\t\t\t\t\tclearInterval(qualityInterval)\n\t\t\t\t\tqualityInterval = null\n\t\t\t\t}\n\t\t\t})\n\n\t\t\t// Auto-reconnect on unexpected disconnect\n\t\t\tif (config.sync.autoReconnect !== false) {\n\t\t\t\tconst engine = syncEngine\n\t\t\t\temitter.on('sync:disconnected', () => {\n\t\t\t\t\tif (intentionalDisconnect) return\n\t\t\t\t\t// Ignore cascading disconnect events from failed reconnection attempts.\n\t\t\t\t\t// The reconnection manager is already retrying — don't restart it.\n\t\t\t\t\tif (reconnectionManager?.isRunning()) return\n\n\t\t\t\t\tengine.setReconnecting(true)\n\t\t\t\t\treconnectionManager?.stop()\n\t\t\t\t\treconnectionManager\n\t\t\t\t\t\t?.start(async () => {\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tawait engine.start()\n\t\t\t\t\t\t\t\tengine.setReconnecting(false)\n\t\t\t\t\t\t\t\treturn true\n\t\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t\treturn false\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t})\n\t\t\t\t\t\t.then(() => {\n\t\t\t\t\t\t\t// If reconnection exhausted max attempts without success, clear flag\n\t\t\t\t\t\t\tengine.setReconnecting(false)\n\t\t\t\t\t\t})\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\t})\n\n\t// Build sync control\n\tconst syncControl: SyncControl | null = config.sync\n\t\t? {\n\t\t\t\tasync connect(): Promise<void> {\n\t\t\t\t\tawait ready\n\t\t\t\t\tif (syncEngine) {\n\t\t\t\t\t\tintentionalDisconnect = false\n\t\t\t\t\t\treconnectionManager?.stop()\n\t\t\t\t\t\treconnectionManager?.reset()\n\t\t\t\t\t\tawait syncEngine.start()\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tasync disconnect(): Promise<void> {\n\t\t\t\t\tawait ready\n\t\t\t\t\tif (syncEngine) {\n\t\t\t\t\t\tintentionalDisconnect = true\n\t\t\t\t\t\treconnectionManager?.stop()\n\t\t\t\t\t\tawait syncEngine.stop()\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tgetStatus(): SyncStatusInfo {\n\t\t\t\t\tif (syncEngine) {\n\t\t\t\t\t\treturn syncEngine.getStatus()\n\t\t\t\t\t}\n\t\t\t\t\treturn {\n\t\t\t\t\t\tstatus: 'offline',\n\t\t\t\t\t\tpendingOperations: 0,\n\t\t\t\t\t\tlastSyncedAt: null,\n\t\t\t\t\t\tlastSuccessfulPush: null,\n\t\t\t\t\t\tlastSuccessfulPull: null,\n\t\t\t\t\t\tconflicts: 0,\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tasync retryNow(): Promise<void> {\n\t\t\t\t\tawait ready\n\t\t\t\t\tif (syncEngine) {\n\t\t\t\t\t\tawait syncEngine.retryNow()\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\texportDiagnostics() {\n\t\t\t\t\tif (syncEngine) {\n\t\t\t\t\t\treturn syncEngine.exportDiagnostics()\n\t\t\t\t\t}\n\t\t\t\t\treturn {\n\t\t\t\t\t\tstate: 'disconnected' as const,\n\t\t\t\t\t\tstatus: {\n\t\t\t\t\t\t\tstatus: 'offline' as const,\n\t\t\t\t\t\t\tpendingOperations: 0,\n\t\t\t\t\t\t\tlastSyncedAt: null,\n\t\t\t\t\t\t\tlastSuccessfulPush: null,\n\t\t\t\t\t\t\tlastSuccessfulPull: null,\n\t\t\t\t\t\t\tconflicts: 0,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tnodeId: '',\n\t\t\t\t\t\turl: config.sync?.url ?? '',\n\t\t\t\t\t\tschemaVersion: config.schema.version,\n\t\t\t\t\t\tlastSyncedAt: null,\n\t\t\t\t\t\tlastSuccessfulPush: null,\n\t\t\t\t\t\tlastSuccessfulPull: null,\n\t\t\t\t\t\tconflicts: 0,\n\t\t\t\t\t\tpendingOperations: 0,\n\t\t\t\t\t\thasInFlightBatch: false,\n\t\t\t\t\t\treconnecting: false,\n\t\t\t\t\t\ttimestamp: Date.now(),\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t}\n\t\t: null\n\n\t// Shared transaction executor for both transaction() and mutation()\n\tasync function executeTransaction(\n\t\tfn: (tx: TransactionProxy) => Promise<void>,\n\t\tmutationName?: string,\n\t): Promise<Operation[]> {\n\t\tawait ready\n\t\tif (!store) {\n\t\t\tthrow new Error('Store not initialized. Await app.ready before using transactions.')\n\t\t}\n\t\tconst txContext = store.createTransaction()\n\t\tif (mutationName !== undefined) {\n\t\t\ttxContext.setMutationName(mutationName)\n\t\t}\n\t\tconst collectionNames = Object.keys(config.schema.collections)\n\n\t\t// Build proxy with collection accessors as direct properties\n\t\tconst proxy: TransactionProxy = {} as TransactionProxy\n\t\tfor (const name of collectionNames) {\n\t\t\tObject.defineProperty(proxy, name, {\n\t\t\t\tget() {\n\t\t\t\t\treturn txContext.collection(name)\n\t\t\t\t},\n\t\t\t\tenumerable: true,\n\t\t\t\tconfigurable: false,\n\t\t\t})\n\t\t}\n\n\t\ttry {\n\t\t\tawait fn(proxy)\n\t\t\tconst { operations } = await txContext.commit()\n\n\t\t\t// Notify subscriptions and emit events after commit\n\t\t\tfor (const op of operations) {\n\t\t\t\tstore.getSubscriptionManager().notify(op.collection, op)\n\t\t\t\temitter.emit({ type: 'operation:created', operation: op })\n\t\t\t}\n\n\t\t\treturn operations\n\t\t} catch (error) {\n\t\t\ttxContext.rollback()\n\t\t\tthrow error\n\t\t}\n\t}\n\n\t// Build sequences accessor (delegates to SequenceManager after ready)\n\tconst sequences: SequenceAccessor = {\n\t\tasync next(name, config) {\n\t\t\tawait ready\n\t\t\tif (!store) throw new Error('Store not initialized. Await app.ready before using sequences.')\n\t\t\treturn store.getSequenceManager().next(name, config)\n\t\t},\n\t\tasync current(name, config) {\n\t\t\tawait ready\n\t\t\tif (!store) throw new Error('Store not initialized. Await app.ready before using sequences.')\n\t\t\treturn store.getSequenceManager().current(name, config)\n\t\t},\n\t\tasync reset(name, config) {\n\t\t\tawait ready\n\t\t\tif (!store) throw new Error('Store not initialized. Await app.ready before using sequences.')\n\t\t\treturn store.getSequenceManager().reset(name, config)\n\t\t},\n\t}\n\n\t// Build the KoraApp object\n\tconst app: KoraApp = {\n\t\tready,\n\t\tevents: emitter,\n\t\tsync: syncControl,\n\t\tsequences,\n\t\tgetStore(): Store {\n\t\t\tif (!store) {\n\t\t\t\tthrow new Error('Store not initialized. Await app.ready before accessing the store.')\n\t\t\t}\n\t\t\treturn store\n\t\t},\n\t\tgetSyncEngine(): SyncEngine | null {\n\t\t\treturn syncEngine\n\t\t},\n\t\tasync transaction(fn: (tx: TransactionProxy) => Promise<void>): Promise<Operation[]> {\n\t\t\treturn executeTransaction(fn)\n\t\t},\n\t\tasync mutation(\n\t\t\tname: string,\n\t\t\tfn: (tx: TransactionProxy) => Promise<void>,\n\t\t): Promise<Operation[]> {\n\t\t\treturn executeTransaction(fn, name)\n\t\t},\n\t\tasync close(): Promise<void> {\n\t\t\tawait ready\n\t\t\tintentionalDisconnect = true\n\t\t\tif (qualityInterval !== null) {\n\t\t\t\tclearInterval(qualityInterval)\n\t\t\t\tqualityInterval = null\n\t\t\t}\n\t\t\treconnectionManager?.stop()\n\t\t\tif (instrumenter) {\n\t\t\t\tinstrumenter.destroy()\n\t\t\t\tinstrumenter = null\n\t\t\t}\n\t\t\tif (unsubscribeSync) {\n\t\t\t\tunsubscribeSync()\n\t\t\t\tunsubscribeSync = null\n\t\t\t}\n\t\t\tif (syncEngine) {\n\t\t\t\tawait syncEngine.stop()\n\t\t\t\tsyncEngine = null\n\t\t\t}\n\t\t\tif (store) {\n\t\t\t\tawait store.close()\n\t\t\t\tstore = null\n\t\t\t}\n\t\t\temitter.clear()\n\t\t},\n\t}\n\n\t// Define collection accessors via Object.defineProperty.\n\t// Before ready resolves, query methods return empty results.\n\tfor (const collectionName of Object.keys(config.schema.collections)) {\n\t\tObject.defineProperty(app, collectionName, {\n\t\t\tget(): CollectionAccessor {\n\t\t\t\treturn createCollectionAccessor(collectionName, () => store)\n\t\t\t},\n\t\t\tenumerable: true,\n\t\t\tconfigurable: false,\n\t\t})\n\t}\n\n\treturn app\n}\n\n/**\n * Asynchronous initialization: create adapter, open store, wire sync.\n */\nasync function initializeAsync(\n\tconfig: KoraConfig,\n\temitter: KoraEventEmitter,\n\tmergeEngine: MergeEngine,\n): Promise<{\n\tstore: Store\n\tsyncEngine: SyncEngine | null\n\tunsubscribeSync: (() => void) | null\n}> {\n\t// Resolve adapter\n\tconst adapterType = config.store?.adapter ?? detectAdapterType()\n\tconst dbName = config.store?.name ?? 'kora-db'\n\tconst adapter: StorageAdapter = await createAdapter(adapterType, dbName, config.store?.workerUrl)\n\n\t// Create and open the store\n\tconst store = new Store({\n\t\tschema: config.schema,\n\t\tadapter,\n\t\temitter,\n\t})\n\tawait store.open()\n\n\t// Wire sync if configured\n\tlet syncEngine: SyncEngine | null = null\n\tlet unsubscribeSync: (() => void) | null = null\n\n\tif (config.sync) {\n\t\tconst transport = new WebSocketTransport()\n\t\tconst mergeAwareStore = new MergeAwareSyncStore(store, mergeEngine, emitter)\n\n\t\t// Build scope map from schema scope declarations + flat scope values\n\t\tconst scopeMap = config.sync.scope ? buildScopeMap(config.schema, config.sync.scope) : undefined\n\n\t\tsyncEngine = new SyncEngine({\n\t\t\ttransport,\n\t\t\tstore: mergeAwareStore,\n\t\t\tconfig: {\n\t\t\t\turl: config.sync.url,\n\t\t\t\ttransport: config.sync.transport,\n\t\t\t\tauth: config.sync.auth,\n\t\t\t\tbatchSize: config.sync.batchSize,\n\t\t\t\tschemaVersion: config.sync.schemaVersion ?? config.schema.version,\n\t\t\t\tscopeMap,\n\t\t\t},\n\t\t\temitter,\n\t\t})\n\n\t\t// Wire local mutations → sync outbound queue\n\t\tunsubscribeSync = emitter.on('operation:created', (event) => {\n\t\t\tif (syncEngine) {\n\t\t\t\tsyncEngine.pushOperation(event.operation)\n\t\t\t}\n\t\t})\n\t}\n\n\treturn { store, syncEngine, unsubscribeSync }\n}\n\nfunction createCollectionAccessor(\n\tcollectionName: string,\n\tgetStore: () => Store | null,\n): CollectionAccessor {\n\treturn {\n\t\tasync insert(data: Record<string, unknown>) {\n\t\t\tconst currentStore = getStore()\n\t\t\tif (!currentStore) {\n\t\t\t\tthrow new Error(`Cannot mutate collection \"${collectionName}\" before app.ready resolves.`)\n\t\t\t}\n\t\t\treturn currentStore.collection(collectionName).insert(data)\n\t\t},\n\t\tasync findById(id: string) {\n\t\t\tconst currentStore = getStore()\n\t\t\tif (!currentStore) return null\n\t\t\treturn currentStore.collection(collectionName).findById(id)\n\t\t},\n\t\tasync update(id: string, data: Record<string, unknown>) {\n\t\t\tconst currentStore = getStore()\n\t\t\tif (!currentStore) {\n\t\t\t\tthrow new Error(`Cannot mutate collection \"${collectionName}\" before app.ready resolves.`)\n\t\t\t}\n\t\t\treturn currentStore.collection(collectionName).update(id, data)\n\t\t},\n\t\tasync delete(id: string) {\n\t\t\tconst currentStore = getStore()\n\t\t\tif (!currentStore) {\n\t\t\t\tthrow new Error(`Cannot mutate collection \"${collectionName}\" before app.ready resolves.`)\n\t\t\t}\n\t\t\treturn currentStore.collection(collectionName).delete(id)\n\t\t},\n\t\twhere(conditions: Record<string, unknown>) {\n\t\t\tconst currentStore = getStore()\n\t\t\tif (!currentStore) {\n\t\t\t\treturn createPendingQueryBuilder(conditions)\n\t\t\t}\n\t\t\treturn currentStore.collection(collectionName).where(conditions)\n\t\t},\n\t}\n}\n\nfunction createPendingQueryBuilder(initialWhere: Record<string, unknown>): QueryBuilder {\n\tconst descriptor = {\n\t\tcollection: '__pending__',\n\t\twhere: { ...initialWhere },\n\t\torderBy: [] as Array<{ field: string; direction: 'asc' | 'desc' }>,\n\t\tlimit: undefined as number | undefined,\n\t\toffset: undefined as number | undefined,\n\t}\n\n\tconst builder = {\n\t\twhere(conditions: Record<string, unknown>) {\n\t\t\tdescriptor.where = { ...descriptor.where, ...conditions }\n\t\t\treturn this\n\t\t},\n\t\torderBy(field: string, direction: 'asc' | 'desc' = 'asc') {\n\t\t\tdescriptor.orderBy.push({ field, direction })\n\t\t\treturn this\n\t\t},\n\t\tlimit(n: number) {\n\t\t\tdescriptor.limit = n\n\t\t\treturn this\n\t\t},\n\t\toffset(n: number) {\n\t\t\tdescriptor.offset = n\n\t\t\treturn this\n\t\t},\n\t\tasync exec() {\n\t\t\treturn []\n\t\t},\n\t\tasync count() {\n\t\t\treturn 0\n\t\t},\n\t\tsubscribe(callback: (results: Array<Record<string, unknown>>) => void) {\n\t\t\tvoid callback([])\n\t\t\treturn () => {}\n\t\t},\n\t\tgetDescriptor() {\n\t\t\treturn { ...descriptor, where: { ...descriptor.where }, orderBy: [...descriptor.orderBy] }\n\t\t},\n\t}\n\n\treturn builder as unknown as QueryBuilder\n}\n","import type { StorageAdapter } from '@korajs/store'\nimport type { AdapterType } from './types'\n\n/**\n * Detect the best storage adapter for the current environment.\n *\n * - Tauri app: 'tauri-sqlite' (native SQLite via Tauri plugin)\n * - Node.js: 'better-sqlite3'\n * - Browser with OPFS: 'sqlite-wasm'\n * - Browser without OPFS: 'indexeddb'\n */\nexport function detectAdapterType(): AdapterType {\n\t// Tauri environment — detected via __TAURI_INTERNALS__ injected by the Tauri runtime\n\tif (\n\t\ttypeof globalThis !== 'undefined' &&\n\t\ttypeof (globalThis as Record<string, unknown>).__TAURI_INTERNALS__ !== 'undefined'\n\t) {\n\t\treturn 'tauri-sqlite'\n\t}\n\n\t// Node.js environment\n\tif (typeof process !== 'undefined' && process.versions?.node) {\n\t\treturn 'better-sqlite3'\n\t}\n\n\t// Browser environment\n\tif (typeof globalThis.navigator !== 'undefined') {\n\t\t// Check for OPFS support (FileSystemHandle indicates OPFS availability)\n\t\tif (typeof (globalThis as Record<string, unknown>).FileSystemHandle !== 'undefined') {\n\t\t\treturn 'sqlite-wasm'\n\t\t}\n\t\treturn 'indexeddb'\n\t}\n\n\t// Default fallback (e.g., Deno, Bun, or other runtimes)\n\treturn 'better-sqlite3'\n}\n\n/**\n * Create a StorageAdapter for the given adapter type.\n * Uses dynamic imports so unused adapters are not bundled.\n *\n * @param type - The adapter type to create\n * @param dbName - Database name (used by all adapters)\n * @returns A configured StorageAdapter instance\n */\nexport async function createAdapter(\n\ttype: AdapterType,\n\tdbName: string,\n\tworkerUrl?: string | URL,\n): Promise<StorageAdapter> {\n\tswitch (type) {\n\t\tcase 'tauri-sqlite': {\n\t\t\t// @korajs/tauri is only installed in Tauri projects (optional peer dep).\n\t\t\t// This code path only runs when __TAURI_INTERNALS__ is detected.\n\t\t\t// Using @vite-ignore so Vite doesn't statically analyze this import —\n\t\t\t// it will still resolve it at runtime through Vite's dev server.\n\t\t\tconst { TauriSqliteAdapter } = await import(/* @vite-ignore */ '@korajs/tauri')\n\t\t\treturn new TauriSqliteAdapter({ path: `${dbName}.db` })\n\t\t}\n\t\tcase 'better-sqlite3': {\n\t\t\tconst { BetterSqlite3Adapter } = await import(\n\t\t\t\t/* @vite-ignore */ '@korajs/store/better-sqlite3'\n\t\t\t)\n\t\t\treturn new BetterSqlite3Adapter(dbName)\n\t\t}\n\t\tcase 'sqlite-wasm': {\n\t\t\tconst { SqliteWasmAdapter } = await import('@korajs/store/sqlite-wasm')\n\t\t\treturn new SqliteWasmAdapter({ dbName, workerUrl })\n\t\t}\n\t\tcase 'indexeddb': {\n\t\t\tconst { IndexedDbAdapter } = await import('@korajs/store/indexeddb')\n\t\t\treturn new IndexedDbAdapter({ dbName, workerUrl })\n\t\t}\n\t\tdefault: {\n\t\t\tconst _exhaustive: never = type\n\t\t\tthrow new Error(`Unknown adapter type: ${_exhaustive}`)\n\t\t}\n\t}\n}\n","import type { KoraEventEmitter, Operation, VersionVector } from '@korajs/core'\nimport type { MergeEngine, MergeInput } from '@korajs/merge'\nimport type { Store } from '@korajs/store'\nimport type { ApplyResult, SyncStore } from '@korajs/sync'\n\n/**\n * Wraps a Store to interpose merge resolution before applying remote operations.\n *\n * For inserts and deletes, delegates directly to the underlying Store.\n * For updates, checks whether the remote operation's previousData conflicts\n * with the current local state. If so, runs MergeEngine to resolve and\n * applies the merged result instead.\n *\n * This keeps MergeEngine integration out of Store and SyncEngine internals.\n */\nexport class MergeAwareSyncStore implements SyncStore {\n\tconstructor(\n\t\tprivate readonly store: Store,\n\t\tprivate readonly mergeEngine: MergeEngine,\n\t\tprivate readonly emitter: KoraEventEmitter | null,\n\t) {}\n\n\tgetVersionVector(): VersionVector {\n\t\treturn this.store.getVersionVector()\n\t}\n\n\tgetNodeId(): string {\n\t\treturn this.store.getNodeId()\n\t}\n\n\tasync getOperationRange(nodeId: string, fromSeq: number, toSeq: number): Promise<Operation[]> {\n\t\treturn this.store.getOperationRange(nodeId, fromSeq, toSeq)\n\t}\n\n\tasync applyRemoteOperation(op: Operation): Promise<ApplyResult> {\n\t\t// Only intercept updates that have previousData (needed for 3-way merge)\n\t\tif (op.type !== 'update' || !op.data || !op.previousData) {\n\t\t\treturn this.store.applyRemoteOperation(op)\n\t\t}\n\n\t\t// Look up current local record to detect conflicts\n\t\tconst schema = this.store.getSchema()\n\t\tconst collectionDef = schema.collections[op.collection]\n\t\tif (!collectionDef) {\n\t\t\treturn this.store.applyRemoteOperation(op)\n\t\t}\n\n\t\tconst accessor = this.store.collection(op.collection)\n\t\tconst currentRecord = await accessor.findById(op.recordId)\n\n\t\t// If record doesn't exist locally, delegate directly\n\t\tif (!currentRecord) {\n\t\t\treturn this.store.applyRemoteOperation(op)\n\t\t}\n\n\t\t// Check for conflicts: do any of the remote op's changed fields differ\n\t\t// from what the remote op expected them to be (previousData)?\n\t\tlet hasConflict = false\n\t\tfor (const field of Object.keys(op.data)) {\n\t\t\tconst expectedBase = op.previousData[field]\n\t\t\tconst currentLocal = currentRecord[field]\n\n\t\t\t// If the local state doesn't match what the remote expected,\n\t\t\t// it means the local side also changed this field — conflict.\n\t\t\tif (!deepEqual(expectedBase, currentLocal)) {\n\t\t\t\thasConflict = true\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\t// No conflict: safe to apply directly\n\t\tif (!hasConflict) {\n\t\t\treturn this.store.applyRemoteOperation(op)\n\t\t}\n\n\t\t// Conflict detected — run merge engine\n\t\t// Build a synthetic \"local operation\" representing the current local state changes\n\t\t// relative to the same base the remote operation used.\n\t\tthis.emitter?.emit({\n\t\t\ttype: 'merge:started',\n\t\t\toperationA: op,\n\t\t\toperationB: op,\n\t\t})\n\n\t\tconst baseState: Record<string, unknown> = { ...op.previousData }\n\t\tconst localOp: Operation = {\n\t\t\t...op,\n\t\t\t// The \"local\" operation's data is the diff between base and current local state\n\t\t\tdata: buildLocalDiff(op.previousData, currentRecord, Object.keys(op.data)),\n\t\t\tpreviousData: op.previousData,\n\t\t\tnodeId: this.store.getNodeId(),\n\t\t}\n\n\t\tconst input: MergeInput = {\n\t\t\tlocal: localOp,\n\t\t\tremote: op,\n\t\t\tbaseState,\n\t\t\tcollectionDef,\n\t\t}\n\n\t\tconst result = this.mergeEngine.mergeFields(input)\n\n\t\t// Emit merge traces\n\t\tfor (const trace of result.traces) {\n\t\t\tthis.emitter?.emit({ type: 'merge:conflict', trace })\n\t\t}\n\t\tconst firstTrace = result.traces[0]\n\t\tif (firstTrace) {\n\t\t\tthis.emitter?.emit({ type: 'merge:completed', trace: firstTrace })\n\t\t}\n\n\t\t// Create a modified operation with the merged data to apply\n\t\tconst mergedOp: Operation = {\n\t\t\t...op,\n\t\t\tdata: result.mergedData,\n\t\t}\n\n\t\treturn this.store.applyRemoteOperation(mergedOp)\n\t}\n}\n\n/**\n * Build the local diff: for each field the remote op changed,\n * extract the current local value (which may differ from both base and remote).\n */\nfunction buildLocalDiff(\n\tbaseState: Record<string, unknown>,\n\tcurrentRecord: Record<string, unknown>,\n\tfields: string[],\n): Record<string, unknown> {\n\tconst diff: Record<string, unknown> = {}\n\tfor (const field of fields) {\n\t\tdiff[field] = currentRecord[field]\n\t}\n\treturn diff\n}\n\n/**\n * Simple deep equality check for comparing field values.\n * Handles primitives, arrays, and plain objects.\n */\nfunction deepEqual(a: unknown, b: unknown): boolean {\n\tif (a === b) return true\n\tif (a === null || b === null) return false\n\tif (a === undefined || b === undefined) return false\n\tif (typeof a !== typeof b) return false\n\n\tif (Array.isArray(a) && Array.isArray(b)) {\n\t\tif (a.length !== b.length) return false\n\t\treturn a.every((val, i) => deepEqual(val, b[i]))\n\t}\n\n\tif (typeof a === 'object' && typeof b === 'object') {\n\t\tconst keysA = Object.keys(a as Record<string, unknown>)\n\t\tconst keysB = Object.keys(b as Record<string, unknown>)\n\t\tif (keysA.length !== keysB.length) return false\n\t\treturn keysA.every((key) =>\n\t\t\tdeepEqual((a as Record<string, unknown>)[key], (b as Record<string, unknown>)[key]),\n\t\t)\n\t}\n\n\treturn false\n}\n","// kora — meta-package re-exporting core, store, merge, sync\n// This is the primary entry point for `import { createApp, defineSchema, t } from 'korajs'`\n\n// === createApp factory ===\nexport { createApp } from './create-app'\n\n// === App types ===\nexport type {\n\tAdapterType,\n\tKoraApp,\n\tKoraConfig,\n\tStoreOptions,\n\tSyncControl,\n\tSyncOptions,\n\tSequenceAccessor,\n\tTransactionCollectionProxy,\n\tTransactionProxy,\n\tTypedCollectionAccessor,\n\tTypedKoraApp,\n\tTypedKoraConfig,\n} from './types'\n\n// === @korajs/core re-exports ===\nexport { defineSchema, migrate, t } from '@korajs/core'\nexport { HybridLogicalClock } from '@korajs/core'\nexport { generateUUIDv7 } from '@korajs/core'\nexport { createOperation } from '@korajs/core'\nexport { KoraError } from '@korajs/core'\nexport { op } from '@korajs/core'\nexport type {\n\tAtomicOp,\n\tAtomicOpType,\n\tCollectionDefinition,\n\tConnectionQuality,\n\tConstraint,\n\tFieldDescriptor,\n\tFieldKindToType,\n\tHLCTimestamp,\n\tInferFieldType,\n\tInferInsertInput,\n\tInferRecord,\n\tInferUpdateInput,\n\tKoraEvent,\n\tKoraEventEmitter,\n\tKoraEventListener,\n\tKoraEventType,\n\tMergeStrategy,\n\tMergeTrace,\n\tMigrationDefinition,\n\tMigrationStep,\n\tOperation,\n\tSchemaDefinition,\n\tSchemaInput,\n\tSequenceConfig,\n\tTypedSchemaDefinition,\n\tVersionVector,\n} from '@korajs/core'\n\n// === @korajs/store re-exports ===\nexport { SequenceManager, Store } from '@korajs/store'\nexport { TransactionContext } from '@korajs/store'\nexport type {\n\tCollectionAccessor,\n\tCollectionRecord,\n\tStorageAdapter,\n\tStoreConfig,\n\tTransactionCollectionAccessor,\n\tTransactionContextConfig,\n} from '@korajs/store'\n\n// === @korajs/merge re-exports ===\nexport { MergeEngine } from '@korajs/merge'\nexport type { MergeInput, MergeResult } from '@korajs/merge'\n\n// === @korajs/sync re-exports ===\nexport { SyncEngine, WebSocketTransport } from '@korajs/sync'\nexport type {\n\tSyncConfig,\n\tSyncDiagnostics,\n\tSyncState,\n\tSyncStatus,\n\tSyncStatusInfo,\n\tSyncStore,\n} from '@korajs/sync'\n"],"mappings":"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","names":["op","op","config","Store","MergeEngine","SyncEngine","WebSocketTransport"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "korajs",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Kora.js — offline-first application framework",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -32,11 +32,11 @@
|
|
|
32
32
|
"dist"
|
|
33
33
|
],
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@korajs/core": "0.
|
|
36
|
-
"@korajs/store": "0.
|
|
37
|
-
"@korajs/merge": "0.
|
|
38
|
-
"@korajs/sync": "0.
|
|
39
|
-
"@korajs/devtools": "0.
|
|
35
|
+
"@korajs/core": "0.4.0",
|
|
36
|
+
"@korajs/store": "0.4.0",
|
|
37
|
+
"@korajs/merge": "0.4.0",
|
|
38
|
+
"@korajs/sync": "0.4.0",
|
|
39
|
+
"@korajs/devtools": "0.4.0"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"@types/better-sqlite3": "^7.6.13",
|