korajs 0.3.1 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +8 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -1
- package/package.json +6 -6
package/dist/index.cjs
CHANGED
|
@@ -53,6 +53,9 @@ var import_sync = require("@korajs/sync");
|
|
|
53
53
|
|
|
54
54
|
// src/adapter-resolver.ts
|
|
55
55
|
function detectAdapterType() {
|
|
56
|
+
if (typeof globalThis !== "undefined" && typeof globalThis.__TAURI_INTERNALS__ !== "undefined") {
|
|
57
|
+
return "tauri-sqlite";
|
|
58
|
+
}
|
|
56
59
|
if (typeof process !== "undefined" && process.versions?.node) {
|
|
57
60
|
return "better-sqlite3";
|
|
58
61
|
}
|
|
@@ -66,6 +69,11 @@ function detectAdapterType() {
|
|
|
66
69
|
}
|
|
67
70
|
async function createAdapter(type, dbName, workerUrl) {
|
|
68
71
|
switch (type) {
|
|
72
|
+
case "tauri-sqlite": {
|
|
73
|
+
const dynamicImport = new Function("specifier", "return import(specifier)");
|
|
74
|
+
const { TauriSqliteAdapter } = await dynamicImport("@korajs/tauri");
|
|
75
|
+
return new TauriSqliteAdapter({ path: `${dbName}.db` });
|
|
76
|
+
}
|
|
69
77
|
case "better-sqlite3": {
|
|
70
78
|
const { BetterSqlite3Adapter } = await import(
|
|
71
79
|
/* @vite-ignore */
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/create-app.ts","../src/adapter-resolver.ts","../src/merge-aware-sync-store.ts"],"sourcesContent":["// kora — meta-package re-exporting core, store, merge, sync\n// This is the primary entry point for `import { createApp, defineSchema, t } from 'korajs'`\n\n// === createApp factory ===\nexport { createApp } from './create-app'\n\n// === App types ===\nexport type {\n\tAdapterType,\n\tKoraApp,\n\tKoraConfig,\n\tStoreOptions,\n\tSyncControl,\n\tSyncOptions,\n\tTypedCollectionAccessor,\n\tTypedKoraApp,\n\tTypedKoraConfig,\n} from './types'\n\n// === @korajs/core re-exports ===\nexport { defineSchema, t } from '@korajs/core'\nexport { HybridLogicalClock } from '@korajs/core'\nexport { generateUUIDv7 } from '@korajs/core'\nexport { createOperation } from '@korajs/core'\nexport { KoraError } from '@korajs/core'\nexport type {\n\tCollectionDefinition,\n\tConnectionQuality,\n\tConstraint,\n\tFieldDescriptor,\n\tFieldKindToType,\n\tHLCTimestamp,\n\tInferFieldType,\n\tInferInsertInput,\n\tInferRecord,\n\tInferUpdateInput,\n\tKoraEvent,\n\tKoraEventEmitter,\n\tKoraEventListener,\n\tKoraEventType,\n\tMergeStrategy,\n\tMergeTrace,\n\tOperation,\n\tSchemaDefinition,\n\tSchemaInput,\n\tTypedSchemaDefinition,\n\tVersionVector,\n} from '@korajs/core'\n\n// === @korajs/store re-exports ===\nexport { Store } from '@korajs/store'\nexport type {\n\tCollectionAccessor,\n\tCollectionRecord,\n\tStorageAdapter,\n\tStoreConfig,\n} from '@korajs/store'\n\n// === @korajs/merge re-exports ===\nexport { MergeEngine } from '@korajs/merge'\nexport type { MergeInput, MergeResult } from '@korajs/merge'\n\n// === @korajs/sync re-exports ===\nexport { SyncEngine, WebSocketTransport } from '@korajs/sync'\nexport type {\n\tSyncConfig,\n\tSyncState,\n\tSyncStatus,\n\tSyncStatusInfo,\n\tSyncStore,\n} from '@korajs/sync'\n","import type { KoraEventEmitter, Operation, SchemaInput } from '@korajs/core'\nimport { SimpleEventEmitter } from '@korajs/core/internal'\nimport { Instrumenter } from '@korajs/devtools'\nimport { MergeEngine } from '@korajs/merge'\nimport { Store } from '@korajs/store'\nimport type { CollectionAccessor, StorageAdapter } from '@korajs/store'\nimport type { QueryBuilder } from '@korajs/store'\nimport { ConnectionMonitor, ReconnectionManager, SyncEngine, WebSocketTransport } from '@korajs/sync'\nimport type { SyncStatusInfo } from '@korajs/sync'\nimport { createAdapter, detectAdapterType } from './adapter-resolver'\nimport { MergeAwareSyncStore } from './merge-aware-sync-store'\nimport type { KoraApp, KoraConfig, SyncControl, TypedKoraApp, TypedKoraConfig } from './types'\n\n/**\n * Creates a new Kora application instance.\n *\n * Wires together store, merge engine, event emitter, and optionally sync\n * into a single developer-facing `KoraApp` object. Collection accessors\n * (e.g. `app.todos`) are defined as properties for immediate use after `await app.ready`.\n *\n * @param config - Application configuration including schema and optional sync settings\n * @returns A KoraApp instance with reactive collections ready for use\n *\n * @example\n * ```typescript\n * const app = createApp({\n * schema: defineSchema({\n * version: 1,\n * collections: {\n * todos: {\n * fields: {\n * title: t.string(),\n * completed: t.boolean().default(false)\n * }\n * }\n * }\n * })\n * })\n *\n * await app.ready\n * const todo = await app.todos.insert({ title: 'Hello' })\n * ```\n */\n/**\n * Creates a new typed Kora application instance.\n * When the schema is created with `defineSchema()`, full type inference flows through\n * to collection accessors, providing autocomplete and type checking for all CRUD operations.\n */\nexport function createApp<const S extends SchemaInput>(config: TypedKoraConfig<S>): TypedKoraApp<S>\n/**\n * Creates a new Kora application instance (untyped fallback).\n */\nexport function createApp(config: KoraConfig): KoraApp\nexport function createApp(config: KoraConfig): KoraApp {\n\tconst emitter: KoraEventEmitter & { clear(): void } = new SimpleEventEmitter()\n\tconst mergeEngine = new MergeEngine()\n\n\tlet store: Store | null = null\n\tlet syncEngine: SyncEngine | null = null\n\tlet unsubscribeSync: (() => void) | null = null\n\tlet reconnectionManager: ReconnectionManager | null = null\n\tlet connectionMonitor: ConnectionMonitor | null = null\n\tlet instrumenter: Instrumenter | null = null\n\tlet intentionalDisconnect = false\n\tlet qualityInterval: ReturnType<typeof setInterval> | null = null\n\n\t// Wire DevTools instrumentation immediately (emitter exists synchronously)\n\tif (config.devtools) {\n\t\tinstrumenter = new Instrumenter(emitter, {\n\t\t\tbridgeEnabled: typeof globalThis !== 'undefined' && 'window' in globalThis,\n\t\t})\n\t}\n\n\t// Build the ready promise — resolves when the store is open and wired\n\tconst ready = initializeAsync(config, emitter, mergeEngine).then((result) => {\n\t\tstore = result.store\n\t\tsyncEngine = result.syncEngine\n\t\tunsubscribeSync = result.unsubscribeSync\n\n\t\t// Wire reconnection and connection quality after sync engine is ready\n\t\tif (config.sync && syncEngine) {\n\t\t\tconnectionMonitor = new ConnectionMonitor()\n\t\t\treconnectionManager = new ReconnectionManager({\n\t\t\t\tinitialDelay: config.sync.reconnectInterval,\n\t\t\t\tmaxDelay: config.sync.maxReconnectInterval,\n\t\t\t})\n\n\t\t\t// Track activity for connection quality\n\t\t\temitter.on('sync:sent', () => connectionMonitor?.recordActivity())\n\t\t\temitter.on('sync:received', () => connectionMonitor?.recordActivity())\n\t\t\temitter.on('sync:acknowledged', () => connectionMonitor?.recordActivity())\n\n\t\t\t// Emit quality on timer while connected\n\t\t\temitter.on('sync:connected', () => {\n\t\t\t\tif (qualityInterval !== null) clearInterval(qualityInterval)\n\t\t\t\tqualityInterval = setInterval(() => {\n\t\t\t\t\tif (connectionMonitor) {\n\t\t\t\t\t\temitter.emit({ type: 'connection:quality', quality: connectionMonitor.getQuality() })\n\t\t\t\t\t}\n\t\t\t\t}, 5000)\n\t\t\t})\n\n\t\t\t// Reset monitor and clear timer on disconnect\n\t\t\temitter.on('sync:disconnected', () => {\n\t\t\t\tconnectionMonitor?.reset()\n\t\t\t\tif (qualityInterval !== null) {\n\t\t\t\t\tclearInterval(qualityInterval)\n\t\t\t\t\tqualityInterval = null\n\t\t\t\t}\n\t\t\t})\n\n\t\t\t// Auto-reconnect on unexpected disconnect\n\t\t\tif (config.sync.autoReconnect !== false) {\n\t\t\t\tconst engine = syncEngine\n\t\t\t\temitter.on('sync:disconnected', () => {\n\t\t\t\t\tif (intentionalDisconnect) return\n\t\t\t\t\t// Ignore cascading disconnect events from failed reconnection attempts.\n\t\t\t\t\t// The reconnection manager is already retrying — don't restart it.\n\t\t\t\t\tif (reconnectionManager?.isRunning()) return\n\n\t\t\t\t\tengine.setReconnecting(true)\n\t\t\t\t\treconnectionManager?.stop()\n\t\t\t\t\treconnectionManager?.start(async () => {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tawait engine.start()\n\t\t\t\t\t\t\tengine.setReconnecting(false)\n\t\t\t\t\t\t\treturn true\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\treturn false\n\t\t\t\t\t\t}\n\t\t\t\t\t}).then(() => {\n\t\t\t\t\t\t// If reconnection exhausted max attempts without success, clear flag\n\t\t\t\t\t\tengine.setReconnecting(false)\n\t\t\t\t\t})\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\t})\n\n\t// Build sync control\n\tconst syncControl: SyncControl | null = config.sync\n\t\t? {\n\t\t\t\tasync connect(): Promise<void> {\n\t\t\t\t\tawait ready\n\t\t\t\t\tif (syncEngine) {\n\t\t\t\t\t\tintentionalDisconnect = false\n\t\t\t\t\t\treconnectionManager?.stop()\n\t\t\t\t\t\treconnectionManager?.reset()\n\t\t\t\t\t\tawait syncEngine.start()\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tasync disconnect(): Promise<void> {\n\t\t\t\t\tawait ready\n\t\t\t\t\tif (syncEngine) {\n\t\t\t\t\t\tintentionalDisconnect = true\n\t\t\t\t\t\treconnectionManager?.stop()\n\t\t\t\t\t\tawait syncEngine.stop()\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tgetStatus(): SyncStatusInfo {\n\t\t\t\t\tif (syncEngine) {\n\t\t\t\t\t\treturn syncEngine.getStatus()\n\t\t\t\t\t}\n\t\t\t\t\treturn { status: 'offline', pendingOperations: 0, lastSyncedAt: null }\n\t\t\t\t},\n\t\t\t}\n\t\t: null\n\n\t// Build the KoraApp object\n\tconst app: KoraApp = {\n\t\tready,\n\t\tevents: emitter,\n\t\tsync: syncControl,\n\t\tgetStore(): Store {\n\t\t\tif (!store) {\n\t\t\t\tthrow new Error('Store not initialized. Await app.ready before accessing the store.')\n\t\t\t}\n\t\t\treturn store\n\t\t},\n\t\tgetSyncEngine(): SyncEngine | null {\n\t\t\treturn syncEngine\n\t\t},\n\t\tasync close(): Promise<void> {\n\t\t\tawait ready\n\t\t\tintentionalDisconnect = true\n\t\t\tif (qualityInterval !== null) {\n\t\t\t\tclearInterval(qualityInterval)\n\t\t\t\tqualityInterval = null\n\t\t\t}\n\t\t\treconnectionManager?.stop()\n\t\t\tif (instrumenter) {\n\t\t\t\tinstrumenter.destroy()\n\t\t\t\tinstrumenter = null\n\t\t\t}\n\t\t\tif (unsubscribeSync) {\n\t\t\t\tunsubscribeSync()\n\t\t\t\tunsubscribeSync = null\n\t\t\t}\n\t\t\tif (syncEngine) {\n\t\t\t\tawait syncEngine.stop()\n\t\t\t\tsyncEngine = null\n\t\t\t}\n\t\t\tif (store) {\n\t\t\t\tawait store.close()\n\t\t\t\tstore = null\n\t\t\t}\n\t\t\temitter.clear()\n\t\t},\n\t}\n\n\t// Define collection accessors via Object.defineProperty.\n\t// Before ready resolves, query methods return empty results.\n\tfor (const collectionName of Object.keys(config.schema.collections)) {\n\t\tObject.defineProperty(app, collectionName, {\n\t\t\tget(): CollectionAccessor {\n\t\t\t\treturn createCollectionAccessor(collectionName, () => store)\n\t\t\t},\n\t\t\tenumerable: true,\n\t\t\tconfigurable: false,\n\t\t})\n\t}\n\n\treturn app\n}\n\n/**\n * Asynchronous initialization: create adapter, open store, wire sync.\n */\nasync function initializeAsync(\n\tconfig: KoraConfig,\n\temitter: KoraEventEmitter,\n\tmergeEngine: MergeEngine,\n): Promise<{\n\tstore: Store\n\tsyncEngine: SyncEngine | null\n\tunsubscribeSync: (() => void) | null\n}> {\n\t// Resolve adapter\n\tconst adapterType = config.store?.adapter ?? detectAdapterType()\n\tconst dbName = config.store?.name ?? 'kora-db'\n\tconst adapter: StorageAdapter = await createAdapter(adapterType, dbName, config.store?.workerUrl)\n\n\t// Create and open the store\n\tconst store = new Store({\n\t\tschema: config.schema,\n\t\tadapter,\n\t\temitter,\n\t})\n\tawait store.open()\n\n\t// Wire sync if configured\n\tlet syncEngine: SyncEngine | null = null\n\tlet unsubscribeSync: (() => void) | null = null\n\n\tif (config.sync) {\n\t\tconst transport = new WebSocketTransport()\n\t\tconst mergeAwareStore = new MergeAwareSyncStore(store, mergeEngine, emitter)\n\n\t\tsyncEngine = new SyncEngine({\n\t\t\ttransport,\n\t\t\tstore: mergeAwareStore,\n\t\t\tconfig: {\n\t\t\t\turl: config.sync.url,\n\t\t\t\ttransport: config.sync.transport,\n\t\t\t\tauth: config.sync.auth,\n\t\t\t\tbatchSize: config.sync.batchSize,\n\t\t\t\tschemaVersion: config.sync.schemaVersion ?? config.schema.version,\n\t\t\t},\n\t\t\temitter,\n\t\t})\n\n\t\t// Wire local mutations → sync outbound queue\n\t\tunsubscribeSync = emitter.on('operation:created', (event) => {\n\t\t\tif (syncEngine) {\n\t\t\t\tsyncEngine.pushOperation(event.operation)\n\t\t\t}\n\t\t})\n\t}\n\n\treturn { store, syncEngine, unsubscribeSync }\n}\n\nfunction createCollectionAccessor(\n\tcollectionName: string,\n\tgetStore: () => Store | null,\n): CollectionAccessor {\n\treturn {\n\t\tasync insert(data: Record<string, unknown>) {\n\t\t\tconst currentStore = getStore()\n\t\t\tif (!currentStore) {\n\t\t\t\tthrow new Error(`Cannot mutate collection \"${collectionName}\" before app.ready resolves.`)\n\t\t\t}\n\t\t\treturn currentStore.collection(collectionName).insert(data)\n\t\t},\n\t\tasync findById(id: string) {\n\t\t\tconst currentStore = getStore()\n\t\t\tif (!currentStore) return null\n\t\t\treturn currentStore.collection(collectionName).findById(id)\n\t\t},\n\t\tasync update(id: string, data: Record<string, unknown>) {\n\t\t\tconst currentStore = getStore()\n\t\t\tif (!currentStore) {\n\t\t\t\tthrow new Error(`Cannot mutate collection \"${collectionName}\" before app.ready resolves.`)\n\t\t\t}\n\t\t\treturn currentStore.collection(collectionName).update(id, data)\n\t\t},\n\t\tasync delete(id: string) {\n\t\t\tconst currentStore = getStore()\n\t\t\tif (!currentStore) {\n\t\t\t\tthrow new Error(`Cannot mutate collection \"${collectionName}\" before app.ready resolves.`)\n\t\t\t}\n\t\t\treturn currentStore.collection(collectionName).delete(id)\n\t\t},\n\t\twhere(conditions: Record<string, unknown>) {\n\t\t\tconst currentStore = getStore()\n\t\t\tif (!currentStore) {\n\t\t\t\treturn createPendingQueryBuilder(conditions)\n\t\t\t}\n\t\t\treturn currentStore.collection(collectionName).where(conditions)\n\t\t},\n\t}\n}\n\nfunction createPendingQueryBuilder(initialWhere: Record<string, unknown>): QueryBuilder {\n\tconst descriptor = {\n\t\tcollection: '__pending__',\n\t\twhere: { ...initialWhere },\n\t\torderBy: [] as Array<{ field: string; direction: 'asc' | 'desc' }>,\n\t\tlimit: undefined as number | undefined,\n\t\toffset: undefined as number | undefined,\n\t}\n\n\tconst builder = {\n\t\twhere(conditions: Record<string, unknown>) {\n\t\t\tdescriptor.where = { ...descriptor.where, ...conditions }\n\t\t\treturn this\n\t\t},\n\t\torderBy(field: string, direction: 'asc' | 'desc' = 'asc') {\n\t\t\tdescriptor.orderBy.push({ field, direction })\n\t\t\treturn this\n\t\t},\n\t\tlimit(n: number) {\n\t\t\tdescriptor.limit = n\n\t\t\treturn this\n\t\t},\n\t\toffset(n: number) {\n\t\t\tdescriptor.offset = n\n\t\t\treturn this\n\t\t},\n\t\tasync exec() {\n\t\t\treturn []\n\t\t},\n\t\tasync count() {\n\t\t\treturn 0\n\t\t},\n\t\tsubscribe(callback: (results: Array<Record<string, unknown>>) => void) {\n\t\t\tvoid callback([])\n\t\t\treturn () => {}\n\t\t},\n\t\tgetDescriptor() {\n\t\t\treturn { ...descriptor, where: { ...descriptor.where }, orderBy: [...descriptor.orderBy] }\n\t\t},\n\t}\n\n\treturn builder as unknown as QueryBuilder\n}\n","import type { StorageAdapter } from '@korajs/store'\nimport type { AdapterType } from './types'\n\n/**\n * Detect the best storage adapter for the current environment.\n *\n * - Node.js: 'better-sqlite3'\n * - Browser with OPFS: 'sqlite-wasm'\n * - Browser without OPFS: 'indexeddb'\n */\nexport function detectAdapterType(): AdapterType {\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 '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;;;ACGhF,SAAS,oBAAiC;AAEhD,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,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;;;AC/CO,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\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// Use Function-based import to prevent bundlers (Vite/Rollup/webpack)\n\t\t\t// from resolving @korajs/tauri at build time. This package is only\n\t\t\t// available in Tauri environments and must not be bundled for web.\n\t\t\tconst dynamicImport = new Function('specifier', 'return import(specifier)') as (\n\t\t\t\ts: string,\n\t\t\t) => Promise<{ TauriSqliteAdapter: new (opts: { path: string }) => StorageAdapter }>\n\t\t\tconst { TauriSqliteAdapter } = await dynamicImport('@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":["import_core","import_store","import_merge","import_sync"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -12,8 +12,9 @@ export { MergeEngine, MergeInput, MergeResult } from '@korajs/merge';
|
|
|
12
12
|
* - 'sqlite-wasm': SQLite WASM with OPFS (browser, primary)
|
|
13
13
|
* - 'indexeddb': IndexedDB fallback (browser, when OPFS unavailable)
|
|
14
14
|
* - 'better-sqlite3': Native SQLite (Node.js, server-side, Electron)
|
|
15
|
+
* - 'tauri-sqlite': Native SQLite via Tauri plugin (Tauri desktop/mobile apps)
|
|
15
16
|
*/
|
|
16
|
-
type AdapterType = 'sqlite-wasm' | 'indexeddb' | 'better-sqlite3';
|
|
17
|
+
type AdapterType = 'sqlite-wasm' | 'indexeddb' | 'better-sqlite3' | 'tauri-sqlite';
|
|
17
18
|
/**
|
|
18
19
|
* Store configuration within createApp.
|
|
19
20
|
*/
|
package/dist/index.d.ts
CHANGED
|
@@ -12,8 +12,9 @@ export { MergeEngine, MergeInput, MergeResult } from '@korajs/merge';
|
|
|
12
12
|
* - 'sqlite-wasm': SQLite WASM with OPFS (browser, primary)
|
|
13
13
|
* - 'indexeddb': IndexedDB fallback (browser, when OPFS unavailable)
|
|
14
14
|
* - 'better-sqlite3': Native SQLite (Node.js, server-side, Electron)
|
|
15
|
+
* - 'tauri-sqlite': Native SQLite via Tauri plugin (Tauri desktop/mobile apps)
|
|
15
16
|
*/
|
|
16
|
-
type AdapterType = 'sqlite-wasm' | 'indexeddb' | 'better-sqlite3';
|
|
17
|
+
type AdapterType = 'sqlite-wasm' | 'indexeddb' | 'better-sqlite3' | 'tauri-sqlite';
|
|
17
18
|
/**
|
|
18
19
|
* Store configuration within createApp.
|
|
19
20
|
*/
|
package/dist/index.js
CHANGED
|
@@ -7,6 +7,9 @@ import { ConnectionMonitor, ReconnectionManager, SyncEngine, WebSocketTransport
|
|
|
7
7
|
|
|
8
8
|
// src/adapter-resolver.ts
|
|
9
9
|
function detectAdapterType() {
|
|
10
|
+
if (typeof globalThis !== "undefined" && typeof globalThis.__TAURI_INTERNALS__ !== "undefined") {
|
|
11
|
+
return "tauri-sqlite";
|
|
12
|
+
}
|
|
10
13
|
if (typeof process !== "undefined" && process.versions?.node) {
|
|
11
14
|
return "better-sqlite3";
|
|
12
15
|
}
|
|
@@ -20,6 +23,11 @@ function detectAdapterType() {
|
|
|
20
23
|
}
|
|
21
24
|
async function createAdapter(type, dbName, workerUrl) {
|
|
22
25
|
switch (type) {
|
|
26
|
+
case "tauri-sqlite": {
|
|
27
|
+
const dynamicImport = new Function("specifier", "return import(specifier)");
|
|
28
|
+
const { TauriSqliteAdapter } = await dynamicImport("@korajs/tauri");
|
|
29
|
+
return new TauriSqliteAdapter({ path: `${dbName}.db` });
|
|
30
|
+
}
|
|
23
31
|
case "better-sqlite3": {
|
|
24
32
|
const { BetterSqlite3Adapter } = await import(
|
|
25
33
|
/* @vite-ignore */
|
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 * - Node.js: 'better-sqlite3'\n * - Browser with OPFS: 'sqlite-wasm'\n * - Browser without OPFS: 'indexeddb'\n */\nexport function detectAdapterType(): AdapterType {\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 '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 { 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// Use Function-based import to prevent bundlers (Vite/Rollup/webpack)\n\t\t\t// from resolving @korajs/tauri at build time. This package is only\n\t\t\t// available in Tauri environments and must not be bundled for web.\n\t\t\tconst dynamicImport = new Function('specifier', 'return import(specifier)') as (\n\t\t\t\ts: string,\n\t\t\t) => Promise<{ TauriSqliteAdapter: new (opts: { path: string }) => StorageAdapter }>\n\t\t\tconst { TauriSqliteAdapter } = await dynamicImport('@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\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"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "korajs",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.2",
|
|
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.
|
|
36
|
-
"@korajs/store": "0.3.
|
|
37
|
-
"@korajs/merge": "0.3.
|
|
38
|
-
"@korajs/sync": "0.3.
|
|
39
|
-
"@korajs/devtools": "0.3.
|
|
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"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"@types/better-sqlite3": "^7.6.13",
|