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.
@@ -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":[]}
@@ -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: () => import_core2.HybridLogicalClock,
34
- KoraError: () => import_core5.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: () => import_core4.createOperation,
41
- defineSchema: () => import_core.defineSchema,
42
- generateUUIDv7: () => import_core3.generateUUIDv7,
43
- t: () => import_core.t
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(op) {
121
- if (op.type !== "update" || !op.data || !op.previousData) {
122
- return this.store.applyRemoteOperation(op);
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[op.collection];
130
+ const collectionDef = schema.collections[op2.collection];
126
131
  if (!collectionDef) {
127
- return this.store.applyRemoteOperation(op);
132
+ return this.store.applyRemoteOperation(op2);
128
133
  }
129
- const accessor = this.store.collection(op.collection);
130
- const currentRecord = await accessor.findById(op.recordId);
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(op);
137
+ return this.store.applyRemoteOperation(op2);
133
138
  }
134
139
  let hasConflict = false;
135
- for (const field of Object.keys(op.data)) {
136
- const expectedBase = op.previousData[field];
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(op);
149
+ return this.store.applyRemoteOperation(op2);
145
150
  }
146
151
  this.emitter?.emit({
147
152
  type: "merge:started",
148
- operationA: op,
149
- operationB: op
153
+ operationA: op2,
154
+ operationB: op2
150
155
  });
151
- const baseState = { ...op.previousData };
156
+ const baseState = { ...op2.previousData };
152
157
  const localOp = {
153
- ...op,
158
+ ...op2,
154
159
  // The "local" operation's data is the diff between base and current local state
155
- data: buildLocalDiff(op.previousData, currentRecord, Object.keys(op.data)),
156
- previousData: op.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: op,
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
- ...op,
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 { status: "offline", pendingOperations: 0, lastSyncedAt: null };
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
@@ -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":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACCA,sBAAmC;AACnC,sBAA6B;AAC7B,mBAA4B;AAC5B,mBAAsB;AAGtB,kBAAuF;;;ACIhF,SAAS,oBAAiC;AAEhD,MACC,OAAO,eAAe,eACtB,OAAQ,WAAuC,wBAAwB,aACtE;AACD,WAAO;AAAA,EACR;AAGA,MAAI,OAAO,YAAY,eAAe,QAAQ,UAAU,MAAM;AAC7D,WAAO;AAAA,EACR;AAGA,MAAI,OAAO,WAAW,cAAc,aAAa;AAEhD,QAAI,OAAQ,WAAuC,qBAAqB,aAAa;AACpF,aAAO;AAAA,IACR;AACA,WAAO;AAAA,EACR;AAGA,SAAO;AACR;AAUA,eAAsB,cACrB,MACA,QACA,WAC0B;AAC1B,UAAQ,MAAM;AAAA,IACb,KAAK,gBAAgB;AAKpB,YAAM,EAAE,mBAAmB,IAAI,MAAM;AAAA;AAAA,QACjB;AAAA,MACpB;AACA,aAAO,IAAI,mBAAmB,EAAE,MAAM,GAAG,MAAM,MAAM,CAAC;AAAA,IACvD;AAAA,IACA,KAAK,kBAAkB;AACtB,YAAM,EAAE,qBAAqB,IAAI,MAAM;AAAA;AAAA,QACnB;AAAA,MACpB;AACA,aAAO,IAAI,qBAAqB,MAAM;AAAA,IACvC;AAAA,IACA,KAAK,eAAe;AACnB,YAAM,EAAE,kBAAkB,IAAI,MAAM,OAAO,2BAA2B;AACtE,aAAO,IAAI,kBAAkB,EAAE,QAAQ,UAAU,CAAC;AAAA,IACnD;AAAA,IACA,KAAK,aAAa;AACjB,YAAM,EAAE,iBAAiB,IAAI,MAAM,OAAO,yBAAyB;AACnE,aAAO,IAAI,iBAAiB,EAAE,QAAQ,UAAU,CAAC;AAAA,IAClD;AAAA,IACA,SAAS;AACR,YAAM,cAAqB;AAC3B,YAAM,IAAI,MAAM,yBAAyB,WAAW,EAAE;AAAA,IACvD;AAAA,EACD;AACD;;;AClEO,IAAM,sBAAN,MAA+C;AAAA,EACrD,YACkB,OACA,aACA,SAChB;AAHgB;AACA;AACA;AAAA,EACf;AAAA,EAHe;AAAA,EACA;AAAA,EACA;AAAA,EAGlB,mBAAkC;AACjC,WAAO,KAAK,MAAM,iBAAiB;AAAA,EACpC;AAAA,EAEA,YAAoB;AACnB,WAAO,KAAK,MAAM,UAAU;AAAA,EAC7B;AAAA,EAEA,MAAM,kBAAkB,QAAgB,SAAiB,OAAqC;AAC7F,WAAO,KAAK,MAAM,kBAAkB,QAAQ,SAAS,KAAK;AAAA,EAC3D;AAAA,EAEA,MAAM,qBAAqB,IAAqC;AAE/D,QAAI,GAAG,SAAS,YAAY,CAAC,GAAG,QAAQ,CAAC,GAAG,cAAc;AACzD,aAAO,KAAK,MAAM,qBAAqB,EAAE;AAAA,IAC1C;AAGA,UAAM,SAAS,KAAK,MAAM,UAAU;AACpC,UAAM,gBAAgB,OAAO,YAAY,GAAG,UAAU;AACtD,QAAI,CAAC,eAAe;AACnB,aAAO,KAAK,MAAM,qBAAqB,EAAE;AAAA,IAC1C;AAEA,UAAM,WAAW,KAAK,MAAM,WAAW,GAAG,UAAU;AACpD,UAAM,gBAAgB,MAAM,SAAS,SAAS,GAAG,QAAQ;AAGzD,QAAI,CAAC,eAAe;AACnB,aAAO,KAAK,MAAM,qBAAqB,EAAE;AAAA,IAC1C;AAIA,QAAI,cAAc;AAClB,eAAW,SAAS,OAAO,KAAK,GAAG,IAAI,GAAG;AACzC,YAAM,eAAe,GAAG,aAAa,KAAK;AAC1C,YAAM,eAAe,cAAc,KAAK;AAIxC,UAAI,CAAC,UAAU,cAAc,YAAY,GAAG;AAC3C,sBAAc;AACd;AAAA,MACD;AAAA,IACD;AAGA,QAAI,CAAC,aAAa;AACjB,aAAO,KAAK,MAAM,qBAAqB,EAAE;AAAA,IAC1C;AAKA,SAAK,SAAS,KAAK;AAAA,MAClB,MAAM;AAAA,MACN,YAAY;AAAA,MACZ,YAAY;AAAA,IACb,CAAC;AAED,UAAM,YAAqC,EAAE,GAAG,GAAG,aAAa;AAChE,UAAM,UAAqB;AAAA,MAC1B,GAAG;AAAA;AAAA,MAEH,MAAM,eAAe,GAAG,cAAc,eAAe,OAAO,KAAK,GAAG,IAAI,CAAC;AAAA,MACzE,cAAc,GAAG;AAAA,MACjB,QAAQ,KAAK,MAAM,UAAU;AAAA,IAC9B;AAEA,UAAM,QAAoB;AAAA,MACzB,OAAO;AAAA,MACP,QAAQ;AAAA,MACR;AAAA,MACA;AAAA,IACD;AAEA,UAAM,SAAS,KAAK,YAAY,YAAY,KAAK;AAGjD,eAAW,SAAS,OAAO,QAAQ;AAClC,WAAK,SAAS,KAAK,EAAE,MAAM,kBAAkB,MAAM,CAAC;AAAA,IACrD;AACA,UAAM,aAAa,OAAO,OAAO,CAAC;AAClC,QAAI,YAAY;AACf,WAAK,SAAS,KAAK,EAAE,MAAM,mBAAmB,OAAO,WAAW,CAAC;AAAA,IAClE;AAGA,UAAM,WAAsB;AAAA,MAC3B,GAAG;AAAA,MACH,MAAM,OAAO;AAAA,IACd;AAEA,WAAO,KAAK,MAAM,qBAAqB,QAAQ;AAAA,EAChD;AACD;AAMA,SAAS,eACR,WACA,eACA,QAC0B;AAC1B,QAAM,OAAgC,CAAC;AACvC,aAAW,SAAS,QAAQ;AAC3B,SAAK,KAAK,IAAI,cAAc,KAAK;AAAA,EAClC;AACA,SAAO;AACR;AAMA,SAAS,UAAU,GAAY,GAAqB;AACnD,MAAI,MAAM,EAAG,QAAO;AACpB,MAAI,MAAM,QAAQ,MAAM,KAAM,QAAO;AACrC,MAAI,MAAM,UAAa,MAAM,OAAW,QAAO;AAC/C,MAAI,OAAO,MAAM,OAAO,EAAG,QAAO;AAElC,MAAI,MAAM,QAAQ,CAAC,KAAK,MAAM,QAAQ,CAAC,GAAG;AACzC,QAAI,EAAE,WAAW,EAAE,OAAQ,QAAO;AAClC,WAAO,EAAE,MAAM,CAAC,KAAK,MAAM,UAAU,KAAK,EAAE,CAAC,CAAC,CAAC;AAAA,EAChD;AAEA,MAAI,OAAO,MAAM,YAAY,OAAO,MAAM,UAAU;AACnD,UAAM,QAAQ,OAAO,KAAK,CAA4B;AACtD,UAAM,QAAQ,OAAO,KAAK,CAA4B;AACtD,QAAI,MAAM,WAAW,MAAM,OAAQ,QAAO;AAC1C,WAAO,MAAM;AAAA,MAAM,CAAC,QACnB,UAAW,EAA8B,GAAG,GAAI,EAA8B,GAAG,CAAC;AAAA,IACnF;AAAA,EACD;AAEA,SAAO;AACR;;;AF7GO,SAAS,UAAU,QAA6B;AACtD,QAAM,UAAgD,IAAI,mCAAmB;AAC7E,QAAM,cAAc,IAAI,yBAAY;AAEpC,MAAI,QAAsB;AAC1B,MAAI,aAAgC;AACpC,MAAI,kBAAuC;AAC3C,MAAI,sBAAkD;AACtD,MAAI,oBAA8C;AAClD,MAAI,eAAoC;AACxC,MAAI,wBAAwB;AAC5B,MAAI,kBAAyD;AAG7D,MAAI,OAAO,UAAU;AACpB,mBAAe,IAAI,6BAAa,SAAS;AAAA,MACxC,eAAe,OAAO,eAAe,eAAe,YAAY;AAAA,IACjE,CAAC;AAAA,EACF;AAGA,QAAM,QAAQ,gBAAgB,QAAQ,SAAS,WAAW,EAAE,KAAK,CAAC,WAAW;AAC5E,YAAQ,OAAO;AACf,iBAAa,OAAO;AACpB,sBAAkB,OAAO;AAGzB,QAAI,OAAO,QAAQ,YAAY;AAC9B,0BAAoB,IAAI,8BAAkB;AAC1C,4BAAsB,IAAI,gCAAoB;AAAA,QAC7C,cAAc,OAAO,KAAK;AAAA,QAC1B,UAAU,OAAO,KAAK;AAAA,MACvB,CAAC;AAGD,cAAQ,GAAG,aAAa,MAAM,mBAAmB,eAAe,CAAC;AACjE,cAAQ,GAAG,iBAAiB,MAAM,mBAAmB,eAAe,CAAC;AACrE,cAAQ,GAAG,qBAAqB,MAAM,mBAAmB,eAAe,CAAC;AAGzE,cAAQ,GAAG,kBAAkB,MAAM;AAClC,YAAI,oBAAoB,KAAM,eAAc,eAAe;AAC3D,0BAAkB,YAAY,MAAM;AACnC,cAAI,mBAAmB;AACtB,oBAAQ,KAAK,EAAE,MAAM,sBAAsB,SAAS,kBAAkB,WAAW,EAAE,CAAC;AAAA,UACrF;AAAA,QACD,GAAG,GAAI;AAAA,MACR,CAAC;AAGD,cAAQ,GAAG,qBAAqB,MAAM;AACrC,2BAAmB,MAAM;AACzB,YAAI,oBAAoB,MAAM;AAC7B,wBAAc,eAAe;AAC7B,4BAAkB;AAAA,QACnB;AAAA,MACD,CAAC;AAGD,UAAI,OAAO,KAAK,kBAAkB,OAAO;AACxC,cAAM,SAAS;AACf,gBAAQ,GAAG,qBAAqB,MAAM;AACrC,cAAI,sBAAuB;AAG3B,cAAI,qBAAqB,UAAU,EAAG;AAEtC,iBAAO,gBAAgB,IAAI;AAC3B,+BAAqB,KAAK;AAC1B,+BAAqB,MAAM,YAAY;AACtC,gBAAI;AACH,oBAAM,OAAO,MAAM;AACnB,qBAAO,gBAAgB,KAAK;AAC5B,qBAAO;AAAA,YACR,QAAQ;AACP,qBAAO;AAAA,YACR;AAAA,UACD,CAAC,EAAE,KAAK,MAAM;AAEb,mBAAO,gBAAgB,KAAK;AAAA,UAC7B,CAAC;AAAA,QACF,CAAC;AAAA,MACF;AAAA,IACD;AAAA,EACD,CAAC;AAGD,QAAM,cAAkC,OAAO,OAC5C;AAAA,IACA,MAAM,UAAyB;AAC9B,YAAM;AACN,UAAI,YAAY;AACf,gCAAwB;AACxB,6BAAqB,KAAK;AAC1B,6BAAqB,MAAM;AAC3B,cAAM,WAAW,MAAM;AAAA,MACxB;AAAA,IACD;AAAA,IACA,MAAM,aAA4B;AACjC,YAAM;AACN,UAAI,YAAY;AACf,gCAAwB;AACxB,6BAAqB,KAAK;AAC1B,cAAM,WAAW,KAAK;AAAA,MACvB;AAAA,IACD;AAAA,IACA,YAA4B;AAC3B,UAAI,YAAY;AACf,eAAO,WAAW,UAAU;AAAA,MAC7B;AACA,aAAO,EAAE,QAAQ,WAAW,mBAAmB,GAAG,cAAc,KAAK;AAAA,IACtE;AAAA,EACD,IACC;AAGH,QAAM,MAAe;AAAA,IACpB;AAAA,IACA,QAAQ;AAAA,IACR,MAAM;AAAA,IACN,WAAkB;AACjB,UAAI,CAAC,OAAO;AACX,cAAM,IAAI,MAAM,oEAAoE;AAAA,MACrF;AACA,aAAO;AAAA,IACR;AAAA,IACA,gBAAmC;AAClC,aAAO;AAAA,IACR;AAAA,IACA,MAAM,QAAuB;AAC5B,YAAM;AACN,8BAAwB;AACxB,UAAI,oBAAoB,MAAM;AAC7B,sBAAc,eAAe;AAC7B,0BAAkB;AAAA,MACnB;AACA,2BAAqB,KAAK;AAC1B,UAAI,cAAc;AACjB,qBAAa,QAAQ;AACrB,uBAAe;AAAA,MAChB;AACA,UAAI,iBAAiB;AACpB,wBAAgB;AAChB,0BAAkB;AAAA,MACnB;AACA,UAAI,YAAY;AACf,cAAM,WAAW,KAAK;AACtB,qBAAa;AAAA,MACd;AACA,UAAI,OAAO;AACV,cAAM,MAAM,MAAM;AAClB,gBAAQ;AAAA,MACT;AACA,cAAQ,MAAM;AAAA,IACf;AAAA,EACD;AAIA,aAAW,kBAAkB,OAAO,KAAK,OAAO,OAAO,WAAW,GAAG;AACpE,WAAO,eAAe,KAAK,gBAAgB;AAAA,MAC1C,MAA0B;AACzB,eAAO,yBAAyB,gBAAgB,MAAM,KAAK;AAAA,MAC5D;AAAA,MACA,YAAY;AAAA,MACZ,cAAc;AAAA,IACf,CAAC;AAAA,EACF;AAEA,SAAO;AACR;AAKA,eAAe,gBACd,QACA,SACA,aAKE;AAEF,QAAM,cAAc,OAAO,OAAO,WAAW,kBAAkB;AAC/D,QAAM,SAAS,OAAO,OAAO,QAAQ;AACrC,QAAM,UAA0B,MAAM,cAAc,aAAa,QAAQ,OAAO,OAAO,SAAS;AAGhG,QAAM,QAAQ,IAAI,mBAAM;AAAA,IACvB,QAAQ,OAAO;AAAA,IACf;AAAA,IACA;AAAA,EACD,CAAC;AACD,QAAM,MAAM,KAAK;AAGjB,MAAI,aAAgC;AACpC,MAAI,kBAAuC;AAE3C,MAAI,OAAO,MAAM;AAChB,UAAM,YAAY,IAAI,+BAAmB;AACzC,UAAM,kBAAkB,IAAI,oBAAoB,OAAO,aAAa,OAAO;AAE3E,iBAAa,IAAI,uBAAW;AAAA,MAC3B;AAAA,MACA,OAAO;AAAA,MACP,QAAQ;AAAA,QACP,KAAK,OAAO,KAAK;AAAA,QACjB,WAAW,OAAO,KAAK;AAAA,QACvB,MAAM,OAAO,KAAK;AAAA,QAClB,WAAW,OAAO,KAAK;AAAA,QACvB,eAAe,OAAO,KAAK,iBAAiB,OAAO,OAAO;AAAA,MAC3D;AAAA,MACA;AAAA,IACD,CAAC;AAGD,sBAAkB,QAAQ,GAAG,qBAAqB,CAAC,UAAU;AAC5D,UAAI,YAAY;AACf,mBAAW,cAAc,MAAM,SAAS;AAAA,MACzC;AAAA,IACD,CAAC;AAAA,EACF;AAEA,SAAO,EAAE,OAAO,YAAY,gBAAgB;AAC7C;AAEA,SAAS,yBACR,gBACA,UACqB;AACrB,SAAO;AAAA,IACN,MAAM,OAAO,MAA+B;AAC3C,YAAM,eAAe,SAAS;AAC9B,UAAI,CAAC,cAAc;AAClB,cAAM,IAAI,MAAM,6BAA6B,cAAc,8BAA8B;AAAA,MAC1F;AACA,aAAO,aAAa,WAAW,cAAc,EAAE,OAAO,IAAI;AAAA,IAC3D;AAAA,IACA,MAAM,SAAS,IAAY;AAC1B,YAAM,eAAe,SAAS;AAC9B,UAAI,CAAC,aAAc,QAAO;AAC1B,aAAO,aAAa,WAAW,cAAc,EAAE,SAAS,EAAE;AAAA,IAC3D;AAAA,IACA,MAAM,OAAO,IAAY,MAA+B;AACvD,YAAM,eAAe,SAAS;AAC9B,UAAI,CAAC,cAAc;AAClB,cAAM,IAAI,MAAM,6BAA6B,cAAc,8BAA8B;AAAA,MAC1F;AACA,aAAO,aAAa,WAAW,cAAc,EAAE,OAAO,IAAI,IAAI;AAAA,IAC/D;AAAA,IACA,MAAM,OAAO,IAAY;AACxB,YAAM,eAAe,SAAS;AAC9B,UAAI,CAAC,cAAc;AAClB,cAAM,IAAI,MAAM,6BAA6B,cAAc,8BAA8B;AAAA,MAC1F;AACA,aAAO,aAAa,WAAW,cAAc,EAAE,OAAO,EAAE;AAAA,IACzD;AAAA,IACA,MAAM,YAAqC;AAC1C,YAAM,eAAe,SAAS;AAC9B,UAAI,CAAC,cAAc;AAClB,eAAO,0BAA0B,UAAU;AAAA,MAC5C;AACA,aAAO,aAAa,WAAW,cAAc,EAAE,MAAM,UAAU;AAAA,IAChE;AAAA,EACD;AACD;AAEA,SAAS,0BAA0B,cAAqD;AACvF,QAAM,aAAa;AAAA,IAClB,YAAY;AAAA,IACZ,OAAO,EAAE,GAAG,aAAa;AAAA,IACzB,SAAS,CAAC;AAAA,IACV,OAAO;AAAA,IACP,QAAQ;AAAA,EACT;AAEA,QAAM,UAAU;AAAA,IACf,MAAM,YAAqC;AAC1C,iBAAW,QAAQ,EAAE,GAAG,WAAW,OAAO,GAAG,WAAW;AACxD,aAAO;AAAA,IACR;AAAA,IACA,QAAQ,OAAe,YAA4B,OAAO;AACzD,iBAAW,QAAQ,KAAK,EAAE,OAAO,UAAU,CAAC;AAC5C,aAAO;AAAA,IACR;AAAA,IACA,MAAM,GAAW;AAChB,iBAAW,QAAQ;AACnB,aAAO;AAAA,IACR;AAAA,IACA,OAAO,GAAW;AACjB,iBAAW,SAAS;AACpB,aAAO;AAAA,IACR;AAAA,IACA,MAAM,OAAO;AACZ,aAAO,CAAC;AAAA,IACT;AAAA,IACA,MAAM,QAAQ;AACb,aAAO;AAAA,IACR;AAAA,IACA,UAAU,UAA6D;AACtE,WAAK,SAAS,CAAC,CAAC;AAChB,aAAO,MAAM;AAAA,MAAC;AAAA,IACf;AAAA,IACA,gBAAgB;AACf,aAAO,EAAE,GAAG,YAAY,OAAO,EAAE,GAAG,WAAW,MAAM,GAAG,SAAS,CAAC,GAAG,WAAW,OAAO,EAAE;AAAA,IAC1F;AAAA,EACD;AAEA,SAAO;AACR;;;ADzVA,kBAAgC;AAChC,IAAAA,eAAmC;AACnC,IAAAA,eAA+B;AAC/B,IAAAA,eAAgC;AAChC,IAAAA,eAA0B;AA0B1B,IAAAC,gBAAsB;AAStB,IAAAC,gBAA4B;AAI5B,IAAAC,eAA+C;","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 { ConnectionMonitor, ReconnectionManager, SyncEngine, WebSocketTransport } from "@korajs/sync";
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(op) {
75
- if (op.type !== "update" || !op.data || !op.previousData) {
76
- return this.store.applyRemoteOperation(op);
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[op.collection];
85
+ const collectionDef = schema.collections[op2.collection];
80
86
  if (!collectionDef) {
81
- return this.store.applyRemoteOperation(op);
87
+ return this.store.applyRemoteOperation(op2);
82
88
  }
83
- const accessor = this.store.collection(op.collection);
84
- const currentRecord = await accessor.findById(op.recordId);
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(op);
92
+ return this.store.applyRemoteOperation(op2);
87
93
  }
88
94
  let hasConflict = false;
89
- for (const field of Object.keys(op.data)) {
90
- const expectedBase = op.previousData[field];
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(op);
104
+ return this.store.applyRemoteOperation(op2);
99
105
  }
100
106
  this.emitter?.emit({
101
107
  type: "merge:started",
102
- operationA: op,
103
- operationB: op
108
+ operationA: op2,
109
+ operationB: op2
104
110
  });
105
- const baseState = { ...op.previousData };
111
+ const baseState = { ...op2.previousData };
106
112
  const localOp = {
107
- ...op,
113
+ ...op2,
108
114
  // The "local" operation's data is the diff between base and current local state
109
- data: buildLocalDiff(op.previousData, currentRecord, Object.keys(op.data)),
110
- previousData: op.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: op,
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
- ...op,
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 { status: "offline", pendingOperations: 0, lastSyncedAt: null };
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 { Store as Store2 } from "@korajs/store";
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.5",
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.3.2",
36
- "@korajs/store": "0.3.2",
37
- "@korajs/merge": "0.3.2",
38
- "@korajs/sync": "0.3.2",
39
- "@korajs/devtools": "0.3.2"
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",