@korajs/store 0.3.1 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/store/store.ts","../src/collection/collection.ts","../src/query/sql-builder.ts","../src/serialization/serializer.ts","../src/serialization/richtext-serializer.ts","../src/query/pluralize.ts","../src/query/query-builder.ts","../src/subscription/subscription-manager.ts"],"sourcesContent":["import { HybridLogicalClock, createVersionVector, generateUUIDv7 } from '@korajs/core'\nimport type {\n\tKoraEventEmitter,\n\tOperation,\n\tOperationLog,\n\tSchemaDefinition,\n\tVersionVector,\n} from '@korajs/core'\nimport { Collection } from '../collection/collection'\nimport { StoreNotOpenError } from '../errors'\nimport { QueryBuilder } from '../query/query-builder'\nimport { buildInsertQuery, buildSoftDeleteQuery, buildUpdateQuery } from '../query/sql-builder'\nimport {\n\tdeserializeOperationWithCollection,\n\tserializeOperation,\n\tserializeRecord,\n} from '../serialization/serializer'\nimport { SubscriptionManager } from '../subscription/subscription-manager'\nimport type {\n\tApplyResult,\n\tMetaRow,\n\tOperationRow,\n\tRawCollectionRow,\n\tStorageAdapter,\n\tStoreConfig,\n\tVersionVectorRow,\n} from '../types'\n\n/**\n * Store is the main orchestrator. It owns a schema, a storage adapter,\n * a clock, and a subscription manager. It creates Collection instances\n * for each schema collection, and provides the sync contract via\n * applyRemoteOperation and getOperationRange.\n *\n * @example\n * ```typescript\n * const store = new Store({ schema, adapter })\n * await store.open()\n * const todo = await store.collection('todos').insert({ title: 'Hello' })\n * await store.close()\n * ```\n */\nexport class Store implements OperationLog {\n\tprivate opened = false\n\tprivate nodeId = ''\n\tprivate sequenceNumber = 0\n\tprivate versionVector: VersionVector = createVersionVector()\n\tprivate clock: HybridLogicalClock | null = null\n\tprivate collections = new Map<string, Collection>()\n\tprivate subscriptionManager = new SubscriptionManager()\n\n\tprivate readonly schema: SchemaDefinition\n\tprivate readonly adapter: StorageAdapter\n\tprivate readonly configNodeId: string | undefined\n\tprivate readonly emitter: KoraEventEmitter | null\n\n\tconstructor(config: StoreConfig) {\n\t\tthis.schema = config.schema\n\t\tthis.adapter = config.adapter\n\t\tthis.configNodeId = config.nodeId\n\t\tthis.emitter = config.emitter ?? null\n\t}\n\n\t/**\n\t * Open the store: initialize the database, load or generate a node ID,\n\t * restore the sequence number and version vector, and create Collection instances.\n\t */\n\tasync open(): Promise<void> {\n\t\tawait this.adapter.open(this.schema)\n\n\t\t// Load or generate node ID\n\t\tthis.nodeId = await this.loadOrGenerateNodeId()\n\t\tthis.clock = new HybridLogicalClock(this.nodeId)\n\n\t\t// Load sequence number and version vector\n\t\tthis.sequenceNumber = await this.loadSequenceNumber()\n\t\tthis.versionVector = await this.loadVersionVector()\n\n\t\t// Create collection instances\n\t\tfor (const [name, definition] of Object.entries(this.schema.collections)) {\n\t\t\tconst col = new Collection(\n\t\t\t\tname,\n\t\t\t\tdefinition,\n\t\t\t\tthis.schema,\n\t\t\t\tthis.adapter,\n\t\t\t\tthis.clock,\n\t\t\t\tthis.nodeId,\n\t\t\t\t() => this.nextSequenceNumber(),\n\t\t\t\t(collectionName, operation) => {\n\t\t\t\t\tthis.subscriptionManager.notify(collectionName, operation)\n\t\t\t\t\tif (this.emitter) {\n\t\t\t\t\t\tthis.emitter.emit({ type: 'operation:created', operation })\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t)\n\t\t\tthis.collections.set(name, col)\n\t\t}\n\n\t\tthis.opened = true\n\t}\n\n\t/**\n\t * Close the store: clear subscriptions and close the adapter.\n\t */\n\tasync close(): Promise<void> {\n\t\tthis.subscriptionManager.clear()\n\t\tthis.collections.clear()\n\t\tthis.opened = false\n\t\tawait this.adapter.close()\n\t}\n\n\t/**\n\t * Get a Collection instance for CRUD operations.\n\t * @throws {StoreNotOpenError} If the store is not open\n\t * @throws {Error} If the collection name is not in the schema\n\t */\n\tcollection(name: string): CollectionAccessor {\n\t\tthis.ensureOpen()\n\t\tconst col = this.collections.get(name)\n\t\tif (!col) {\n\t\t\tthrow new Error(\n\t\t\t\t`Unknown collection \"${name}\". Available: ${[...this.collections.keys()].join(', ')}`,\n\t\t\t)\n\t\t}\n\n\t\tconst definition = this.schema.collections[name]\n\t\tif (!definition) {\n\t\t\tthrow new Error(`Collection definition not found for \"${name}\"`)\n\t\t}\n\n\t\treturn {\n\t\t\tinsert: (data: Record<string, unknown>) => col.insert(data),\n\t\t\tfindById: (id: string) => col.findById(id),\n\t\t\tupdate: (id: string, data: Record<string, unknown>) => col.update(id, data),\n\t\t\tdelete: (id: string) => col.delete(id),\n\t\t\twhere: (conditions) =>\n\t\t\t\tnew QueryBuilder(name, definition, this.adapter, this.subscriptionManager, conditions, this.schema),\n\t\t}\n\t}\n\n\t/**\n\t * Get the current version vector.\n\t */\n\tgetVersionVector(): VersionVector {\n\t\tthis.ensureOpen()\n\t\treturn new Map(this.versionVector)\n\t}\n\n\t/**\n\t * Get the node ID for this store instance.\n\t */\n\tgetNodeId(): string {\n\t\tthis.ensureOpen()\n\t\treturn this.nodeId\n\t}\n\n\t/**\n\t * Apply a remote operation received from sync.\n\t * Checks for duplicates, applies to the data table, persists the operation,\n\t * and updates the version vector.\n\t */\n\tasync applyRemoteOperation(op: Operation): Promise<ApplyResult> {\n\t\tthis.ensureOpen()\n\n\t\tconst collection = op.collection\n\t\tconst definition = this.schema.collections[collection]\n\t\tif (!definition) {\n\t\t\treturn 'skipped'\n\t\t}\n\n\t\t// Check for duplicate (content-addressed dedup)\n\t\tconst existing = await this.adapter.query<{ id: string }>(\n\t\t\t`SELECT id FROM _kora_ops_${collection} WHERE id = ?`,\n\t\t\t[op.id],\n\t\t)\n\t\tif (existing.length > 0) {\n\t\t\treturn 'duplicate'\n\t\t}\n\n\t\t// Update the clock with the remote timestamp\n\t\tif (this.clock) {\n\t\t\tthis.clock.receive(op.timestamp)\n\t\t}\n\n\t\t// Apply the operation to the data table\n\t\tawait this.adapter.transaction(async (tx) => {\n\t\t\tif (op.type === 'insert' && op.data) {\n\t\t\t\tconst serializedData = serializeRecord(op.data, definition.fields)\n\t\t\t\tconst now = op.timestamp.wallTime\n\t\t\t\tconst record: Record<string, unknown> = {\n\t\t\t\t\tid: op.recordId,\n\t\t\t\t\t...serializedData,\n\t\t\t\t\t_created_at: now,\n\t\t\t\t\t_updated_at: now,\n\t\t\t\t}\n\t\t\t\tconst insertQuery = buildInsertQuery(collection, record)\n\t\t\t\tawait tx.execute(insertQuery.sql, insertQuery.params)\n\t\t\t} else if (op.type === 'update' && op.data) {\n\t\t\t\tconst serializedChanges = serializeRecord(op.data, definition.fields)\n\t\t\t\tconst updateQuery = buildUpdateQuery(collection, op.recordId, {\n\t\t\t\t\t...serializedChanges,\n\t\t\t\t\t_updated_at: op.timestamp.wallTime,\n\t\t\t\t})\n\t\t\t\tawait tx.execute(updateQuery.sql, updateQuery.params)\n\t\t\t} else if (op.type === 'delete') {\n\t\t\t\tconst deleteQuery = buildSoftDeleteQuery(collection, op.recordId, op.timestamp.wallTime)\n\t\t\t\tawait tx.execute(deleteQuery.sql, deleteQuery.params)\n\t\t\t}\n\n\t\t\t// Persist the operation\n\t\t\tconst opRow = serializeOperation(op)\n\t\t\tconst opInsert = buildInsertQuery(\n\t\t\t\t`_kora_ops_${collection}`,\n\t\t\t\topRow as unknown as Record<string, unknown>,\n\t\t\t)\n\t\t\tawait tx.execute(opInsert.sql, opInsert.params)\n\n\t\t\t// Update version vector\n\t\t\tconst currentSeq = this.versionVector.get(op.nodeId) ?? 0\n\t\t\tif (op.sequenceNumber > currentSeq) {\n\t\t\t\tthis.versionVector.set(op.nodeId, op.sequenceNumber)\n\t\t\t\tawait tx.execute(\n\t\t\t\t\t'INSERT OR REPLACE INTO _kora_version_vector (node_id, sequence_number) VALUES (?, ?)',\n\t\t\t\t\t[op.nodeId, op.sequenceNumber],\n\t\t\t\t)\n\t\t\t}\n\t\t})\n\n\t\t// Notify subscriptions\n\t\tthis.subscriptionManager.notify(collection, op)\n\n\t\treturn 'applied'\n\t}\n\n\t/**\n\t * Get operations from a node within a sequence number range.\n\t * Implements the OperationLog interface for computeDelta.\n\t */\n\tgetRange(nodeId: string, fromSeq: number, toSeq: number): Operation[] {\n\t\t// This is synchronous per the OperationLog interface.\n\t\t// We can't use async here, so this must be called with data already loaded.\n\t\t// For now, this is a placeholder that the sync layer will call after awaiting.\n\t\treturn []\n\t}\n\n\t/**\n\t * Async version of getRange for use by the sync layer.\n\t */\n\tasync getOperationRange(nodeId: string, fromSeq: number, toSeq: number): Promise<Operation[]> {\n\t\tthis.ensureOpen()\n\t\tconst allOps: Operation[] = []\n\n\t\tfor (const collectionName of Object.keys(this.schema.collections)) {\n\t\t\tconst rows = await this.adapter.query<OperationRow>(\n\t\t\t\t`SELECT * FROM _kora_ops_${collectionName} WHERE node_id = ? AND sequence_number >= ? AND sequence_number <= ? ORDER BY sequence_number ASC`,\n\t\t\t\t[nodeId, fromSeq, toSeq],\n\t\t\t)\n\t\t\tfor (const row of rows) {\n\t\t\t\tallOps.push(deserializeOperationWithCollection(row, collectionName))\n\t\t\t}\n\t\t}\n\n\t\t// Sort by sequence number across collections\n\t\tallOps.sort((a, b) => a.sequenceNumber - b.sequenceNumber)\n\t\treturn allOps\n\t}\n\n\t/**\n\t * Get the schema definition.\n\t */\n\tgetSchema(): SchemaDefinition {\n\t\treturn this.schema\n\t}\n\n\t/** Expose the subscription manager for direct access (e.g., by QueryBuilder) */\n\tgetSubscriptionManager(): SubscriptionManager {\n\t\treturn this.subscriptionManager\n\t}\n\n\tprivate nextSequenceNumber(): number {\n\t\tthis.sequenceNumber++\n\t\tthis.versionVector.set(this.nodeId, this.sequenceNumber)\n\t\treturn this.sequenceNumber\n\t}\n\n\tprivate async loadOrGenerateNodeId(): Promise<string> {\n\t\tif (this.configNodeId) {\n\t\t\t// Persist the configured node ID\n\t\t\tawait this.adapter.execute(\n\t\t\t\t\"INSERT OR REPLACE INTO _kora_meta (key, value) VALUES ('node_id', ?)\",\n\t\t\t\t[this.configNodeId],\n\t\t\t)\n\t\t\treturn this.configNodeId\n\t\t}\n\n\t\t// Try to load existing node ID\n\t\tconst rows = await this.adapter.query<MetaRow>(\n\t\t\t\"SELECT value FROM _kora_meta WHERE key = 'node_id'\",\n\t\t)\n\t\tif (rows[0]) {\n\t\t\treturn rows[0].value\n\t\t}\n\n\t\t// Generate new node ID\n\t\tconst newNodeId = generateUUIDv7()\n\t\tawait this.adapter.execute(\"INSERT INTO _kora_meta (key, value) VALUES ('node_id', ?)\", [\n\t\t\tnewNodeId,\n\t\t])\n\t\treturn newNodeId\n\t}\n\n\tprivate async loadSequenceNumber(): Promise<number> {\n\t\tconst rows = await this.adapter.query<VersionVectorRow>(\n\t\t\t'SELECT sequence_number FROM _kora_version_vector WHERE node_id = ?',\n\t\t\t[this.nodeId],\n\t\t)\n\t\treturn rows[0]?.sequence_number ?? 0\n\t}\n\n\tprivate async loadVersionVector(): Promise<VersionVector> {\n\t\tconst rows = await this.adapter.query<VersionVectorRow>(\n\t\t\t'SELECT node_id, sequence_number FROM _kora_version_vector',\n\t\t)\n\t\tconst vector = createVersionVector()\n\t\tfor (const row of rows) {\n\t\t\tvector.set(row.node_id, row.sequence_number)\n\t\t}\n\t\treturn vector\n\t}\n\n\tprivate ensureOpen(): void {\n\t\tif (!this.opened) {\n\t\t\tthrow new StoreNotOpenError()\n\t\t}\n\t}\n}\n\n/**\n * Public-facing collection accessor. Provides CRUD + where.\n */\nexport interface CollectionAccessor {\n\tinsert(data: Record<string, unknown>): Promise<import('../types').CollectionRecord>\n\tfindById(id: string): Promise<import('../types').CollectionRecord | null>\n\tupdate(id: string, data: Record<string, unknown>): Promise<import('../types').CollectionRecord>\n\tdelete(id: string): Promise<void>\n\twhere(conditions: Record<string, unknown>): QueryBuilder\n}\n","import type {\n\tCollectionDefinition,\n\tHLCTimestamp,\n\tHybridLogicalClock,\n\tOperation,\n\tSchemaDefinition,\n} from '@korajs/core'\nimport { createOperation, generateUUIDv7, validateRecord } from '@korajs/core'\nimport { RecordNotFoundError } from '../errors'\nimport { buildInsertQuery, buildSoftDeleteQuery, buildUpdateQuery } from '../query/sql-builder'\nimport { deserializeRecord, serializeOperation, serializeRecord } from '../serialization/serializer'\nimport type { CollectionRecord, RawCollectionRow, StorageAdapter } from '../types'\n\n/**\n * Callback invoked after a mutation so the Store can notify subscriptions.\n */\nexport type MutationCallback = (collection: string, operation: Operation) => void\n\n/**\n * Collection provides CRUD operations on a single schema collection.\n * Each mutation creates an Operation and persists both the data and the operation atomically.\n */\nexport class Collection {\n\tconstructor(\n\t\tprivate readonly name: string,\n\t\tprivate readonly definition: CollectionDefinition,\n\t\tprivate readonly schema: SchemaDefinition,\n\t\tprivate readonly adapter: StorageAdapter,\n\t\tprivate readonly clock: HybridLogicalClock,\n\t\tprivate readonly nodeId: string,\n\t\tprivate readonly getSequenceNumber: () => number,\n\t\tprivate readonly onMutation: MutationCallback,\n\t) {}\n\n\t/**\n\t * Insert a new record into the collection.\n\t * Generates a UUID v7 for the id, validates data, and persists atomically.\n\t *\n\t * @param data - The record data (auto fields and defaults are applied automatically)\n\t * @returns The inserted record with id, createdAt, updatedAt\n\t */\n\tasync insert(data: Record<string, unknown>): Promise<CollectionRecord> {\n\t\tconst validated = validateRecord(this.name, this.definition, data, 'insert')\n\t\tconst recordId = generateUUIDv7()\n\t\tconst now = Date.now()\n\n\t\t// Set auto timestamp fields\n\t\tfor (const [fieldName, descriptor] of Object.entries(this.definition.fields)) {\n\t\t\tif (descriptor.auto && descriptor.kind === 'timestamp') {\n\t\t\t\tvalidated[fieldName] = now\n\t\t\t}\n\t\t}\n\n\t\tconst sequenceNumber = this.getSequenceNumber()\n\t\tconst operation = await createOperation(\n\t\t\t{\n\t\t\t\tnodeId: this.nodeId,\n\t\t\t\ttype: 'insert',\n\t\t\t\tcollection: this.name,\n\t\t\t\trecordId,\n\t\t\t\tdata: { ...validated },\n\t\t\t\tpreviousData: null,\n\t\t\t\tsequenceNumber,\n\t\t\t\tcausalDeps: [],\n\t\t\t\tschemaVersion: this.schema.version,\n\t\t\t},\n\t\t\tthis.clock,\n\t\t)\n\n\t\tconst serializedData = serializeRecord(validated, this.definition.fields)\n\t\tconst record: Record<string, unknown> = {\n\t\t\tid: recordId,\n\t\t\t...serializedData,\n\t\t\t_created_at: now,\n\t\t\t_updated_at: now,\n\t\t}\n\n\t\tconst insertQuery = buildInsertQuery(this.name, record)\n\t\tconst opRow = serializeOperation(operation)\n\t\tconst opInsert = buildInsertQuery(\n\t\t\t`_kora_ops_${this.name}`,\n\t\t\topRow as unknown as Record<string, unknown>,\n\t\t)\n\n\t\tawait this.adapter.transaction(async (tx) => {\n\t\t\tawait tx.execute(insertQuery.sql, insertQuery.params)\n\t\t\tawait tx.execute(opInsert.sql, opInsert.params)\n\t\t\tawait tx.execute(\n\t\t\t\t'INSERT OR REPLACE INTO _kora_version_vector (node_id, sequence_number) VALUES (?, ?)',\n\t\t\t\t[this.nodeId, sequenceNumber],\n\t\t\t)\n\t\t})\n\n\t\tthis.onMutation(this.name, operation)\n\n\t\treturn {\n\t\t\tid: recordId,\n\t\t\t...validated,\n\t\t\tcreatedAt: now,\n\t\t\tupdatedAt: now,\n\t\t}\n\t}\n\n\t/**\n\t * Find a record by its ID. Returns null if not found or soft-deleted.\n\t */\n\tasync findById(id: string): Promise<CollectionRecord | null> {\n\t\tconst rows = await this.adapter.query<RawCollectionRow>(\n\t\t\t`SELECT * FROM ${this.name} WHERE id = ? AND _deleted = 0`,\n\t\t\t[id],\n\t\t)\n\n\t\tconst row = rows[0]\n\t\tif (!row) return null\n\t\treturn deserializeRecord(row, this.definition.fields)\n\t}\n\n\t/**\n\t * Update an existing record. Only the provided fields are changed.\n\t *\n\t * @param id - The record ID to update\n\t * @param data - Partial data with only the fields to change\n\t * @returns The updated record\n\t * @throws {RecordNotFoundError} If the record doesn't exist or is deleted\n\t */\n\tasync update(id: string, data: Record<string, unknown>): Promise<CollectionRecord> {\n\t\tconst currentRows = await this.adapter.query<RawCollectionRow>(\n\t\t\t`SELECT * FROM ${this.name} WHERE id = ? AND _deleted = 0`,\n\t\t\t[id],\n\t\t)\n\t\tconst currentRow = currentRows[0]\n\t\tif (!currentRow) {\n\t\t\tthrow new RecordNotFoundError(this.name, id)\n\t\t}\n\n\t\tconst validated = validateRecord(this.name, this.definition, data, 'update')\n\t\tconst now = Date.now()\n\n\t\t// Build previousData from current row for the changed fields\n\t\tconst previousData: Record<string, unknown> = {}\n\t\tconst currentRecord = deserializeRecord(currentRow, this.definition.fields)\n\t\tfor (const key of Object.keys(validated)) {\n\t\t\tpreviousData[key] = currentRecord[key]\n\t\t}\n\n\t\tconst sequenceNumber = this.getSequenceNumber()\n\t\tconst operation = await createOperation(\n\t\t\t{\n\t\t\t\tnodeId: this.nodeId,\n\t\t\t\ttype: 'update',\n\t\t\t\tcollection: this.name,\n\t\t\t\trecordId: id,\n\t\t\t\tdata: { ...validated },\n\t\t\t\tpreviousData,\n\t\t\t\tsequenceNumber,\n\t\t\t\tcausalDeps: [],\n\t\t\t\tschemaVersion: this.schema.version,\n\t\t\t},\n\t\t\tthis.clock,\n\t\t)\n\n\t\tconst serializedChanges = serializeRecord(validated, this.definition.fields)\n\t\tconst updateQuery = buildUpdateQuery(this.name, id, {\n\t\t\t...serializedChanges,\n\t\t\t_updated_at: now,\n\t\t})\n\t\tconst opRow = serializeOperation(operation)\n\t\tconst opInsert = buildInsertQuery(\n\t\t\t`_kora_ops_${this.name}`,\n\t\t\topRow as unknown as Record<string, unknown>,\n\t\t)\n\n\t\tawait this.adapter.transaction(async (tx) => {\n\t\t\tawait tx.execute(updateQuery.sql, updateQuery.params)\n\t\t\tawait tx.execute(opInsert.sql, opInsert.params)\n\t\t\tawait tx.execute(\n\t\t\t\t'INSERT OR REPLACE INTO _kora_version_vector (node_id, sequence_number) VALUES (?, ?)',\n\t\t\t\t[this.nodeId, sequenceNumber],\n\t\t\t)\n\t\t})\n\n\t\tthis.onMutation(this.name, operation)\n\n\t\t// Return the full updated record\n\t\tconst updatedRow = await this.findById(id)\n\t\tif (!updatedRow) {\n\t\t\tthrow new RecordNotFoundError(this.name, id)\n\t\t}\n\t\treturn updatedRow\n\t}\n\n\t/**\n\t * Soft-delete a record by its ID.\n\t *\n\t * @param id - The record ID to delete\n\t * @throws {RecordNotFoundError} If the record doesn't exist or is already deleted\n\t */\n\tasync delete(id: string): Promise<void> {\n\t\tconst currentRows = await this.adapter.query<RawCollectionRow>(\n\t\t\t`SELECT * FROM ${this.name} WHERE id = ? AND _deleted = 0`,\n\t\t\t[id],\n\t\t)\n\t\tif (!currentRows[0]) {\n\t\t\tthrow new RecordNotFoundError(this.name, id)\n\t\t}\n\n\t\tconst now = Date.now()\n\t\tconst sequenceNumber = this.getSequenceNumber()\n\t\tconst operation = await createOperation(\n\t\t\t{\n\t\t\t\tnodeId: this.nodeId,\n\t\t\t\ttype: 'delete',\n\t\t\t\tcollection: this.name,\n\t\t\t\trecordId: id,\n\t\t\t\tdata: null,\n\t\t\t\tpreviousData: null,\n\t\t\t\tsequenceNumber,\n\t\t\t\tcausalDeps: [],\n\t\t\t\tschemaVersion: this.schema.version,\n\t\t\t},\n\t\t\tthis.clock,\n\t\t)\n\n\t\tconst deleteQuery = buildSoftDeleteQuery(this.name, id, now)\n\t\tconst opRow = serializeOperation(operation)\n\t\tconst opInsert = buildInsertQuery(\n\t\t\t`_kora_ops_${this.name}`,\n\t\t\topRow as unknown as Record<string, unknown>,\n\t\t)\n\n\t\tawait this.adapter.transaction(async (tx) => {\n\t\t\tawait tx.execute(deleteQuery.sql, deleteQuery.params)\n\t\t\tawait tx.execute(opInsert.sql, opInsert.params)\n\t\t\tawait tx.execute(\n\t\t\t\t'INSERT OR REPLACE INTO _kora_version_vector (node_id, sequence_number) VALUES (?, ?)',\n\t\t\t\t[this.nodeId, sequenceNumber],\n\t\t\t)\n\t\t})\n\n\t\tthis.onMutation(this.name, operation)\n\t}\n\n\t/** Get the collection name */\n\tgetName(): string {\n\t\treturn this.name\n\t}\n\n\t/** Get the collection definition */\n\tgetDefinition(): CollectionDefinition {\n\t\treturn this.definition\n\t}\n}\n","import type { CollectionDefinition, FieldDescriptor } from '@korajs/core'\nimport { QueryError } from '../errors'\nimport type { QueryDescriptor, WhereOperators } from '../types'\n\n/**\n * Result of building a SQL query: the parameterized SQL string and its bound values.\n */\nexport interface SqlQuery {\n\tsql: string\n\tparams: unknown[]\n}\n\n/**\n * Build a SELECT query from a QueryDescriptor.\n * Automatically adds `WHERE _deleted = 0` to exclude soft-deleted records.\n *\n * @param descriptor - The query descriptor\n * @param fields - The field descriptors from the collection schema\n * @returns A parameterized SQL query\n */\nexport function buildSelectQuery(\n\tdescriptor: QueryDescriptor,\n\tfields: Record<string, FieldDescriptor>,\n): SqlQuery {\n\tconst params: unknown[] = []\n\tconst parts = [`SELECT * FROM ${descriptor.collection}`]\n\n\tconst whereClause = buildWhereClauseParts(descriptor.where, fields, params)\n\t// Always filter out soft-deleted records\n\tconst deletedFilter = '_deleted = 0'\n\tif (whereClause) {\n\t\tparts.push(`WHERE ${deletedFilter} AND ${whereClause}`)\n\t} else {\n\t\tparts.push(`WHERE ${deletedFilter}`)\n\t}\n\n\tif (descriptor.orderBy.length > 0) {\n\t\tconst orderParts = descriptor.orderBy.map((o) => {\n\t\t\tvalidateFieldName(o.field, fields)\n\t\t\treturn `${o.field} ${o.direction.toUpperCase()}`\n\t\t})\n\t\tparts.push(`ORDER BY ${orderParts.join(', ')}`)\n\t}\n\n\tif (descriptor.limit !== undefined) {\n\t\tparts.push(`LIMIT ${descriptor.limit}`)\n\t}\n\n\tif (descriptor.offset !== undefined) {\n\t\tparts.push(`OFFSET ${descriptor.offset}`)\n\t}\n\n\treturn { sql: parts.join(' '), params }\n}\n\n/**\n * Build a COUNT query from a QueryDescriptor.\n * Automatically adds `WHERE _deleted = 0`.\n *\n * @param descriptor - The query descriptor\n * @param fields - The field descriptors from the collection schema\n * @returns A parameterized SQL query that returns { count: number }\n */\nexport function buildCountQuery(\n\tdescriptor: QueryDescriptor,\n\tfields: Record<string, FieldDescriptor>,\n): SqlQuery {\n\tconst params: unknown[] = []\n\tconst parts = [`SELECT COUNT(*) as count FROM ${descriptor.collection}`]\n\n\tconst whereClause = buildWhereClauseParts(descriptor.where, fields, params)\n\tconst deletedFilter = '_deleted = 0'\n\tif (whereClause) {\n\t\tparts.push(`WHERE ${deletedFilter} AND ${whereClause}`)\n\t} else {\n\t\tparts.push(`WHERE ${deletedFilter}`)\n\t}\n\n\treturn { sql: parts.join(' '), params }\n}\n\n/**\n * Build an INSERT query for a collection record.\n *\n * @param collection - The collection name\n * @param record - The record data (already serialized with id, _created_at, _updated_at)\n * @returns A parameterized SQL query\n */\nexport function buildInsertQuery(collection: string, record: Record<string, unknown>): SqlQuery {\n\tconst columns = Object.keys(record)\n\tconst placeholders = columns.map(() => '?')\n\tconst params = Object.values(record)\n\n\tconst sql = `INSERT INTO ${collection} (${columns.join(', ')}) VALUES (${placeholders.join(', ')})`\n\treturn { sql, params }\n}\n\n/**\n * Build an UPDATE query for a collection record.\n *\n * @param collection - The collection name\n * @param id - The record ID\n * @param changes - The fields to update (already serialized)\n * @returns A parameterized SQL query\n */\nexport function buildUpdateQuery(\n\tcollection: string,\n\tid: string,\n\tchanges: Record<string, unknown>,\n): SqlQuery {\n\tconst setClauses = Object.keys(changes).map((col) => `${col} = ?`)\n\tconst params = [...Object.values(changes), id]\n\n\tconst sql = `UPDATE ${collection} SET ${setClauses.join(', ')} WHERE id = ?`\n\treturn { sql, params }\n}\n\n/**\n * Build a soft-delete query (SET _deleted = 1).\n *\n * @param collection - The collection name\n * @param id - The record ID\n * @param updatedAt - The timestamp to set on _updated_at\n * @returns A parameterized SQL query\n */\nexport function buildSoftDeleteQuery(collection: string, id: string, updatedAt: number): SqlQuery {\n\treturn {\n\t\tsql: `UPDATE ${collection} SET _deleted = 1, _updated_at = ? WHERE id = ?`,\n\t\tparams: [updatedAt, id],\n\t}\n}\n\n/**\n * Build a WHERE clause from conditions, validating field names against the schema.\n *\n * @param where - The where conditions\n * @param fields - The field descriptors from the collection schema\n * @returns The SQL WHERE clause string and params, or null if no conditions\n */\nexport function buildWhereClause(\n\twhere: Record<string, unknown>,\n\tfields: Record<string, FieldDescriptor>,\n): SqlQuery | null {\n\tconst params: unknown[] = []\n\tconst result = buildWhereClauseParts(where, fields, params)\n\tif (!result) return null\n\treturn { sql: result, params }\n}\n\n// --- Internal helpers ---\n\nconst VALID_OPERATORS = new Set(['$eq', '$ne', '$gt', '$gte', '$lt', '$lte', '$in'])\n\nfunction buildWhereClauseParts(\n\twhere: Record<string, unknown>,\n\tfields: Record<string, FieldDescriptor>,\n\tparams: unknown[],\n): string | null {\n\tconst conditions: string[] = []\n\n\tfor (const [fieldName, value] of Object.entries(where)) {\n\t\tvalidateFieldName(fieldName, fields)\n\t\tconst descriptor = fields[fieldName]\n\n\t\tif (value !== null && typeof value === 'object' && !Array.isArray(value)) {\n\t\t\t// Operator object: { $gt: 5, $lt: 10 }\n\t\t\tconst ops = value as WhereOperators\n\t\t\tfor (const [op, opValue] of Object.entries(ops)) {\n\t\t\t\tif (!VALID_OPERATORS.has(op)) {\n\t\t\t\t\tthrow new QueryError(`Unknown operator \"${op}\" on field \"${fieldName}\"`, {\n\t\t\t\t\t\tfield: fieldName,\n\t\t\t\t\t\toperator: op,\n\t\t\t\t\t\tvalidOperators: [...VALID_OPERATORS],\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t\tconditions.push(buildOperatorCondition(fieldName, op, opValue, descriptor, params))\n\t\t\t}\n\t\t} else {\n\t\t\t// Shorthand: { completed: false } means { completed: { $eq: false } }\n\t\t\tconditions.push(buildOperatorCondition(fieldName, '$eq', value, descriptor, params))\n\t\t}\n\t}\n\n\tif (conditions.length === 0) return null\n\treturn conditions.join(' AND ')\n}\n\nfunction buildOperatorCondition(\n\tfieldName: string,\n\toperator: string,\n\tvalue: unknown,\n\tdescriptor: FieldDescriptor | undefined,\n\tparams: unknown[],\n): string {\n\t// Serialize boolean values to 0/1 for SQL comparison\n\tconst sqlValue =\n\t\tdescriptor?.kind === 'boolean' && typeof value === 'boolean' ? (value ? 1 : 0) : value\n\n\tswitch (operator) {\n\t\tcase '$eq':\n\t\t\tif (sqlValue === null) {\n\t\t\t\treturn `${fieldName} IS NULL`\n\t\t\t}\n\t\t\tparams.push(sqlValue)\n\t\t\treturn `${fieldName} = ?`\n\t\tcase '$ne':\n\t\t\tif (sqlValue === null) {\n\t\t\t\treturn `${fieldName} IS NOT NULL`\n\t\t\t}\n\t\t\tparams.push(sqlValue)\n\t\t\treturn `${fieldName} != ?`\n\t\tcase '$gt':\n\t\t\tparams.push(sqlValue)\n\t\t\treturn `${fieldName} > ?`\n\t\tcase '$gte':\n\t\t\tparams.push(sqlValue)\n\t\t\treturn `${fieldName} >= ?`\n\t\tcase '$lt':\n\t\t\tparams.push(sqlValue)\n\t\t\treturn `${fieldName} < ?`\n\t\tcase '$lte':\n\t\t\tparams.push(sqlValue)\n\t\t\treturn `${fieldName} <= ?`\n\t\tcase '$in': {\n\t\t\tif (!Array.isArray(sqlValue)) {\n\t\t\t\tthrow new QueryError(`$in operator requires an array value for field \"${fieldName}\"`, {\n\t\t\t\t\tfield: fieldName,\n\t\t\t\t\treceived: typeof sqlValue,\n\t\t\t\t})\n\t\t\t}\n\t\t\tconst placeholders = sqlValue.map(() => '?')\n\t\t\tfor (const item of sqlValue) {\n\t\t\t\tparams.push(\n\t\t\t\t\tdescriptor?.kind === 'boolean' && typeof item === 'boolean' ? (item ? 1 : 0) : item,\n\t\t\t\t)\n\t\t\t}\n\t\t\treturn `${fieldName} IN (${placeholders.join(', ')})`\n\t\t}\n\t\tdefault:\n\t\t\tthrow new QueryError(`Unknown operator \"${operator}\"`, { operator })\n\t}\n}\n\nfunction validateFieldName(fieldName: string, fields: Record<string, FieldDescriptor>): void {\n\t// Allow schema fields plus metadata fields that map to query-able columns\n\tconst allowedFields = new Set([\n\t\t...Object.keys(fields),\n\t\t'id',\n\t\t'createdAt',\n\t\t'updatedAt',\n\t\t'_created_at',\n\t\t'_updated_at',\n\t])\n\tif (!allowedFields.has(fieldName)) {\n\t\tthrow new QueryError(\n\t\t\t`Unknown field \"${fieldName}\" in query. Available fields: ${[...allowedFields].join(', ')}`,\n\t\t\t{ field: fieldName },\n\t\t)\n\t}\n}\n","import { HybridLogicalClock } from '@korajs/core'\nimport type { CollectionDefinition, FieldDescriptor, Operation } from '@korajs/core'\nimport type { CollectionRecord, OperationRow, RawCollectionRow } from '../types'\nimport { decodeRichtext, encodeRichtext } from './richtext-serializer'\n\n/**\n * Serialize a JS record to SQL-compatible values for INSERT/UPDATE.\n * Transforms: boolean → 0/1, array → JSON string, richtext → Yjs binary update.\n *\n * @param data - The record data with JS-native types\n * @param fields - The field descriptors from the schema\n * @returns An object with SQL-compatible values\n */\nexport function serializeRecord(\n\tdata: Record<string, unknown>,\n\tfields: Record<string, FieldDescriptor>,\n): Record<string, unknown> {\n\tconst result: Record<string, unknown> = {}\n\tfor (const [key, value] of Object.entries(data)) {\n\t\tconst descriptor = fields[key]\n\t\tif (!descriptor) {\n\t\t\tresult[key] = value\n\t\t\tcontinue\n\t\t}\n\t\tresult[key] = serializeValue(value, descriptor)\n\t}\n\treturn result\n}\n\n/**\n * Deserialize a SQL row to JS-native types for the application layer.\n * Transforms: 0/1 → boolean, JSON string → array, strips _deleted, maps _created_at/_updated_at.\n *\n * @param row - The raw SQL row\n * @param fields - The field descriptors from the schema\n * @returns A CollectionRecord with JS-native types\n */\nexport function deserializeRecord(\n\trow: RawCollectionRow,\n\tfields: Record<string, FieldDescriptor>,\n): CollectionRecord {\n\tconst result: CollectionRecord = {\n\t\tid: row.id,\n\t\tcreatedAt: row._created_at,\n\t\tupdatedAt: row._updated_at,\n\t}\n\n\tfor (const [key, descriptor] of Object.entries(fields)) {\n\t\tconst rawValue = row[key]\n\t\tif (rawValue === undefined || rawValue === null) {\n\t\t\tresult[key] = rawValue ?? null\n\t\t\tcontinue\n\t\t}\n\t\tresult[key] = deserializeValue(rawValue, descriptor)\n\t}\n\n\treturn result\n}\n\n/**\n * Serialize an Operation to a row for the operations log table.\n *\n * @param op - The operation to serialize\n * @returns An OperationRow suitable for SQL INSERT\n */\nexport function serializeOperation(op: Operation): OperationRow {\n\treturn {\n\t\tid: op.id,\n\t\tnode_id: op.nodeId,\n\t\ttype: op.type,\n\t\trecord_id: op.recordId,\n\t\tdata: op.data ? JSON.stringify(op.data) : null,\n\t\tprevious_data: op.previousData ? JSON.stringify(op.previousData) : null,\n\t\ttimestamp: HybridLogicalClock.serialize(op.timestamp),\n\t\tsequence_number: op.sequenceNumber,\n\t\tcausal_deps: JSON.stringify(op.causalDeps),\n\t\tschema_version: op.schemaVersion,\n\t}\n}\n\n/**\n * Deserialize a row from the operations log table back to an Operation.\n *\n * @param row - The raw operation row from SQL\n * @returns The deserialized Operation object\n */\nexport function deserializeOperation(row: OperationRow): Operation {\n\treturn {\n\t\tid: row.id,\n\t\tnodeId: row.node_id,\n\t\ttype: row.type as Operation['type'],\n\t\tcollection: '', // Collection name is derived from the table name by the caller\n\t\trecordId: row.record_id,\n\t\tdata: row.data ? (JSON.parse(row.data) as Record<string, unknown>) : null,\n\t\tpreviousData: row.previous_data\n\t\t\t? (JSON.parse(row.previous_data) as Record<string, unknown>)\n\t\t\t: null,\n\t\ttimestamp: HybridLogicalClock.deserialize(row.timestamp),\n\t\tsequenceNumber: row.sequence_number,\n\t\tcausalDeps: JSON.parse(row.causal_deps) as string[],\n\t\tschemaVersion: row.schema_version,\n\t}\n}\n\n/**\n * Deserialize an operation row with collection name already known.\n */\nexport function deserializeOperationWithCollection(\n\trow: OperationRow,\n\tcollection: string,\n): Operation {\n\tconst op = deserializeOperation(row)\n\treturn { ...op, collection }\n}\n\nfunction serializeValue(value: unknown, descriptor: FieldDescriptor): unknown {\n\tif (value === null || value === undefined) {\n\t\treturn null\n\t}\n\n\tswitch (descriptor.kind) {\n\t\tcase 'boolean':\n\t\t\treturn value ? 1 : 0\n\t\tcase 'array':\n\t\t\treturn JSON.stringify(value)\n\t\tcase 'richtext':\n\t\t\treturn encodeRichtext(value as string | Uint8Array | ArrayBuffer)\n\t\tdefault:\n\t\t\treturn value\n\t}\n}\n\nfunction deserializeValue(value: unknown, descriptor: FieldDescriptor): unknown {\n\tswitch (descriptor.kind) {\n\t\tcase 'boolean':\n\t\t\treturn value === 1 || value === true\n\t\tcase 'array':\n\t\t\tif (typeof value === 'string') {\n\t\t\t\treturn JSON.parse(value) as unknown[]\n\t\t\t}\n\t\t\treturn value\n\t\tcase 'richtext':\n\t\t\treturn decodeRichtext(value)\n\t\tdefault:\n\t\t\treturn value\n\t}\n}\n","import * as Y from 'yjs'\n\nconst TEXT_KEY = 'content'\n\nexport type RichtextInput = string | Uint8Array | ArrayBuffer | null | undefined\n\n/**\n * Encodes richtext values into Yjs document updates.\n */\nexport function encodeRichtext(value: RichtextInput): Uint8Array | null {\n\tif (value === null || value === undefined) {\n\t\treturn null\n\t}\n\n\tif (typeof value === 'string') {\n\t\tconst doc = new Y.Doc()\n\t\tdoc.getText(TEXT_KEY).insert(0, value)\n\t\treturn Y.encodeStateAsUpdate(doc)\n\t}\n\n\tif (value instanceof Uint8Array) {\n\t\treturn value\n\t}\n\n\tif (value instanceof ArrayBuffer) {\n\t\treturn new Uint8Array(value)\n\t}\n\n\tthrow new Error('Richtext value must be a string, Uint8Array, ArrayBuffer, null, or undefined.')\n}\n\n/**\n * Decodes driver-provided richtext values into Uint8Array.\n */\nexport function decodeRichtext(value: unknown): Uint8Array | null {\n\tif (value === null || value === undefined) {\n\t\treturn null\n\t}\n\n\tif (typeof Buffer !== 'undefined' && Buffer.isBuffer(value)) {\n\t\treturn new Uint8Array(value)\n\t}\n\n\tif (value instanceof Uint8Array) {\n\t\treturn value\n\t}\n\n\tif (value instanceof ArrayBuffer) {\n\t\treturn new Uint8Array(value)\n\t}\n\n\tthrow new Error('Richtext storage value must be Uint8Array, ArrayBuffer, Buffer, null, or undefined.')\n}\n\n/**\n * Reads plain text from a richtext Yjs state update.\n */\nexport function richtextToPlainText(value: RichtextInput): string {\n\tconst encoded = encodeRichtext(value)\n\tif (!encoded) return ''\n\n\tconst doc = new Y.Doc()\n\tY.applyUpdate(doc, encoded)\n\treturn doc.getText(TEXT_KEY).toString()\n}\n","/**\n * Minimal pluralization/singularization utilities for relation name resolution.\n * Handles common English patterns — not meant to be exhaustive.\n */\n\nfunction isVowel(char: string | undefined): boolean {\n\tif (!char) return false\n\treturn 'aeiouAEIOU'.includes(char)\n}\n\n/**\n * Pluralize a word using common English rules.\n *\n * @example\n * ```\n * pluralize('project') // 'projects'\n * pluralize('category') // 'categories'\n * pluralize('match') // 'matches'\n * ```\n */\nexport function pluralize(word: string): string {\n\tif (word.endsWith('s')) return word\n\tif (word.endsWith('y') && !isVowel(word[word.length - 2])) {\n\t\treturn `${word.slice(0, -1)}ies`\n\t}\n\tif (word.endsWith('sh') || word.endsWith('ch') || word.endsWith('x') || word.endsWith('z')) {\n\t\treturn `${word}es`\n\t}\n\treturn `${word}s`\n}\n\n/**\n * Singularize a word using common English rules.\n *\n * @example\n * ```\n * singularize('projects') // 'project'\n * singularize('categories') // 'category'\n * singularize('matches') // 'match'\n * ```\n */\nexport function singularize(word: string): string {\n\tif (word.endsWith('ies') && !isVowel(word[word.length - 4])) {\n\t\treturn `${word.slice(0, -3)}y`\n\t}\n\tif (\n\t\tword.endsWith('shes') ||\n\t\tword.endsWith('ches') ||\n\t\tword.endsWith('xes') ||\n\t\tword.endsWith('zes')\n\t) {\n\t\treturn word.slice(0, -2)\n\t}\n\tif (word.endsWith('ses')) {\n\t\treturn word.slice(0, -2)\n\t}\n\tif (word.endsWith('s') && !word.endsWith('ss')) {\n\t\treturn word.slice(0, -1)\n\t}\n\treturn word\n}\n","import type { CollectionDefinition, SchemaDefinition } from '@korajs/core'\nimport { deserializeRecord } from '../serialization/serializer'\nimport type { SubscriptionManager } from '../subscription/subscription-manager'\nimport type {\n\tCollectionRecord,\n\tOrderByDirection,\n\tQueryDescriptor,\n\tRawCollectionRow,\n\tStorageAdapter,\n\tSubscriptionCallback,\n\tWhereClause,\n} from '../types'\nimport { pluralize, singularize } from './pluralize'\nimport { buildCountQuery, buildSelectQuery } from './sql-builder'\n\n/**\n * Fluent query builder for constructing and executing collection queries.\n * Supports where, orderBy, limit, offset, include, exec, count, and subscribe.\n *\n * The generic parameter `T` defaults to `CollectionRecord` for backward compatibility\n * but can be narrowed to a specific record type for full type inference.\n *\n * @example\n * ```typescript\n * const todos = await app.todos\n * .where({ completed: false })\n * .orderBy('createdAt', 'desc')\n * .limit(10)\n * .exec()\n * ```\n */\nexport class QueryBuilder<T = CollectionRecord> {\n\tprivate descriptor: QueryDescriptor\n\n\tconstructor(\n\t\tprivate readonly collectionName: string,\n\t\tprivate readonly definition: CollectionDefinition,\n\t\tprivate readonly adapter: StorageAdapter,\n\t\tprivate readonly subscriptionManager: SubscriptionManager,\n\t\tinitialWhere: WhereClause = {},\n\t\tprivate readonly schema?: SchemaDefinition,\n\t) {\n\t\tthis.descriptor = {\n\t\t\tcollection: collectionName,\n\t\t\twhere: { ...initialWhere },\n\t\t\torderBy: [],\n\t\t}\n\t}\n\n\t/**\n\t * Add WHERE conditions (AND semantics, merged with existing conditions).\n\t */\n\twhere(conditions: WhereClause): QueryBuilder<T> {\n\t\tconst clone = this.clone()\n\t\tclone.descriptor = {\n\t\t\t...clone.descriptor,\n\t\t\twhere: { ...clone.descriptor.where, ...conditions },\n\t\t}\n\t\treturn clone\n\t}\n\n\t/**\n\t * Add ORDER BY clause.\n\t */\n\torderBy(field: string, direction: OrderByDirection = 'asc'): QueryBuilder<T> {\n\t\tconst clone = this.clone()\n\t\tclone.descriptor = {\n\t\t\t...clone.descriptor,\n\t\t\torderBy: [...clone.descriptor.orderBy, { field, direction }],\n\t\t}\n\t\treturn clone\n\t}\n\n\t/**\n\t * Set result limit.\n\t */\n\tlimit(n: number): QueryBuilder<T> {\n\t\tconst clone = this.clone()\n\t\tclone.descriptor = { ...clone.descriptor, limit: n }\n\t\treturn clone\n\t}\n\n\t/**\n\t * Set result offset.\n\t */\n\toffset(n: number): QueryBuilder<T> {\n\t\tconst clone = this.clone()\n\t\tclone.descriptor = { ...clone.descriptor, offset: n }\n\t\treturn clone\n\t}\n\n\t/**\n\t * Include related records in the query results.\n\t * Follows relations defined in the schema to batch-fetch related data.\n\t *\n\t * @param targets - Relation target names (collection names or relation names)\n\t * @returns A new QueryBuilder with include targets added\n\t *\n\t * @example\n\t * ```typescript\n\t * const todosWithProject = await app.todos\n\t * .where({ completed: false })\n\t * .include('project')\n\t * .exec()\n\t * ```\n\t */\n\tinclude(...targets: string[]): QueryBuilder<T> {\n\t\tconst clone = this.clone()\n\t\tconst existing = clone.descriptor.include ?? []\n\t\tclone.descriptor = {\n\t\t\t...clone.descriptor,\n\t\t\tinclude: [...existing, ...targets],\n\t\t}\n\t\treturn clone\n\t}\n\n\t/**\n\t * Execute the query and return results.\n\t */\n\tasync exec(): Promise<T[]> {\n\t\tconst { sql, params } = buildSelectQuery(this.descriptor, this.definition.fields)\n\t\tconst rows = await this.adapter.query<RawCollectionRow>(sql, params)\n\t\tconst records = rows.map((row) => deserializeRecord(row, this.definition.fields))\n\n\t\t// Resolve includes if any\n\t\tif (this.descriptor.include && this.descriptor.include.length > 0 && this.schema) {\n\t\t\tawait this.resolveIncludes(records)\n\t\t}\n\n\t\treturn records as T[]\n\t}\n\n\t/**\n\t * Execute a COUNT query and return the count.\n\t */\n\tasync count(): Promise<number> {\n\t\tconst { sql, params } = buildCountQuery(this.descriptor, this.definition.fields)\n\t\tconst rows = await this.adapter.query<{ count: number }>(sql, params)\n\t\treturn rows[0]?.count ?? 0\n\t}\n\n\t/**\n\t * Subscribe to query results. Callback is called immediately with current results,\n\t * then again whenever the results change due to mutations.\n\t *\n\t * @returns An unsubscribe function\n\t */\n\tsubscribe(callback: SubscriptionCallback<T>): () => void {\n\t\tconst executeFn = () => this.exec()\n\n\t\t// Resolve includeCollections for subscription tracking\n\t\tconst descriptorCopy = { ...this.descriptor }\n\t\tif (descriptorCopy.include && descriptorCopy.include.length > 0 && this.schema) {\n\t\t\tdescriptorCopy.includeCollections = this.resolveIncludeCollections(descriptorCopy.include)\n\t\t}\n\n\t\t// Use registerAndFetch to execute immediately, set lastResults,\n\t\t// and call callback — ensuring subsequent flushes diff correctly.\n\t\treturn this.subscriptionManager.registerAndFetch(\n\t\t\tdescriptorCopy,\n\t\t\tcallback as SubscriptionCallback<CollectionRecord>,\n\t\t\texecuteFn as () => Promise<CollectionRecord[]>,\n\t\t)\n\t}\n\n\t/** Get the internal descriptor (for testing/debugging) */\n\tgetDescriptor(): QueryDescriptor {\n\t\treturn { ...this.descriptor }\n\t}\n\n\tprivate clone(): QueryBuilder<T> {\n\t\tconst qb = new QueryBuilder<T>(\n\t\t\tthis.collectionName,\n\t\t\tthis.definition,\n\t\t\tthis.adapter,\n\t\t\tthis.subscriptionManager,\n\t\t\t{},\n\t\t\tthis.schema,\n\t\t)\n\t\tqb.descriptor = {\n\t\t\t...this.descriptor,\n\t\t\twhere: { ...this.descriptor.where },\n\t\t\torderBy: [...this.descriptor.orderBy],\n\t\t\tinclude: this.descriptor.include ? [...this.descriptor.include] : undefined,\n\t\t\tincludeCollections: this.descriptor.includeCollections\n\t\t\t\t? [...this.descriptor.includeCollections]\n\t\t\t\t: undefined,\n\t\t}\n\t\treturn qb\n\t}\n\n\t/**\n\t * Resolve include targets to their actual collection names for subscription tracking.\n\t */\n\tprivate resolveIncludeCollections(targets: string[]): string[] {\n\t\tif (!this.schema) return []\n\t\tconst collections: string[] = []\n\n\t\tfor (const target of targets) {\n\t\t\tconst relation = this.findRelation(target)\n\t\t\tif (relation) {\n\t\t\t\t// For many-to-one: the related collection is `relation.to`\n\t\t\t\t// For one-to-many: the related collection is `relation.from`\n\t\t\t\tif (relation.from === this.collectionName) {\n\t\t\t\t\tcollections.push(relation.to)\n\t\t\t\t} else {\n\t\t\t\t\tcollections.push(relation.from)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn collections\n\t}\n\n\t/**\n\t * Resolve includes after primary query, batch-fetching related records.\n\t */\n\tprivate async resolveIncludes(records: CollectionRecord[]): Promise<void> {\n\t\tif (!this.schema || !this.descriptor.include || records.length === 0) return\n\n\t\tfor (const target of this.descriptor.include) {\n\t\t\tconst relation = this.findRelation(target)\n\t\t\tif (!relation) {\n\t\t\t\tthrow new QueryError(\n\t\t\t\t\t`No relation found for include target \"${target}\" on collection \"${this.collectionName}\". ` +\n\t\t\t\t\t\t`Check that a relation is defined in your schema that connects \"${this.collectionName}\" to \"${target}\".`,\n\t\t\t\t)\n\t\t\t}\n\n\t\t\tif (relation.from === this.collectionName) {\n\t\t\t\t// Many-to-one or one-to-one: primary has FK → fetch parent records\n\t\t\t\tawait this.resolveManyToOneInclude(records, relation, target)\n\t\t\t} else {\n\t\t\t\t// One-to-many: related collection has FK → fetch children\n\t\t\t\tawait this.resolveOneToManyInclude(records, relation, target)\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Many-to-one: collect FK values from primary results, batch-fetch related, attach as singular.\n\t */\n\tprivate async resolveManyToOneInclude(\n\t\trecords: CollectionRecord[],\n\t\trelation: { from: string; to: string; field: string },\n\t\ttarget: string,\n\t): Promise<void> {\n\t\tconst fkField = relation.field\n\t\tconst fkValues = records\n\t\t\t.map((r) => r[fkField])\n\t\t\t.filter((v): v is string => v !== null && v !== undefined && typeof v === 'string')\n\n\t\tif (fkValues.length === 0) {\n\t\t\t// All null FKs — set property to null on all records\n\t\t\tconst propName = singularize(target)\n\t\t\tfor (const record of records) {\n\t\t\t\t;(record as Record<string, unknown>)[propName] = null\n\t\t\t}\n\t\t\treturn\n\t\t}\n\n\t\tconst uniqueFks = [...new Set(fkValues)]\n\t\tconst relatedCollection = relation.to\n\t\tconst relatedDef = this.schema?.collections[relatedCollection]\n\t\tif (!relatedDef) return\n\n\t\t// Batch fetch: SELECT * FROM <to> WHERE id IN (...) AND _deleted = 0\n\t\tconst placeholders = uniqueFks.map(() => '?').join(', ')\n\t\tconst sql = `SELECT * FROM ${relatedCollection} WHERE id IN (${placeholders}) AND _deleted = 0`\n\t\tconst rows = await this.adapter.query<RawCollectionRow>(sql, uniqueFks)\n\t\tconst relatedRecords = rows.map((row) => deserializeRecord(row, relatedDef.fields))\n\n\t\t// Build lookup\n\t\tconst lookup = new Map<string, CollectionRecord>()\n\t\tfor (const r of relatedRecords) {\n\t\t\tlookup.set(r.id, r)\n\t\t}\n\n\t\t// Attach as singular property\n\t\tconst propName = singularize(target)\n\t\tfor (const record of records) {\n\t\t\tconst fk = record[fkField] as string | null\n\t\t\t;(record as Record<string, unknown>)[propName] = fk ? (lookup.get(fk) ?? null) : null\n\t\t}\n\t}\n\n\t/**\n\t * One-to-many: collect primary IDs, batch-fetch children, attach as array.\n\t */\n\tprivate async resolveOneToManyInclude(\n\t\trecords: CollectionRecord[],\n\t\trelation: { from: string; to: string; field: string },\n\t\ttarget: string,\n\t): Promise<void> {\n\t\tconst primaryIds = records.map((r) => r.id)\n\t\tconst relatedCollection = relation.from\n\t\tconst relatedDef = this.schema?.collections[relatedCollection]\n\t\tif (!relatedDef) return\n\n\t\tconst fkField = relation.field\n\t\tconst placeholders = primaryIds.map(() => '?').join(', ')\n\t\tconst sql = `SELECT * FROM ${relatedCollection} WHERE ${fkField} IN (${placeholders}) AND _deleted = 0`\n\t\tconst rows = await this.adapter.query<RawCollectionRow>(sql, primaryIds)\n\t\tconst relatedRecords = rows.map((row) => deserializeRecord(row, relatedDef.fields))\n\n\t\t// Group by FK\n\t\tconst grouped = new Map<string, CollectionRecord[]>()\n\t\tfor (const r of relatedRecords) {\n\t\t\tconst fk = r[fkField] as string\n\t\t\tif (!grouped.has(fk)) {\n\t\t\t\tgrouped.set(fk, [])\n\t\t\t}\n\t\t\tgrouped.get(fk)?.push(r)\n\t\t}\n\n\t\t// Attach as array property\n\t\tconst propName = pluralize(target)\n\t\tfor (const record of records) {\n\t\t\t;(record as Record<string, unknown>)[propName] = grouped.get(record.id) ?? []\n\t\t}\n\t}\n\n\t/**\n\t * Find a relation definition matching the include target.\n\t * Searches by relation name, target collection name, and singularized/pluralized variants.\n\t */\n\tprivate findRelation(\n\t\ttarget: string,\n\t): { from: string; to: string; field: string; type: string } | null {\n\t\tif (!this.schema) return null\n\n\t\tfor (const [_name, rel] of Object.entries(this.schema.relations)) {\n\t\t\t// Direct match: target is the related collection name\n\t\t\tif (rel.from === this.collectionName && rel.to === target) return rel\n\t\t\tif (rel.to === this.collectionName && rel.from === target) return rel\n\n\t\t\t// Singularized match: \"project\" matches relation to \"projects\"\n\t\t\tif (rel.from === this.collectionName && rel.to === pluralize(target)) return rel\n\t\t\tif (rel.to === this.collectionName && rel.from === pluralize(target)) return rel\n\n\t\t\t// Pluralized match: \"todos\" matches relation from \"todos\"\n\t\t\tif (rel.from === this.collectionName && rel.to === singularize(target)) return rel\n\t\t\tif (rel.to === this.collectionName && rel.from === singularize(target)) return rel\n\t\t}\n\n\t\treturn null\n\t}\n}\n\n/**\n * Error thrown when a query encounters an invalid state.\n */\nclass QueryError extends Error {\n\tconstructor(message: string) {\n\t\tsuper(message)\n\t\tthis.name = 'QueryError'\n\t}\n}\n","import type { Operation } from '@korajs/core'\nimport type {\n\tCollectionRecord,\n\tQueryDescriptor,\n\tSubscription,\n\tSubscriptionCallback,\n} from '../types'\n\nlet nextSubId = 0\n\n/**\n * Manages reactive subscriptions. When a mutation occurs on a collection,\n * affected subscriptions are re-evaluated in a microtask batch and callbacks\n * are invoked only if results actually changed.\n */\nexport class SubscriptionManager {\n\tprivate subscriptions = new Map<string, Subscription>()\n\tprivate pendingCollections = new Set<string>()\n\tprivate flushScheduled = false\n\n\t/**\n\t * Register a new subscription.\n\t *\n\t * @param descriptor - The query descriptor defining what this subscription watches\n\t * @param callback - Called with results whenever they change\n\t * @param executeFn - Function to re-execute the query and get current results\n\t * @returns An unsubscribe function\n\t */\n\tregister(\n\t\tdescriptor: QueryDescriptor,\n\t\tcallback: SubscriptionCallback<CollectionRecord>,\n\t\texecuteFn: () => Promise<CollectionRecord[]>,\n\t): () => void {\n\t\tconst id = `sub_${++nextSubId}`\n\t\tconst subscription: Subscription = {\n\t\t\tid,\n\t\t\tdescriptor,\n\t\t\tcallback,\n\t\t\texecuteFn,\n\t\t\tlastResults: [],\n\t\t}\n\t\tthis.subscriptions.set(id, subscription)\n\n\t\treturn () => {\n\t\t\tthis.subscriptions.delete(id)\n\t\t}\n\t}\n\n\t/**\n\t * Register a subscription and immediately execute the query.\n\t * The initial results are stored as lastResults so subsequent flushes\n\t * correctly diff against the initial state.\n\t *\n\t * @returns An unsubscribe function\n\t */\n\tregisterAndFetch(\n\t\tdescriptor: QueryDescriptor,\n\t\tcallback: SubscriptionCallback<CollectionRecord>,\n\t\texecuteFn: () => Promise<CollectionRecord[]>,\n\t): () => void {\n\t\tconst id = `sub_${++nextSubId}`\n\t\tconst subscription: Subscription = {\n\t\t\tid,\n\t\t\tdescriptor,\n\t\t\tcallback,\n\t\t\texecuteFn,\n\t\t\tlastResults: [],\n\t\t}\n\t\tthis.subscriptions.set(id, subscription)\n\n\t\t// Execute immediately, set lastResults, and call callback\n\t\texecuteFn().then((results) => {\n\t\t\t// Guard: subscription may have been removed before the async fetch completes\n\t\t\tif (this.subscriptions.has(id)) {\n\t\t\t\tsubscription.lastResults = results\n\t\t\t\tcallback(results)\n\t\t\t}\n\t\t})\n\n\t\treturn () => {\n\t\t\tthis.subscriptions.delete(id)\n\t\t}\n\t}\n\n\t/**\n\t * Notify the manager that a mutation occurred on a collection.\n\t * Schedules a microtask flush to batch multiple mutations in the same tick.\n\t */\n\tnotify(collection: string, _operation: Operation): void {\n\t\tthis.pendingCollections.add(collection)\n\t\tthis.scheduleFlush()\n\t}\n\n\t/**\n\t * Immediately flush all pending notifications.\n\t * Useful for testing. In production, flushing happens via microtask.\n\t */\n\tasync flush(): Promise<void> {\n\t\tif (this.pendingCollections.size === 0) return\n\n\t\tconst collections = new Set(this.pendingCollections)\n\t\tthis.pendingCollections.clear()\n\t\tthis.flushScheduled = false\n\n\t\t// Find affected subscriptions (including those with related collection includes)\n\t\tconst affected: Subscription[] = []\n\t\tfor (const sub of this.subscriptions.values()) {\n\t\t\tif (collections.has(sub.descriptor.collection)) {\n\t\t\t\taffected.push(sub)\n\t\t\t} else if (sub.descriptor.includeCollections) {\n\t\t\t\t// Re-evaluate if a mutation affects an included (related) collection\n\t\t\t\tfor (const incCol of sub.descriptor.includeCollections) {\n\t\t\t\t\tif (collections.has(incCol)) {\n\t\t\t\t\t\taffected.push(sub)\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Re-execute and diff\n\t\tfor (const sub of affected) {\n\t\t\ttry {\n\t\t\t\tconst newResults = await sub.executeFn()\n\t\t\t\tif (!this.resultsEqual(sub.lastResults, newResults)) {\n\t\t\t\t\tsub.lastResults = newResults\n\t\t\t\t\tsub.callback(newResults)\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\t// Subscription re-execution failed — skip silently for now.\n\t\t\t\t// In future, we could emit an error event for DevTools.\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Remove all subscriptions. Called on store close.\n\t */\n\tclear(): void {\n\t\tthis.subscriptions.clear()\n\t\tthis.pendingCollections.clear()\n\t\tthis.flushScheduled = false\n\t}\n\n\t/** Number of active subscriptions (for testing/debugging) */\n\tget size(): number {\n\t\treturn this.subscriptions.size\n\t}\n\n\tprivate scheduleFlush(): void {\n\t\tif (this.flushScheduled) return\n\t\tthis.flushScheduled = true\n\t\tqueueMicrotask(() => {\n\t\t\tthis.flush()\n\t\t})\n\t}\n\n\t/**\n\t * Compare two result sets. Uses length check + JSON comparison as pragmatic approach.\n\t * Sufficient for typical query results. Can be optimized to id-based diffing if profiling shows need.\n\t */\n\tprivate resultsEqual(prev: CollectionRecord[], next: CollectionRecord[]): boolean {\n\t\tif (prev.length !== next.length) return false\n\t\t// Fast path: both empty\n\t\tif (prev.length === 0) return true\n\t\treturn JSON.stringify(prev) === JSON.stringify(next)\n\t}\n}\n"],"mappings":";;;;;;;;;;;AAAA,SAAS,sBAAAA,qBAAoB,qBAAqB,kBAAAC,uBAAsB;;;ACOxE,SAAS,iBAAiB,gBAAgB,sBAAsB;;;ACazD,SAAS,iBACf,YACA,QACW;AACX,QAAM,SAAoB,CAAC;AAC3B,QAAM,QAAQ,CAAC,iBAAiB,WAAW,UAAU,EAAE;AAEvD,QAAM,cAAc,sBAAsB,WAAW,OAAO,QAAQ,MAAM;AAE1E,QAAM,gBAAgB;AACtB,MAAI,aAAa;AAChB,UAAM,KAAK,SAAS,aAAa,QAAQ,WAAW,EAAE;AAAA,EACvD,OAAO;AACN,UAAM,KAAK,SAAS,aAAa,EAAE;AAAA,EACpC;AAEA,MAAI,WAAW,QAAQ,SAAS,GAAG;AAClC,UAAM,aAAa,WAAW,QAAQ,IAAI,CAAC,MAAM;AAChD,wBAAkB,EAAE,OAAO,MAAM;AACjC,aAAO,GAAG,EAAE,KAAK,IAAI,EAAE,UAAU,YAAY,CAAC;AAAA,IAC/C,CAAC;AACD,UAAM,KAAK,YAAY,WAAW,KAAK,IAAI,CAAC,EAAE;AAAA,EAC/C;AAEA,MAAI,WAAW,UAAU,QAAW;AACnC,UAAM,KAAK,SAAS,WAAW,KAAK,EAAE;AAAA,EACvC;AAEA,MAAI,WAAW,WAAW,QAAW;AACpC,UAAM,KAAK,UAAU,WAAW,MAAM,EAAE;AAAA,EACzC;AAEA,SAAO,EAAE,KAAK,MAAM,KAAK,GAAG,GAAG,OAAO;AACvC;AAUO,SAAS,gBACf,YACA,QACW;AACX,QAAM,SAAoB,CAAC;AAC3B,QAAM,QAAQ,CAAC,iCAAiC,WAAW,UAAU,EAAE;AAEvE,QAAM,cAAc,sBAAsB,WAAW,OAAO,QAAQ,MAAM;AAC1E,QAAM,gBAAgB;AACtB,MAAI,aAAa;AAChB,UAAM,KAAK,SAAS,aAAa,QAAQ,WAAW,EAAE;AAAA,EACvD,OAAO;AACN,UAAM,KAAK,SAAS,aAAa,EAAE;AAAA,EACpC;AAEA,SAAO,EAAE,KAAK,MAAM,KAAK,GAAG,GAAG,OAAO;AACvC;AASO,SAAS,iBAAiB,YAAoB,QAA2C;AAC/F,QAAM,UAAU,OAAO,KAAK,MAAM;AAClC,QAAM,eAAe,QAAQ,IAAI,MAAM,GAAG;AAC1C,QAAM,SAAS,OAAO,OAAO,MAAM;AAEnC,QAAM,MAAM,eAAe,UAAU,KAAK,QAAQ,KAAK,IAAI,CAAC,aAAa,aAAa,KAAK,IAAI,CAAC;AAChG,SAAO,EAAE,KAAK,OAAO;AACtB;AAUO,SAAS,iBACf,YACA,IACA,SACW;AACX,QAAM,aAAa,OAAO,KAAK,OAAO,EAAE,IAAI,CAAC,QAAQ,GAAG,GAAG,MAAM;AACjE,QAAM,SAAS,CAAC,GAAG,OAAO,OAAO,OAAO,GAAG,EAAE;AAE7C,QAAM,MAAM,UAAU,UAAU,QAAQ,WAAW,KAAK,IAAI,CAAC;AAC7D,SAAO,EAAE,KAAK,OAAO;AACtB;AAUO,SAAS,qBAAqB,YAAoB,IAAY,WAA6B;AACjG,SAAO;AAAA,IACN,KAAK,UAAU,UAAU;AAAA,IACzB,QAAQ,CAAC,WAAW,EAAE;AAAA,EACvB;AACD;AAqBA,IAAM,kBAAkB,oBAAI,IAAI,CAAC,OAAO,OAAO,OAAO,QAAQ,OAAO,QAAQ,KAAK,CAAC;AAEnF,SAAS,sBACR,OACA,QACA,QACgB;AAChB,QAAM,aAAuB,CAAC;AAE9B,aAAW,CAAC,WAAW,KAAK,KAAK,OAAO,QAAQ,KAAK,GAAG;AACvD,sBAAkB,WAAW,MAAM;AACnC,UAAM,aAAa,OAAO,SAAS;AAEnC,QAAI,UAAU,QAAQ,OAAO,UAAU,YAAY,CAAC,MAAM,QAAQ,KAAK,GAAG;AAEzE,YAAM,MAAM;AACZ,iBAAW,CAAC,IAAI,OAAO,KAAK,OAAO,QAAQ,GAAG,GAAG;AAChD,YAAI,CAAC,gBAAgB,IAAI,EAAE,GAAG;AAC7B,gBAAM,IAAI,WAAW,qBAAqB,EAAE,eAAe,SAAS,KAAK;AAAA,YACxE,OAAO;AAAA,YACP,UAAU;AAAA,YACV,gBAAgB,CAAC,GAAG,eAAe;AAAA,UACpC,CAAC;AAAA,QACF;AACA,mBAAW,KAAK,uBAAuB,WAAW,IAAI,SAAS,YAAY,MAAM,CAAC;AAAA,MACnF;AAAA,IACD,OAAO;AAEN,iBAAW,KAAK,uBAAuB,WAAW,OAAO,OAAO,YAAY,MAAM,CAAC;AAAA,IACpF;AAAA,EACD;AAEA,MAAI,WAAW,WAAW,EAAG,QAAO;AACpC,SAAO,WAAW,KAAK,OAAO;AAC/B;AAEA,SAAS,uBACR,WACA,UACA,OACA,YACA,QACS;AAET,QAAM,WACL,YAAY,SAAS,aAAa,OAAO,UAAU,YAAa,QAAQ,IAAI,IAAK;AAElF,UAAQ,UAAU;AAAA,IACjB,KAAK;AACJ,UAAI,aAAa,MAAM;AACtB,eAAO,GAAG,SAAS;AAAA,MACpB;AACA,aAAO,KAAK,QAAQ;AACpB,aAAO,GAAG,SAAS;AAAA,IACpB,KAAK;AACJ,UAAI,aAAa,MAAM;AACtB,eAAO,GAAG,SAAS;AAAA,MACpB;AACA,aAAO,KAAK,QAAQ;AACpB,aAAO,GAAG,SAAS;AAAA,IACpB,KAAK;AACJ,aAAO,KAAK,QAAQ;AACpB,aAAO,GAAG,SAAS;AAAA,IACpB,KAAK;AACJ,aAAO,KAAK,QAAQ;AACpB,aAAO,GAAG,SAAS;AAAA,IACpB,KAAK;AACJ,aAAO,KAAK,QAAQ;AACpB,aAAO,GAAG,SAAS;AAAA,IACpB,KAAK;AACJ,aAAO,KAAK,QAAQ;AACpB,aAAO,GAAG,SAAS;AAAA,IACpB,KAAK,OAAO;AACX,UAAI,CAAC,MAAM,QAAQ,QAAQ,GAAG;AAC7B,cAAM,IAAI,WAAW,mDAAmD,SAAS,KAAK;AAAA,UACrF,OAAO;AAAA,UACP,UAAU,OAAO;AAAA,QAClB,CAAC;AAAA,MACF;AACA,YAAM,eAAe,SAAS,IAAI,MAAM,GAAG;AAC3C,iBAAW,QAAQ,UAAU;AAC5B,eAAO;AAAA,UACN,YAAY,SAAS,aAAa,OAAO,SAAS,YAAa,OAAO,IAAI,IAAK;AAAA,QAChF;AAAA,MACD;AACA,aAAO,GAAG,SAAS,QAAQ,aAAa,KAAK,IAAI,CAAC;AAAA,IACnD;AAAA,IACA;AACC,YAAM,IAAI,WAAW,qBAAqB,QAAQ,KAAK,EAAE,SAAS,CAAC;AAAA,EACrE;AACD;AAEA,SAAS,kBAAkB,WAAmB,QAA+C;AAE5F,QAAM,gBAAgB,oBAAI,IAAI;AAAA,IAC7B,GAAG,OAAO,KAAK,MAAM;AAAA,IACrB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACD,CAAC;AACD,MAAI,CAAC,cAAc,IAAI,SAAS,GAAG;AAClC,UAAM,IAAI;AAAA,MACT,kBAAkB,SAAS,iCAAiC,CAAC,GAAG,aAAa,EAAE,KAAK,IAAI,CAAC;AAAA,MACzF,EAAE,OAAO,UAAU;AAAA,IACpB;AAAA,EACD;AACD;;;ACnQA,SAAS,0BAA0B;;;ACAnC,YAAY,OAAO;AAEnB,IAAM,WAAW;AAOV,SAAS,eAAe,OAAyC;AACvE,MAAI,UAAU,QAAQ,UAAU,QAAW;AAC1C,WAAO;AAAA,EACR;AAEA,MAAI,OAAO,UAAU,UAAU;AAC9B,UAAM,MAAM,IAAM,MAAI;AACtB,QAAI,QAAQ,QAAQ,EAAE,OAAO,GAAG,KAAK;AACrC,WAAS,sBAAoB,GAAG;AAAA,EACjC;AAEA,MAAI,iBAAiB,YAAY;AAChC,WAAO;AAAA,EACR;AAEA,MAAI,iBAAiB,aAAa;AACjC,WAAO,IAAI,WAAW,KAAK;AAAA,EAC5B;AAEA,QAAM,IAAI,MAAM,+EAA+E;AAChG;AAKO,SAAS,eAAe,OAAmC;AACjE,MAAI,UAAU,QAAQ,UAAU,QAAW;AAC1C,WAAO;AAAA,EACR;AAEA,MAAI,OAAO,WAAW,eAAe,OAAO,SAAS,KAAK,GAAG;AAC5D,WAAO,IAAI,WAAW,KAAK;AAAA,EAC5B;AAEA,MAAI,iBAAiB,YAAY;AAChC,WAAO;AAAA,EACR;AAEA,MAAI,iBAAiB,aAAa;AACjC,WAAO,IAAI,WAAW,KAAK;AAAA,EAC5B;AAEA,QAAM,IAAI,MAAM,qFAAqF;AACtG;AAKO,SAAS,oBAAoB,OAA8B;AACjE,QAAM,UAAU,eAAe,KAAK;AACpC,MAAI,CAAC,QAAS,QAAO;AAErB,QAAM,MAAM,IAAM,MAAI;AACtB,EAAE,cAAY,KAAK,OAAO;AAC1B,SAAO,IAAI,QAAQ,QAAQ,EAAE,SAAS;AACvC;;;ADnDO,SAAS,gBACf,MACA,QAC0B;AAC1B,QAAM,SAAkC,CAAC;AACzC,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,IAAI,GAAG;AAChD,UAAM,aAAa,OAAO,GAAG;AAC7B,QAAI,CAAC,YAAY;AAChB,aAAO,GAAG,IAAI;AACd;AAAA,IACD;AACA,WAAO,GAAG,IAAI,eAAe,OAAO,UAAU;AAAA,EAC/C;AACA,SAAO;AACR;AAUO,SAAS,kBACf,KACA,QACmB;AACnB,QAAM,SAA2B;AAAA,IAChC,IAAI,IAAI;AAAA,IACR,WAAW,IAAI;AAAA,IACf,WAAW,IAAI;AAAA,EAChB;AAEA,aAAW,CAAC,KAAK,UAAU,KAAK,OAAO,QAAQ,MAAM,GAAG;AACvD,UAAM,WAAW,IAAI,GAAG;AACxB,QAAI,aAAa,UAAa,aAAa,MAAM;AAChD,aAAO,GAAG,IAAI,YAAY;AAC1B;AAAA,IACD;AACA,WAAO,GAAG,IAAI,iBAAiB,UAAU,UAAU;AAAA,EACpD;AAEA,SAAO;AACR;AAQO,SAAS,mBAAmB,IAA6B;AAC/D,SAAO;AAAA,IACN,IAAI,GAAG;AAAA,IACP,SAAS,GAAG;AAAA,IACZ,MAAM,GAAG;AAAA,IACT,WAAW,GAAG;AAAA,IACd,MAAM,GAAG,OAAO,KAAK,UAAU,GAAG,IAAI,IAAI;AAAA,IAC1C,eAAe,GAAG,eAAe,KAAK,UAAU,GAAG,YAAY,IAAI;AAAA,IACnE,WAAW,mBAAmB,UAAU,GAAG,SAAS;AAAA,IACpD,iBAAiB,GAAG;AAAA,IACpB,aAAa,KAAK,UAAU,GAAG,UAAU;AAAA,IACzC,gBAAgB,GAAG;AAAA,EACpB;AACD;AAQO,SAAS,qBAAqB,KAA8B;AAClE,SAAO;AAAA,IACN,IAAI,IAAI;AAAA,IACR,QAAQ,IAAI;AAAA,IACZ,MAAM,IAAI;AAAA,IACV,YAAY;AAAA;AAAA,IACZ,UAAU,IAAI;AAAA,IACd,MAAM,IAAI,OAAQ,KAAK,MAAM,IAAI,IAAI,IAAgC;AAAA,IACrE,cAAc,IAAI,gBACd,KAAK,MAAM,IAAI,aAAa,IAC7B;AAAA,IACH,WAAW,mBAAmB,YAAY,IAAI,SAAS;AAAA,IACvD,gBAAgB,IAAI;AAAA,IACpB,YAAY,KAAK,MAAM,IAAI,WAAW;AAAA,IACtC,eAAe,IAAI;AAAA,EACpB;AACD;AAKO,SAAS,mCACf,KACA,YACY;AACZ,QAAM,KAAK,qBAAqB,GAAG;AACnC,SAAO,EAAE,GAAG,IAAI,WAAW;AAC5B;AAEA,SAAS,eAAe,OAAgB,YAAsC;AAC7E,MAAI,UAAU,QAAQ,UAAU,QAAW;AAC1C,WAAO;AAAA,EACR;AAEA,UAAQ,WAAW,MAAM;AAAA,IACxB,KAAK;AACJ,aAAO,QAAQ,IAAI;AAAA,IACpB,KAAK;AACJ,aAAO,KAAK,UAAU,KAAK;AAAA,IAC5B,KAAK;AACJ,aAAO,eAAe,KAA0C;AAAA,IACjE;AACC,aAAO;AAAA,EACT;AACD;AAEA,SAAS,iBAAiB,OAAgB,YAAsC;AAC/E,UAAQ,WAAW,MAAM;AAAA,IACxB,KAAK;AACJ,aAAO,UAAU,KAAK,UAAU;AAAA,IACjC,KAAK;AACJ,UAAI,OAAO,UAAU,UAAU;AAC9B,eAAO,KAAK,MAAM,KAAK;AAAA,MACxB;AACA,aAAO;AAAA,IACR,KAAK;AACJ,aAAO,eAAe,KAAK;AAAA,IAC5B;AACC,aAAO;AAAA,EACT;AACD;;;AF5HO,IAAM,aAAN,MAAiB;AAAA,EACvB,YACkB,MACA,YACA,QACA,SACA,OACA,QACA,mBACA,YAChB;AARgB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA,EACf;AAAA,EARe;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUlB,MAAM,OAAO,MAA0D;AACtE,UAAM,YAAY,eAAe,KAAK,MAAM,KAAK,YAAY,MAAM,QAAQ;AAC3E,UAAM,WAAW,eAAe;AAChC,UAAM,MAAM,KAAK,IAAI;AAGrB,eAAW,CAAC,WAAW,UAAU,KAAK,OAAO,QAAQ,KAAK,WAAW,MAAM,GAAG;AAC7E,UAAI,WAAW,QAAQ,WAAW,SAAS,aAAa;AACvD,kBAAU,SAAS,IAAI;AAAA,MACxB;AAAA,IACD;AAEA,UAAM,iBAAiB,KAAK,kBAAkB;AAC9C,UAAM,YAAY,MAAM;AAAA,MACvB;AAAA,QACC,QAAQ,KAAK;AAAA,QACb,MAAM;AAAA,QACN,YAAY,KAAK;AAAA,QACjB;AAAA,QACA,MAAM,EAAE,GAAG,UAAU;AAAA,QACrB,cAAc;AAAA,QACd;AAAA,QACA,YAAY,CAAC;AAAA,QACb,eAAe,KAAK,OAAO;AAAA,MAC5B;AAAA,MACA,KAAK;AAAA,IACN;AAEA,UAAM,iBAAiB,gBAAgB,WAAW,KAAK,WAAW,MAAM;AACxE,UAAM,SAAkC;AAAA,MACvC,IAAI;AAAA,MACJ,GAAG;AAAA,MACH,aAAa;AAAA,MACb,aAAa;AAAA,IACd;AAEA,UAAM,cAAc,iBAAiB,KAAK,MAAM,MAAM;AACtD,UAAM,QAAQ,mBAAmB,SAAS;AAC1C,UAAM,WAAW;AAAA,MAChB,aAAa,KAAK,IAAI;AAAA,MACtB;AAAA,IACD;AAEA,UAAM,KAAK,QAAQ,YAAY,OAAO,OAAO;AAC5C,YAAM,GAAG,QAAQ,YAAY,KAAK,YAAY,MAAM;AACpD,YAAM,GAAG,QAAQ,SAAS,KAAK,SAAS,MAAM;AAC9C,YAAM,GAAG;AAAA,QACR;AAAA,QACA,CAAC,KAAK,QAAQ,cAAc;AAAA,MAC7B;AAAA,IACD,CAAC;AAED,SAAK,WAAW,KAAK,MAAM,SAAS;AAEpC,WAAO;AAAA,MACN,IAAI;AAAA,MACJ,GAAG;AAAA,MACH,WAAW;AAAA,MACX,WAAW;AAAA,IACZ;AAAA,EACD;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,SAAS,IAA8C;AAC5D,UAAM,OAAO,MAAM,KAAK,QAAQ;AAAA,MAC/B,iBAAiB,KAAK,IAAI;AAAA,MAC1B,CAAC,EAAE;AAAA,IACJ;AAEA,UAAM,MAAM,KAAK,CAAC;AAClB,QAAI,CAAC,IAAK,QAAO;AACjB,WAAO,kBAAkB,KAAK,KAAK,WAAW,MAAM;AAAA,EACrD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,MAAM,OAAO,IAAY,MAA0D;AAClF,UAAM,cAAc,MAAM,KAAK,QAAQ;AAAA,MACtC,iBAAiB,KAAK,IAAI;AAAA,MAC1B,CAAC,EAAE;AAAA,IACJ;AACA,UAAM,aAAa,YAAY,CAAC;AAChC,QAAI,CAAC,YAAY;AAChB,YAAM,IAAI,oBAAoB,KAAK,MAAM,EAAE;AAAA,IAC5C;AAEA,UAAM,YAAY,eAAe,KAAK,MAAM,KAAK,YAAY,MAAM,QAAQ;AAC3E,UAAM,MAAM,KAAK,IAAI;AAGrB,UAAM,eAAwC,CAAC;AAC/C,UAAM,gBAAgB,kBAAkB,YAAY,KAAK,WAAW,MAAM;AAC1E,eAAW,OAAO,OAAO,KAAK,SAAS,GAAG;AACzC,mBAAa,GAAG,IAAI,cAAc,GAAG;AAAA,IACtC;AAEA,UAAM,iBAAiB,KAAK,kBAAkB;AAC9C,UAAM,YAAY,MAAM;AAAA,MACvB;AAAA,QACC,QAAQ,KAAK;AAAA,QACb,MAAM;AAAA,QACN,YAAY,KAAK;AAAA,QACjB,UAAU;AAAA,QACV,MAAM,EAAE,GAAG,UAAU;AAAA,QACrB;AAAA,QACA;AAAA,QACA,YAAY,CAAC;AAAA,QACb,eAAe,KAAK,OAAO;AAAA,MAC5B;AAAA,MACA,KAAK;AAAA,IACN;AAEA,UAAM,oBAAoB,gBAAgB,WAAW,KAAK,WAAW,MAAM;AAC3E,UAAM,cAAc,iBAAiB,KAAK,MAAM,IAAI;AAAA,MACnD,GAAG;AAAA,MACH,aAAa;AAAA,IACd,CAAC;AACD,UAAM,QAAQ,mBAAmB,SAAS;AAC1C,UAAM,WAAW;AAAA,MAChB,aAAa,KAAK,IAAI;AAAA,MACtB;AAAA,IACD;AAEA,UAAM,KAAK,QAAQ,YAAY,OAAO,OAAO;AAC5C,YAAM,GAAG,QAAQ,YAAY,KAAK,YAAY,MAAM;AACpD,YAAM,GAAG,QAAQ,SAAS,KAAK,SAAS,MAAM;AAC9C,YAAM,GAAG;AAAA,QACR;AAAA,QACA,CAAC,KAAK,QAAQ,cAAc;AAAA,MAC7B;AAAA,IACD,CAAC;AAED,SAAK,WAAW,KAAK,MAAM,SAAS;AAGpC,UAAM,aAAa,MAAM,KAAK,SAAS,EAAE;AACzC,QAAI,CAAC,YAAY;AAChB,YAAM,IAAI,oBAAoB,KAAK,MAAM,EAAE;AAAA,IAC5C;AACA,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,OAAO,IAA2B;AACvC,UAAM,cAAc,MAAM,KAAK,QAAQ;AAAA,MACtC,iBAAiB,KAAK,IAAI;AAAA,MAC1B,CAAC,EAAE;AAAA,IACJ;AACA,QAAI,CAAC,YAAY,CAAC,GAAG;AACpB,YAAM,IAAI,oBAAoB,KAAK,MAAM,EAAE;AAAA,IAC5C;AAEA,UAAM,MAAM,KAAK,IAAI;AACrB,UAAM,iBAAiB,KAAK,kBAAkB;AAC9C,UAAM,YAAY,MAAM;AAAA,MACvB;AAAA,QACC,QAAQ,KAAK;AAAA,QACb,MAAM;AAAA,QACN,YAAY,KAAK;AAAA,QACjB,UAAU;AAAA,QACV,MAAM;AAAA,QACN,cAAc;AAAA,QACd;AAAA,QACA,YAAY,CAAC;AAAA,QACb,eAAe,KAAK,OAAO;AAAA,MAC5B;AAAA,MACA,KAAK;AAAA,IACN;AAEA,UAAM,cAAc,qBAAqB,KAAK,MAAM,IAAI,GAAG;AAC3D,UAAM,QAAQ,mBAAmB,SAAS;AAC1C,UAAM,WAAW;AAAA,MAChB,aAAa,KAAK,IAAI;AAAA,MACtB;AAAA,IACD;AAEA,UAAM,KAAK,QAAQ,YAAY,OAAO,OAAO;AAC5C,YAAM,GAAG,QAAQ,YAAY,KAAK,YAAY,MAAM;AACpD,YAAM,GAAG,QAAQ,SAAS,KAAK,SAAS,MAAM;AAC9C,YAAM,GAAG;AAAA,QACR;AAAA,QACA,CAAC,KAAK,QAAQ,cAAc;AAAA,MAC7B;AAAA,IACD,CAAC;AAED,SAAK,WAAW,KAAK,MAAM,SAAS;AAAA,EACrC;AAAA;AAAA,EAGA,UAAkB;AACjB,WAAO,KAAK;AAAA,EACb;AAAA;AAAA,EAGA,gBAAsC;AACrC,WAAO,KAAK;AAAA,EACb;AACD;;;AItPA,SAAS,QAAQ,MAAmC;AACnD,MAAI,CAAC,KAAM,QAAO;AAClB,SAAO,aAAa,SAAS,IAAI;AAClC;AAYO,SAAS,UAAU,MAAsB;AAC/C,MAAI,KAAK,SAAS,GAAG,EAAG,QAAO;AAC/B,MAAI,KAAK,SAAS,GAAG,KAAK,CAAC,QAAQ,KAAK,KAAK,SAAS,CAAC,CAAC,GAAG;AAC1D,WAAO,GAAG,KAAK,MAAM,GAAG,EAAE,CAAC;AAAA,EAC5B;AACA,MAAI,KAAK,SAAS,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,SAAS,GAAG,KAAK,KAAK,SAAS,GAAG,GAAG;AAC3F,WAAO,GAAG,IAAI;AAAA,EACf;AACA,SAAO,GAAG,IAAI;AACf;AAYO,SAAS,YAAY,MAAsB;AACjD,MAAI,KAAK,SAAS,KAAK,KAAK,CAAC,QAAQ,KAAK,KAAK,SAAS,CAAC,CAAC,GAAG;AAC5D,WAAO,GAAG,KAAK,MAAM,GAAG,EAAE,CAAC;AAAA,EAC5B;AACA,MACC,KAAK,SAAS,MAAM,KACpB,KAAK,SAAS,MAAM,KACpB,KAAK,SAAS,KAAK,KACnB,KAAK,SAAS,KAAK,GAClB;AACD,WAAO,KAAK,MAAM,GAAG,EAAE;AAAA,EACxB;AACA,MAAI,KAAK,SAAS,KAAK,GAAG;AACzB,WAAO,KAAK,MAAM,GAAG,EAAE;AAAA,EACxB;AACA,MAAI,KAAK,SAAS,GAAG,KAAK,CAAC,KAAK,SAAS,IAAI,GAAG;AAC/C,WAAO,KAAK,MAAM,GAAG,EAAE;AAAA,EACxB;AACA,SAAO;AACR;;;AC7BO,IAAM,eAAN,MAAM,cAAmC;AAAA,EAG/C,YACkB,gBACA,YACA,SACA,qBACjB,eAA4B,CAAC,GACZ,QAChB;AANgB;AACA;AACA;AACA;AAEA;AAEjB,SAAK,aAAa;AAAA,MACjB,YAAY;AAAA,MACZ,OAAO,EAAE,GAAG,aAAa;AAAA,MACzB,SAAS,CAAC;AAAA,IACX;AAAA,EACD;AAAA,EAZkB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAEA;AAAA,EARV;AAAA;AAAA;AAAA;AAAA,EAoBR,MAAM,YAA0C;AAC/C,UAAM,QAAQ,KAAK,MAAM;AACzB,UAAM,aAAa;AAAA,MAClB,GAAG,MAAM;AAAA,MACT,OAAO,EAAE,GAAG,MAAM,WAAW,OAAO,GAAG,WAAW;AAAA,IACnD;AACA,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA,EAKA,QAAQ,OAAe,YAA8B,OAAwB;AAC5E,UAAM,QAAQ,KAAK,MAAM;AACzB,UAAM,aAAa;AAAA,MAClB,GAAG,MAAM;AAAA,MACT,SAAS,CAAC,GAAG,MAAM,WAAW,SAAS,EAAE,OAAO,UAAU,CAAC;AAAA,IAC5D;AACA,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,GAA4B;AACjC,UAAM,QAAQ,KAAK,MAAM;AACzB,UAAM,aAAa,EAAE,GAAG,MAAM,YAAY,OAAO,EAAE;AACnD,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO,GAA4B;AAClC,UAAM,QAAQ,KAAK,MAAM;AACzB,UAAM,aAAa,EAAE,GAAG,MAAM,YAAY,QAAQ,EAAE;AACpD,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAiBA,WAAW,SAAoC;AAC9C,UAAM,QAAQ,KAAK,MAAM;AACzB,UAAM,WAAW,MAAM,WAAW,WAAW,CAAC;AAC9C,UAAM,aAAa;AAAA,MAClB,GAAG,MAAM;AAAA,MACT,SAAS,CAAC,GAAG,UAAU,GAAG,OAAO;AAAA,IAClC;AACA,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,OAAqB;AAC1B,UAAM,EAAE,KAAK,OAAO,IAAI,iBAAiB,KAAK,YAAY,KAAK,WAAW,MAAM;AAChF,UAAM,OAAO,MAAM,KAAK,QAAQ,MAAwB,KAAK,MAAM;AACnE,UAAM,UAAU,KAAK,IAAI,CAAC,QAAQ,kBAAkB,KAAK,KAAK,WAAW,MAAM,CAAC;AAGhF,QAAI,KAAK,WAAW,WAAW,KAAK,WAAW,QAAQ,SAAS,KAAK,KAAK,QAAQ;AACjF,YAAM,KAAK,gBAAgB,OAAO;AAAA,IACnC;AAEA,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,QAAyB;AAC9B,UAAM,EAAE,KAAK,OAAO,IAAI,gBAAgB,KAAK,YAAY,KAAK,WAAW,MAAM;AAC/E,UAAM,OAAO,MAAM,KAAK,QAAQ,MAAyB,KAAK,MAAM;AACpE,WAAO,KAAK,CAAC,GAAG,SAAS;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,UAAU,UAA+C;AACxD,UAAM,YAAY,MAAM,KAAK,KAAK;AAGlC,UAAM,iBAAiB,EAAE,GAAG,KAAK,WAAW;AAC5C,QAAI,eAAe,WAAW,eAAe,QAAQ,SAAS,KAAK,KAAK,QAAQ;AAC/E,qBAAe,qBAAqB,KAAK,0BAA0B,eAAe,OAAO;AAAA,IAC1F;AAIA,WAAO,KAAK,oBAAoB;AAAA,MAC/B;AAAA,MACA;AAAA,MACA;AAAA,IACD;AAAA,EACD;AAAA;AAAA,EAGA,gBAAiC;AAChC,WAAO,EAAE,GAAG,KAAK,WAAW;AAAA,EAC7B;AAAA,EAEQ,QAAyB;AAChC,UAAM,KAAK,IAAI;AAAA,MACd,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,CAAC;AAAA,MACD,KAAK;AAAA,IACN;AACA,OAAG,aAAa;AAAA,MACf,GAAG,KAAK;AAAA,MACR,OAAO,EAAE,GAAG,KAAK,WAAW,MAAM;AAAA,MAClC,SAAS,CAAC,GAAG,KAAK,WAAW,OAAO;AAAA,MACpC,SAAS,KAAK,WAAW,UAAU,CAAC,GAAG,KAAK,WAAW,OAAO,IAAI;AAAA,MAClE,oBAAoB,KAAK,WAAW,qBACjC,CAAC,GAAG,KAAK,WAAW,kBAAkB,IACtC;AAAA,IACJ;AACA,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA,EAKQ,0BAA0B,SAA6B;AAC9D,QAAI,CAAC,KAAK,OAAQ,QAAO,CAAC;AAC1B,UAAM,cAAwB,CAAC;AAE/B,eAAW,UAAU,SAAS;AAC7B,YAAM,WAAW,KAAK,aAAa,MAAM;AACzC,UAAI,UAAU;AAGb,YAAI,SAAS,SAAS,KAAK,gBAAgB;AAC1C,sBAAY,KAAK,SAAS,EAAE;AAAA,QAC7B,OAAO;AACN,sBAAY,KAAK,SAAS,IAAI;AAAA,QAC/B;AAAA,MACD;AAAA,IACD;AAEA,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,gBAAgB,SAA4C;AACzE,QAAI,CAAC,KAAK,UAAU,CAAC,KAAK,WAAW,WAAW,QAAQ,WAAW,EAAG;AAEtE,eAAW,UAAU,KAAK,WAAW,SAAS;AAC7C,YAAM,WAAW,KAAK,aAAa,MAAM;AACzC,UAAI,CAAC,UAAU;AACd,cAAM,IAAIC;AAAA,UACT,yCAAyC,MAAM,oBAAoB,KAAK,cAAc,qEACnB,KAAK,cAAc,SAAS,MAAM;AAAA,QACtG;AAAA,MACD;AAEA,UAAI,SAAS,SAAS,KAAK,gBAAgB;AAE1C,cAAM,KAAK,wBAAwB,SAAS,UAAU,MAAM;AAAA,MAC7D,OAAO;AAEN,cAAM,KAAK,wBAAwB,SAAS,UAAU,MAAM;AAAA,MAC7D;AAAA,IACD;AAAA,EACD;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,wBACb,SACA,UACA,QACgB;AAChB,UAAM,UAAU,SAAS;AACzB,UAAM,WAAW,QACf,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC,EACrB,OAAO,CAAC,MAAmB,MAAM,QAAQ,MAAM,UAAa,OAAO,MAAM,QAAQ;AAEnF,QAAI,SAAS,WAAW,GAAG;AAE1B,YAAMC,YAAW,YAAY,MAAM;AACnC,iBAAW,UAAU,SAAS;AAC7B;AAAC,QAAC,OAAmCA,SAAQ,IAAI;AAAA,MAClD;AACA;AAAA,IACD;AAEA,UAAM,YAAY,CAAC,GAAG,IAAI,IAAI,QAAQ,CAAC;AACvC,UAAM,oBAAoB,SAAS;AACnC,UAAM,aAAa,KAAK,QAAQ,YAAY,iBAAiB;AAC7D,QAAI,CAAC,WAAY;AAGjB,UAAM,eAAe,UAAU,IAAI,MAAM,GAAG,EAAE,KAAK,IAAI;AACvD,UAAM,MAAM,iBAAiB,iBAAiB,iBAAiB,YAAY;AAC3E,UAAM,OAAO,MAAM,KAAK,QAAQ,MAAwB,KAAK,SAAS;AACtE,UAAM,iBAAiB,KAAK,IAAI,CAAC,QAAQ,kBAAkB,KAAK,WAAW,MAAM,CAAC;AAGlF,UAAM,SAAS,oBAAI,IAA8B;AACjD,eAAW,KAAK,gBAAgB;AAC/B,aAAO,IAAI,EAAE,IAAI,CAAC;AAAA,IACnB;AAGA,UAAM,WAAW,YAAY,MAAM;AACnC,eAAW,UAAU,SAAS;AAC7B,YAAM,KAAK,OAAO,OAAO;AACxB,MAAC,OAAmC,QAAQ,IAAI,KAAM,OAAO,IAAI,EAAE,KAAK,OAAQ;AAAA,IAClF;AAAA,EACD;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,wBACb,SACA,UACA,QACgB;AAChB,UAAM,aAAa,QAAQ,IAAI,CAAC,MAAM,EAAE,EAAE;AAC1C,UAAM,oBAAoB,SAAS;AACnC,UAAM,aAAa,KAAK,QAAQ,YAAY,iBAAiB;AAC7D,QAAI,CAAC,WAAY;AAEjB,UAAM,UAAU,SAAS;AACzB,UAAM,eAAe,WAAW,IAAI,MAAM,GAAG,EAAE,KAAK,IAAI;AACxD,UAAM,MAAM,iBAAiB,iBAAiB,UAAU,OAAO,QAAQ,YAAY;AACnF,UAAM,OAAO,MAAM,KAAK,QAAQ,MAAwB,KAAK,UAAU;AACvE,UAAM,iBAAiB,KAAK,IAAI,CAAC,QAAQ,kBAAkB,KAAK,WAAW,MAAM,CAAC;AAGlF,UAAM,UAAU,oBAAI,IAAgC;AACpD,eAAW,KAAK,gBAAgB;AAC/B,YAAM,KAAK,EAAE,OAAO;AACpB,UAAI,CAAC,QAAQ,IAAI,EAAE,GAAG;AACrB,gBAAQ,IAAI,IAAI,CAAC,CAAC;AAAA,MACnB;AACA,cAAQ,IAAI,EAAE,GAAG,KAAK,CAAC;AAAA,IACxB;AAGA,UAAM,WAAW,UAAU,MAAM;AACjC,eAAW,UAAU,SAAS;AAC7B;AAAC,MAAC,OAAmC,QAAQ,IAAI,QAAQ,IAAI,OAAO,EAAE,KAAK,CAAC;AAAA,IAC7E;AAAA,EACD;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,aACP,QACmE;AACnE,QAAI,CAAC,KAAK,OAAQ,QAAO;AAEzB,eAAW,CAAC,OAAO,GAAG,KAAK,OAAO,QAAQ,KAAK,OAAO,SAAS,GAAG;AAEjE,UAAI,IAAI,SAAS,KAAK,kBAAkB,IAAI,OAAO,OAAQ,QAAO;AAClE,UAAI,IAAI,OAAO,KAAK,kBAAkB,IAAI,SAAS,OAAQ,QAAO;AAGlE,UAAI,IAAI,SAAS,KAAK,kBAAkB,IAAI,OAAO,UAAU,MAAM,EAAG,QAAO;AAC7E,UAAI,IAAI,OAAO,KAAK,kBAAkB,IAAI,SAAS,UAAU,MAAM,EAAG,QAAO;AAG7E,UAAI,IAAI,SAAS,KAAK,kBAAkB,IAAI,OAAO,YAAY,MAAM,EAAG,QAAO;AAC/E,UAAI,IAAI,OAAO,KAAK,kBAAkB,IAAI,SAAS,YAAY,MAAM,EAAG,QAAO;AAAA,IAChF;AAEA,WAAO;AAAA,EACR;AACD;AAKA,IAAMD,cAAN,cAAyB,MAAM;AAAA,EAC9B,YAAY,SAAiB;AAC5B,UAAM,OAAO;AACb,SAAK,OAAO;AAAA,EACb;AACD;;;AC7VA,IAAI,YAAY;AAOT,IAAM,sBAAN,MAA0B;AAAA,EACxB,gBAAgB,oBAAI,IAA0B;AAAA,EAC9C,qBAAqB,oBAAI,IAAY;AAAA,EACrC,iBAAiB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUzB,SACC,YACA,UACA,WACa;AACb,UAAM,KAAK,OAAO,EAAE,SAAS;AAC7B,UAAM,eAA6B;AAAA,MAClC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,aAAa,CAAC;AAAA,IACf;AACA,SAAK,cAAc,IAAI,IAAI,YAAY;AAEvC,WAAO,MAAM;AACZ,WAAK,cAAc,OAAO,EAAE;AAAA,IAC7B;AAAA,EACD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,iBACC,YACA,UACA,WACa;AACb,UAAM,KAAK,OAAO,EAAE,SAAS;AAC7B,UAAM,eAA6B;AAAA,MAClC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,aAAa,CAAC;AAAA,IACf;AACA,SAAK,cAAc,IAAI,IAAI,YAAY;AAGvC,cAAU,EAAE,KAAK,CAAC,YAAY;AAE7B,UAAI,KAAK,cAAc,IAAI,EAAE,GAAG;AAC/B,qBAAa,cAAc;AAC3B,iBAAS,OAAO;AAAA,MACjB;AAAA,IACD,CAAC;AAED,WAAO,MAAM;AACZ,WAAK,cAAc,OAAO,EAAE;AAAA,IAC7B;AAAA,EACD;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,OAAO,YAAoB,YAA6B;AACvD,SAAK,mBAAmB,IAAI,UAAU;AACtC,SAAK,cAAc;AAAA,EACpB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,QAAuB;AAC5B,QAAI,KAAK,mBAAmB,SAAS,EAAG;AAExC,UAAM,cAAc,IAAI,IAAI,KAAK,kBAAkB;AACnD,SAAK,mBAAmB,MAAM;AAC9B,SAAK,iBAAiB;AAGtB,UAAM,WAA2B,CAAC;AAClC,eAAW,OAAO,KAAK,cAAc,OAAO,GAAG;AAC9C,UAAI,YAAY,IAAI,IAAI,WAAW,UAAU,GAAG;AAC/C,iBAAS,KAAK,GAAG;AAAA,MAClB,WAAW,IAAI,WAAW,oBAAoB;AAE7C,mBAAW,UAAU,IAAI,WAAW,oBAAoB;AACvD,cAAI,YAAY,IAAI,MAAM,GAAG;AAC5B,qBAAS,KAAK,GAAG;AACjB;AAAA,UACD;AAAA,QACD;AAAA,MACD;AAAA,IACD;AAGA,eAAW,OAAO,UAAU;AAC3B,UAAI;AACH,cAAM,aAAa,MAAM,IAAI,UAAU;AACvC,YAAI,CAAC,KAAK,aAAa,IAAI,aAAa,UAAU,GAAG;AACpD,cAAI,cAAc;AAClB,cAAI,SAAS,UAAU;AAAA,QACxB;AAAA,MACD,QAAQ;AAAA,MAGR;AAAA,IACD;AAAA,EACD;AAAA;AAAA;AAAA;AAAA,EAKA,QAAc;AACb,SAAK,cAAc,MAAM;AACzB,SAAK,mBAAmB,MAAM;AAC9B,SAAK,iBAAiB;AAAA,EACvB;AAAA;AAAA,EAGA,IAAI,OAAe;AAClB,WAAO,KAAK,cAAc;AAAA,EAC3B;AAAA,EAEQ,gBAAsB;AAC7B,QAAI,KAAK,eAAgB;AACzB,SAAK,iBAAiB;AACtB,mBAAe,MAAM;AACpB,WAAK,MAAM;AAAA,IACZ,CAAC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,aAAa,MAA0B,MAAmC;AACjF,QAAI,KAAK,WAAW,KAAK,OAAQ,QAAO;AAExC,QAAI,KAAK,WAAW,EAAG,QAAO;AAC9B,WAAO,KAAK,UAAU,IAAI,MAAM,KAAK,UAAU,IAAI;AAAA,EACpD;AACD;;;AP7HO,IAAM,QAAN,MAAoC;AAAA,EAClC,SAAS;AAAA,EACT,SAAS;AAAA,EACT,iBAAiB;AAAA,EACjB,gBAA+B,oBAAoB;AAAA,EACnD,QAAmC;AAAA,EACnC,cAAc,oBAAI,IAAwB;AAAA,EAC1C,sBAAsB,IAAI,oBAAoB;AAAA,EAErC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAEjB,YAAY,QAAqB;AAChC,SAAK,SAAS,OAAO;AACrB,SAAK,UAAU,OAAO;AACtB,SAAK,eAAe,OAAO;AAC3B,SAAK,UAAU,OAAO,WAAW;AAAA,EAClC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,OAAsB;AAC3B,UAAM,KAAK,QAAQ,KAAK,KAAK,MAAM;AAGnC,SAAK,SAAS,MAAM,KAAK,qBAAqB;AAC9C,SAAK,QAAQ,IAAIE,oBAAmB,KAAK,MAAM;AAG/C,SAAK,iBAAiB,MAAM,KAAK,mBAAmB;AACpD,SAAK,gBAAgB,MAAM,KAAK,kBAAkB;AAGlD,eAAW,CAAC,MAAM,UAAU,KAAK,OAAO,QAAQ,KAAK,OAAO,WAAW,GAAG;AACzE,YAAM,MAAM,IAAI;AAAA,QACf;AAAA,QACA;AAAA,QACA,KAAK;AAAA,QACL,KAAK;AAAA,QACL,KAAK;AAAA,QACL,KAAK;AAAA,QACL,MAAM,KAAK,mBAAmB;AAAA,QAC9B,CAAC,gBAAgB,cAAc;AAC9B,eAAK,oBAAoB,OAAO,gBAAgB,SAAS;AACzD,cAAI,KAAK,SAAS;AACjB,iBAAK,QAAQ,KAAK,EAAE,MAAM,qBAAqB,UAAU,CAAC;AAAA,UAC3D;AAAA,QACD;AAAA,MACD;AACA,WAAK,YAAY,IAAI,MAAM,GAAG;AAAA,IAC/B;AAEA,SAAK,SAAS;AAAA,EACf;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,QAAuB;AAC5B,SAAK,oBAAoB,MAAM;AAC/B,SAAK,YAAY,MAAM;AACvB,SAAK,SAAS;AACd,UAAM,KAAK,QAAQ,MAAM;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,WAAW,MAAkC;AAC5C,SAAK,WAAW;AAChB,UAAM,MAAM,KAAK,YAAY,IAAI,IAAI;AACrC,QAAI,CAAC,KAAK;AACT,YAAM,IAAI;AAAA,QACT,uBAAuB,IAAI,iBAAiB,CAAC,GAAG,KAAK,YAAY,KAAK,CAAC,EAAE,KAAK,IAAI,CAAC;AAAA,MACpF;AAAA,IACD;AAEA,UAAM,aAAa,KAAK,OAAO,YAAY,IAAI;AAC/C,QAAI,CAAC,YAAY;AAChB,YAAM,IAAI,MAAM,wCAAwC,IAAI,GAAG;AAAA,IAChE;AAEA,WAAO;AAAA,MACN,QAAQ,CAAC,SAAkC,IAAI,OAAO,IAAI;AAAA,MAC1D,UAAU,CAAC,OAAe,IAAI,SAAS,EAAE;AAAA,MACzC,QAAQ,CAAC,IAAY,SAAkC,IAAI,OAAO,IAAI,IAAI;AAAA,MAC1E,QAAQ,CAAC,OAAe,IAAI,OAAO,EAAE;AAAA,MACrC,OAAO,CAAC,eACP,IAAI,aAAa,MAAM,YAAY,KAAK,SAAS,KAAK,qBAAqB,YAAY,KAAK,MAAM;AAAA,IACpG;AAAA,EACD;AAAA;AAAA;AAAA;AAAA,EAKA,mBAAkC;AACjC,SAAK,WAAW;AAChB,WAAO,IAAI,IAAI,KAAK,aAAa;AAAA,EAClC;AAAA;AAAA;AAAA;AAAA,EAKA,YAAoB;AACnB,SAAK,WAAW;AAChB,WAAO,KAAK;AAAA,EACb;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,qBAAqB,IAAqC;AAC/D,SAAK,WAAW;AAEhB,UAAM,aAAa,GAAG;AACtB,UAAM,aAAa,KAAK,OAAO,YAAY,UAAU;AACrD,QAAI,CAAC,YAAY;AAChB,aAAO;AAAA,IACR;AAGA,UAAM,WAAW,MAAM,KAAK,QAAQ;AAAA,MACnC,4BAA4B,UAAU;AAAA,MACtC,CAAC,GAAG,EAAE;AAAA,IACP;AACA,QAAI,SAAS,SAAS,GAAG;AACxB,aAAO;AAAA,IACR;AAGA,QAAI,KAAK,OAAO;AACf,WAAK,MAAM,QAAQ,GAAG,SAAS;AAAA,IAChC;AAGA,UAAM,KAAK,QAAQ,YAAY,OAAO,OAAO;AAC5C,UAAI,GAAG,SAAS,YAAY,GAAG,MAAM;AACpC,cAAM,iBAAiB,gBAAgB,GAAG,MAAM,WAAW,MAAM;AACjE,cAAM,MAAM,GAAG,UAAU;AACzB,cAAM,SAAkC;AAAA,UACvC,IAAI,GAAG;AAAA,UACP,GAAG;AAAA,UACH,aAAa;AAAA,UACb,aAAa;AAAA,QACd;AACA,cAAM,cAAc,iBAAiB,YAAY,MAAM;AACvD,cAAM,GAAG,QAAQ,YAAY,KAAK,YAAY,MAAM;AAAA,MACrD,WAAW,GAAG,SAAS,YAAY,GAAG,MAAM;AAC3C,cAAM,oBAAoB,gBAAgB,GAAG,MAAM,WAAW,MAAM;AACpE,cAAM,cAAc,iBAAiB,YAAY,GAAG,UAAU;AAAA,UAC7D,GAAG;AAAA,UACH,aAAa,GAAG,UAAU;AAAA,QAC3B,CAAC;AACD,cAAM,GAAG,QAAQ,YAAY,KAAK,YAAY,MAAM;AAAA,MACrD,WAAW,GAAG,SAAS,UAAU;AAChC,cAAM,cAAc,qBAAqB,YAAY,GAAG,UAAU,GAAG,UAAU,QAAQ;AACvF,cAAM,GAAG,QAAQ,YAAY,KAAK,YAAY,MAAM;AAAA,MACrD;AAGA,YAAM,QAAQ,mBAAmB,EAAE;AACnC,YAAM,WAAW;AAAA,QAChB,aAAa,UAAU;AAAA,QACvB;AAAA,MACD;AACA,YAAM,GAAG,QAAQ,SAAS,KAAK,SAAS,MAAM;AAG9C,YAAM,aAAa,KAAK,cAAc,IAAI,GAAG,MAAM,KAAK;AACxD,UAAI,GAAG,iBAAiB,YAAY;AACnC,aAAK,cAAc,IAAI,GAAG,QAAQ,GAAG,cAAc;AACnD,cAAM,GAAG;AAAA,UACR;AAAA,UACA,CAAC,GAAG,QAAQ,GAAG,cAAc;AAAA,QAC9B;AAAA,MACD;AAAA,IACD,CAAC;AAGD,SAAK,oBAAoB,OAAO,YAAY,EAAE;AAE9C,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,SAAS,QAAgB,SAAiB,OAA4B;AAIrE,WAAO,CAAC;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,kBAAkB,QAAgB,SAAiB,OAAqC;AAC7F,SAAK,WAAW;AAChB,UAAM,SAAsB,CAAC;AAE7B,eAAW,kBAAkB,OAAO,KAAK,KAAK,OAAO,WAAW,GAAG;AAClE,YAAM,OAAO,MAAM,KAAK,QAAQ;AAAA,QAC/B,2BAA2B,cAAc;AAAA,QACzC,CAAC,QAAQ,SAAS,KAAK;AAAA,MACxB;AACA,iBAAW,OAAO,MAAM;AACvB,eAAO,KAAK,mCAAmC,KAAK,cAAc,CAAC;AAAA,MACpE;AAAA,IACD;AAGA,WAAO,KAAK,CAAC,GAAG,MAAM,EAAE,iBAAiB,EAAE,cAAc;AACzD,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA,EAKA,YAA8B;AAC7B,WAAO,KAAK;AAAA,EACb;AAAA;AAAA,EAGA,yBAA8C;AAC7C,WAAO,KAAK;AAAA,EACb;AAAA,EAEQ,qBAA6B;AACpC,SAAK;AACL,SAAK,cAAc,IAAI,KAAK,QAAQ,KAAK,cAAc;AACvD,WAAO,KAAK;AAAA,EACb;AAAA,EAEA,MAAc,uBAAwC;AACrD,QAAI,KAAK,cAAc;AAEtB,YAAM,KAAK,QAAQ;AAAA,QAClB;AAAA,QACA,CAAC,KAAK,YAAY;AAAA,MACnB;AACA,aAAO,KAAK;AAAA,IACb;AAGA,UAAM,OAAO,MAAM,KAAK,QAAQ;AAAA,MAC/B;AAAA,IACD;AACA,QAAI,KAAK,CAAC,GAAG;AACZ,aAAO,KAAK,CAAC,EAAE;AAAA,IAChB;AAGA,UAAM,YAAYC,gBAAe;AACjC,UAAM,KAAK,QAAQ,QAAQ,6DAA6D;AAAA,MACvF;AAAA,IACD,CAAC;AACD,WAAO;AAAA,EACR;AAAA,EAEA,MAAc,qBAAsC;AACnD,UAAM,OAAO,MAAM,KAAK,QAAQ;AAAA,MAC/B;AAAA,MACA,CAAC,KAAK,MAAM;AAAA,IACb;AACA,WAAO,KAAK,CAAC,GAAG,mBAAmB;AAAA,EACpC;AAAA,EAEA,MAAc,oBAA4C;AACzD,UAAM,OAAO,MAAM,KAAK,QAAQ;AAAA,MAC/B;AAAA,IACD;AACA,UAAM,SAAS,oBAAoB;AACnC,eAAW,OAAO,MAAM;AACvB,aAAO,IAAI,IAAI,SAAS,IAAI,eAAe;AAAA,IAC5C;AACA,WAAO;AAAA,EACR;AAAA,EAEQ,aAAmB;AAC1B,QAAI,CAAC,KAAK,QAAQ;AACjB,YAAM,IAAI,kBAAkB;AAAA,IAC7B;AAAA,EACD;AACD;","names":["HybridLogicalClock","generateUUIDv7","QueryError","propName","HybridLogicalClock","generateUUIDv7"]}
1
+ {"version":3,"sources":["../src/store/store.ts","../src/collection/collection.ts","../src/query/sql-builder.ts","../src/serialization/serializer.ts","../src/serialization/richtext-serializer.ts","../src/state-machine/state-validator.ts","../src/query/pluralize.ts","../src/query/query-builder.ts","../src/relations/relation-enforcer.ts","../src/relations/relation-lookup.ts","../src/sequences/sequence-manager.ts","../src/subscription/bloom-filter.ts","../src/subscription/subscription-manager.ts","../src/transaction/transaction-context.ts"],"sourcesContent":["import {\n\tHybridLogicalClock,\n\tcreateVersionVector,\n\tgenerateUUIDv7,\n\tmigrationStepsToSQL,\n} from '@korajs/core'\nimport type {\n\tKoraEventEmitter,\n\tMigrationStep,\n\tOperation,\n\tOperationLog,\n\tSchemaDefinition,\n\tVersionVector,\n} from '@korajs/core'\nimport { Collection } from '../collection/collection'\nimport { StoreNotOpenError } from '../errors'\nimport { QueryBuilder } from '../query/query-builder'\nimport { buildInsertQuery, buildSoftDeleteQuery, buildUpdateQuery } from '../query/sql-builder'\nimport { RelationEnforcer } from '../relations/relation-enforcer'\nimport { SequenceManager } from '../sequences/sequence-manager'\nimport {\n\tdeserializeOperationWithCollection,\n\tserializeOperation,\n\tserializeRecord,\n} from '../serialization/serializer'\nimport { SubscriptionManager } from '../subscription/subscription-manager'\nimport { TransactionContext } from '../transaction/transaction-context'\nimport type {\n\tApplyResult,\n\tMetaRow,\n\tOperationRow,\n\tRawCollectionRow,\n\tStorageAdapter,\n\tStoreConfig,\n\tVersionVectorRow,\n} from '../types'\n\n/**\n * Store is the main orchestrator. It owns a schema, a storage adapter,\n * a clock, and a subscription manager. It creates Collection instances\n * for each schema collection, and provides the sync contract via\n * applyRemoteOperation and getOperationRange.\n *\n * @example\n * ```typescript\n * const store = new Store({ schema, adapter })\n * await store.open()\n * const todo = await store.collection('todos').insert({ title: 'Hello' })\n * await store.close()\n * ```\n */\nexport class Store implements OperationLog {\n\tprivate opened = false\n\tprivate nodeId = ''\n\tprivate sequenceNumber = 0\n\tprivate versionVector: VersionVector = createVersionVector()\n\tprivate clock: HybridLogicalClock | null = null\n\tprivate collections = new Map<string, Collection>()\n\tprivate subscriptionManager = new SubscriptionManager()\n\tprivate sequenceManager: SequenceManager | null = null\n\n\tprivate readonly schema: SchemaDefinition\n\tprivate readonly adapter: StorageAdapter\n\tprivate readonly configNodeId: string | undefined\n\tprivate readonly emitter: KoraEventEmitter | null\n\n\tconstructor(config: StoreConfig) {\n\t\tthis.schema = config.schema\n\t\tthis.adapter = config.adapter\n\t\tthis.configNodeId = config.nodeId\n\t\tthis.emitter = config.emitter ?? null\n\t}\n\n\t/**\n\t * Open the store: initialize the database, load or generate a node ID,\n\t * restore the sequence number and version vector, and create Collection instances.\n\t */\n\tasync open(): Promise<void> {\n\t\tawait this.adapter.open(this.schema)\n\n\t\t// Run schema migrations if needed\n\t\tawait this.runMigrationsIfNeeded()\n\n\t\t// Load or generate node ID\n\t\tthis.nodeId = await this.loadOrGenerateNodeId()\n\t\tthis.clock = new HybridLogicalClock(this.nodeId)\n\n\t\t// Initialize sequence manager\n\t\tthis.sequenceManager = new SequenceManager(this.adapter, this.nodeId)\n\n\t\t// Load sequence number and version vector\n\t\tthis.sequenceNumber = await this.loadSequenceNumber()\n\t\tthis.versionVector = await this.loadVersionVector()\n\n\t\t// Create RelationEnforcer if the schema has relations.\n\t\t// The enforcer is shared across all Collection instances so that\n\t\t// cascading deletes can cross collection boundaries.\n\t\tconst hasRelations = Object.keys(this.schema.relations).length > 0\n\t\tconst relationEnforcer = hasRelations\n\t\t\t? new RelationEnforcer({\n\t\t\t\t\tschema: this.schema,\n\t\t\t\t\tadapter: this.adapter,\n\t\t\t\t\tclock: this.clock,\n\t\t\t\t\tnodeId: this.nodeId,\n\t\t\t\t\tgetSequenceNumber: () => this.nextSequenceNumber(),\n\t\t\t\t})\n\t\t\t: undefined\n\n\t\t// Create collection instances\n\t\tfor (const [name, definition] of Object.entries(this.schema.collections)) {\n\t\t\tconst col = new Collection(\n\t\t\t\tname,\n\t\t\t\tdefinition,\n\t\t\t\tthis.schema,\n\t\t\t\tthis.adapter,\n\t\t\t\tthis.clock,\n\t\t\t\tthis.nodeId,\n\t\t\t\t() => this.nextSequenceNumber(),\n\t\t\t\t(collectionName, operation) => {\n\t\t\t\t\tthis.subscriptionManager.notify(collectionName, operation)\n\t\t\t\t\tif (this.emitter) {\n\t\t\t\t\t\tthis.emitter.emit({ type: 'operation:created', operation })\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\trelationEnforcer,\n\t\t\t)\n\t\t\tthis.collections.set(name, col)\n\t\t}\n\n\t\tthis.opened = true\n\t}\n\n\t/**\n\t * Close the store: clear subscriptions and close the adapter.\n\t */\n\tasync close(): Promise<void> {\n\t\tthis.subscriptionManager.clear()\n\t\tthis.collections.clear()\n\t\tthis.opened = false\n\t\tawait this.adapter.close()\n\t}\n\n\t/**\n\t * Get a Collection instance for CRUD operations.\n\t * @throws {StoreNotOpenError} If the store is not open\n\t * @throws {Error} If the collection name is not in the schema\n\t */\n\tcollection(name: string): CollectionAccessor {\n\t\tthis.ensureOpen()\n\t\tconst col = this.collections.get(name)\n\t\tif (!col) {\n\t\t\tthrow new Error(\n\t\t\t\t`Unknown collection \"${name}\". Available: ${[...this.collections.keys()].join(', ')}`,\n\t\t\t)\n\t\t}\n\n\t\tconst definition = this.schema.collections[name]\n\t\tif (!definition) {\n\t\t\tthrow new Error(`Collection definition not found for \"${name}\"`)\n\t\t}\n\n\t\treturn {\n\t\t\tinsert: (data: Record<string, unknown>) => col.insert(data),\n\t\t\tfindById: (id: string) => col.findById(id),\n\t\t\tupdate: (id: string, data: Record<string, unknown>) => col.update(id, data),\n\t\t\tdelete: (id: string) => col.delete(id),\n\t\t\twhere: (conditions) =>\n\t\t\t\tnew QueryBuilder(\n\t\t\t\t\tname,\n\t\t\t\t\tdefinition,\n\t\t\t\t\tthis.adapter,\n\t\t\t\t\tthis.subscriptionManager,\n\t\t\t\t\tconditions,\n\t\t\t\t\tthis.schema,\n\t\t\t\t),\n\t\t}\n\t}\n\n\t/**\n\t * Get the current version vector.\n\t */\n\tgetVersionVector(): VersionVector {\n\t\tthis.ensureOpen()\n\t\treturn new Map(this.versionVector)\n\t}\n\n\t/**\n\t * Get the node ID for this store instance.\n\t */\n\tgetNodeId(): string {\n\t\tthis.ensureOpen()\n\t\treturn this.nodeId\n\t}\n\n\t/**\n\t * Apply a remote operation received from sync.\n\t * Checks for duplicates, applies to the data table, persists the operation,\n\t * and updates the version vector.\n\t */\n\tasync applyRemoteOperation(op: Operation): Promise<ApplyResult> {\n\t\tthis.ensureOpen()\n\n\t\tconst collection = op.collection\n\t\tconst definition = this.schema.collections[collection]\n\t\tif (!definition) {\n\t\t\treturn 'skipped'\n\t\t}\n\n\t\t// Check for duplicate (content-addressed dedup)\n\t\tconst existing = await this.adapter.query<{ id: string }>(\n\t\t\t`SELECT id FROM _kora_ops_${collection} WHERE id = ?`,\n\t\t\t[op.id],\n\t\t)\n\t\tif (existing.length > 0) {\n\t\t\treturn 'duplicate'\n\t\t}\n\n\t\t// Update the clock with the remote timestamp\n\t\tif (this.clock) {\n\t\t\tthis.clock.receive(op.timestamp)\n\t\t}\n\n\t\t// Apply the operation to the data table\n\t\tawait this.adapter.transaction(async (tx) => {\n\t\t\tif (op.type === 'insert' && op.data) {\n\t\t\t\tconst serializedData = serializeRecord(op.data, definition.fields)\n\t\t\t\tconst now = op.timestamp.wallTime\n\t\t\t\tconst record: Record<string, unknown> = {\n\t\t\t\t\tid: op.recordId,\n\t\t\t\t\t...serializedData,\n\t\t\t\t\t_created_at: now,\n\t\t\t\t\t_updated_at: now,\n\t\t\t\t}\n\t\t\t\tconst insertQuery = buildInsertQuery(collection, record)\n\t\t\t\tawait tx.execute(insertQuery.sql, insertQuery.params)\n\t\t\t} else if (op.type === 'update' && op.data) {\n\t\t\t\tconst serializedChanges = serializeRecord(op.data, definition.fields)\n\t\t\t\tconst updateQuery = buildUpdateQuery(collection, op.recordId, {\n\t\t\t\t\t...serializedChanges,\n\t\t\t\t\t_updated_at: op.timestamp.wallTime,\n\t\t\t\t})\n\t\t\t\tawait tx.execute(updateQuery.sql, updateQuery.params)\n\t\t\t} else if (op.type === 'delete') {\n\t\t\t\tconst deleteQuery = buildSoftDeleteQuery(collection, op.recordId, op.timestamp.wallTime)\n\t\t\t\tawait tx.execute(deleteQuery.sql, deleteQuery.params)\n\t\t\t}\n\n\t\t\t// Persist the operation\n\t\t\tconst opRow = serializeOperation(op)\n\t\t\tconst opInsert = buildInsertQuery(\n\t\t\t\t`_kora_ops_${collection}`,\n\t\t\t\topRow as unknown as Record<string, unknown>,\n\t\t\t)\n\t\t\tawait tx.execute(opInsert.sql, opInsert.params)\n\n\t\t\t// Update version vector\n\t\t\tconst currentSeq = this.versionVector.get(op.nodeId) ?? 0\n\t\t\tif (op.sequenceNumber > currentSeq) {\n\t\t\t\tthis.versionVector.set(op.nodeId, op.sequenceNumber)\n\t\t\t\tawait tx.execute(\n\t\t\t\t\t'INSERT OR REPLACE INTO _kora_version_vector (node_id, sequence_number) VALUES (?, ?)',\n\t\t\t\t\t[op.nodeId, op.sequenceNumber],\n\t\t\t\t)\n\t\t\t}\n\t\t})\n\n\t\t// Notify subscriptions\n\t\tthis.subscriptionManager.notify(collection, op)\n\n\t\treturn 'applied'\n\t}\n\n\t/**\n\t * Get operations from a node within a sequence number range.\n\t * Implements the OperationLog interface for computeDelta.\n\t */\n\tgetRange(nodeId: string, fromSeq: number, toSeq: number): Operation[] {\n\t\t// This is synchronous per the OperationLog interface.\n\t\t// We can't use async here, so this must be called with data already loaded.\n\t\t// For now, this is a placeholder that the sync layer will call after awaiting.\n\t\treturn []\n\t}\n\n\t/**\n\t * Async version of getRange for use by the sync layer.\n\t */\n\tasync getOperationRange(nodeId: string, fromSeq: number, toSeq: number): Promise<Operation[]> {\n\t\tthis.ensureOpen()\n\t\tconst allOps: Operation[] = []\n\n\t\tfor (const collectionName of Object.keys(this.schema.collections)) {\n\t\t\tconst rows = await this.adapter.query<OperationRow>(\n\t\t\t\t`SELECT * FROM _kora_ops_${collectionName} WHERE node_id = ? AND sequence_number >= ? AND sequence_number <= ? ORDER BY sequence_number ASC`,\n\t\t\t\t[nodeId, fromSeq, toSeq],\n\t\t\t)\n\t\t\tfor (const row of rows) {\n\t\t\t\tallOps.push(deserializeOperationWithCollection(row, collectionName))\n\t\t\t}\n\t\t}\n\n\t\t// Sort by sequence number across collections\n\t\tallOps.sort((a, b) => a.sequenceNumber - b.sequenceNumber)\n\t\treturn allOps\n\t}\n\n\t/**\n\t * Get the schema definition.\n\t */\n\tgetSchema(): SchemaDefinition {\n\t\treturn this.schema\n\t}\n\n\t/** Expose the subscription manager for direct access (e.g., by QueryBuilder) */\n\tgetSubscriptionManager(): SubscriptionManager {\n\t\treturn this.subscriptionManager\n\t}\n\n\t/**\n\t * Get the sequence manager for offline-safe sequence generation.\n\t * @throws {StoreNotOpenError} If the store is not open\n\t */\n\tgetSequenceManager(): SequenceManager {\n\t\tthis.ensureOpen()\n\t\tif (!this.sequenceManager) {\n\t\t\tthrow new StoreNotOpenError()\n\t\t}\n\t\treturn this.sequenceManager\n\t}\n\n\t/**\n\t * Create a TransactionContext for atomic multi-collection operations.\n\t * The returned context buffers all mutations and commits them atomically.\n\t *\n\t * After commit, the caller is responsible for notifying subscriptions\n\t * and emitting events for each operation.\n\t */\n\tcreateTransaction(): TransactionContext {\n\t\tthis.ensureOpen()\n\t\tif (!this.clock) {\n\t\t\tthrow new StoreNotOpenError()\n\t\t}\n\t\treturn new TransactionContext({\n\t\t\tschema: this.schema,\n\t\t\tadapter: this.adapter,\n\t\t\tclock: this.clock,\n\t\t\tnodeId: this.nodeId,\n\t\t\tgetSequenceNumber: () => this.nextSequenceNumber(),\n\t\t})\n\t}\n\n\t/**\n\t * Execute a function within a transaction. All mutations performed on the\n\t * TransactionContext are committed atomically. Subscription notifications\n\t * are batched and fired after the commit.\n\t *\n\t * If the function throws, the transaction is rolled back and the error is re-thrown.\n\t *\n\t * @param fn - Function receiving a TransactionContext for buffered operations\n\t * @returns The operations that were committed\n\t */\n\tasync transaction(fn: (tx: TransactionContext) => Promise<void>): Promise<Operation[]> {\n\t\tconst tx = this.createTransaction()\n\t\ttry {\n\t\t\tawait fn(tx)\n\t\t\tconst { operations, affectedCollections } = await tx.commit()\n\n\t\t\t// Notify subscriptions and emit events after commit\n\t\t\tfor (const op of operations) {\n\t\t\t\tthis.subscriptionManager.notify(op.collection, op)\n\t\t\t\tif (this.emitter) {\n\t\t\t\t\tthis.emitter.emit({ type: 'operation:created', operation: op })\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn operations\n\t\t} catch (error) {\n\t\t\ttx.rollback()\n\t\t\tthrow error\n\t\t}\n\t}\n\n\tprivate nextSequenceNumber(): number {\n\t\tthis.sequenceNumber++\n\t\tthis.versionVector.set(this.nodeId, this.sequenceNumber)\n\t\treturn this.sequenceNumber\n\t}\n\n\t/**\n\t * Check the stored schema version and run any pending migrations.\n\t * Migrations are applied in version order within a transaction.\n\t */\n\tprivate async runMigrationsIfNeeded(): Promise<void> {\n\t\tconst storedVersion = await this.getStoredSchemaVersion()\n\t\tconst targetVersion = this.schema.version\n\n\t\tif (storedVersion >= targetVersion) {\n\t\t\t// Already up to date (or first run with version 1)\n\t\t\tif (storedVersion === 0) {\n\t\t\t\t// First open — store the initial version\n\t\t\t\tawait this.adapter.execute(\n\t\t\t\t\t\"INSERT OR REPLACE INTO _kora_meta (key, value) VALUES ('schema_version', ?)\",\n\t\t\t\t\t[String(targetVersion)],\n\t\t\t\t)\n\t\t\t}\n\t\t\treturn\n\t\t}\n\n\t\t// Run each migration in order from storedVersion+1 to targetVersion\n\t\tconst migrations = this.schema.migrations ?? {}\n\t\tfor (let v = storedVersion + 1; v <= targetVersion; v++) {\n\t\t\tconst migration = migrations[v]\n\t\t\tif (!migration) continue\n\n\t\t\t// Generate SQL from structural steps\n\t\t\tconst sqlStatements = migrationStepsToSQL(migration.steps)\n\n\t\t\t// Execute structural changes individually, tolerating \"duplicate column\" errors\n\t\t\t// because generateFullDDL already runs safe-alter for the current schema's columns.\n\t\t\tfor (const sql of sqlStatements) {\n\t\t\t\ttry {\n\t\t\t\t\tawait this.adapter.execute(sql)\n\t\t\t\t} catch (e) {\n\t\t\t\t\tconst msg = (e as Error).message || ''\n\t\t\t\t\tif (!msg.includes('duplicate column name')) {\n\t\t\t\t\t\tthrow e\n\t\t\t\t\t}\n\t\t\t\t\t// Column already exists (added by generateFullDDL) — safe to skip\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Run backfills in a transaction\n\t\t\tconst backfillSteps = migration.steps.filter(\n\t\t\t\t(s): s is Extract<MigrationStep, { type: 'backfill' }> => s.type === 'backfill',\n\t\t\t)\n\t\t\tfor (const step of backfillSteps) {\n\t\t\t\tawait this.runBackfill(step.collection, step.transform)\n\t\t\t}\n\t\t}\n\n\t\t// Update stored schema version\n\t\tawait this.adapter.execute(\n\t\t\t\"INSERT OR REPLACE INTO _kora_meta (key, value) VALUES ('schema_version', ?)\",\n\t\t\t[String(targetVersion)],\n\t\t)\n\t}\n\n\t/**\n\t * Get the stored schema version from _kora_meta. Returns 0 if not set.\n\t */\n\tprivate async getStoredSchemaVersion(): Promise<number> {\n\t\tconst rows = await this.adapter.query<MetaRow>(\n\t\t\t\"SELECT value FROM _kora_meta WHERE key = 'schema_version'\",\n\t\t)\n\t\treturn rows[0] ? Number(rows[0].value) : 0\n\t}\n\n\t/**\n\t * Run a backfill transform on all records in a collection.\n\t * Reads all rows, applies the transform, and updates changed fields.\n\t */\n\tprivate async runBackfill(\n\t\tcollection: string,\n\t\ttransform: (record: Record<string, unknown>) => Record<string, unknown>,\n\t): Promise<void> {\n\t\tconst rows = await this.adapter.query<RawCollectionRow>(\n\t\t\t`SELECT * FROM ${collection} WHERE _deleted = 0`,\n\t\t)\n\n\t\tawait this.adapter.transaction(async (tx) => {\n\t\t\tfor (const row of rows) {\n\t\t\t\tconst updates = transform(row as Record<string, unknown>)\n\t\t\t\tconst fields = Object.keys(updates)\n\t\t\t\tif (fields.length === 0) continue\n\n\t\t\t\tconst setClauses = fields.map((f) => `${f} = ?`).join(', ')\n\t\t\t\tconst values = fields.map((f) => {\n\t\t\t\t\tconst val = updates[f]\n\t\t\t\t\t// Serialize booleans to 0/1 for SQLite\n\t\t\t\t\tif (typeof val === 'boolean') return val ? 1 : 0\n\t\t\t\t\t// Serialize arrays/objects to JSON\n\t\t\t\t\tif (Array.isArray(val) || (typeof val === 'object' && val !== null)) {\n\t\t\t\t\t\treturn JSON.stringify(val)\n\t\t\t\t\t}\n\t\t\t\t\treturn val\n\t\t\t\t})\n\t\t\t\tvalues.push(row.id)\n\n\t\t\t\tawait tx.execute(`UPDATE ${collection} SET ${setClauses} WHERE id = ?`, values)\n\t\t\t}\n\t\t})\n\t}\n\n\tprivate async loadOrGenerateNodeId(): Promise<string> {\n\t\tif (this.configNodeId) {\n\t\t\t// Persist the configured node ID\n\t\t\tawait this.adapter.execute(\n\t\t\t\t\"INSERT OR REPLACE INTO _kora_meta (key, value) VALUES ('node_id', ?)\",\n\t\t\t\t[this.configNodeId],\n\t\t\t)\n\t\t\treturn this.configNodeId\n\t\t}\n\n\t\t// Try to load existing node ID\n\t\tconst rows = await this.adapter.query<MetaRow>(\n\t\t\t\"SELECT value FROM _kora_meta WHERE key = 'node_id'\",\n\t\t)\n\t\tif (rows[0]) {\n\t\t\treturn rows[0].value\n\t\t}\n\n\t\t// Generate new node ID\n\t\tconst newNodeId = generateUUIDv7()\n\t\tawait this.adapter.execute(\"INSERT INTO _kora_meta (key, value) VALUES ('node_id', ?)\", [\n\t\t\tnewNodeId,\n\t\t])\n\t\treturn newNodeId\n\t}\n\n\tprivate async loadSequenceNumber(): Promise<number> {\n\t\tconst rows = await this.adapter.query<VersionVectorRow>(\n\t\t\t'SELECT sequence_number FROM _kora_version_vector WHERE node_id = ?',\n\t\t\t[this.nodeId],\n\t\t)\n\t\treturn rows[0]?.sequence_number ?? 0\n\t}\n\n\tprivate async loadVersionVector(): Promise<VersionVector> {\n\t\tconst rows = await this.adapter.query<VersionVectorRow>(\n\t\t\t'SELECT node_id, sequence_number FROM _kora_version_vector',\n\t\t)\n\t\tconst vector = createVersionVector()\n\t\tfor (const row of rows) {\n\t\t\tvector.set(row.node_id, row.sequence_number)\n\t\t}\n\t\treturn vector\n\t}\n\n\tprivate ensureOpen(): void {\n\t\tif (!this.opened) {\n\t\t\tthrow new StoreNotOpenError()\n\t\t}\n\t}\n}\n\n/**\n * Public-facing collection accessor. Provides CRUD + where.\n */\nexport interface CollectionAccessor {\n\tinsert(data: Record<string, unknown>): Promise<import('../types').CollectionRecord>\n\tfindById(id: string): Promise<import('../types').CollectionRecord | null>\n\tupdate(id: string, data: Record<string, unknown>): Promise<import('../types').CollectionRecord>\n\tdelete(id: string): Promise<void>\n\twhere(conditions: Record<string, unknown>): QueryBuilder\n}\n","import type {\n\tAtomicOp,\n\tCollectionDefinition,\n\tHLCTimestamp,\n\tHybridLogicalClock,\n\tOperation,\n\tSchemaDefinition,\n} from '@korajs/core'\nimport {\n\tcreateOperation,\n\tgenerateUUIDv7,\n\tisAtomicOp,\n\tresolveAtomicOp,\n\ttoAtomicOp,\n\tvalidateRecord,\n} from '@korajs/core'\nimport { RecordNotFoundError } from '../errors'\nimport { buildInsertQuery, buildSoftDeleteQuery, buildUpdateQuery } from '../query/sql-builder'\nimport type { RelationEnforcer } from '../relations/relation-enforcer'\nimport { deserializeRecord, serializeOperation, serializeRecord } from '../serialization/serializer'\nimport { validateUpdateStateMachine } from '../state-machine/state-validator'\nimport type { CollectionRecord, RawCollectionRow, StorageAdapter } from '../types'\n\n/**\n * Callback invoked after a mutation so the Store can notify subscriptions.\n */\nexport type MutationCallback = (collection: string, operation: Operation) => void\n\n/**\n * Collection provides CRUD operations on a single schema collection.\n * Each mutation creates an Operation and persists both the data and the operation atomically.\n *\n * When a RelationEnforcer is provided, delete operations enforce referential integrity\n * policies (cascade, set-null, restrict) defined in the schema's relations.\n */\nexport class Collection {\n\tprivate readonly relationEnforcer: RelationEnforcer | null\n\n\tconstructor(\n\t\tprivate readonly name: string,\n\t\tprivate readonly definition: CollectionDefinition,\n\t\tprivate readonly schema: SchemaDefinition,\n\t\tprivate readonly adapter: StorageAdapter,\n\t\tprivate readonly clock: HybridLogicalClock,\n\t\tprivate readonly nodeId: string,\n\t\tprivate readonly getSequenceNumber: () => number,\n\t\tprivate readonly onMutation: MutationCallback,\n\t\trelationEnforcer?: RelationEnforcer,\n\t) {\n\t\tthis.relationEnforcer = relationEnforcer ?? null\n\t}\n\n\t/**\n\t * Insert a new record into the collection.\n\t * Generates a UUID v7 for the id, validates data, and persists atomically.\n\t *\n\t * @param data - The record data (auto fields and defaults are applied automatically)\n\t * @returns The inserted record with id, createdAt, updatedAt\n\t */\n\tasync insert(data: Record<string, unknown>): Promise<CollectionRecord> {\n\t\tconst validated = validateRecord(this.name, this.definition, data, 'insert')\n\t\tconst recordId = generateUUIDv7()\n\t\tconst now = Date.now()\n\n\t\t// Set auto timestamp fields\n\t\tfor (const [fieldName, descriptor] of Object.entries(this.definition.fields)) {\n\t\t\tif (descriptor.auto && descriptor.kind === 'timestamp') {\n\t\t\t\tvalidated[fieldName] = now\n\t\t\t}\n\t\t}\n\n\t\tconst sequenceNumber = this.getSequenceNumber()\n\t\tconst operation = await createOperation(\n\t\t\t{\n\t\t\t\tnodeId: this.nodeId,\n\t\t\t\ttype: 'insert',\n\t\t\t\tcollection: this.name,\n\t\t\t\trecordId,\n\t\t\t\tdata: { ...validated },\n\t\t\t\tpreviousData: null,\n\t\t\t\tsequenceNumber,\n\t\t\t\tcausalDeps: [],\n\t\t\t\tschemaVersion: this.schema.version,\n\t\t\t},\n\t\t\tthis.clock,\n\t\t)\n\n\t\tconst serializedData = serializeRecord(validated, this.definition.fields)\n\t\tconst record: Record<string, unknown> = {\n\t\t\tid: recordId,\n\t\t\t...serializedData,\n\t\t\t_created_at: now,\n\t\t\t_updated_at: now,\n\t\t}\n\n\t\tconst insertQuery = buildInsertQuery(this.name, record)\n\t\tconst opRow = serializeOperation(operation)\n\t\tconst opInsert = buildInsertQuery(\n\t\t\t`_kora_ops_${this.name}`,\n\t\t\topRow as unknown as Record<string, unknown>,\n\t\t)\n\n\t\tawait this.adapter.transaction(async (tx) => {\n\t\t\tawait tx.execute(insertQuery.sql, insertQuery.params)\n\t\t\tawait tx.execute(opInsert.sql, opInsert.params)\n\t\t\tawait tx.execute(\n\t\t\t\t'INSERT OR REPLACE INTO _kora_version_vector (node_id, sequence_number) VALUES (?, ?)',\n\t\t\t\t[this.nodeId, sequenceNumber],\n\t\t\t)\n\t\t})\n\n\t\tthis.onMutation(this.name, operation)\n\n\t\treturn {\n\t\t\tid: recordId,\n\t\t\t...validated,\n\t\t\tcreatedAt: now,\n\t\t\tupdatedAt: now,\n\t\t}\n\t}\n\n\t/**\n\t * Find a record by its ID. Returns null if not found or soft-deleted.\n\t */\n\tasync findById(id: string): Promise<CollectionRecord | null> {\n\t\tconst rows = await this.adapter.query<RawCollectionRow>(\n\t\t\t`SELECT * FROM ${this.name} WHERE id = ? AND _deleted = 0`,\n\t\t\t[id],\n\t\t)\n\n\t\tconst row = rows[0]\n\t\tif (!row) return null\n\t\treturn deserializeRecord(row, this.definition.fields)\n\t}\n\n\t/**\n\t * Update an existing record. Only the provided fields are changed.\n\t *\n\t * @param id - The record ID to update\n\t * @param data - Partial data with only the fields to change\n\t * @returns The updated record\n\t * @throws {RecordNotFoundError} If the record doesn't exist or is deleted\n\t */\n\tasync update(id: string, data: Record<string, unknown>): Promise<CollectionRecord> {\n\t\tconst currentRows = await this.adapter.query<RawCollectionRow>(\n\t\t\t`SELECT * FROM ${this.name} WHERE id = ? AND _deleted = 0`,\n\t\t\t[id],\n\t\t)\n\t\tconst currentRow = currentRows[0]\n\t\tif (!currentRow) {\n\t\t\tthrow new RecordNotFoundError(this.name, id)\n\t\t}\n\n\t\tlet validated = validateRecord(this.name, this.definition, data, 'update')\n\t\tconst now = Date.now()\n\n\t\t// Validate state machine transitions before proceeding.\n\t\t// In 'last-valid-state' mode this may strip the state field from validated data.\n\t\t// In 'reject' mode this will throw InvalidStateTransitionError.\n\t\tconst currentRecord = deserializeRecord(currentRow, this.definition.fields)\n\t\tvalidated = validateUpdateStateMachine(\n\t\t\tthis.name,\n\t\t\tid,\n\t\t\tthis.definition,\n\t\t\tcurrentRecord,\n\t\t\tvalidated,\n\t\t)\n\n\t\t// If state machine validation removed all fields, the update is a no-op.\n\t\tif (Object.keys(validated).length === 0) {\n\t\t\tconst fullRecord = await this.findById(id)\n\t\t\tif (!fullRecord) {\n\t\t\t\tthrow new RecordNotFoundError(this.name, id)\n\t\t\t}\n\t\t\treturn fullRecord\n\t\t}\n\n\t\t// Build previousData from current row for the changed fields,\n\t\t// and resolve any atomic op sentinels to concrete values.\n\t\tconst previousData: Record<string, unknown> = {}\n\t\tconst resolvedData: Record<string, unknown> = {}\n\t\tconst atomicOps: Record<string, AtomicOp> = {}\n\n\t\tfor (const key of Object.keys(validated)) {\n\t\t\tconst value = validated[key]\n\t\t\tpreviousData[key] = currentRecord[key]\n\n\t\t\tif (isAtomicOp(value)) {\n\t\t\t\t// Resolve the sentinel to a concrete value using the current record state\n\t\t\t\tresolvedData[key] = resolveAtomicOp(currentRecord[key], value)\n\t\t\t\tatomicOps[key] = toAtomicOp(value)\n\t\t\t} else {\n\t\t\t\tresolvedData[key] = value\n\t\t\t}\n\t\t}\n\n\t\tconst hasAtomicOps = Object.keys(atomicOps).length > 0\n\n\t\tconst sequenceNumber = this.getSequenceNumber()\n\t\tconst operation = await createOperation(\n\t\t\t{\n\t\t\t\tnodeId: this.nodeId,\n\t\t\t\ttype: 'update',\n\t\t\t\tcollection: this.name,\n\t\t\t\trecordId: id,\n\t\t\t\tdata: { ...resolvedData },\n\t\t\t\tpreviousData,\n\t\t\t\tsequenceNumber,\n\t\t\t\tcausalDeps: [],\n\t\t\t\tschemaVersion: this.schema.version,\n\t\t\t\t...(hasAtomicOps ? { atomicOps } : {}),\n\t\t\t},\n\t\t\tthis.clock,\n\t\t)\n\n\t\tconst serializedChanges = serializeRecord(resolvedData, this.definition.fields)\n\t\tconst updateQuery = buildUpdateQuery(this.name, id, {\n\t\t\t...serializedChanges,\n\t\t\t_updated_at: now,\n\t\t})\n\t\tconst opRow = serializeOperation(operation)\n\t\tconst opInsert = buildInsertQuery(\n\t\t\t`_kora_ops_${this.name}`,\n\t\t\topRow as unknown as Record<string, unknown>,\n\t\t)\n\n\t\tawait this.adapter.transaction(async (tx) => {\n\t\t\tawait tx.execute(updateQuery.sql, updateQuery.params)\n\t\t\tawait tx.execute(opInsert.sql, opInsert.params)\n\t\t\tawait tx.execute(\n\t\t\t\t'INSERT OR REPLACE INTO _kora_version_vector (node_id, sequence_number) VALUES (?, ?)',\n\t\t\t\t[this.nodeId, sequenceNumber],\n\t\t\t)\n\t\t})\n\n\t\tthis.onMutation(this.name, operation)\n\n\t\t// Return the full updated record\n\t\tconst updatedRow = await this.findById(id)\n\t\tif (!updatedRow) {\n\t\t\tthrow new RecordNotFoundError(this.name, id)\n\t\t}\n\t\treturn updatedRow\n\t}\n\n\t/**\n\t * Soft-delete a record by its ID.\n\t *\n\t * When a RelationEnforcer is configured, referential integrity policies\n\t * are enforced within the same transaction:\n\t * - **cascade**: Recursively deletes all referencing records\n\t * - **set-null**: Sets foreign keys to null on referencing records\n\t * - **restrict**: Throws ReferentialIntegrityError if references exist\n\t * - **no-action**: Does nothing (dangling references are left)\n\t *\n\t * All cascaded operations are created atomically within the same transaction\n\t * and share causal dependencies with the original delete.\n\t *\n\t * @param id - The record ID to delete\n\t * @throws {RecordNotFoundError} If the record doesn't exist or is already deleted\n\t * @throws {ReferentialIntegrityError} If a 'restrict' policy is violated\n\t */\n\tasync delete(id: string): Promise<void> {\n\t\tconst currentRows = await this.adapter.query<RawCollectionRow>(\n\t\t\t`SELECT * FROM ${this.name} WHERE id = ? AND _deleted = 0`,\n\t\t\t[id],\n\t\t)\n\t\tif (!currentRows[0]) {\n\t\t\tthrow new RecordNotFoundError(this.name, id)\n\t\t}\n\n\t\tconst now = Date.now()\n\t\tconst sequenceNumber = this.getSequenceNumber()\n\t\tconst operation = await createOperation(\n\t\t\t{\n\t\t\t\tnodeId: this.nodeId,\n\t\t\t\ttype: 'delete',\n\t\t\t\tcollection: this.name,\n\t\t\t\trecordId: id,\n\t\t\t\tdata: null,\n\t\t\t\tpreviousData: null,\n\t\t\t\tsequenceNumber,\n\t\t\t\tcausalDeps: [],\n\t\t\t\tschemaVersion: this.schema.version,\n\t\t\t},\n\t\t\tthis.clock,\n\t\t)\n\n\t\tconst deleteQuery = buildSoftDeleteQuery(this.name, id, now)\n\t\tconst opRow = serializeOperation(operation)\n\t\tconst opInsert = buildInsertQuery(\n\t\t\t`_kora_ops_${this.name}`,\n\t\t\topRow as unknown as Record<string, unknown>,\n\t\t)\n\n\t\tconst cascadedOps: Operation[] = []\n\n\t\tawait this.adapter.transaction(async (tx) => {\n\t\t\t// Enforce referential integrity BEFORE the delete, within the transaction.\n\t\t\t// This ensures restrict can block the delete, and cascade/set-null are atomic.\n\t\t\tif (this.relationEnforcer) {\n\t\t\t\tconst enforcementResult = await this.relationEnforcer.enforceDelete(\n\t\t\t\t\tthis.name,\n\t\t\t\t\tid,\n\t\t\t\t\ttx,\n\t\t\t\t\t[operation.id],\n\t\t\t\t)\n\t\t\t\tcascadedOps.push(...enforcementResult.operations)\n\t\t\t}\n\n\t\t\tawait tx.execute(deleteQuery.sql, deleteQuery.params)\n\t\t\tawait tx.execute(opInsert.sql, opInsert.params)\n\t\t\tawait tx.execute(\n\t\t\t\t'INSERT OR REPLACE INTO _kora_version_vector (node_id, sequence_number) VALUES (?, ?)',\n\t\t\t\t[this.nodeId, sequenceNumber],\n\t\t\t)\n\t\t})\n\n\t\t// Notify for the primary delete and all cascaded operations\n\t\tthis.onMutation(this.name, operation)\n\t\tfor (const cascadedOp of cascadedOps) {\n\t\t\tthis.onMutation(cascadedOp.collection, cascadedOp)\n\t\t}\n\t}\n\n\t/** Get the collection name */\n\tgetName(): string {\n\t\treturn this.name\n\t}\n\n\t/** Get the collection definition */\n\tgetDefinition(): CollectionDefinition {\n\t\treturn this.definition\n\t}\n}\n","import type { CollectionDefinition, FieldDescriptor } from '@korajs/core'\nimport { QueryError } from '../errors'\nimport type { QueryDescriptor, WhereOperators } from '../types'\n\n/**\n * Result of building a SQL query: the parameterized SQL string and its bound values.\n */\nexport interface SqlQuery {\n\tsql: string\n\tparams: unknown[]\n}\n\n/**\n * Build a SELECT query from a QueryDescriptor.\n * Automatically adds `WHERE _deleted = 0` to exclude soft-deleted records.\n *\n * @param descriptor - The query descriptor\n * @param fields - The field descriptors from the collection schema\n * @returns A parameterized SQL query\n */\nexport function buildSelectQuery(\n\tdescriptor: QueryDescriptor,\n\tfields: Record<string, FieldDescriptor>,\n): SqlQuery {\n\tconst params: unknown[] = []\n\tconst parts = [`SELECT * FROM ${descriptor.collection}`]\n\n\tconst whereClause = buildWhereClauseParts(descriptor.where, fields, params)\n\t// Always filter out soft-deleted records\n\tconst deletedFilter = '_deleted = 0'\n\tif (whereClause) {\n\t\tparts.push(`WHERE ${deletedFilter} AND ${whereClause}`)\n\t} else {\n\t\tparts.push(`WHERE ${deletedFilter}`)\n\t}\n\n\tif (descriptor.orderBy.length > 0) {\n\t\tconst orderParts = descriptor.orderBy.map((o) => {\n\t\t\tvalidateFieldName(o.field, fields)\n\t\t\treturn `${o.field} ${o.direction.toUpperCase()}`\n\t\t})\n\t\tparts.push(`ORDER BY ${orderParts.join(', ')}`)\n\t}\n\n\tif (descriptor.limit !== undefined) {\n\t\tparts.push(`LIMIT ${descriptor.limit}`)\n\t}\n\n\tif (descriptor.offset !== undefined) {\n\t\tparts.push(`OFFSET ${descriptor.offset}`)\n\t}\n\n\treturn { sql: parts.join(' '), params }\n}\n\n/**\n * Build a COUNT query from a QueryDescriptor.\n * Automatically adds `WHERE _deleted = 0`.\n *\n * @param descriptor - The query descriptor\n * @param fields - The field descriptors from the collection schema\n * @returns A parameterized SQL query that returns { count: number }\n */\nexport function buildCountQuery(\n\tdescriptor: QueryDescriptor,\n\tfields: Record<string, FieldDescriptor>,\n): SqlQuery {\n\tconst params: unknown[] = []\n\tconst parts = [`SELECT COUNT(*) as count FROM ${descriptor.collection}`]\n\n\tconst whereClause = buildWhereClauseParts(descriptor.where, fields, params)\n\tconst deletedFilter = '_deleted = 0'\n\tif (whereClause) {\n\t\tparts.push(`WHERE ${deletedFilter} AND ${whereClause}`)\n\t} else {\n\t\tparts.push(`WHERE ${deletedFilter}`)\n\t}\n\n\treturn { sql: parts.join(' '), params }\n}\n\n/**\n * Build an INSERT query for a collection record.\n *\n * @param collection - The collection name\n * @param record - The record data (already serialized with id, _created_at, _updated_at)\n * @returns A parameterized SQL query\n */\nexport function buildInsertQuery(collection: string, record: Record<string, unknown>): SqlQuery {\n\tconst columns = Object.keys(record)\n\tconst placeholders = columns.map(() => '?')\n\tconst params = Object.values(record)\n\n\tconst sql = `INSERT INTO ${collection} (${columns.join(', ')}) VALUES (${placeholders.join(', ')})`\n\treturn { sql, params }\n}\n\n/**\n * Build an UPDATE query for a collection record.\n *\n * @param collection - The collection name\n * @param id - The record ID\n * @param changes - The fields to update (already serialized)\n * @returns A parameterized SQL query\n */\nexport function buildUpdateQuery(\n\tcollection: string,\n\tid: string,\n\tchanges: Record<string, unknown>,\n): SqlQuery {\n\tconst setClauses = Object.keys(changes).map((col) => `${col} = ?`)\n\tconst params = [...Object.values(changes), id]\n\n\tconst sql = `UPDATE ${collection} SET ${setClauses.join(', ')} WHERE id = ?`\n\treturn { sql, params }\n}\n\n/**\n * Build a soft-delete query (SET _deleted = 1).\n *\n * @param collection - The collection name\n * @param id - The record ID\n * @param updatedAt - The timestamp to set on _updated_at\n * @returns A parameterized SQL query\n */\nexport function buildSoftDeleteQuery(collection: string, id: string, updatedAt: number): SqlQuery {\n\treturn {\n\t\tsql: `UPDATE ${collection} SET _deleted = 1, _updated_at = ? WHERE id = ?`,\n\t\tparams: [updatedAt, id],\n\t}\n}\n\n/**\n * Build a WHERE clause from conditions, validating field names against the schema.\n *\n * @param where - The where conditions\n * @param fields - The field descriptors from the collection schema\n * @returns The SQL WHERE clause string and params, or null if no conditions\n */\nexport function buildWhereClause(\n\twhere: Record<string, unknown>,\n\tfields: Record<string, FieldDescriptor>,\n): SqlQuery | null {\n\tconst params: unknown[] = []\n\tconst result = buildWhereClauseParts(where, fields, params)\n\tif (!result) return null\n\treturn { sql: result, params }\n}\n\n// --- Internal helpers ---\n\nconst VALID_OPERATORS = new Set(['$eq', '$ne', '$gt', '$gte', '$lt', '$lte', '$in'])\n\nfunction buildWhereClauseParts(\n\twhere: Record<string, unknown>,\n\tfields: Record<string, FieldDescriptor>,\n\tparams: unknown[],\n): string | null {\n\tconst conditions: string[] = []\n\n\tfor (const [fieldName, value] of Object.entries(where)) {\n\t\tvalidateFieldName(fieldName, fields)\n\t\tconst descriptor = fields[fieldName]\n\n\t\tif (value !== null && typeof value === 'object' && !Array.isArray(value)) {\n\t\t\t// Operator object: { $gt: 5, $lt: 10 }\n\t\t\tconst ops = value as WhereOperators\n\t\t\tfor (const [op, opValue] of Object.entries(ops)) {\n\t\t\t\tif (!VALID_OPERATORS.has(op)) {\n\t\t\t\t\tthrow new QueryError(`Unknown operator \"${op}\" on field \"${fieldName}\"`, {\n\t\t\t\t\t\tfield: fieldName,\n\t\t\t\t\t\toperator: op,\n\t\t\t\t\t\tvalidOperators: [...VALID_OPERATORS],\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t\tconditions.push(buildOperatorCondition(fieldName, op, opValue, descriptor, params))\n\t\t\t}\n\t\t} else {\n\t\t\t// Shorthand: { completed: false } means { completed: { $eq: false } }\n\t\t\tconditions.push(buildOperatorCondition(fieldName, '$eq', value, descriptor, params))\n\t\t}\n\t}\n\n\tif (conditions.length === 0) return null\n\treturn conditions.join(' AND ')\n}\n\nfunction buildOperatorCondition(\n\tfieldName: string,\n\toperator: string,\n\tvalue: unknown,\n\tdescriptor: FieldDescriptor | undefined,\n\tparams: unknown[],\n): string {\n\t// Serialize boolean values to 0/1 for SQL comparison\n\tconst sqlValue =\n\t\tdescriptor?.kind === 'boolean' && typeof value === 'boolean' ? (value ? 1 : 0) : value\n\n\tswitch (operator) {\n\t\tcase '$eq':\n\t\t\tif (sqlValue === null) {\n\t\t\t\treturn `${fieldName} IS NULL`\n\t\t\t}\n\t\t\tparams.push(sqlValue)\n\t\t\treturn `${fieldName} = ?`\n\t\tcase '$ne':\n\t\t\tif (sqlValue === null) {\n\t\t\t\treturn `${fieldName} IS NOT NULL`\n\t\t\t}\n\t\t\tparams.push(sqlValue)\n\t\t\treturn `${fieldName} != ?`\n\t\tcase '$gt':\n\t\t\tparams.push(sqlValue)\n\t\t\treturn `${fieldName} > ?`\n\t\tcase '$gte':\n\t\t\tparams.push(sqlValue)\n\t\t\treturn `${fieldName} >= ?`\n\t\tcase '$lt':\n\t\t\tparams.push(sqlValue)\n\t\t\treturn `${fieldName} < ?`\n\t\tcase '$lte':\n\t\t\tparams.push(sqlValue)\n\t\t\treturn `${fieldName} <= ?`\n\t\tcase '$in': {\n\t\t\tif (!Array.isArray(sqlValue)) {\n\t\t\t\tthrow new QueryError(`$in operator requires an array value for field \"${fieldName}\"`, {\n\t\t\t\t\tfield: fieldName,\n\t\t\t\t\treceived: typeof sqlValue,\n\t\t\t\t})\n\t\t\t}\n\t\t\tconst placeholders = sqlValue.map(() => '?')\n\t\t\tfor (const item of sqlValue) {\n\t\t\t\tparams.push(\n\t\t\t\t\tdescriptor?.kind === 'boolean' && typeof item === 'boolean' ? (item ? 1 : 0) : item,\n\t\t\t\t)\n\t\t\t}\n\t\t\treturn `${fieldName} IN (${placeholders.join(', ')})`\n\t\t}\n\t\tdefault:\n\t\t\tthrow new QueryError(`Unknown operator \"${operator}\"`, { operator })\n\t}\n}\n\nfunction validateFieldName(fieldName: string, fields: Record<string, FieldDescriptor>): void {\n\t// Allow schema fields plus metadata fields that map to query-able columns\n\tconst allowedFields = new Set([\n\t\t...Object.keys(fields),\n\t\t'id',\n\t\t'createdAt',\n\t\t'updatedAt',\n\t\t'_created_at',\n\t\t'_updated_at',\n\t])\n\tif (!allowedFields.has(fieldName)) {\n\t\tthrow new QueryError(\n\t\t\t`Unknown field \"${fieldName}\" in query. Available fields: ${[...allowedFields].join(', ')}`,\n\t\t\t{ field: fieldName },\n\t\t)\n\t}\n}\n","import { HybridLogicalClock } from '@korajs/core'\nimport type { CollectionDefinition, FieldDescriptor, Operation } from '@korajs/core'\nimport type { CollectionRecord, OperationRow, RawCollectionRow } from '../types'\nimport { decodeRichtext, encodeRichtext } from './richtext-serializer'\n\n/**\n * Serialize a JS record to SQL-compatible values for INSERT/UPDATE.\n * Transforms: boolean → 0/1, array → JSON string, richtext → Yjs binary update.\n *\n * @param data - The record data with JS-native types\n * @param fields - The field descriptors from the schema\n * @returns An object with SQL-compatible values\n */\nexport function serializeRecord(\n\tdata: Record<string, unknown>,\n\tfields: Record<string, FieldDescriptor>,\n): Record<string, unknown> {\n\tconst result: Record<string, unknown> = {}\n\tfor (const [key, value] of Object.entries(data)) {\n\t\tconst descriptor = fields[key]\n\t\tif (!descriptor) {\n\t\t\tresult[key] = value\n\t\t\tcontinue\n\t\t}\n\t\tresult[key] = serializeValue(value, descriptor)\n\t}\n\treturn result\n}\n\n/**\n * Deserialize a SQL row to JS-native types for the application layer.\n * Transforms: 0/1 → boolean, JSON string → array, strips _deleted, maps _created_at/_updated_at.\n *\n * @param row - The raw SQL row\n * @param fields - The field descriptors from the schema\n * @returns A CollectionRecord with JS-native types\n */\nexport function deserializeRecord(\n\trow: RawCollectionRow,\n\tfields: Record<string, FieldDescriptor>,\n): CollectionRecord {\n\tconst result: CollectionRecord = {\n\t\tid: row.id,\n\t\tcreatedAt: row._created_at,\n\t\tupdatedAt: row._updated_at,\n\t}\n\n\tfor (const [key, descriptor] of Object.entries(fields)) {\n\t\tconst rawValue = row[key]\n\t\tif (rawValue === undefined || rawValue === null) {\n\t\t\tresult[key] = rawValue ?? null\n\t\t\tcontinue\n\t\t}\n\t\tresult[key] = deserializeValue(rawValue, descriptor)\n\t}\n\n\treturn result\n}\n\n/**\n * Internal key used to embed atomicOps metadata in the data JSON column.\n * This avoids adding a new column to the ops table (no migration needed).\n */\nconst ATOMIC_OPS_KEY = '__kora_atomic_ops__'\n\n/**\n * Internal key used to embed transactionId in the data JSON column.\n */\nconst TX_ID_KEY = '__kora_tx_id__'\n\n/**\n * Internal key used to embed mutationName in the data JSON column.\n */\nconst MUTATION_NAME_KEY = '__kora_mutation__'\n\n/**\n * Serialize an Operation to a row for the operations log table.\n *\n * @param op - The operation to serialize\n * @returns An OperationRow suitable for SQL INSERT\n */\nexport function serializeOperation(op: Operation): OperationRow {\n\tconst hasMetadata = op.transactionId !== undefined || op.mutationName !== undefined\n\tlet dataPayload: Record<string, unknown> | null = null\n\tif (op.data) {\n\t\t// Embed metadata in the data JSON when present\n\t\tdataPayload = { ...op.data }\n\t\tif (op.atomicOps !== undefined && Object.keys(op.atomicOps).length > 0) {\n\t\t\tdataPayload[ATOMIC_OPS_KEY] = op.atomicOps\n\t\t}\n\t\tif (op.transactionId !== undefined) {\n\t\t\tdataPayload[TX_ID_KEY] = op.transactionId\n\t\t}\n\t\tif (op.mutationName !== undefined) {\n\t\t\tdataPayload[MUTATION_NAME_KEY] = op.mutationName\n\t\t}\n\t} else if (hasMetadata) {\n\t\t// For delete operations (data is null), we still need to store metadata\n\t\tdataPayload = {}\n\t\tif (op.transactionId !== undefined) {\n\t\t\tdataPayload[TX_ID_KEY] = op.transactionId\n\t\t}\n\t\tif (op.mutationName !== undefined) {\n\t\t\tdataPayload[MUTATION_NAME_KEY] = op.mutationName\n\t\t}\n\t}\n\n\treturn {\n\t\tid: op.id,\n\t\tnode_id: op.nodeId,\n\t\ttype: op.type,\n\t\trecord_id: op.recordId,\n\t\tdata: dataPayload ? JSON.stringify(dataPayload) : null,\n\t\tprevious_data: op.previousData ? JSON.stringify(op.previousData) : null,\n\t\ttimestamp: HybridLogicalClock.serialize(op.timestamp),\n\t\tsequence_number: op.sequenceNumber,\n\t\tcausal_deps: JSON.stringify(op.causalDeps),\n\t\tschema_version: op.schemaVersion,\n\t}\n}\n\n/**\n * Deserialize a row from the operations log table back to an Operation.\n *\n * @param row - The raw operation row from SQL\n * @returns The deserialized Operation object\n */\nexport function deserializeOperation(row: OperationRow): Operation {\n\tlet data: Record<string, unknown> | null = null\n\tlet atomicOps: Record<string, unknown> | undefined\n\tlet transactionId: string | undefined\n\tlet mutationName: string | undefined\n\n\tif (row.data) {\n\t\tconst parsed = JSON.parse(row.data) as Record<string, unknown>\n\t\t// Extract embedded metadata keys\n\t\tif (ATOMIC_OPS_KEY in parsed) {\n\t\t\tatomicOps = parsed[ATOMIC_OPS_KEY] as Record<string, unknown>\n\t\t}\n\t\tif (TX_ID_KEY in parsed) {\n\t\t\ttransactionId = parsed[TX_ID_KEY] as string\n\t\t}\n\t\tif (MUTATION_NAME_KEY in parsed) {\n\t\t\tmutationName = parsed[MUTATION_NAME_KEY] as string\n\t\t}\n\t\t// Remove metadata keys from data\n\t\tconst { [ATOMIC_OPS_KEY]: _a, [TX_ID_KEY]: _t, [MUTATION_NAME_KEY]: _m, ...rest } = parsed\n\t\tdata = Object.keys(rest).length > 0 ? rest : null\n\t}\n\n\treturn {\n\t\tid: row.id,\n\t\tnodeId: row.node_id,\n\t\ttype: row.type as Operation['type'],\n\t\tcollection: '', // Collection name is derived from the table name by the caller\n\t\trecordId: row.record_id,\n\t\tdata,\n\t\tpreviousData: row.previous_data\n\t\t\t? (JSON.parse(row.previous_data) as Record<string, unknown>)\n\t\t\t: null,\n\t\ttimestamp: HybridLogicalClock.deserialize(row.timestamp),\n\t\tsequenceNumber: row.sequence_number,\n\t\tcausalDeps: JSON.parse(row.causal_deps) as string[],\n\t\tschemaVersion: row.schema_version,\n\t\t...(atomicOps !== undefined ? { atomicOps: atomicOps as Operation['atomicOps'] } : {}),\n\t\t...(transactionId !== undefined ? { transactionId } : {}),\n\t\t...(mutationName !== undefined ? { mutationName } : {}),\n\t}\n}\n\n/**\n * Deserialize an operation row with collection name already known.\n */\nexport function deserializeOperationWithCollection(\n\trow: OperationRow,\n\tcollection: string,\n): Operation {\n\tconst op = deserializeOperation(row)\n\treturn { ...op, collection }\n}\n\nfunction serializeValue(value: unknown, descriptor: FieldDescriptor): unknown {\n\tif (value === null || value === undefined) {\n\t\treturn null\n\t}\n\n\tswitch (descriptor.kind) {\n\t\tcase 'boolean':\n\t\t\treturn value ? 1 : 0\n\t\tcase 'array':\n\t\t\treturn JSON.stringify(value)\n\t\tcase 'richtext':\n\t\t\treturn encodeRichtext(value as string | Uint8Array | ArrayBuffer)\n\t\tdefault:\n\t\t\treturn value\n\t}\n}\n\nfunction deserializeValue(value: unknown, descriptor: FieldDescriptor): unknown {\n\tswitch (descriptor.kind) {\n\t\tcase 'boolean':\n\t\t\treturn value === 1 || value === true\n\t\tcase 'array':\n\t\t\tif (typeof value === 'string') {\n\t\t\t\treturn JSON.parse(value) as unknown[]\n\t\t\t}\n\t\t\treturn value\n\t\tcase 'richtext':\n\t\t\treturn decodeRichtext(value)\n\t\tdefault:\n\t\t\treturn value\n\t}\n}\n","import * as Y from 'yjs'\n\nconst TEXT_KEY = 'content'\n\nexport type RichtextInput = string | Uint8Array | ArrayBuffer | null | undefined\n\n/**\n * Encodes richtext values into Yjs document updates.\n */\nexport function encodeRichtext(value: RichtextInput): Uint8Array | null {\n\tif (value === null || value === undefined) {\n\t\treturn null\n\t}\n\n\tif (typeof value === 'string') {\n\t\tconst doc = new Y.Doc()\n\t\tdoc.getText(TEXT_KEY).insert(0, value)\n\t\treturn Y.encodeStateAsUpdate(doc)\n\t}\n\n\tif (value instanceof Uint8Array) {\n\t\treturn value\n\t}\n\n\tif (value instanceof ArrayBuffer) {\n\t\treturn new Uint8Array(value)\n\t}\n\n\tthrow new Error('Richtext value must be a string, Uint8Array, ArrayBuffer, null, or undefined.')\n}\n\n/**\n * Decodes driver-provided richtext values into Uint8Array.\n */\nexport function decodeRichtext(value: unknown): Uint8Array | null {\n\tif (value === null || value === undefined) {\n\t\treturn null\n\t}\n\n\tif (typeof Buffer !== 'undefined' && Buffer.isBuffer(value)) {\n\t\treturn new Uint8Array(value)\n\t}\n\n\tif (value instanceof Uint8Array) {\n\t\treturn value\n\t}\n\n\tif (value instanceof ArrayBuffer) {\n\t\treturn new Uint8Array(value)\n\t}\n\n\tthrow new Error(\n\t\t'Richtext storage value must be Uint8Array, ArrayBuffer, Buffer, null, or undefined.',\n\t)\n}\n\n/**\n * Reads plain text from a richtext Yjs state update.\n */\nexport function richtextToPlainText(value: RichtextInput): string {\n\tconst encoded = encodeRichtext(value)\n\tif (!encoded) return ''\n\n\tconst doc = new Y.Doc()\n\tY.applyUpdate(doc, encoded)\n\treturn doc.getText(TEXT_KEY).toString()\n}\n","import { KoraError, validateTransition } from '@korajs/core'\nimport type {\n\tCollectionDefinition,\n\tStateMachineConstraint,\n\tStateMachineDefinition,\n} from '@korajs/core'\n\n/**\n * Error thrown when a local mutation attempts an invalid state transition.\n *\n * Contains enough context to debug without reproduction:\n * the collection, record, field, current state, attempted state, and allowed transitions.\n */\nexport class InvalidStateTransitionError extends KoraError {\n\tconstructor(\n\t\tpublic readonly collection: string,\n\t\tpublic readonly recordId: string,\n\t\tpublic readonly field: string,\n\t\tpublic readonly fromState: string,\n\t\tpublic readonly toState: string,\n\t\tpublic readonly allowedStates: string[],\n\t) {\n\t\tsuper(\n\t\t\t`Invalid state transition in collection \"${collection}\": ` +\n\t\t\t\t`cannot transition field \"${field}\" from \"${fromState}\" to \"${toState}\". ` +\n\t\t\t\t`Allowed transitions from \"${fromState}\": ${allowedStates.length > 0 ? allowedStates.join(', ') : '(none -- terminal state)'}`,\n\t\t\t'INVALID_STATE_TRANSITION',\n\t\t\t{ collection, recordId, field, fromState, toState, allowedStates },\n\t\t)\n\t\tthis.name = 'InvalidStateTransitionError'\n\t}\n}\n\n/**\n * Validates a state machine transition for a local mutation (insert or update).\n *\n * For inserts: validates that the initial state (from the data or the default value)\n * is a known state in the state machine.\n *\n * For updates: looks up the current state field value and checks whether\n * the transition to the new value is allowed.\n *\n * @param collectionName - Name of the collection\n * @param recordId - The record being mutated\n * @param stateMachine - The state machine definition\n * @param currentState - The current value of the state field (null for inserts)\n * @param newState - The new value being set for the state field\n * @returns An object indicating whether the transition is valid, and if not, the allowed states.\n * When `onInvalidTransition` is 'last-valid-state', callers should suppress the field update\n * rather than throwing.\n */\nexport function validateStateTransition(\n\tcollectionName: string,\n\trecordId: string,\n\tstateMachine: StateMachineDefinition,\n\tcurrentState: string | null,\n\tnewState: string,\n): { valid: boolean; allowedStates: string[] } {\n\t// For inserts, any valid enum value is acceptable as the initial state\n\t// (schema validation already ensures the value is a valid enum value)\n\tif (currentState === null) {\n\t\treturn { valid: true, allowedStates: [] }\n\t}\n\n\t// Same-state transitions are always valid (idempotent updates)\n\tif (currentState === newState) {\n\t\treturn { valid: true, allowedStates: stateMachine.transitions[currentState] ?? [] }\n\t}\n\n\tconst constraint: StateMachineConstraint = {\n\t\tfield: stateMachine.field,\n\t\tcollection: collectionName,\n\t\ttransitions: stateMachine.transitions,\n\t}\n\tconst transitionResult = validateTransition(constraint, currentState, newState)\n\tif (transitionResult.valid) {\n\t\treturn { valid: true, allowedStates: transitionResult.allowedTargets }\n\t}\n\n\tconst allowedStates = transitionResult.allowedTargets\n\n\tif (stateMachine.onInvalidTransition === 'reject') {\n\t\tthrow new InvalidStateTransitionError(\n\t\t\tcollectionName,\n\t\t\trecordId,\n\t\t\tstateMachine.field,\n\t\t\tcurrentState,\n\t\t\tnewState,\n\t\t\tallowedStates,\n\t\t)\n\t}\n\n\t// 'last-valid-state': return invalid so the caller can suppress the field update\n\treturn { valid: false, allowedStates }\n}\n\n/**\n * Checks whether a collection update data object contains a change to the state machine field,\n * and if so, validates the transition.\n *\n * If the state field is not in the update data, returns the data unchanged.\n * If the transition is invalid and mode is 'last-valid-state', removes the field from the data.\n * If the transition is invalid and mode is 'reject', throws InvalidStateTransitionError.\n *\n * @param collectionName - Name of the collection\n * @param recordId - The record being updated\n * @param collectionDef - The collection definition from the schema\n * @param currentRecord - The current record data (must include the state field)\n * @param updateData - The partial update data\n * @returns The update data, potentially with the state field removed if invalid and mode is 'last-valid-state'\n */\nexport function validateUpdateStateMachine(\n\tcollectionName: string,\n\trecordId: string,\n\tcollectionDef: CollectionDefinition,\n\tcurrentRecord: Record<string, unknown>,\n\tupdateData: Record<string, unknown>,\n): Record<string, unknown> {\n\tconst stateMachine = collectionDef.stateMachine\n\tif (stateMachine === undefined) {\n\t\treturn updateData\n\t}\n\n\tconst stateField = stateMachine.field\n\tif (!(stateField in updateData)) {\n\t\t// State field not being changed -- no validation needed\n\t\treturn updateData\n\t}\n\n\tconst currentState = currentRecord[stateField]\n\tconst newState = updateData[stateField]\n\n\t// Both values must be strings for state machine validation\n\tif (typeof currentState !== 'string' || typeof newState !== 'string') {\n\t\treturn updateData\n\t}\n\n\tconst result = validateStateTransition(\n\t\tcollectionName,\n\t\trecordId,\n\t\tstateMachine,\n\t\tcurrentState,\n\t\tnewState,\n\t)\n\n\tif (result.valid) {\n\t\treturn updateData\n\t}\n\n\t// Mode is 'last-valid-state': silently remove the state field from the update\n\tconst filtered = { ...updateData }\n\tdelete filtered[stateField]\n\n\t// If no fields remain after removing the state field, the update becomes a no-op.\n\t// Return the empty object -- the caller can decide whether to proceed.\n\treturn filtered\n}\n","/**\n * Minimal pluralization/singularization utilities for relation name resolution.\n * Handles common English patterns — not meant to be exhaustive.\n */\n\nfunction isVowel(char: string | undefined): boolean {\n\tif (!char) return false\n\treturn 'aeiouAEIOU'.includes(char)\n}\n\n/**\n * Pluralize a word using common English rules.\n *\n * @example\n * ```\n * pluralize('project') // 'projects'\n * pluralize('category') // 'categories'\n * pluralize('match') // 'matches'\n * ```\n */\nexport function pluralize(word: string): string {\n\tif (word.endsWith('s')) return word\n\tif (word.endsWith('y') && !isVowel(word[word.length - 2])) {\n\t\treturn `${word.slice(0, -1)}ies`\n\t}\n\tif (word.endsWith('sh') || word.endsWith('ch') || word.endsWith('x') || word.endsWith('z')) {\n\t\treturn `${word}es`\n\t}\n\treturn `${word}s`\n}\n\n/**\n * Singularize a word using common English rules.\n *\n * @example\n * ```\n * singularize('projects') // 'project'\n * singularize('categories') // 'category'\n * singularize('matches') // 'match'\n * ```\n */\nexport function singularize(word: string): string {\n\tif (word.endsWith('ies') && !isVowel(word[word.length - 4])) {\n\t\treturn `${word.slice(0, -3)}y`\n\t}\n\tif (\n\t\tword.endsWith('shes') ||\n\t\tword.endsWith('ches') ||\n\t\tword.endsWith('xes') ||\n\t\tword.endsWith('zes')\n\t) {\n\t\treturn word.slice(0, -2)\n\t}\n\tif (word.endsWith('ses')) {\n\t\treturn word.slice(0, -2)\n\t}\n\tif (word.endsWith('s') && !word.endsWith('ss')) {\n\t\treturn word.slice(0, -1)\n\t}\n\treturn word\n}\n","import type { CollectionDefinition, SchemaDefinition } from '@korajs/core'\nimport { deserializeRecord } from '../serialization/serializer'\nimport type { SubscriptionManager } from '../subscription/subscription-manager'\nimport type {\n\tCollectionRecord,\n\tOrderByDirection,\n\tQueryDescriptor,\n\tRawCollectionRow,\n\tStorageAdapter,\n\tSubscriptionCallback,\n\tWhereClause,\n} from '../types'\nimport { pluralize, singularize } from './pluralize'\nimport { buildCountQuery, buildSelectQuery } from './sql-builder'\n\n/**\n * Fluent query builder for constructing and executing collection queries.\n * Supports where, orderBy, limit, offset, include, exec, count, and subscribe.\n *\n * The generic parameter `T` defaults to `CollectionRecord` for backward compatibility\n * but can be narrowed to a specific record type for full type inference.\n *\n * @example\n * ```typescript\n * const todos = await app.todos\n * .where({ completed: false })\n * .orderBy('createdAt', 'desc')\n * .limit(10)\n * .exec()\n * ```\n */\nexport class QueryBuilder<T = CollectionRecord> {\n\tprivate descriptor: QueryDescriptor\n\n\tconstructor(\n\t\tprivate readonly collectionName: string,\n\t\tprivate readonly definition: CollectionDefinition,\n\t\tprivate readonly adapter: StorageAdapter,\n\t\tprivate readonly subscriptionManager: SubscriptionManager,\n\t\tinitialWhere: WhereClause = {},\n\t\tprivate readonly schema?: SchemaDefinition,\n\t) {\n\t\tthis.descriptor = {\n\t\t\tcollection: collectionName,\n\t\t\twhere: { ...initialWhere },\n\t\t\torderBy: [],\n\t\t}\n\t}\n\n\t/**\n\t * Add WHERE conditions (AND semantics, merged with existing conditions).\n\t */\n\twhere(conditions: WhereClause): QueryBuilder<T> {\n\t\tconst clone = this.clone()\n\t\tclone.descriptor = {\n\t\t\t...clone.descriptor,\n\t\t\twhere: { ...clone.descriptor.where, ...conditions },\n\t\t}\n\t\treturn clone\n\t}\n\n\t/**\n\t * Add ORDER BY clause.\n\t */\n\torderBy(field: string, direction: OrderByDirection = 'asc'): QueryBuilder<T> {\n\t\tconst clone = this.clone()\n\t\tclone.descriptor = {\n\t\t\t...clone.descriptor,\n\t\t\torderBy: [...clone.descriptor.orderBy, { field, direction }],\n\t\t}\n\t\treturn clone\n\t}\n\n\t/**\n\t * Set result limit.\n\t */\n\tlimit(n: number): QueryBuilder<T> {\n\t\tconst clone = this.clone()\n\t\tclone.descriptor = { ...clone.descriptor, limit: n }\n\t\treturn clone\n\t}\n\n\t/**\n\t * Set result offset.\n\t */\n\toffset(n: number): QueryBuilder<T> {\n\t\tconst clone = this.clone()\n\t\tclone.descriptor = { ...clone.descriptor, offset: n }\n\t\treturn clone\n\t}\n\n\t/**\n\t * Include related records in the query results.\n\t * Follows relations defined in the schema to batch-fetch related data.\n\t *\n\t * @param targets - Relation target names (collection names or relation names)\n\t * @returns A new QueryBuilder with include targets added\n\t *\n\t * @example\n\t * ```typescript\n\t * const todosWithProject = await app.todos\n\t * .where({ completed: false })\n\t * .include('project')\n\t * .exec()\n\t * ```\n\t */\n\tinclude(...targets: string[]): QueryBuilder<T> {\n\t\tconst clone = this.clone()\n\t\tconst existing = clone.descriptor.include ?? []\n\t\tclone.descriptor = {\n\t\t\t...clone.descriptor,\n\t\t\tinclude: [...existing, ...targets],\n\t\t}\n\t\treturn clone\n\t}\n\n\t/**\n\t * Execute the query and return results.\n\t */\n\tasync exec(): Promise<T[]> {\n\t\tconst { sql, params } = buildSelectQuery(this.descriptor, this.definition.fields)\n\t\tconst rows = await this.adapter.query<RawCollectionRow>(sql, params)\n\t\tconst records = rows.map((row) => deserializeRecord(row, this.definition.fields))\n\n\t\t// Resolve includes if any\n\t\tif (this.descriptor.include && this.descriptor.include.length > 0 && this.schema) {\n\t\t\tawait this.resolveIncludes(records)\n\t\t}\n\n\t\treturn records as T[]\n\t}\n\n\t/**\n\t * Execute a COUNT query and return the count.\n\t */\n\tasync count(): Promise<number> {\n\t\tconst { sql, params } = buildCountQuery(this.descriptor, this.definition.fields)\n\t\tconst rows = await this.adapter.query<{ count: number }>(sql, params)\n\t\treturn rows[0]?.count ?? 0\n\t}\n\n\t/**\n\t * Subscribe to query results. Callback is called immediately with current results,\n\t * then again whenever the results change due to mutations.\n\t *\n\t * @returns An unsubscribe function\n\t */\n\tsubscribe(callback: SubscriptionCallback<T>): () => void {\n\t\tconst executeFn = () => this.exec()\n\n\t\t// Resolve includeCollections for subscription tracking\n\t\tconst descriptorCopy = { ...this.descriptor }\n\t\tif (descriptorCopy.include && descriptorCopy.include.length > 0 && this.schema) {\n\t\t\tdescriptorCopy.includeCollections = this.resolveIncludeCollections(descriptorCopy.include)\n\t\t}\n\n\t\t// Use registerAndFetch to execute immediately, set lastResults,\n\t\t// and call callback — ensuring subsequent flushes diff correctly.\n\t\treturn this.subscriptionManager.registerAndFetch(\n\t\t\tdescriptorCopy,\n\t\t\tcallback as SubscriptionCallback<CollectionRecord>,\n\t\t\texecuteFn as () => Promise<CollectionRecord[]>,\n\t\t)\n\t}\n\n\t/** Get the internal descriptor (for testing/debugging) */\n\tgetDescriptor(): QueryDescriptor {\n\t\treturn { ...this.descriptor }\n\t}\n\n\tprivate clone(): QueryBuilder<T> {\n\t\tconst qb = new QueryBuilder<T>(\n\t\t\tthis.collectionName,\n\t\t\tthis.definition,\n\t\t\tthis.adapter,\n\t\t\tthis.subscriptionManager,\n\t\t\t{},\n\t\t\tthis.schema,\n\t\t)\n\t\tqb.descriptor = {\n\t\t\t...this.descriptor,\n\t\t\twhere: { ...this.descriptor.where },\n\t\t\torderBy: [...this.descriptor.orderBy],\n\t\t\tinclude: this.descriptor.include ? [...this.descriptor.include] : undefined,\n\t\t\tincludeCollections: this.descriptor.includeCollections\n\t\t\t\t? [...this.descriptor.includeCollections]\n\t\t\t\t: undefined,\n\t\t}\n\t\treturn qb\n\t}\n\n\t/**\n\t * Resolve include targets to their actual collection names for subscription tracking.\n\t */\n\tprivate resolveIncludeCollections(targets: string[]): string[] {\n\t\tif (!this.schema) return []\n\t\tconst collections: string[] = []\n\n\t\tfor (const target of targets) {\n\t\t\tconst relation = this.findRelation(target)\n\t\t\tif (relation) {\n\t\t\t\t// For many-to-one: the related collection is `relation.to`\n\t\t\t\t// For one-to-many: the related collection is `relation.from`\n\t\t\t\tif (relation.from === this.collectionName) {\n\t\t\t\t\tcollections.push(relation.to)\n\t\t\t\t} else {\n\t\t\t\t\tcollections.push(relation.from)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn collections\n\t}\n\n\t/**\n\t * Resolve includes after primary query, batch-fetching related records.\n\t */\n\tprivate async resolveIncludes(records: CollectionRecord[]): Promise<void> {\n\t\tif (!this.schema || !this.descriptor.include || records.length === 0) return\n\n\t\tfor (const target of this.descriptor.include) {\n\t\t\tconst relation = this.findRelation(target)\n\t\t\tif (!relation) {\n\t\t\t\tthrow new QueryError(\n\t\t\t\t\t`No relation found for include target \"${target}\" on collection \"${this.collectionName}\". ` +\n\t\t\t\t\t\t`Check that a relation is defined in your schema that connects \"${this.collectionName}\" to \"${target}\".`,\n\t\t\t\t)\n\t\t\t}\n\n\t\t\tif (relation.from === this.collectionName) {\n\t\t\t\t// Many-to-one or one-to-one: primary has FK → fetch parent records\n\t\t\t\tawait this.resolveManyToOneInclude(records, relation, target)\n\t\t\t} else {\n\t\t\t\t// One-to-many: related collection has FK → fetch children\n\t\t\t\tawait this.resolveOneToManyInclude(records, relation, target)\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Many-to-one: collect FK values from primary results, batch-fetch related, attach as singular.\n\t */\n\tprivate async resolveManyToOneInclude(\n\t\trecords: CollectionRecord[],\n\t\trelation: { from: string; to: string; field: string },\n\t\ttarget: string,\n\t): Promise<void> {\n\t\tconst fkField = relation.field\n\t\tconst fkValues = records\n\t\t\t.map((r) => r[fkField])\n\t\t\t.filter((v): v is string => v !== null && v !== undefined && typeof v === 'string')\n\n\t\tif (fkValues.length === 0) {\n\t\t\t// All null FKs — set property to null on all records\n\t\t\tconst propName = singularize(target)\n\t\t\tfor (const record of records) {\n\t\t\t\t;(record as Record<string, unknown>)[propName] = null\n\t\t\t}\n\t\t\treturn\n\t\t}\n\n\t\tconst uniqueFks = [...new Set(fkValues)]\n\t\tconst relatedCollection = relation.to\n\t\tconst relatedDef = this.schema?.collections[relatedCollection]\n\t\tif (!relatedDef) return\n\n\t\t// Batch fetch: SELECT * FROM <to> WHERE id IN (...) AND _deleted = 0\n\t\tconst placeholders = uniqueFks.map(() => '?').join(', ')\n\t\tconst sql = `SELECT * FROM ${relatedCollection} WHERE id IN (${placeholders}) AND _deleted = 0`\n\t\tconst rows = await this.adapter.query<RawCollectionRow>(sql, uniqueFks)\n\t\tconst relatedRecords = rows.map((row) => deserializeRecord(row, relatedDef.fields))\n\n\t\t// Build lookup\n\t\tconst lookup = new Map<string, CollectionRecord>()\n\t\tfor (const r of relatedRecords) {\n\t\t\tlookup.set(r.id, r)\n\t\t}\n\n\t\t// Attach as singular property\n\t\tconst propName = singularize(target)\n\t\tfor (const record of records) {\n\t\t\tconst fk = record[fkField] as string | null\n\t\t\t;(record as Record<string, unknown>)[propName] = fk ? (lookup.get(fk) ?? null) : null\n\t\t}\n\t}\n\n\t/**\n\t * One-to-many: collect primary IDs, batch-fetch children, attach as array.\n\t */\n\tprivate async resolveOneToManyInclude(\n\t\trecords: CollectionRecord[],\n\t\trelation: { from: string; to: string; field: string },\n\t\ttarget: string,\n\t): Promise<void> {\n\t\tconst primaryIds = records.map((r) => r.id)\n\t\tconst relatedCollection = relation.from\n\t\tconst relatedDef = this.schema?.collections[relatedCollection]\n\t\tif (!relatedDef) return\n\n\t\tconst fkField = relation.field\n\t\tconst placeholders = primaryIds.map(() => '?').join(', ')\n\t\tconst sql = `SELECT * FROM ${relatedCollection} WHERE ${fkField} IN (${placeholders}) AND _deleted = 0`\n\t\tconst rows = await this.adapter.query<RawCollectionRow>(sql, primaryIds)\n\t\tconst relatedRecords = rows.map((row) => deserializeRecord(row, relatedDef.fields))\n\n\t\t// Group by FK\n\t\tconst grouped = new Map<string, CollectionRecord[]>()\n\t\tfor (const r of relatedRecords) {\n\t\t\tconst fk = r[fkField] as string\n\t\t\tif (!grouped.has(fk)) {\n\t\t\t\tgrouped.set(fk, [])\n\t\t\t}\n\t\t\tgrouped.get(fk)?.push(r)\n\t\t}\n\n\t\t// Attach as array property\n\t\tconst propName = pluralize(target)\n\t\tfor (const record of records) {\n\t\t\t;(record as Record<string, unknown>)[propName] = grouped.get(record.id) ?? []\n\t\t}\n\t}\n\n\t/**\n\t * Find a relation definition matching the include target.\n\t * Searches by relation name, target collection name, and singularized/pluralized variants.\n\t */\n\tprivate findRelation(\n\t\ttarget: string,\n\t): { from: string; to: string; field: string; type: string } | null {\n\t\tif (!this.schema) return null\n\n\t\tfor (const [_name, rel] of Object.entries(this.schema.relations)) {\n\t\t\t// Direct match: target is the related collection name\n\t\t\tif (rel.from === this.collectionName && rel.to === target) return rel\n\t\t\tif (rel.to === this.collectionName && rel.from === target) return rel\n\n\t\t\t// Singularized match: \"project\" matches relation to \"projects\"\n\t\t\tif (rel.from === this.collectionName && rel.to === pluralize(target)) return rel\n\t\t\tif (rel.to === this.collectionName && rel.from === pluralize(target)) return rel\n\n\t\t\t// Pluralized match: \"todos\" matches relation from \"todos\"\n\t\t\tif (rel.from === this.collectionName && rel.to === singularize(target)) return rel\n\t\t\tif (rel.to === this.collectionName && rel.from === singularize(target)) return rel\n\t\t}\n\n\t\treturn null\n\t}\n}\n\n/**\n * Error thrown when a query encounters an invalid state.\n */\nclass QueryError extends Error {\n\tconstructor(message: string) {\n\t\tsuper(message)\n\t\tthis.name = 'QueryError'\n\t}\n}\n","import type { HybridLogicalClock, Operation, SchemaDefinition } from '@korajs/core'\nimport { KoraError, createOperation } from '@korajs/core'\nimport { buildInsertQuery, buildSoftDeleteQuery, buildUpdateQuery } from '../query/sql-builder'\nimport { serializeOperation, serializeRecord } from '../serialization/serializer'\nimport type { StorageAdapter, Transaction } from '../types'\nimport type { IncomingRelation } from './relation-lookup'\nimport { buildRelationLookup, getIncomingRelations } from './relation-lookup'\n\n/**\n * Error thrown when a delete is refused due to a 'restrict' referential integrity policy.\n * The error includes context about which relation caused the restriction and\n * how many referencing records exist.\n */\nexport class ReferentialIntegrityError extends KoraError {\n\tconstructor(\n\t\tcollection: string,\n\t\trecordId: string,\n\t\treferencingCollection: string,\n\t\trelationName: string,\n\t\treferencingCount: number,\n\t) {\n\t\tsuper(\n\t\t\t`Cannot delete record \"${recordId}\" from \"${collection}\": ${referencingCount} record(s) in \"${referencingCollection}\" reference it via relation \"${relationName}\" with onDelete: 'restrict'. Delete or reassign the referencing records first.`,\n\t\t\t'REFERENTIAL_INTEGRITY',\n\t\t\t{\n\t\t\t\tcollection,\n\t\t\t\trecordId,\n\t\t\t\treferencingCollection,\n\t\t\t\trelationName,\n\t\t\t\treferencingCount,\n\t\t\t},\n\t\t)\n\t\tthis.name = 'ReferentialIntegrityError'\n\t}\n}\n\n/**\n * Configuration for the RelationEnforcer.\n */\nexport interface RelationEnforcerConfig {\n\tschema: SchemaDefinition\n\tadapter: StorageAdapter\n\tclock: HybridLogicalClock\n\tnodeId: string\n\tgetSequenceNumber: () => number\n}\n\n/**\n * Result of enforcing referential integrity on a delete operation.\n * Contains all additional operations that were created as side effects\n * (cascaded deletes and set-null updates).\n */\nexport interface EnforcementResult {\n\t/** Additional operations created by cascading deletes and set-null updates */\n\toperations: Operation[]\n}\n\n/**\n * Enforces referential integrity constraints during local delete operations.\n *\n * When a record is deleted, this enforcer checks all relations that reference\n * the deleted record's collection and applies the appropriate onDelete policy:\n *\n * - **cascade**: Recursively deletes all referencing records\n * - **set-null**: Sets the foreign key to null on all referencing records\n * - **restrict**: Throws a ReferentialIntegrityError if any references exist\n * - **no-action**: Does nothing (the foreign key is left dangling)\n *\n * The enforcer operates within a provided transaction to ensure atomicity.\n * All generated operations (cascaded deletes, set-null updates) share a\n * causal dependency chain through the original delete operation.\n *\n * @example\n * ```typescript\n * const enforcer = new RelationEnforcer({\n * schema, adapter, clock, nodeId,\n * getSequenceNumber: () => ++seq,\n * })\n * const result = await enforcer.enforceDelete(\n * 'projects', 'proj-1', tx, ['delete-op-id']\n * )\n * // result.operations contains any cascaded delete/update ops\n * ```\n */\nexport class RelationEnforcer {\n\tprivate readonly lookup: Map<string, IncomingRelation[]>\n\tprivate readonly schema: SchemaDefinition\n\tprivate readonly adapter: StorageAdapter\n\tprivate readonly clock: HybridLogicalClock\n\tprivate readonly nodeId: string\n\tprivate readonly getSequenceNumber: () => number\n\n\tconstructor(config: RelationEnforcerConfig) {\n\t\tthis.schema = config.schema\n\t\tthis.adapter = config.adapter\n\t\tthis.clock = config.clock\n\t\tthis.nodeId = config.nodeId\n\t\tthis.getSequenceNumber = config.getSequenceNumber\n\t\tthis.lookup = buildRelationLookup(config.schema)\n\t}\n\n\t/**\n\t * Enforce referential integrity after deleting a record.\n\t *\n\t * Must be called within a transaction. The transaction handle is used\n\t * for all cascaded writes to ensure atomicity.\n\t *\n\t * @param collection - The collection the deleted record belongs to\n\t * @param recordId - The ID of the deleted record\n\t * @param tx - The active transaction handle\n\t * @param causalDeps - Causal dependencies for generated operations\n\t * @returns All additional operations created as side effects\n\t * @throws {ReferentialIntegrityError} If a 'restrict' policy is violated\n\t */\n\tasync enforceDelete(\n\t\tcollection: string,\n\t\trecordId: string,\n\t\ttx: Transaction,\n\t\tcausalDeps: string[],\n\t): Promise<EnforcementResult> {\n\t\tconst incomingRelations = getIncomingRelations(this.lookup, collection)\n\t\tif (incomingRelations.length === 0) {\n\t\t\treturn { operations: [] }\n\t\t}\n\n\t\tconst allOperations: Operation[] = []\n\n\t\t// Process relations in a deterministic order (sorted by relation name)\n\t\t// to ensure identical results regardless of Map iteration order.\n\t\tconst sortedRelations = [...incomingRelations].sort((a, b) =>\n\t\t\ta.relationName.localeCompare(b.relationName),\n\t\t)\n\n\t\tfor (const incoming of sortedRelations) {\n\t\t\tconst ops = await this.enforceRelation(incoming, recordId, tx, causalDeps)\n\t\t\tallOperations.push(...ops)\n\t\t}\n\n\t\treturn { operations: allOperations }\n\t}\n\n\t/**\n\t * Enforce a single relation's onDelete policy.\n\t */\n\tprivate async enforceRelation(\n\t\tincoming: IncomingRelation,\n\t\tdeletedRecordId: string,\n\t\ttx: Transaction,\n\t\tcausalDeps: string[],\n\t): Promise<Operation[]> {\n\t\tswitch (incoming.onDelete) {\n\t\t\tcase 'cascade':\n\t\t\t\treturn this.enforceCascade(incoming, deletedRecordId, tx, causalDeps)\n\t\t\tcase 'set-null':\n\t\t\t\treturn this.enforceSetNull(incoming, deletedRecordId, tx, causalDeps)\n\t\t\tcase 'restrict':\n\t\t\t\treturn this.enforceRestrict(incoming, deletedRecordId, tx)\n\t\t\tcase 'no-action':\n\t\t\t\treturn []\n\t\t}\n\t}\n\n\t/**\n\t * Cascade: delete all records in the source collection that reference\n\t * the deleted record, then recursively cascade those deletes.\n\t */\n\tprivate async enforceCascade(\n\t\tincoming: IncomingRelation,\n\t\tdeletedRecordId: string,\n\t\ttx: Transaction,\n\t\tcausalDeps: string[],\n\t): Promise<Operation[]> {\n\t\tconst { sourceCollection, foreignKeyField } = incoming\n\n\t\t// Find all non-deleted records that reference the deleted record\n\t\tconst referencingRows = await tx.query<{ id: string }>(\n\t\t\t`SELECT id FROM ${sourceCollection} WHERE ${foreignKeyField} = ? AND _deleted = 0`,\n\t\t\t[deletedRecordId],\n\t\t)\n\n\t\tif (referencingRows.length === 0) {\n\t\t\treturn []\n\t\t}\n\n\t\tconst operations: Operation[] = []\n\n\t\tfor (const row of referencingRows) {\n\t\t\tconst now = Date.now()\n\t\t\tconst sequenceNumber = this.getSequenceNumber()\n\n\t\t\tconst operation = await createOperation(\n\t\t\t\t{\n\t\t\t\t\tnodeId: this.nodeId,\n\t\t\t\t\ttype: 'delete',\n\t\t\t\t\tcollection: sourceCollection,\n\t\t\t\t\trecordId: row.id,\n\t\t\t\t\tdata: null,\n\t\t\t\t\tpreviousData: null,\n\t\t\t\t\tsequenceNumber,\n\t\t\t\t\tcausalDeps: [...causalDeps],\n\t\t\t\t\tschemaVersion: this.schema.version,\n\t\t\t\t},\n\t\t\t\tthis.clock,\n\t\t\t)\n\n\t\t\t// Soft-delete the record\n\t\t\tconst deleteQuery = buildSoftDeleteQuery(sourceCollection, row.id, now)\n\t\t\tawait tx.execute(deleteQuery.sql, deleteQuery.params)\n\n\t\t\t// Persist the operation\n\t\t\tconst opRow = serializeOperation(operation)\n\t\t\tconst opInsert = buildInsertQuery(\n\t\t\t\t`_kora_ops_${sourceCollection}`,\n\t\t\t\topRow as unknown as Record<string, unknown>,\n\t\t\t)\n\t\t\tawait tx.execute(opInsert.sql, opInsert.params)\n\n\t\t\t// Update version vector\n\t\t\tawait tx.execute(\n\t\t\t\t'INSERT OR REPLACE INTO _kora_version_vector (node_id, sequence_number) VALUES (?, ?)',\n\t\t\t\t[this.nodeId, sequenceNumber],\n\t\t\t)\n\n\t\t\toperations.push(operation)\n\n\t\t\t// Recursively cascade: this deleted record might also be referenced\n\t\t\tconst cascadeResult = await this.enforceDelete(sourceCollection, row.id, tx, [operation.id])\n\t\t\toperations.push(...cascadeResult.operations)\n\t\t}\n\n\t\treturn operations\n\t}\n\n\t/**\n\t * Set-null: update all referencing records to set the foreign key to null.\n\t */\n\tprivate async enforceSetNull(\n\t\tincoming: IncomingRelation,\n\t\tdeletedRecordId: string,\n\t\ttx: Transaction,\n\t\tcausalDeps: string[],\n\t): Promise<Operation[]> {\n\t\tconst { sourceCollection, foreignKeyField } = incoming\n\t\tconst collectionDef = this.schema.collections[sourceCollection]\n\t\tif (!collectionDef) {\n\t\t\treturn []\n\t\t}\n\n\t\t// Find all non-deleted records that reference the deleted record\n\t\tconst referencingRows = await tx.query<{ id: string }>(\n\t\t\t`SELECT id FROM ${sourceCollection} WHERE ${foreignKeyField} = ? AND _deleted = 0`,\n\t\t\t[deletedRecordId],\n\t\t)\n\n\t\tif (referencingRows.length === 0) {\n\t\t\treturn []\n\t\t}\n\n\t\tconst operations: Operation[] = []\n\n\t\tfor (const row of referencingRows) {\n\t\t\tconst now = Date.now()\n\t\t\tconst sequenceNumber = this.getSequenceNumber()\n\n\t\t\tconst updateData: Record<string, unknown> = { [foreignKeyField]: null }\n\t\t\tconst previousData: Record<string, unknown> = { [foreignKeyField]: deletedRecordId }\n\n\t\t\tconst operation = await createOperation(\n\t\t\t\t{\n\t\t\t\t\tnodeId: this.nodeId,\n\t\t\t\t\ttype: 'update',\n\t\t\t\t\tcollection: sourceCollection,\n\t\t\t\t\trecordId: row.id,\n\t\t\t\t\tdata: { ...updateData },\n\t\t\t\t\tpreviousData,\n\t\t\t\t\tsequenceNumber,\n\t\t\t\t\tcausalDeps: [...causalDeps],\n\t\t\t\t\tschemaVersion: this.schema.version,\n\t\t\t\t},\n\t\t\t\tthis.clock,\n\t\t\t)\n\n\t\t\t// Update the record's foreign key to null\n\t\t\tconst serializedChanges = serializeRecord(updateData, collectionDef.fields)\n\t\t\tconst updateQuery = buildUpdateQuery(sourceCollection, row.id, {\n\t\t\t\t...serializedChanges,\n\t\t\t\t_updated_at: now,\n\t\t\t})\n\t\t\tawait tx.execute(updateQuery.sql, updateQuery.params)\n\n\t\t\t// Persist the operation\n\t\t\tconst opRow = serializeOperation(operation)\n\t\t\tconst opInsert = buildInsertQuery(\n\t\t\t\t`_kora_ops_${sourceCollection}`,\n\t\t\t\topRow as unknown as Record<string, unknown>,\n\t\t\t)\n\t\t\tawait tx.execute(opInsert.sql, opInsert.params)\n\n\t\t\t// Update version vector\n\t\t\tawait tx.execute(\n\t\t\t\t'INSERT OR REPLACE INTO _kora_version_vector (node_id, sequence_number) VALUES (?, ?)',\n\t\t\t\t[this.nodeId, sequenceNumber],\n\t\t\t)\n\n\t\t\toperations.push(operation)\n\t\t}\n\n\t\treturn operations\n\t}\n\n\t/**\n\t * Restrict: refuse the delete if any referencing records exist.\n\t */\n\tprivate async enforceRestrict(\n\t\tincoming: IncomingRelation,\n\t\tdeletedRecordId: string,\n\t\ttx: Transaction,\n\t): Promise<Operation[]> {\n\t\tconst { sourceCollection, foreignKeyField, relationName } = incoming\n\n\t\tconst countRows = await tx.query<{ cnt: number }>(\n\t\t\t`SELECT COUNT(*) as cnt FROM ${sourceCollection} WHERE ${foreignKeyField} = ? AND _deleted = 0`,\n\t\t\t[deletedRecordId],\n\t\t)\n\t\tconst count = countRows[0]?.cnt ?? 0\n\n\t\tif (count > 0) {\n\t\t\t// Determine the target collection from the relation lookup\n\t\t\tconst targetCollection = incoming.relation.to\n\t\t\tthrow new ReferentialIntegrityError(\n\t\t\t\ttargetCollection,\n\t\t\t\tdeletedRecordId,\n\t\t\t\tsourceCollection,\n\t\t\t\trelationName,\n\t\t\t\tcount,\n\t\t\t)\n\t\t}\n\n\t\treturn []\n\t}\n\n\t/**\n\t * Get the relation lookup map for external use (e.g., by the merge engine).\n\t */\n\tgetRelationLookup(): Map<string, IncomingRelation[]> {\n\t\treturn this.lookup\n\t}\n}\n","import type { OnDeleteAction, RelationDefinition, SchemaDefinition } from '@korajs/core'\n\n/**\n * A resolved relation reference: describes a relation that points TO a given collection.\n * When a record in `targetCollection` is deleted, we must handle records in\n * `sourceCollection` that reference it via `foreignKeyField`.\n */\nexport interface IncomingRelation {\n\t/** Name of the relation in the schema */\n\trelationName: string\n\t/** Collection that holds the foreign key (the \"from\" side) */\n\tsourceCollection: string\n\t/** Field in the source collection that references the target */\n\tforeignKeyField: string\n\t/** What to do when the referenced record is deleted */\n\tonDelete: OnDeleteAction\n\t/** The full relation definition */\n\trelation: RelationDefinition\n}\n\n/**\n * Builds an efficient lookup from target collection to all relations that reference it.\n *\n * Given a schema with relations like:\n * ```\n * todoBelongsToProject: { from: 'todos', to: 'projects', field: 'projectId', onDelete: 'cascade' }\n * ```\n *\n * The lookup for 'projects' would return:\n * ```\n * [{ sourceCollection: 'todos', foreignKeyField: 'projectId', onDelete: 'cascade', ... }]\n * ```\n *\n * This enables O(1) lookup when deleting a record to find all dependent relations.\n *\n * @param schema - The full schema definition containing relations\n * @returns A map from target collection name to its incoming relations\n */\nexport function buildRelationLookup(schema: SchemaDefinition): Map<string, IncomingRelation[]> {\n\tconst lookup = new Map<string, IncomingRelation[]>()\n\n\tfor (const [relationName, relation] of Object.entries(schema.relations)) {\n\t\tconst targetCollection = relation.to\n\t\tconst existing = lookup.get(targetCollection) ?? []\n\t\texisting.push({\n\t\t\trelationName,\n\t\t\tsourceCollection: relation.from,\n\t\t\tforeignKeyField: relation.field,\n\t\t\tonDelete: relation.onDelete,\n\t\t\trelation,\n\t\t})\n\t\tlookup.set(targetCollection, existing)\n\t}\n\n\treturn lookup\n}\n\n/**\n * Get all incoming relations for a given collection.\n * Returns an empty array if no relations reference the collection.\n *\n * @param lookup - The pre-built relation lookup map\n * @param collection - The target collection name\n * @returns Array of incoming relations\n */\nexport function getIncomingRelations(\n\tlookup: Map<string, IncomingRelation[]>,\n\tcollection: string,\n): IncomingRelation[] {\n\treturn lookup.get(collection) ?? []\n}\n","import type { SequenceConfig } from '@korajs/core'\nimport { defaultSequenceFormat, formatSequenceValue } from '@korajs/core'\nimport type { StorageAdapter } from '../types'\n\ninterface SequenceRow {\n\tcounter: number\n}\n\n/**\n * Manages offline-safe sequences backed by a `_kora_sequences` table.\n *\n * Each sequence counter is scoped by (name, scope, nodeId), ensuring\n * that different devices never collide. The counter is atomically\n * incremented within a database transaction.\n *\n * @example\n * ```typescript\n * const mgr = new SequenceManager(adapter, 'node-abc')\n *\n * const receipt = await mgr.next('receipt', {\n * scope: 'store-1',\n * format: 'S-{date}-{node4}-{seq}',\n * })\n * // → \"S-20260508-node-0001\"\n * ```\n */\nexport class SequenceManager {\n\tprivate readonly adapter: StorageAdapter\n\tprivate readonly nodeId: string\n\n\tconstructor(adapter: StorageAdapter, nodeId: string) {\n\t\tthis.adapter = adapter\n\t\tthis.nodeId = nodeId\n\t}\n\n\t/**\n\t * Get the next value in a sequence, atomically incrementing the counter.\n\t *\n\t * @param name - The sequence name (e.g., 'receipt', 'invoice')\n\t * @param config - Optional configuration for scope, format, and starting value\n\t * @returns The formatted sequence value\n\t */\n\tasync next(name: string, config?: SequenceConfig): Promise<string> {\n\t\tconst scope = config?.scope ?? ''\n\t\tconst startAt = config?.startAt ?? 1\n\t\tconst format = config?.format ?? defaultSequenceFormat(name)\n\n\t\tlet counter = 0\n\n\t\tawait this.adapter.transaction(async (tx) => {\n\t\t\t// Try to read the current counter\n\t\t\tconst rows = await tx.query<SequenceRow>(\n\t\t\t\t'SELECT counter FROM _kora_sequences WHERE name = ? AND scope = ? AND node_id = ?',\n\t\t\t\t[name, scope, this.nodeId],\n\t\t\t)\n\n\t\t\tif (rows.length > 0) {\n\t\t\t\tconst row = rows[0] as SequenceRow\n\t\t\t\tcounter = row.counter + 1\n\t\t\t\tawait tx.execute(\n\t\t\t\t\t'UPDATE _kora_sequences SET counter = ? WHERE name = ? AND scope = ? AND node_id = ?',\n\t\t\t\t\t[counter, name, scope, this.nodeId],\n\t\t\t\t)\n\t\t\t} else {\n\t\t\t\t// First use — initialize with startAt\n\t\t\t\tcounter = startAt\n\t\t\t\tawait tx.execute(\n\t\t\t\t\t'INSERT INTO _kora_sequences (name, scope, node_id, counter) VALUES (?, ?, ?, ?)',\n\t\t\t\t\t[name, scope, this.nodeId, counter],\n\t\t\t\t)\n\t\t\t}\n\t\t})\n\n\t\treturn formatSequenceValue(format, counter, this.nodeId)\n\t}\n\n\t/**\n\t * Get the current counter value without incrementing.\n\t *\n\t * @param name - The sequence name\n\t * @param config - Optional scope\n\t * @returns The current counter value, or 0 if the sequence has never been used\n\t */\n\tasync current(name: string, config?: { scope?: string }): Promise<number> {\n\t\tconst scope = config?.scope ?? ''\n\n\t\tconst rows = await this.adapter.query<SequenceRow>(\n\t\t\t'SELECT counter FROM _kora_sequences WHERE name = ? AND scope = ? AND node_id = ?',\n\t\t\t[name, scope, this.nodeId],\n\t\t)\n\n\t\tif (rows.length > 0) {\n\t\t\treturn (rows[0] as SequenceRow).counter\n\t\t}\n\t\treturn 0\n\t}\n\n\t/**\n\t * Reset a sequence counter.\n\t *\n\t * @param name - The sequence name\n\t * @param config - Optional scope and target value\n\t */\n\tasync reset(name: string, config?: { scope?: string; to?: number }): Promise<void> {\n\t\tconst scope = config?.scope ?? ''\n\t\tconst to = config?.to ?? 0\n\n\t\tawait this.adapter.execute(\n\t\t\t'DELETE FROM _kora_sequences WHERE name = ? AND scope = ? AND node_id = ?',\n\t\t\t[name, scope, this.nodeId],\n\t\t)\n\n\t\tif (to > 0) {\n\t\t\tawait this.adapter.execute(\n\t\t\t\t'INSERT INTO _kora_sequences (name, scope, node_id, counter) VALUES (?, ?, ?, ?)',\n\t\t\t\t[name, scope, this.nodeId, to],\n\t\t\t)\n\t\t}\n\t}\n}\n","/**\n * Bloom filter for fast subscription dependency pre-checking.\n *\n * When the SubscriptionManager has many active subscriptions, checking whether a\n * mutation might affect any subscription requires scanning all subscriptions.\n * This bloom filter provides a fast O(k) pre-check: if the filter says \"definitely\n * not present\", we can skip the subscription entirely. If it says \"maybe present\",\n * we fall through to the precise collection/field matching.\n *\n * Uses FNV-1a for hashing and Kirsch-Mitzenmacker double hashing to derive k\n * hash functions from two base hashes.\n */\n\n// FNV-1a constants for 32-bit hashes\nconst FNV_OFFSET_BASIS = 0x811c9dc5\nconst FNV_PRIME = 0x01000193\n\n/**\n * Compute FNV-1a 32-bit hash of a string.\n *\n * FNV-1a is a non-cryptographic hash function optimized for speed and distribution.\n * It processes one byte at a time: XOR then multiply, which gives better avalanche\n * behavior than the original FNV-1 (multiply then XOR).\n *\n * @param input - The string to hash\n * @returns A 32-bit unsigned integer hash\n */\nexport function fnv1a32(input: string): number {\n\tlet hash = FNV_OFFSET_BASIS\n\tfor (let i = 0; i < input.length; i++) {\n\t\thash ^= input.charCodeAt(i)\n\t\t// Math.imul gives true 32-bit integer multiplication without overflow issues\n\t\thash = Math.imul(hash, FNV_PRIME)\n\t}\n\t// Ensure unsigned 32-bit result\n\treturn hash >>> 0\n}\n\n/**\n * Calculate the optimal number of bits for a bloom filter.\n *\n * Formula: m = -(n * ln(p)) / (ln(2)^2)\n * Rounded up to the nearest multiple of 32 for Uint32Array alignment.\n *\n * @param expectedItems - Expected number of items to insert\n * @param falsePositiveRate - Desired false positive rate (0-1)\n * @returns Number of bits, rounded to nearest 32-bit multiple (minimum 32)\n */\nexport function optimalBitCount(expectedItems: number, falsePositiveRate: number): number {\n\tif (expectedItems <= 0) return 32\n\tif (falsePositiveRate <= 0 || falsePositiveRate >= 1) return 32\n\n\tconst ln2Squared = Math.LN2 * Math.LN2\n\tconst rawBits = -(expectedItems * Math.log(falsePositiveRate)) / ln2Squared\n\n\t// Round up to nearest 32-bit multiple for Uint32Array alignment\n\tconst aligned = Math.ceil(rawBits / 32) * 32\n\treturn Math.max(32, aligned)\n}\n\n/**\n * Calculate the optimal number of hash functions for a bloom filter.\n *\n * Formula: k = (m/n) * ln(2)\n * Clamped to [1, 30] to avoid degenerate cases.\n *\n * @param bitCount - Total number of bits in the filter\n * @param expectedItems - Expected number of items to insert\n * @returns Number of hash functions, clamped to [1, 30]\n */\nexport function optimalHashCount(bitCount: number, expectedItems: number): number {\n\tif (expectedItems <= 0) return 1\n\tconst raw = (bitCount / expectedItems) * Math.LN2\n\treturn Math.max(1, Math.min(30, Math.round(raw)))\n}\n\n/**\n * Bloom filter for subscription dependency tracking.\n *\n * Each subscription adds its watched collection (and optionally fields) to the\n * filter. When a mutation arrives, we check \"collection\" and \"collection:field\"\n * keys against the filter. A negative result means no subscription cares about\n * this mutation, so we can skip the expensive per-subscription scan.\n *\n * @example\n * ```typescript\n * const filter = new SubscriptionBloomFilter(100, 0.01)\n * filter.add('todos')\n * filter.add('todos', 'completed')\n *\n * filter.mightContain('todos') // true (definitely added)\n * filter.mightContain('projects') // false (definitely not added)\n * filter.mightContain('todos', 'completed') // true (definitely added)\n * ```\n */\nexport class SubscriptionBloomFilter {\n\tprivate bits: Uint32Array\n\tprivate readonly bitCount: number\n\tprivate readonly hashCount: number\n\tprivate itemCount = 0\n\n\tconstructor(expectedItems: number, falsePositiveRate = 0.01) {\n\t\tthis.bitCount = optimalBitCount(expectedItems, falsePositiveRate)\n\t\tthis.hashCount = optimalHashCount(this.bitCount, expectedItems)\n\t\tthis.bits = new Uint32Array(this.bitCount / 32)\n\t}\n\n\t/**\n\t * Add a collection (and optional field) to the bloom filter.\n\t *\n\t * @param collection - Collection name (e.g., \"todos\")\n\t * @param field - Optional field name (e.g., \"completed\")\n\t */\n\tadd(collection: string, field?: string): void {\n\t\tconst key = field !== undefined ? `${collection}:${field}` : collection\n\t\tconst positions = this.getPositions(key)\n\t\tfor (const pos of positions) {\n\t\t\tconst wordIndex = pos >>> 5 // equivalent to Math.floor(pos / 32)\n\t\t\tconst bitIndex = pos & 31 // equivalent to pos % 32\n\t\t\tconst current = this.bits[wordIndex] ?? 0\n\t\t\tthis.bits[wordIndex] = current | (1 << bitIndex)\n\t\t}\n\t\tthis.itemCount++\n\t}\n\n\t/**\n\t * Check if a collection (and optional field) might be in the filter.\n\t *\n\t * A return value of `false` means the item is DEFINITELY NOT in the filter.\n\t * A return value of `true` means the item MIGHT be in the filter (possible false positive).\n\t *\n\t * @param collection - Collection name to check\n\t * @param field - Optional field name to check\n\t * @returns false = definitely absent, true = possibly present\n\t */\n\tmightContain(collection: string, field?: string): boolean {\n\t\tconst key = field !== undefined ? `${collection}:${field}` : collection\n\t\tconst positions = this.getPositions(key)\n\t\tfor (const pos of positions) {\n\t\t\tconst wordIndex = pos >>> 5\n\t\t\tconst bitIndex = pos & 31\n\t\t\tif (((this.bits[wordIndex] ?? 0) & (1 << bitIndex)) === 0) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\t\treturn true\n\t}\n\n\t/**\n\t * Reset the bloom filter, clearing all bits and the item count.\n\t */\n\tclear(): void {\n\t\tthis.bits.fill(0)\n\t\tthis.itemCount = 0\n\t}\n\n\t/**\n\t * Estimate the current false positive rate based on the number of items inserted.\n\t *\n\t * Formula: (1 - e^(-kn/m))^k\n\t * where k = hash count, n = item count, m = bit count.\n\t *\n\t * @returns Estimated false positive rate as a number between 0 and 1\n\t */\n\testimatedFalsePositiveRate(): number {\n\t\tif (this.itemCount === 0) return 0\n\t\tconst exponent = -(this.hashCount * this.itemCount) / this.bitCount\n\t\treturn (1 - Math.exp(exponent)) ** this.hashCount\n\t}\n\n\t/**\n\t * @returns The number of items that have been added to the filter\n\t */\n\tgetItemCount(): number {\n\t\treturn this.itemCount\n\t}\n\n\t/**\n\t * @returns The total number of bits in the filter\n\t */\n\tgetBitCount(): number {\n\t\treturn this.bitCount\n\t}\n\n\t/**\n\t * @returns The number of hash functions used\n\t */\n\tgetHashCount(): number {\n\t\treturn this.hashCount\n\t}\n\n\t/**\n\t * Count the number of bits currently set to 1.\n\t * Uses Brian Kernighan's algorithm: each iteration clears the lowest set bit,\n\t * so the loop runs exactly as many times as there are set bits.\n\t *\n\t * @returns Number of bits set to 1\n\t */\n\tgetSetBitCount(): number {\n\t\tlet count = 0\n\t\tfor (let i = 0; i < this.bits.length; i++) {\n\t\t\tlet word = this.bits[i] ?? 0\n\t\t\twhile (word !== 0) {\n\t\t\t\t// Clear the lowest set bit: n & (n - 1) removes the rightmost 1-bit\n\t\t\t\tword &= word - 1\n\t\t\t\tcount++\n\t\t\t}\n\t\t}\n\t\treturn count\n\t}\n\n\t/**\n\t * Compute k bit positions for a given key using Kirsch-Mitzenmacker double hashing.\n\t *\n\t * Instead of computing k independent hash functions, we compute two base hashes\n\t * (h1 and h2) and derive the rest as: h_i = (h1 + i * h2) mod m.\n\t * This technique is proven to have the same asymptotic false positive rate as\n\t * k independent hash functions.\n\t *\n\t * We derive h1 and h2 from a single FNV-1a hash by splitting and mixing:\n\t * h1 = fnv1a(key), h2 = fnv1a(key + \"\\0salt\") to ensure independence.\n\t */\n\tprivate getPositions(key: string): number[] {\n\t\tconst h1 = fnv1a32(key)\n\t\t// Use a null-byte separator + salt suffix to derive a second independent hash\n\t\tconst h2 = fnv1a32(`${key}\\0bloom`)\n\n\t\tconst positions = new Array<number>(this.hashCount)\n\t\tfor (let i = 0; i < this.hashCount; i++) {\n\t\t\t// Combine h1 and h2 with Kirsch-Mitzenmacker technique\n\t\t\tpositions[i] = ((h1 + Math.imul(i, h2)) >>> 0) % this.bitCount\n\t\t}\n\t\treturn positions\n\t}\n}\n","import type { Operation } from '@korajs/core'\nimport type {\n\tCollectionRecord,\n\tQueryDescriptor,\n\tSubscription,\n\tSubscriptionCallback,\n} from '../types'\nimport { SubscriptionBloomFilter } from './bloom-filter'\n\nlet nextSubId = 0\n\n/**\n * Default threshold for activating bloom filter-based dependency tracking.\n * Below this count, linear scanning is faster due to bloom filter rebuild overhead.\n */\nconst DEFAULT_BLOOM_THRESHOLD = 100\n\n/**\n * Default expected items for bloom filter sizing.\n * Sized to handle typical subscription dependency counts with headroom.\n */\nconst DEFAULT_BLOOM_EXPECTED_ITEMS = 500\n\n/**\n * Default false positive rate for bloom filter.\n * 1% provides a good balance between filter size and accuracy.\n */\nconst DEFAULT_BLOOM_FALSE_POSITIVE_RATE = 0.01\n\n/**\n * Configuration options for the SubscriptionManager.\n */\nexport interface SubscriptionManagerOptions {\n\t/**\n\t * Minimum number of subscriptions before activating bloom filter.\n\t * Below this threshold, linear scanning is used (bloom filter overhead not worth it).\n\t * @default 100\n\t */\n\tbloomThreshold?: number\n\n\t/**\n\t * Expected number of unique collection+field dependencies for bloom filter sizing.\n\t * @default 500\n\t */\n\tbloomExpectedItems?: number\n\n\t/**\n\t * Target false positive rate for the bloom filter.\n\t * Lower values require more memory but reduce unnecessary precise checks.\n\t * @default 0.01\n\t */\n\tbloomFalsePositiveRate?: number\n}\n\n/**\n * Performance statistics for monitoring subscription checking efficiency.\n */\nexport interface SubscriptionStats {\n\t/** Total number of mutation notifications processed */\n\ttotalChecks: number\n\t/** Number of times bloom filter said \"maybe\" (proceeded to precise check) */\n\tbloomFilterHits: number\n\t/** Number of times bloom filter said \"definitely not\" (skipped all subscriptions) */\n\tbloomFilterMisses: number\n\t/** Number of times bloom filter said \"maybe\" but precise check found no match */\n\tfalsePositives: number\n\t/** Average time per check in milliseconds */\n\taverageCheckTimeMs: number\n\t/** Whether bloom filter is currently active */\n\tbloomFilterActive: boolean\n\t/** Current subscription count */\n\tsubscriptionCount: number\n}\n\n/**\n * Manages reactive subscriptions with two-level dependency checking.\n *\n * When a mutation occurs on a collection, affected subscriptions are re-evaluated\n * in a microtask batch and callbacks are invoked only if results actually changed.\n *\n * For large subscription counts (>= bloomThreshold), a bloom filter provides O(k)\n * pre-filtering to avoid scanning all subscriptions on every mutation:\n *\n * Level 1 (Bloom filter): Fast O(k) check -- does this mutation potentially affect\n * any subscription? If NO: skip all subscriptions (guaranteed correct).\n * If MAYBE: proceed to Level 2.\n *\n * Level 2 (Precise check): Only evaluate subscriptions that match the mutated\n * collection, including included (related) collection tracking.\n */\nexport class SubscriptionManager {\n\tprivate subscriptions = new Map<string, Subscription>()\n\tprivate pendingCollections = new Set<string>()\n\tprivate flushScheduled = false\n\n\t// Bloom filter state\n\tprivate bloomFilter: SubscriptionBloomFilter | null = null\n\tprivate bloomDirty = false\n\tprivate readonly bloomThreshold: number\n\tprivate readonly bloomExpectedItems: number\n\tprivate readonly bloomFalsePositiveRate: number\n\n\t// Performance stats\n\tprivate totalChecks = 0\n\tprivate bloomFilterHits = 0\n\tprivate bloomFilterMisses = 0\n\tprivate falsePositives = 0\n\tprivate totalCheckTimeMs = 0\n\n\tconstructor(options?: SubscriptionManagerOptions) {\n\t\tthis.bloomThreshold = options?.bloomThreshold ?? DEFAULT_BLOOM_THRESHOLD\n\t\tthis.bloomExpectedItems = options?.bloomExpectedItems ?? DEFAULT_BLOOM_EXPECTED_ITEMS\n\t\tthis.bloomFalsePositiveRate =\n\t\t\toptions?.bloomFalsePositiveRate ?? DEFAULT_BLOOM_FALSE_POSITIVE_RATE\n\t}\n\n\t/**\n\t * Register a new subscription.\n\t *\n\t * @param descriptor - The query descriptor defining what this subscription watches\n\t * @param callback - Called with results whenever they change\n\t * @param executeFn - Function to re-execute the query and get current results\n\t * @returns An unsubscribe function\n\t */\n\tregister(\n\t\tdescriptor: QueryDescriptor,\n\t\tcallback: SubscriptionCallback<CollectionRecord>,\n\t\texecuteFn: () => Promise<CollectionRecord[]>,\n\t): () => void {\n\t\tconst id = `sub_${++nextSubId}`\n\t\tconst subscription: Subscription = {\n\t\t\tid,\n\t\t\tdescriptor,\n\t\t\tcallback,\n\t\t\texecuteFn,\n\t\t\tlastResults: [],\n\t\t}\n\t\tthis.subscriptions.set(id, subscription)\n\n\t\t// Mark bloom filter as needing rebuild since dependencies changed\n\t\tthis.bloomDirty = true\n\n\t\treturn () => {\n\t\t\tthis.subscriptions.delete(id)\n\t\t\tthis.bloomDirty = true\n\t\t}\n\t}\n\n\t/**\n\t * Register a subscription and immediately execute the query.\n\t * The initial results are stored as lastResults so subsequent flushes\n\t * correctly diff against the initial state.\n\t *\n\t * @returns An unsubscribe function\n\t */\n\tregisterAndFetch(\n\t\tdescriptor: QueryDescriptor,\n\t\tcallback: SubscriptionCallback<CollectionRecord>,\n\t\texecuteFn: () => Promise<CollectionRecord[]>,\n\t): () => void {\n\t\tconst id = `sub_${++nextSubId}`\n\t\tconst subscription: Subscription = {\n\t\t\tid,\n\t\t\tdescriptor,\n\t\t\tcallback,\n\t\t\texecuteFn,\n\t\t\tlastResults: [],\n\t\t}\n\t\tthis.subscriptions.set(id, subscription)\n\n\t\t// Mark bloom filter as needing rebuild since dependencies changed\n\t\tthis.bloomDirty = true\n\n\t\t// Execute immediately, set lastResults, and call callback\n\t\texecuteFn().then((results) => {\n\t\t\t// Guard: subscription may have been removed before the async fetch completes\n\t\t\tif (this.subscriptions.has(id)) {\n\t\t\t\tsubscription.lastResults = results\n\t\t\t\tcallback(results)\n\t\t\t}\n\t\t})\n\n\t\treturn () => {\n\t\t\tthis.subscriptions.delete(id)\n\t\t\tthis.bloomDirty = true\n\t\t}\n\t}\n\n\t/**\n\t * Notify the manager that a mutation occurred on a collection.\n\t * Schedules a microtask flush to batch multiple mutations in the same tick.\n\t */\n\tnotify(collection: string, _operation: Operation): void {\n\t\tthis.pendingCollections.add(collection)\n\t\tthis.scheduleFlush()\n\t}\n\n\t/**\n\t * Immediately flush all pending notifications.\n\t * Useful for testing. In production, flushing happens via microtask.\n\t */\n\tasync flush(): Promise<void> {\n\t\tif (this.pendingCollections.size === 0) return\n\n\t\tconst collections = new Set(this.pendingCollections)\n\t\tthis.pendingCollections.clear()\n\t\tthis.flushScheduled = false\n\n\t\tconst affected = this.findAffectedSubscriptions(collections)\n\n\t\t// Re-execute and diff\n\t\tfor (const sub of affected) {\n\t\t\ttry {\n\t\t\t\tconst newResults = await sub.executeFn()\n\t\t\t\tif (!this.resultsEqual(sub.lastResults, newResults)) {\n\t\t\t\t\tsub.lastResults = newResults\n\t\t\t\t\tsub.callback(newResults)\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\t// Subscription re-execution failed -- skip silently for now.\n\t\t\t\t// In future, we could emit an error event for DevTools.\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Remove all subscriptions. Called on store close.\n\t */\n\tclear(): void {\n\t\tthis.subscriptions.clear()\n\t\tthis.pendingCollections.clear()\n\t\tthis.flushScheduled = false\n\t\tthis.bloomFilter = null\n\t\tthis.bloomDirty = false\n\t\tthis.totalChecks = 0\n\t\tthis.bloomFilterHits = 0\n\t\tthis.bloomFilterMisses = 0\n\t\tthis.falsePositives = 0\n\t\tthis.totalCheckTimeMs = 0\n\t}\n\n\t/** Number of active subscriptions (for testing/debugging) */\n\tget size(): number {\n\t\treturn this.subscriptions.size\n\t}\n\n\t/**\n\t * Get performance statistics for monitoring subscription checking efficiency.\n\t * Useful for DevTools integration and performance tuning.\n\t */\n\tgetStats(): SubscriptionStats {\n\t\treturn {\n\t\t\ttotalChecks: this.totalChecks,\n\t\t\tbloomFilterHits: this.bloomFilterHits,\n\t\t\tbloomFilterMisses: this.bloomFilterMisses,\n\t\t\tfalsePositives: this.falsePositives,\n\t\t\taverageCheckTimeMs:\n\t\t\t\tthis.totalChecks > 0 ? this.totalCheckTimeMs / this.totalChecks : 0,\n\t\t\tbloomFilterActive: this.isBloomActive(),\n\t\t\tsubscriptionCount: this.subscriptions.size,\n\t\t}\n\t}\n\n\t/**\n\t * Check if bloom filter is currently active.\n\t * Active when subscription count meets or exceeds the threshold.\n\t */\n\tisBloomActive(): boolean {\n\t\treturn this.subscriptions.size >= this.bloomThreshold\n\t}\n\n\t/**\n\t * Find subscriptions affected by mutations to the given collections.\n\t * Uses two-level checking when bloom filter is active:\n\t *\n\t * Level 1: Bloom filter pre-check -- if no subscription depends on any\n\t * of the mutated collections, skip everything (O(k) per collection).\n\t *\n\t * Level 2: Precise check -- linear scan of subscriptions, matching\n\t * against the mutated collections.\n\t */\n\tprivate findAffectedSubscriptions(collections: Set<string>): Subscription[] {\n\t\tconst startTime = performance.now()\n\t\tthis.totalChecks++\n\n\t\tconst useBloom = this.isBloomActive()\n\n\t\tif (useBloom) {\n\t\t\t// Rebuild bloom filter if dependencies have changed\n\t\t\tif (this.bloomDirty || this.bloomFilter === null) {\n\t\t\t\tthis.rebuildBloomFilter()\n\t\t\t}\n\n\t\t\tconst filter = this.bloomFilter\n\t\t\tif (filter !== null) {\n\t\t\t\t// Level 1: Bloom filter pre-check\n\t\t\t\tlet anyPossibleMatch = false\n\t\t\t\tfor (const col of collections) {\n\t\t\t\t\tif (filter.mightContain(col)) {\n\t\t\t\t\t\tanyPossibleMatch = true\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (!anyPossibleMatch) {\n\t\t\t\t\t// Bloom filter guarantees no subscription depends on these collections\n\t\t\t\t\tthis.bloomFilterMisses++\n\t\t\t\t\tthis.totalCheckTimeMs += performance.now() - startTime\n\t\t\t\t\treturn []\n\t\t\t\t}\n\n\t\t\t\tthis.bloomFilterHits++\n\t\t\t}\n\t\t}\n\n\t\t// Level 2: Precise check (or only check when bloom is not active)\n\t\tconst affected: Subscription[] = []\n\t\tlet anyPreciseMatch = false\n\n\t\tfor (const sub of this.subscriptions.values()) {\n\t\t\tif (collections.has(sub.descriptor.collection)) {\n\t\t\t\taffected.push(sub)\n\t\t\t\tanyPreciseMatch = true\n\t\t\t} else if (sub.descriptor.includeCollections) {\n\t\t\t\t// Re-evaluate if a mutation affects an included (related) collection\n\t\t\t\tfor (const incCol of sub.descriptor.includeCollections) {\n\t\t\t\t\tif (collections.has(incCol)) {\n\t\t\t\t\t\taffected.push(sub)\n\t\t\t\t\t\tanyPreciseMatch = true\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Track false positives: bloom said \"maybe\" but precise check found nothing\n\t\tif (useBloom && !anyPreciseMatch) {\n\t\t\tthis.falsePositives++\n\t\t}\n\n\t\tthis.totalCheckTimeMs += performance.now() - startTime\n\t\treturn affected\n\t}\n\n\t/**\n\t * Rebuild the bloom filter from all current subscriptions.\n\t * Adds collection-level dependencies for every subscription, plus\n\t * any included collection dependencies.\n\t */\n\tprivate rebuildBloomFilter(): void {\n\t\tconst filter = new SubscriptionBloomFilter(\n\t\t\tthis.bloomExpectedItems,\n\t\t\tthis.bloomFalsePositiveRate,\n\t\t)\n\n\t\tfor (const sub of this.subscriptions.values()) {\n\t\t\t// Add the primary collection dependency\n\t\t\tfilter.add(sub.descriptor.collection)\n\n\t\t\t// Add included (related) collection dependencies\n\t\t\tif (sub.descriptor.includeCollections) {\n\t\t\t\tfor (const incCol of sub.descriptor.includeCollections) {\n\t\t\t\t\tfilter.add(incCol)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tthis.bloomFilter = filter\n\t\tthis.bloomDirty = false\n\t}\n\n\tprivate scheduleFlush(): void {\n\t\tif (this.flushScheduled) return\n\t\tthis.flushScheduled = true\n\t\tqueueMicrotask(() => {\n\t\t\tthis.flush()\n\t\t})\n\t}\n\n\t/**\n\t * Compare two result sets. Uses length check + JSON comparison as pragmatic approach.\n\t * Sufficient for typical query results. Can be optimized to id-based diffing if profiling shows need.\n\t */\n\tprivate resultsEqual(prev: CollectionRecord[], next: CollectionRecord[]): boolean {\n\t\tif (prev.length !== next.length) return false\n\t\t// Fast path: both empty\n\t\tif (prev.length === 0) return true\n\t\treturn JSON.stringify(prev) === JSON.stringify(next)\n\t}\n}\n","import type {\n\tAtomicOp,\n\tCollectionDefinition,\n\tHybridLogicalClock,\n\tOperation,\n\tSchemaDefinition,\n} from '@korajs/core'\nimport {\n\tcreateOperation,\n\tgenerateUUIDv7,\n\tisAtomicOp,\n\tresolveAtomicOp,\n\ttoAtomicOp,\n\tvalidateRecord,\n} from '@korajs/core'\nimport { RecordNotFoundError } from '../errors'\nimport { buildInsertQuery, buildSoftDeleteQuery, buildUpdateQuery } from '../query/sql-builder'\nimport { deserializeRecord, serializeOperation, serializeRecord } from '../serialization/serializer'\nimport type { CollectionRecord, RawCollectionRow, StorageAdapter, Transaction } from '../types'\n\n/**\n * A buffered SQL command to be executed during commit.\n */\ninterface BufferedCommand {\n\tsql: string\n\tparams: unknown[]\n}\n\n/**\n * A buffered operation with its associated SQL commands.\n */\ninterface BufferedEntry {\n\toperation: Operation\n\tcommands: BufferedCommand[]\n\tcollection: string\n}\n\n/**\n * Internal configuration for creating a TransactionContext.\n * Passed from Store to avoid exposing Store internals publicly.\n */\nexport interface TransactionContextConfig {\n\tschema: SchemaDefinition\n\tadapter: StorageAdapter\n\tclock: HybridLogicalClock\n\tnodeId: string\n\tgetSequenceNumber: () => number\n}\n\n/**\n * A collection accessor within a transaction.\n * Operations are buffered and committed atomically when the transaction completes.\n */\nexport interface TransactionCollectionAccessor {\n\tinsert(data: Record<string, unknown>): Promise<CollectionRecord>\n\tupdate(id: string, data: Record<string, unknown>): Promise<CollectionRecord>\n\tdelete(id: string): Promise<void>\n\tfindById(id: string): Promise<CollectionRecord | null>\n}\n\n/**\n * TransactionContext provides atomic multi-collection operations.\n *\n * All mutations are buffered and committed in a single StorageAdapter.transaction()\n * call. All operations share the same transactionId (UUID v7).\n *\n * Subscription notifications are deferred until after commit.\n *\n * @example\n * ```typescript\n * const { operations, affectedCollections } = await txContext.commit()\n * // Notify subscriptions after commit\n * for (const op of operations) {\n * subscriptionManager.notify(op.collection, op)\n * }\n * ```\n */\nexport class TransactionContext {\n\tprivate readonly transactionId: string\n\tprivate mutationName: string | undefined\n\tprivate readonly buffer: BufferedEntry[] = []\n\tprivate committed = false\n\tprivate rolledBack = false\n\tprivate readonly config: TransactionContextConfig\n\n\tconstructor(config: TransactionContextConfig) {\n\t\tthis.config = config\n\t\tthis.transactionId = generateUUIDv7()\n\t}\n\n\t/**\n\t * Set a human-readable mutation name for this transaction.\n\t * Propagated to all operations for DevTools display.\n\t */\n\tsetMutationName(name: string): void {\n\t\tthis.mutationName = name\n\t}\n\n\t/**\n\t * Get the mutation name, if set.\n\t */\n\tgetMutationName(): string | undefined {\n\t\treturn this.mutationName\n\t}\n\n\t/**\n\t * Get a collection accessor for buffered operations within this transaction.\n\t */\n\tcollection(name: string): TransactionCollectionAccessor {\n\t\tconst definition = this.config.schema.collections[name]\n\t\tif (!definition) {\n\t\t\tthrow new Error(\n\t\t\t\t`Unknown collection \"${name}\". Available: ${Object.keys(this.config.schema.collections).join(', ')}`,\n\t\t\t)\n\t\t}\n\n\t\treturn {\n\t\t\tinsert: (data: Record<string, unknown>) => this.insert(name, definition, data),\n\t\t\tupdate: (id: string, data: Record<string, unknown>) =>\n\t\t\t\tthis.update(name, definition, id, data),\n\t\t\tdelete: (id: string) => this.deleteRecord(name, definition, id),\n\t\t\tfindById: (id: string) => this.findById(name, definition, id),\n\t\t}\n\t}\n\n\t/**\n\t * Commit all buffered operations atomically.\n\t * Returns the list of operations and affected collections for subscription notification.\n\t */\n\tasync commit(): Promise<{ operations: Operation[]; affectedCollections: Set<string> }> {\n\t\tif (this.committed) {\n\t\t\tthrow new Error('Transaction already committed.')\n\t\t}\n\t\tif (this.rolledBack) {\n\t\t\tthrow new Error('Transaction was rolled back and cannot be committed.')\n\t\t}\n\n\t\tthis.committed = true\n\n\t\tif (this.buffer.length === 0) {\n\t\t\treturn { operations: [], affectedCollections: new Set() }\n\t\t}\n\n\t\tconst operations: Operation[] = []\n\t\tconst affectedCollections = new Set<string>()\n\n\t\t// Execute all buffered commands in a single adapter transaction\n\t\tawait this.config.adapter.transaction(async (tx: Transaction) => {\n\t\t\tfor (const entry of this.buffer) {\n\t\t\t\tfor (const cmd of entry.commands) {\n\t\t\t\t\tawait tx.execute(cmd.sql, cmd.params)\n\t\t\t\t}\n\t\t\t\toperations.push(entry.operation)\n\t\t\t\taffectedCollections.add(entry.collection)\n\t\t\t}\n\t\t})\n\n\t\treturn { operations, affectedCollections }\n\t}\n\n\t/**\n\t * Mark the transaction as rolled back. No operations will be committed.\n\t */\n\trollback(): void {\n\t\tthis.rolledBack = true\n\t\tthis.buffer.length = 0\n\t}\n\n\t/**\n\t * Get the transaction ID shared by all operations in this transaction.\n\t */\n\tgetTransactionId(): string {\n\t\treturn this.transactionId\n\t}\n\n\tprivate ensureActive(): void {\n\t\tif (this.committed) {\n\t\t\tthrow new Error('Cannot perform operations on a committed transaction.')\n\t\t}\n\t\tif (this.rolledBack) {\n\t\t\tthrow new Error('Cannot perform operations on a rolled-back transaction.')\n\t\t}\n\t}\n\n\tprivate async insert(\n\t\tcollectionName: string,\n\t\tdefinition: CollectionDefinition,\n\t\tdata: Record<string, unknown>,\n\t): Promise<CollectionRecord> {\n\t\tthis.ensureActive()\n\n\t\tconst validated = validateRecord(collectionName, definition, data, 'insert')\n\t\tconst recordId = generateUUIDv7()\n\t\tconst now = Date.now()\n\n\t\t// Set auto timestamp fields\n\t\tfor (const [fieldName, descriptor] of Object.entries(definition.fields)) {\n\t\t\tif (descriptor.auto && descriptor.kind === 'timestamp') {\n\t\t\t\tvalidated[fieldName] = now\n\t\t\t}\n\t\t}\n\n\t\tconst sequenceNumber = this.config.getSequenceNumber()\n\t\tconst operation = await createOperation(\n\t\t\t{\n\t\t\t\tnodeId: this.config.nodeId,\n\t\t\t\ttype: 'insert',\n\t\t\t\tcollection: collectionName,\n\t\t\t\trecordId,\n\t\t\t\tdata: { ...validated },\n\t\t\t\tpreviousData: null,\n\t\t\t\tsequenceNumber,\n\t\t\t\tcausalDeps: [],\n\t\t\t\tschemaVersion: this.config.schema.version,\n\t\t\t\ttransactionId: this.transactionId,\n\t\t\t\t...(this.mutationName !== undefined ? { mutationName: this.mutationName } : {}),\n\t\t\t},\n\t\t\tthis.config.clock,\n\t\t)\n\n\t\tconst serializedData = serializeRecord(validated, definition.fields)\n\t\tconst record: Record<string, unknown> = {\n\t\t\tid: recordId,\n\t\t\t...serializedData,\n\t\t\t_created_at: now,\n\t\t\t_updated_at: now,\n\t\t}\n\n\t\tconst insertQuery = buildInsertQuery(collectionName, record)\n\t\tconst opRow = serializeOperation(operation)\n\t\tconst opInsert = buildInsertQuery(\n\t\t\t`_kora_ops_${collectionName}`,\n\t\t\topRow as unknown as Record<string, unknown>,\n\t\t)\n\n\t\tthis.buffer.push({\n\t\t\toperation,\n\t\t\tcollection: collectionName,\n\t\t\tcommands: [\n\t\t\t\t{ sql: insertQuery.sql, params: insertQuery.params },\n\t\t\t\t{ sql: opInsert.sql, params: opInsert.params },\n\t\t\t\t{\n\t\t\t\t\tsql: 'INSERT OR REPLACE INTO _kora_version_vector (node_id, sequence_number) VALUES (?, ?)',\n\t\t\t\t\tparams: [this.config.nodeId, sequenceNumber],\n\t\t\t\t},\n\t\t\t],\n\t\t})\n\n\t\treturn {\n\t\t\tid: recordId,\n\t\t\t...validated,\n\t\t\tcreatedAt: now,\n\t\t\tupdatedAt: now,\n\t\t}\n\t}\n\n\tprivate async update(\n\t\tcollectionName: string,\n\t\tdefinition: CollectionDefinition,\n\t\tid: string,\n\t\tdata: Record<string, unknown>,\n\t): Promise<CollectionRecord> {\n\t\tthis.ensureActive()\n\n\t\t// Check for buffered inserts/updates for this record to get current state\n\t\tconst currentRecord = await this.getEffectiveRecord(collectionName, definition, id)\n\t\tif (!currentRecord) {\n\t\t\tthrow new RecordNotFoundError(collectionName, id)\n\t\t}\n\n\t\tconst validated = validateRecord(collectionName, definition, data, 'update')\n\t\tconst now = Date.now()\n\n\t\tconst previousData: Record<string, unknown> = {}\n\t\tconst resolvedData: Record<string, unknown> = {}\n\t\tconst atomicOps: Record<string, AtomicOp> = {}\n\n\t\tfor (const key of Object.keys(validated)) {\n\t\t\tconst value = validated[key]\n\t\t\tpreviousData[key] = currentRecord[key]\n\n\t\t\tif (isAtomicOp(value)) {\n\t\t\t\tresolvedData[key] = resolveAtomicOp(currentRecord[key], value)\n\t\t\t\tatomicOps[key] = toAtomicOp(value)\n\t\t\t} else {\n\t\t\t\tresolvedData[key] = value\n\t\t\t}\n\t\t}\n\n\t\tconst hasAtomicOps = Object.keys(atomicOps).length > 0\n\n\t\tconst sequenceNumber = this.config.getSequenceNumber()\n\t\tconst operation = await createOperation(\n\t\t\t{\n\t\t\t\tnodeId: this.config.nodeId,\n\t\t\t\ttype: 'update',\n\t\t\t\tcollection: collectionName,\n\t\t\t\trecordId: id,\n\t\t\t\tdata: { ...resolvedData },\n\t\t\t\tpreviousData,\n\t\t\t\tsequenceNumber,\n\t\t\t\tcausalDeps: [],\n\t\t\t\tschemaVersion: this.config.schema.version,\n\t\t\t\ttransactionId: this.transactionId,\n\t\t\t\t...(this.mutationName !== undefined ? { mutationName: this.mutationName } : {}),\n\t\t\t\t...(hasAtomicOps ? { atomicOps } : {}),\n\t\t\t},\n\t\t\tthis.config.clock,\n\t\t)\n\n\t\tconst serializedChanges = serializeRecord(resolvedData, definition.fields)\n\t\tconst updateQuery = buildUpdateQuery(collectionName, id, {\n\t\t\t...serializedChanges,\n\t\t\t_updated_at: now,\n\t\t})\n\t\tconst opRow = serializeOperation(operation)\n\t\tconst opInsert = buildInsertQuery(\n\t\t\t`_kora_ops_${collectionName}`,\n\t\t\topRow as unknown as Record<string, unknown>,\n\t\t)\n\n\t\tthis.buffer.push({\n\t\t\toperation,\n\t\t\tcollection: collectionName,\n\t\t\tcommands: [\n\t\t\t\t{ sql: updateQuery.sql, params: updateQuery.params },\n\t\t\t\t{ sql: opInsert.sql, params: opInsert.params },\n\t\t\t\t{\n\t\t\t\t\tsql: 'INSERT OR REPLACE INTO _kora_version_vector (node_id, sequence_number) VALUES (?, ?)',\n\t\t\t\t\tparams: [this.config.nodeId, sequenceNumber],\n\t\t\t\t},\n\t\t\t],\n\t\t})\n\n\t\t// Merge current record with resolved changes for return value\n\t\treturn {\n\t\t\t...currentRecord,\n\t\t\t...resolvedData,\n\t\t\tupdatedAt: now,\n\t\t} as CollectionRecord\n\t}\n\n\tprivate async deleteRecord(\n\t\tcollectionName: string,\n\t\tdefinition: CollectionDefinition,\n\t\tid: string,\n\t): Promise<void> {\n\t\tthis.ensureActive()\n\n\t\tconst currentRecord = await this.getEffectiveRecord(collectionName, definition, id)\n\t\tif (!currentRecord) {\n\t\t\tthrow new RecordNotFoundError(collectionName, id)\n\t\t}\n\n\t\tconst now = Date.now()\n\t\tconst sequenceNumber = this.config.getSequenceNumber()\n\t\tconst operation = await createOperation(\n\t\t\t{\n\t\t\t\tnodeId: this.config.nodeId,\n\t\t\t\ttype: 'delete',\n\t\t\t\tcollection: collectionName,\n\t\t\t\trecordId: id,\n\t\t\t\tdata: null,\n\t\t\t\tpreviousData: null,\n\t\t\t\tsequenceNumber,\n\t\t\t\tcausalDeps: [],\n\t\t\t\tschemaVersion: this.config.schema.version,\n\t\t\t\ttransactionId: this.transactionId,\n\t\t\t\t...(this.mutationName !== undefined ? { mutationName: this.mutationName } : {}),\n\t\t\t},\n\t\t\tthis.config.clock,\n\t\t)\n\n\t\tconst deleteQuery = buildSoftDeleteQuery(collectionName, id, now)\n\t\tconst opRow = serializeOperation(operation)\n\t\tconst opInsert = buildInsertQuery(\n\t\t\t`_kora_ops_${collectionName}`,\n\t\t\topRow as unknown as Record<string, unknown>,\n\t\t)\n\n\t\tthis.buffer.push({\n\t\t\toperation,\n\t\t\tcollection: collectionName,\n\t\t\tcommands: [\n\t\t\t\t{ sql: deleteQuery.sql, params: deleteQuery.params },\n\t\t\t\t{ sql: opInsert.sql, params: opInsert.params },\n\t\t\t\t{\n\t\t\t\t\tsql: 'INSERT OR REPLACE INTO _kora_version_vector (node_id, sequence_number) VALUES (?, ?)',\n\t\t\t\t\tparams: [this.config.nodeId, sequenceNumber],\n\t\t\t\t},\n\t\t\t],\n\t\t})\n\t}\n\n\tprivate async findById(\n\t\tcollectionName: string,\n\t\tdefinition: CollectionDefinition,\n\t\tid: string,\n\t): Promise<CollectionRecord | null> {\n\t\treturn this.getEffectiveRecord(collectionName, definition, id)\n\t}\n\n\t/**\n\t * Get the effective state of a record, considering both the database and buffered operations.\n\t * Buffered inserts/updates take precedence over the database state.\n\t */\n\tprivate async getEffectiveRecord(\n\t\tcollectionName: string,\n\t\tdefinition: CollectionDefinition,\n\t\tid: string,\n\t): Promise<CollectionRecord | null> {\n\t\t// Check if there's a buffered delete for this record (scan from newest to oldest)\n\t\tfor (let i = this.buffer.length - 1; i >= 0; i--) {\n\t\t\tconst entry = this.buffer[i] as BufferedEntry\n\t\t\tif (entry.collection === collectionName && entry.operation.recordId === id) {\n\t\t\t\tif (entry.operation.type === 'delete') {\n\t\t\t\t\treturn null\n\t\t\t\t}\n\t\t\t\t// For buffered inserts/updates, reconstruct the record from the database + buffered changes\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\t// Read from database first\n\t\tconst rows = await this.config.adapter.query<RawCollectionRow>(\n\t\t\t`SELECT * FROM ${collectionName} WHERE id = ? AND _deleted = 0`,\n\t\t\t[id],\n\t\t)\n\n\t\tlet record: CollectionRecord | null = rows[0]\n\t\t\t? deserializeRecord(rows[0], definition.fields)\n\t\t\t: null\n\n\t\t// Apply buffered operations on top\n\t\tfor (const entry of this.buffer) {\n\t\t\tif (entry.collection !== collectionName || entry.operation.recordId !== id) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif (entry.operation.type === 'insert' && entry.operation.data) {\n\t\t\t\trecord = {\n\t\t\t\t\tid,\n\t\t\t\t\t...entry.operation.data,\n\t\t\t\t\tcreatedAt: entry.operation.timestamp.wallTime,\n\t\t\t\t\tupdatedAt: entry.operation.timestamp.wallTime,\n\t\t\t\t}\n\t\t\t} else if (entry.operation.type === 'update' && entry.operation.data && record) {\n\t\t\t\trecord = {\n\t\t\t\t\t...record,\n\t\t\t\t\t...entry.operation.data,\n\t\t\t\t\tupdatedAt: entry.operation.timestamp.wallTime,\n\t\t\t\t}\n\t\t\t} else if (entry.operation.type === 'delete') {\n\t\t\t\trecord = null\n\t\t\t}\n\t\t}\n\n\t\treturn record\n\t}\n}\n"],"mappings":"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","names":["HybridLogicalClock","generateUUIDv7","QueryError","propName","KoraError","createOperation","KoraError","createOperation","createOperation","generateUUIDv7","isAtomicOp","resolveAtomicOp","toAtomicOp","validateRecord","generateUUIDv7","validateRecord","createOperation","isAtomicOp","resolveAtomicOp","toAtomicOp","HybridLogicalClock","generateUUIDv7"]}