@korajs/server 0.3.2 → 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/README.md +33 -0
- package/dist/index.cjs +253 -75
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +142 -2
- package/dist/index.d.ts +142 -2
- package/dist/index.js +249 -77
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/store/memory-server-store.ts","../src/store/materialization.ts","../src/store/postgres-server-store.ts","../src/store/drizzle-pg-schema.ts","../src/store/sqlite-server-store.ts","../src/store/drizzle-schema.ts","../src/transport/http-server-transport.ts","../src/transport/ws-server-transport.ts","../src/session/client-session.ts","../src/scopes/server-scope-filter.ts","../src/server/kora-sync-server.ts","../src/auth/no-auth.ts","../src/auth/token-auth.ts","../src/auth/kora-auth-provider.ts","../src/server/create-server.ts","../src/server/production-server.ts"],"sourcesContent":["import type { Operation, SchemaDefinition, VersionVector } from '@korajs/core'\nimport { generateUUIDv7 } from '@korajs/core'\nimport type { ApplyResult } from '@korajs/sync'\nimport {\n\tdeserializeFieldValue,\n\treplayOperationsForRecord,\n\tserializeFieldValue,\n\tvalidateFieldName,\n} from './materialization'\nimport type { CollectionQueryOptions, MaterializedRecord, ServerStore } from './server-store'\n\n/**\n * In-memory server store for testing and quick prototyping.\n * Not suitable for production — data does not survive process restart.\n *\n * When a schema is set via setSchema(), maintains materialized records\n * in-memory for efficient queries.\n */\nexport class MemoryServerStore implements ServerStore {\n\tprivate readonly nodeId: string\n\tprivate readonly operations: Operation[] = []\n\tprivate readonly operationIndex = new Map<string, Operation>()\n\tprivate readonly versionVector: Map<string, number> = new Map()\n\tprivate schema: SchemaDefinition | null = null\n\n\t/** Materialized records: collection -> recordId -> record data */\n\tprivate readonly materializedRecords = new Map<string, Map<string, MaterializedRecord>>()\n\n\tprivate closed = false\n\n\tconstructor(nodeId?: string) {\n\t\tthis.nodeId = nodeId ?? generateUUIDv7()\n\t}\n\n\tgetVersionVector(): VersionVector {\n\t\treturn new Map(this.versionVector)\n\t}\n\n\tgetNodeId(): string {\n\t\treturn this.nodeId\n\t}\n\n\tasync setSchema(schema: SchemaDefinition): Promise<void> {\n\t\tthis.assertOpen()\n\t\tthis.schema = schema\n\n\t\t// Initialize collection maps\n\t\tfor (const collectionName of Object.keys(schema.collections)) {\n\t\t\tif (!this.materializedRecords.has(collectionName)) {\n\t\t\t\tthis.materializedRecords.set(collectionName, new Map())\n\t\t\t}\n\t\t}\n\n\t\t// Backfill from existing operations\n\t\tthis.backfillAllCollections()\n\t}\n\n\tasync applyRemoteOperation(op: Operation): Promise<ApplyResult> {\n\t\tthis.assertOpen()\n\n\t\t// Content-addressed dedup: same id = same content\n\t\tif (this.operationIndex.has(op.id)) {\n\t\t\treturn 'duplicate'\n\t\t}\n\n\t\tthis.operations.push(op)\n\t\tthis.operationIndex.set(op.id, op)\n\n\t\t// Advance version vector\n\t\tconst currentSeq = this.versionVector.get(op.nodeId) ?? 0\n\t\tif (op.sequenceNumber > currentSeq) {\n\t\t\tthis.versionVector.set(op.nodeId, op.sequenceNumber)\n\t\t}\n\n\t\t// Dual-write: update materialized records if schema is set\n\t\tif (this.schema && this.schema.collections[op.collection]) {\n\t\t\tthis.rebuildMaterializedRecord(op.collection, op.recordId)\n\t\t}\n\n\t\treturn 'applied'\n\t}\n\n\tasync getOperationRange(nodeId: string, fromSeq: number, toSeq: number): Promise<Operation[]> {\n\t\tthis.assertOpen()\n\n\t\treturn this.operations\n\t\t\t.filter(\n\t\t\t\t(op) => op.nodeId === nodeId && op.sequenceNumber >= fromSeq && op.sequenceNumber <= toSeq,\n\t\t\t)\n\t\t\t.sort((a, b) => a.sequenceNumber - b.sequenceNumber)\n\t}\n\n\tasync getOperationCount(): Promise<number> {\n\t\tthis.assertOpen()\n\t\treturn this.operations.length\n\t}\n\n\tasync materializeCollection(collection: string): Promise<MaterializedRecord[]> {\n\t\tthis.assertOpen()\n\n\t\t// Fast path: if schema is set, read from materialized records\n\t\tif (this.schema && this.schema.collections[collection]) {\n\t\t\treturn this.queryCollection(collection)\n\t\t}\n\n\t\t// Fallback: replay operations\n\t\treturn this.materializeFromOps(collection)\n\t}\n\n\tasync queryCollection(\n\t\tcollection: string,\n\t\toptions?: CollectionQueryOptions,\n\t): Promise<MaterializedRecord[]> {\n\t\tthis.assertOpen()\n\t\tthis.assertSchema()\n\t\tthis.assertCollection(collection)\n\n\t\t// Validate field names\n\t\tif (options?.where) {\n\t\t\tfor (const key of Object.keys(options.where)) {\n\t\t\t\tvalidateFieldName(collection, key, this.schema!)\n\t\t\t}\n\t\t}\n\t\tif (options?.orderBy) {\n\t\t\tvalidateFieldName(collection, options.orderBy, this.schema!)\n\t\t}\n\n\t\tconst collectionMap = this.materializedRecords.get(collection)\n\t\tif (!collectionMap) return []\n\n\t\t// Get all non-deleted records\n\t\tlet records = Array.from(collectionMap.values()).filter((r) => {\n\t\t\tif (!options?.includeDeleted && r._deleted === 1) return false\n\t\t\treturn true\n\t\t})\n\n\t\t// Apply WHERE filters\n\t\tif (options?.where) {\n\t\t\tfor (const [key, value] of Object.entries(options.where)) {\n\t\t\t\trecords = records.filter((r) => r[key] === value)\n\t\t\t}\n\t\t}\n\n\t\t// Apply ORDER BY\n\t\tif (options?.orderBy) {\n\t\t\tconst field = options.orderBy\n\t\t\tconst dir = options.orderDirection === 'desc' ? -1 : 1\n\t\t\trecords.sort((a, b) => {\n\t\t\t\tconst aVal = a[field]\n\t\t\t\tconst bVal = b[field]\n\t\t\t\tif (aVal === bVal) return 0\n\t\t\t\tif (aVal === null || aVal === undefined) return 1\n\t\t\t\tif (bVal === null || bVal === undefined) return -1\n\t\t\t\treturn aVal < bVal ? -1 * dir : 1 * dir\n\t\t\t})\n\t\t}\n\n\t\t// Apply OFFSET\n\t\tif (options?.offset !== undefined) {\n\t\t\trecords = records.slice(options.offset)\n\t\t}\n\n\t\t// Apply LIMIT\n\t\tif (options?.limit !== undefined) {\n\t\t\trecords = records.slice(0, options.limit)\n\t\t}\n\n\t\t// Return clean copies without internal fields\n\t\treturn records.map((r) => {\n\t\t\tconst clean: MaterializedRecord = { id: r.id }\n\t\t\tconst collectionDef = this.schema!.collections[collection]!\n\t\t\tfor (const fieldName of Object.keys(collectionDef.fields)) {\n\t\t\t\tif (fieldName in r) {\n\t\t\t\t\tclean[fieldName] = r[fieldName]\n\t\t\t\t}\n\t\t\t}\n\t\t\tif ('_created_at' in r) clean._created_at = r._created_at\n\t\t\tif ('_updated_at' in r) clean._updated_at = r._updated_at\n\t\t\treturn clean\n\t\t})\n\t}\n\n\tasync findRecord(collection: string, id: string): Promise<MaterializedRecord | null> {\n\t\tthis.assertOpen()\n\t\tthis.assertSchema()\n\t\tthis.assertCollection(collection)\n\n\t\tconst collectionMap = this.materializedRecords.get(collection)\n\t\tif (!collectionMap) return null\n\n\t\tconst record = collectionMap.get(id)\n\t\tif (!record || record._deleted === 1) return null\n\n\t\t// Return clean copy\n\t\tconst clean: MaterializedRecord = { id: record.id }\n\t\tconst collectionDef = this.schema!.collections[collection]!\n\t\tfor (const fieldName of Object.keys(collectionDef.fields)) {\n\t\t\tif (fieldName in record) {\n\t\t\t\tclean[fieldName] = record[fieldName]\n\t\t\t}\n\t\t}\n\t\tif ('_created_at' in record) clean._created_at = record._created_at\n\t\tif ('_updated_at' in record) clean._updated_at = record._updated_at\n\t\treturn clean\n\t}\n\n\tasync countCollection(collection: string, where?: Record<string, unknown>): Promise<number> {\n\t\tthis.assertOpen()\n\t\tthis.assertSchema()\n\t\tthis.assertCollection(collection)\n\n\t\tif (where) {\n\t\t\tfor (const key of Object.keys(where)) {\n\t\t\t\tvalidateFieldName(collection, key, this.schema!)\n\t\t\t}\n\t\t}\n\n\t\tconst collectionMap = this.materializedRecords.get(collection)\n\t\tif (!collectionMap) return 0\n\n\t\tlet count = 0\n\t\tfor (const record of collectionMap.values()) {\n\t\t\tif (record._deleted === 1) continue\n\t\t\tif (where) {\n\t\t\t\tlet matches = true\n\t\t\t\tfor (const [key, value] of Object.entries(where)) {\n\t\t\t\t\tif (record[key] !== value) {\n\t\t\t\t\t\tmatches = false\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (!matches) continue\n\t\t\t}\n\t\t\tcount++\n\t\t}\n\t\treturn count\n\t}\n\n\tasync close(): Promise<void> {\n\t\tthis.closed = true\n\t}\n\n\t// --- Testing helpers (not on interface) ---\n\n\t/**\n\t * Get all stored operations (for test assertions).\n\t */\n\tgetAllOperations(): Operation[] {\n\t\treturn [...this.operations]\n\t}\n\n\t// ---------------------------------------------------------------------------\n\t// Materialization internals\n\t// ---------------------------------------------------------------------------\n\n\tprivate rebuildMaterializedRecord(collection: string, recordId: string): void {\n\t\tconst collectionDef = this.schema!.collections[collection]\n\t\tif (!collectionDef) return\n\n\t\t// Get or create collection map\n\t\tlet collectionMap = this.materializedRecords.get(collection)\n\t\tif (!collectionMap) {\n\t\t\tcollectionMap = new Map()\n\t\t\tthis.materializedRecords.set(collection, collectionMap)\n\t\t}\n\n\t\t// Get all ops for this record in HLC order\n\t\tconst recordOps = this.operations\n\t\t\t.filter((op) => op.collection === collection && op.recordId === recordId)\n\t\t\t.sort((a, b) => {\n\t\t\t\tif (a.timestamp.wallTime !== b.timestamp.wallTime) return a.timestamp.wallTime - b.timestamp.wallTime\n\t\t\t\tif (a.timestamp.logical !== b.timestamp.logical) return a.timestamp.logical - b.timestamp.logical\n\t\t\t\treturn a.sequenceNumber - b.sequenceNumber\n\t\t\t})\n\n\t\tconst parsedOps = recordOps.map((op) => ({\n\t\t\ttype: op.type,\n\t\t\tdata: op.data,\n\t\t}))\n\t\tconst recordData = replayOperationsForRecord(parsedOps)\n\n\t\tif (recordData) {\n\t\t\tconst createdAt = recordOps.length > 0 ? recordOps[0]!.timestamp.wallTime : Date.now()\n\t\t\tconst updatedAt = recordOps.length > 0 ? recordOps[recordOps.length - 1]!.timestamp.wallTime : Date.now()\n\n\t\t\tconst materialized: MaterializedRecord = {\n\t\t\t\tid: recordId,\n\t\t\t\t...recordData,\n\t\t\t\t_created_at: createdAt,\n\t\t\t\t_updated_at: updatedAt,\n\t\t\t\t_deleted: 0,\n\t\t\t}\n\t\t\tcollectionMap.set(recordId, materialized)\n\t\t} else {\n\t\t\t// Record was deleted\n\t\t\tconst existing = collectionMap.get(recordId)\n\t\t\tif (existing) {\n\t\t\t\texisting._deleted = 1\n\t\t\t\texisting._updated_at = Date.now()\n\t\t\t} else {\n\t\t\t\tcollectionMap.set(recordId, {\n\t\t\t\t\tid: recordId,\n\t\t\t\t\t_deleted: 1,\n\t\t\t\t\t_created_at: Date.now(),\n\t\t\t\t\t_updated_at: Date.now(),\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate backfillAllCollections(): void {\n\t\tif (!this.schema) return\n\n\t\t// Get all unique (collection, recordId) pairs\n\t\tconst recordKeys = new Set<string>()\n\t\tfor (const op of this.operations) {\n\t\t\tif (this.schema.collections[op.collection]) {\n\t\t\t\trecordKeys.add(`${op.collection}:::${op.recordId}`)\n\t\t\t}\n\t\t}\n\n\t\tfor (const key of recordKeys) {\n\t\t\tconst [collection, recordId] = key.split(':::') as [string, string]\n\t\t\tthis.rebuildMaterializedRecord(collection, recordId)\n\t\t}\n\t}\n\n\t// ---------------------------------------------------------------------------\n\t// Fallback materialization (no schema)\n\t// ---------------------------------------------------------------------------\n\n\tprivate materializeFromOps(collection: string): MaterializedRecord[] {\n\t\tconst collectionOps = this.operations\n\t\t\t.filter((op) => op.collection === collection)\n\t\t\t.sort((a, b) => {\n\t\t\t\tif (a.timestamp.wallTime !== b.timestamp.wallTime) return a.timestamp.wallTime - b.timestamp.wallTime\n\t\t\t\tif (a.timestamp.logical !== b.timestamp.logical) return a.timestamp.logical - b.timestamp.logical\n\t\t\t\treturn a.sequenceNumber - b.sequenceNumber\n\t\t\t})\n\n\t\tconst records = new Map<string, Record<string, unknown>>()\n\t\tconst deleted = new Set<string>()\n\n\t\tfor (const op of collectionOps) {\n\t\t\tswitch (op.type) {\n\t\t\t\tcase 'insert':\n\t\t\t\t\tif (op.data) {\n\t\t\t\t\t\trecords.set(op.recordId, { id: op.recordId, ...op.data })\n\t\t\t\t\t\tdeleted.delete(op.recordId)\n\t\t\t\t\t}\n\t\t\t\t\tbreak\n\t\t\t\tcase 'update':\n\t\t\t\t\tif (op.data) {\n\t\t\t\t\t\tconst existing = records.get(op.recordId) ?? { id: op.recordId }\n\t\t\t\t\t\trecords.set(op.recordId, { ...existing, ...op.data })\n\t\t\t\t\t\tdeleted.delete(op.recordId)\n\t\t\t\t\t}\n\t\t\t\t\tbreak\n\t\t\t\tcase 'delete':\n\t\t\t\t\tdeleted.add(op.recordId)\n\t\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\tfor (const id of deleted) {\n\t\t\trecords.delete(id)\n\t\t}\n\n\t\treturn Array.from(records.values()) as MaterializedRecord[]\n\t}\n\n\t// ---------------------------------------------------------------------------\n\t// Assertions\n\t// ---------------------------------------------------------------------------\n\n\tprivate assertOpen(): void {\n\t\tif (this.closed) {\n\t\t\tthrow new Error('MemoryServerStore is closed')\n\t\t}\n\t}\n\n\tprivate assertSchema(): void {\n\t\tif (!this.schema) {\n\t\t\tthrow new Error(\n\t\t\t\t'Schema not set. Call setSchema() before using queryCollection/findRecord/countCollection.',\n\t\t\t)\n\t\t}\n\t}\n\n\tprivate assertCollection(collection: string): void {\n\t\tif (!this.schema!.collections[collection]) {\n\t\t\tthrow new Error(\n\t\t\t\t`Unknown collection \"${collection}\". Available: ${Object.keys(this.schema!.collections).join(', ')}`,\n\t\t\t)\n\t\t}\n\t}\n}\n","import type { CollectionDefinition, FieldDescriptor, SchemaDefinition } from '@korajs/core'\n\n/**\n * SQL dialect for DDL generation.\n * SQLite and PostgreSQL differ in some column types.\n */\nexport type SqlDialect = 'sqlite' | 'postgres'\n\n/**\n * Map a Kora field kind to its SQL column type for the given dialect.\n */\nfunction fieldTypeToSql(descriptor: FieldDescriptor, dialect: SqlDialect): string {\n\tswitch (descriptor.kind) {\n\t\tcase 'string':\n\t\t\treturn 'TEXT'\n\t\tcase 'number':\n\t\t\treturn dialect === 'postgres' ? 'DOUBLE PRECISION' : 'REAL'\n\t\tcase 'boolean':\n\t\t\treturn 'INTEGER'\n\t\tcase 'enum':\n\t\t\treturn 'TEXT'\n\t\tcase 'timestamp':\n\t\t\treturn dialect === 'postgres' ? 'BIGINT' : 'INTEGER'\n\t\tcase 'array':\n\t\t\treturn dialect === 'postgres' ? 'JSONB' : 'TEXT'\n\t\tcase 'richtext':\n\t\t\treturn dialect === 'postgres' ? 'BYTEA' : 'BLOB'\n\t}\n}\n\nfunction sqlDefaultLiteral(value: unknown): string {\n\tif (value === null) return 'NULL'\n\tif (typeof value === 'string') return `'${value}'`\n\tif (typeof value === 'number') return String(value)\n\tif (typeof value === 'boolean') return value ? '1' : '0'\n\treturn `'${JSON.stringify(value)}'`\n}\n\n/**\n * Generate DDL statements for creating a materialized collection table.\n * Includes CREATE TABLE, safe ALTER TABLE for schema evolution, and indexes.\n *\n * @param name - Collection/table name\n * @param collection - Collection definition from the schema\n * @param dialect - SQL dialect ('sqlite' or 'postgres')\n * @returns Array of DDL SQL strings\n */\nexport function generateCollectionDDL(\n\tname: string,\n\tcollection: CollectionDefinition,\n\tdialect: SqlDialect,\n): string[] {\n\tconst statements: string[] = []\n\tconst columns: string[] = ['id TEXT PRIMARY KEY NOT NULL']\n\n\tfor (const [fieldName, descriptor] of Object.entries(collection.fields)) {\n\t\tconst sqlType = fieldTypeToSql(descriptor, dialect)\n\t\tlet colDef = `${fieldName} ${sqlType}`\n\t\tif (descriptor.defaultValue !== undefined) {\n\t\t\tcolDef += ` DEFAULT ${sqlDefaultLiteral(descriptor.defaultValue)}`\n\t\t}\n\t\tif (descriptor.kind === 'enum' && descriptor.enumValues) {\n\t\t\tconst values = descriptor.enumValues.map((v) => `'${v}'`).join(', ')\n\t\t\tcolDef += ` CHECK (${fieldName} IN (${values}))`\n\t\t}\n\t\tcolumns.push(colDef)\n\t}\n\n\tconst tsType = dialect === 'postgres' ? 'BIGINT' : 'INTEGER'\n\tcolumns.push(`_created_at ${tsType} NOT NULL DEFAULT 0`)\n\tcolumns.push(`_updated_at ${tsType} NOT NULL DEFAULT 0`)\n\tcolumns.push('_deleted INTEGER NOT NULL DEFAULT 0')\n\n\tstatements.push(`CREATE TABLE IF NOT EXISTS ${name} (\\n ${columns.join(',\\n ')}\\n)`)\n\n\t// Safe ALTER TABLE for adding new columns to existing tables\n\tfor (const [fieldName, descriptor] of Object.entries(collection.fields)) {\n\t\tconst sqlType = fieldTypeToSql(descriptor, dialect)\n\t\tlet colDef = `${fieldName} ${sqlType}`\n\t\tif (descriptor.defaultValue !== undefined) {\n\t\t\tcolDef += ` DEFAULT ${sqlDefaultLiteral(descriptor.defaultValue)}`\n\t\t}\n\t\tstatements.push(`--kora:safe-alter\\nALTER TABLE ${name} ADD COLUMN ${colDef}`)\n\t}\n\n\t// User-defined indexes from schema\n\tfor (const indexField of collection.indexes) {\n\t\tstatements.push(\n\t\t\t`CREATE INDEX IF NOT EXISTS idx_${name}_${indexField} ON ${name} (${indexField})`,\n\t\t)\n\t}\n\n\t// Always index _deleted for efficient soft-delete filtering\n\tstatements.push(\n\t\t`CREATE INDEX IF NOT EXISTS idx_${name}__deleted ON ${name} (_deleted)`,\n\t)\n\n\treturn statements\n}\n\n/**\n * Generate all collection table DDL from a full schema.\n */\nexport function generateAllCollectionDDL(\n\tschema: SchemaDefinition,\n\tdialect: SqlDialect,\n): string[] {\n\tconst statements: string[] = []\n\tfor (const [name, collection] of Object.entries(schema.collections)) {\n\t\tstatements.push(...generateCollectionDDL(name, collection, dialect))\n\t}\n\treturn statements\n}\n\n/**\n * Replay a list of operations (must be sorted by HLC order) to produce\n * the current state of a single record.\n *\n * Returns the record field data (without `id`) or null if the record was deleted\n * or never inserted.\n */\nexport function replayOperationsForRecord(\n\tops: Array<{ type: string; data: Record<string, unknown> | null }>,\n): Record<string, unknown> | null {\n\tlet record: Record<string, unknown> | null = null\n\tlet deleted = false\n\n\tfor (const op of ops) {\n\t\tswitch (op.type) {\n\t\t\tcase 'insert':\n\t\t\t\tif (op.data) {\n\t\t\t\t\trecord = { ...op.data }\n\t\t\t\t\tdeleted = false\n\t\t\t\t}\n\t\t\t\tbreak\n\t\t\tcase 'update':\n\t\t\t\tif (op.data) {\n\t\t\t\t\trecord = { ...(record ?? {}), ...op.data }\n\t\t\t\t\tdeleted = false\n\t\t\t\t}\n\t\t\t\tbreak\n\t\t\tcase 'delete':\n\t\t\t\tdeleted = true\n\t\t\t\tbreak\n\t\t}\n\t}\n\n\treturn deleted ? null : record\n}\n\n/**\n * Serialize a field value for SQL storage.\n * Arrays become JSON strings, booleans become 0/1, etc.\n */\nexport function serializeFieldValue(value: unknown, descriptor: FieldDescriptor): unknown {\n\tif (value === null || value === undefined) return null\n\tswitch (descriptor.kind) {\n\t\tcase 'array':\n\t\t\treturn typeof value === 'string' ? value : JSON.stringify(value)\n\t\tcase 'boolean':\n\t\t\treturn value ? 1 : 0\n\t\tdefault:\n\t\t\treturn value\n\t}\n}\n\n/**\n * Deserialize a field value from SQL storage back to JavaScript types.\n */\nexport function deserializeFieldValue(value: unknown, descriptor: FieldDescriptor): unknown {\n\tif (value === null || value === undefined) return null\n\tswitch (descriptor.kind) {\n\t\tcase 'array':\n\t\t\treturn typeof value === 'string' ? JSON.parse(value) : value\n\t\tcase 'boolean':\n\t\t\treturn value === 1 || value === true\n\t\tdefault:\n\t\t\treturn value\n\t}\n}\n\n/**\n * Validate that a field name is a valid column in the given collection schema.\n * Includes system fields (id, _created_at, _updated_at, _deleted).\n */\nexport function validateFieldName(\n\tcollectionName: string,\n\tfieldName: string,\n\tschema: SchemaDefinition,\n): void {\n\tconst collection = schema.collections[collectionName]\n\tif (!collection) {\n\t\tthrow new Error(`Unknown collection: ${collectionName}`)\n\t}\n\tconst validFields = new Set([\n\t\t'id',\n\t\t'_created_at',\n\t\t'_updated_at',\n\t\t'_deleted',\n\t\t...Object.keys(collection.fields),\n\t])\n\tif (!validFields.has(fieldName)) {\n\t\tthrow new Error(\n\t\t\t`Invalid field name \"${fieldName}\" for collection \"${collectionName}\". ` +\n\t\t\t\t`Valid fields: ${Array.from(validFields).join(', ')}`,\n\t\t)\n\t}\n}\n","import type { Operation, SchemaDefinition, VersionVector } from '@korajs/core'\nimport { generateUUIDv7 } from '@korajs/core'\nimport type { ApplyResult } from '@korajs/sync'\nimport type { SQL } from 'drizzle-orm'\nimport { and, asc, between, count, eq, sql } from 'drizzle-orm'\nimport type { PostgresJsDatabase } from 'drizzle-orm/postgres-js'\nimport { pgOperations, pgSyncState } from './drizzle-pg-schema'\nimport {\n\tdeserializeFieldValue,\n\tgenerateAllCollectionDDL,\n\treplayOperationsForRecord,\n\tserializeFieldValue,\n\tvalidateFieldName,\n} from './materialization'\nimport type { CollectionQueryOptions, MaterializedRecord, ServerStore } from './server-store'\n\n/**\n * PostgreSQL-backed server store using Drizzle ORM.\n * All reads and writes go through Drizzle's typed query builder.\n *\n * When a schema is set via setSchema(), also maintains materialized\n * collection tables for efficient indexed queries (dual-write).\n */\nexport class PostgresServerStore implements ServerStore {\n\tprivate readonly nodeId: string\n\tprivate readonly db: PostgresJsDatabase\n\tprivate readonly versionVector: VersionVector = new Map()\n\tprivate readonly ready: Promise<void>\n\tprivate schema: SchemaDefinition | null = null\n\tprivate closed = false\n\n\tconstructor(db: PostgresJsDatabase, nodeId?: string) {\n\t\tthis.db = db\n\t\tthis.nodeId = nodeId ?? generateUUIDv7()\n\t\tthis.ready = this.initialize()\n\t}\n\n\tgetVersionVector(): VersionVector {\n\t\tthis.assertOpen()\n\t\treturn new Map(this.versionVector)\n\t}\n\n\tgetNodeId(): string {\n\t\treturn this.nodeId\n\t}\n\n\tasync setSchema(schema: SchemaDefinition): Promise<void> {\n\t\tthis.assertOpen()\n\t\tawait this.ready\n\t\tthis.schema = schema\n\n\t\t// Generate and execute DDL for all collection tables\n\t\tconst ddlStatements = generateAllCollectionDDL(schema, 'postgres')\n\t\tfor (const stmt of ddlStatements) {\n\t\t\tif (stmt.startsWith('--kora:safe-alter')) {\n\t\t\t\tconst alterSql = stmt.replace('--kora:safe-alter\\n', '')\n\t\t\t\ttry {\n\t\t\t\t\tawait this.db.execute(sql.raw(alterSql))\n\t\t\t\t} catch (e) {\n\t\t\t\t\t// Ignore \"already exists\" errors from safe ALTER TABLE\n\t\t\t\t\tif (\n\t\t\t\t\t\t!(\n\t\t\t\t\t\t\te instanceof Error &&\n\t\t\t\t\t\t\t(e.message.includes('already exists') ||\n\t\t\t\t\t\t\t\te.message.includes('duplicate column'))\n\t\t\t\t\t\t)\n\t\t\t\t\t) {\n\t\t\t\t\t\tthrow e\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tawait this.db.execute(sql.raw(stmt))\n\t\t\t}\n\t\t}\n\n\t\t// Backfill materialized tables from existing operations\n\t\tawait this.backfillAllCollections()\n\t}\n\n\tasync applyRemoteOperation(op: Operation): Promise<ApplyResult> {\n\t\tthis.assertOpen()\n\t\tawait this.ready\n\n\t\t// Content-addressed dedup check\n\t\tconst existing = await this.db\n\t\t\t.select({ id: pgOperations.id })\n\t\t\t.from(pgOperations)\n\t\t\t.where(eq(pgOperations.id, op.id))\n\t\t\t.limit(1)\n\n\t\tif (existing.length > 0) {\n\t\t\treturn 'duplicate'\n\t\t}\n\n\t\tconst now = Date.now()\n\t\tconst row = this.serializeOperation(op, now)\n\n\t\tawait this.db.transaction(async (tx) => {\n\t\t\t// Insert operation with dedup\n\t\t\tawait tx\n\t\t\t\t.insert(pgOperations)\n\t\t\t\t.values(row)\n\t\t\t\t.onConflictDoNothing({ target: pgOperations.id })\n\n\t\t\t// Upsert version vector: advance max sequence number with GREATEST\n\t\t\tawait tx\n\t\t\t\t.insert(pgSyncState)\n\t\t\t\t.values({\n\t\t\t\t\tnodeId: op.nodeId,\n\t\t\t\t\tmaxSequenceNumber: op.sequenceNumber,\n\t\t\t\t\tlastSeenAt: now,\n\t\t\t\t})\n\t\t\t\t.onConflictDoUpdate({\n\t\t\t\t\ttarget: pgSyncState.nodeId,\n\t\t\t\t\tset: {\n\t\t\t\t\t\tmaxSequenceNumber: sql`GREATEST(${pgSyncState.maxSequenceNumber}, ${op.sequenceNumber})`,\n\t\t\t\t\t\tlastSeenAt: sql`${now}`,\n\t\t\t\t\t},\n\t\t\t\t})\n\n\t\t\t// Dual-write: update materialized collection table if schema is set\n\t\t\tif (this.schema && this.schema.collections[op.collection]) {\n\t\t\t\tawait this.rebuildMaterializedRecord(tx, op.collection, op.recordId)\n\t\t\t}\n\t\t})\n\n\t\t// Update in-memory version vector cache\n\t\tconst currentMax = this.versionVector.get(op.nodeId) ?? 0\n\t\tif (op.sequenceNumber > currentMax) {\n\t\t\tthis.versionVector.set(op.nodeId, op.sequenceNumber)\n\t\t}\n\n\t\treturn 'applied'\n\t}\n\n\tasync getOperationRange(nodeId: string, fromSeq: number, toSeq: number): Promise<Operation[]> {\n\t\tthis.assertOpen()\n\t\tawait this.ready\n\n\t\tconst rows = await this.db\n\t\t\t.select()\n\t\t\t.from(pgOperations)\n\t\t\t.where(\n\t\t\t\tand(\n\t\t\t\t\teq(pgOperations.nodeId, nodeId),\n\t\t\t\t\tbetween(pgOperations.sequenceNumber, fromSeq, toSeq),\n\t\t\t\t),\n\t\t\t)\n\t\t\t.orderBy(asc(pgOperations.sequenceNumber))\n\n\t\treturn rows.map((row) => this.deserializeOperation(row))\n\t}\n\n\tasync getOperationCount(): Promise<number> {\n\t\tthis.assertOpen()\n\t\tawait this.ready\n\n\t\tconst result = await this.db.select({ value: count() }).from(pgOperations)\n\t\treturn result[0]?.value ?? 0\n\t}\n\n\tasync materializeCollection(collection: string): Promise<MaterializedRecord[]> {\n\t\tthis.assertOpen()\n\t\tawait this.ready\n\n\t\t// Fast path: if schema is set, read directly from the materialized table\n\t\tif (this.schema && this.schema.collections[collection]) {\n\t\t\treturn this.queryCollection(collection)\n\t\t}\n\n\t\t// Fallback: replay operations (legacy path when schema is not set)\n\t\treturn this.materializeFromOpsLog(collection)\n\t}\n\n\tasync queryCollection(\n\t\tcollection: string,\n\t\toptions?: CollectionQueryOptions,\n\t): Promise<MaterializedRecord[]> {\n\t\tthis.assertOpen()\n\t\tawait this.ready\n\t\tthis.assertSchema()\n\t\tthis.assertCollection(collection)\n\n\t\tconst collectionDef = this.schema!.collections[collection]!\n\n\t\t// Validate field names in options\n\t\tif (options?.where) {\n\t\t\tfor (const key of Object.keys(options.where)) {\n\t\t\t\tvalidateFieldName(collection, key, this.schema!)\n\t\t\t}\n\t\t}\n\t\tif (options?.orderBy) {\n\t\t\tvalidateFieldName(collection, options.orderBy, this.schema!)\n\t\t}\n\n\t\tconst query = this.buildSelectQuery(collection, options)\n\t\tconst rows = (await this.db.execute(query)) as unknown as Record<string, unknown>[]\n\n\t\treturn rows.map((row) => this.deserializeRow(row, collectionDef))\n\t}\n\n\tasync findRecord(collection: string, id: string): Promise<MaterializedRecord | null> {\n\t\tthis.assertOpen()\n\t\tawait this.ready\n\t\tthis.assertSchema()\n\t\tthis.assertCollection(collection)\n\n\t\tconst collectionDef = this.schema!.collections[collection]!\n\t\tconst query = sql`SELECT * FROM ${sql.raw(collection)} WHERE id = ${id} AND _deleted = 0`\n\t\tconst rows = (await this.db.execute(query)) as unknown as Record<string, unknown>[]\n\n\t\tif (rows.length === 0) return null\n\t\treturn this.deserializeRow(rows[0]!, collectionDef)\n\t}\n\n\tasync countCollection(collection: string, where?: Record<string, unknown>): Promise<number> {\n\t\tthis.assertOpen()\n\t\tawait this.ready\n\t\tthis.assertSchema()\n\t\tthis.assertCollection(collection)\n\n\t\tif (where) {\n\t\t\tfor (const key of Object.keys(where)) {\n\t\t\t\tvalidateFieldName(collection, key, this.schema!)\n\t\t\t}\n\t\t}\n\n\t\tconst whereClause = this.buildWhereClause(where ?? {}, false)\n\t\tconst query = sql`SELECT COUNT(*) as cnt FROM ${sql.raw(collection)} WHERE ${whereClause}`\n\t\tconst rows = (await this.db.execute(query)) as unknown as Array<{ cnt: number | string }>\n\t\tconst cnt = rows[0]?.cnt\n\t\treturn typeof cnt === 'string' ? Number.parseInt(cnt, 10) : (cnt ?? 0)\n\t}\n\n\tasync close(): Promise<void> {\n\t\tthis.closed = true\n\t}\n\n\t// ---------------------------------------------------------------------------\n\t// Materialization internals\n\t// ---------------------------------------------------------------------------\n\n\t/**\n\t * Rebuild a single record in the materialized collection table by replaying\n\t * all operations for that record.\n\t */\n\tprivate async rebuildMaterializedRecord(\n\t\ttxOrDb: PostgresJsDatabase,\n\t\tcollection: string,\n\t\trecordId: string,\n\t): Promise<void> {\n\t\tconst collectionDef = this.schema!.collections[collection]\n\t\tif (!collectionDef) return\n\n\t\t// Fetch all ops for this specific record, ordered by HLC\n\t\tconst ops = await txOrDb\n\t\t\t.select({\n\t\t\t\ttype: pgOperations.type,\n\t\t\t\tdata: pgOperations.data,\n\t\t\t\twallTime: pgOperations.wallTime,\n\t\t\t})\n\t\t\t.from(pgOperations)\n\t\t\t.where(\n\t\t\t\tand(\n\t\t\t\t\teq(pgOperations.collection, collection),\n\t\t\t\t\teq(pgOperations.recordId, recordId),\n\t\t\t\t),\n\t\t\t)\n\t\t\t.orderBy(\n\t\t\t\tasc(pgOperations.wallTime),\n\t\t\t\tasc(pgOperations.logical),\n\t\t\t\tasc(pgOperations.sequenceNumber),\n\t\t\t)\n\n\t\t// Replay to get current state\n\t\tconst parsedOps = ops.map((op) => ({\n\t\t\ttype: op.type,\n\t\t\tdata: op.data !== null ? JSON.parse(op.data) : null,\n\t\t}))\n\t\tconst recordData = replayOperationsForRecord(parsedOps)\n\n\t\tconst fieldNames = Object.keys(collectionDef.fields)\n\n\t\tif (recordData) {\n\t\t\tconst createdAt = ops.length > 0 ? ops[0]!.wallTime : Date.now()\n\t\t\tconst updatedAt = ops.length > 0 ? ops[ops.length - 1]!.wallTime : Date.now()\n\n\t\t\tawait this.upsertMaterializedRecord(\n\t\t\t\ttxOrDb,\n\t\t\t\tcollection,\n\t\t\t\trecordId,\n\t\t\t\trecordData,\n\t\t\t\tfieldNames,\n\t\t\t\tcollectionDef,\n\t\t\t\tcreatedAt,\n\t\t\t\tupdatedAt,\n\t\t\t)\n\t\t} else {\n\t\t\tawait txOrDb.execute(\n\t\t\t\tsql`UPDATE ${sql.raw(collection)} SET _deleted = 1, _updated_at = ${Date.now()} WHERE id = ${recordId}`,\n\t\t\t)\n\t\t}\n\t}\n\n\t/**\n\t * UPSERT a record into the materialized collection table.\n\t */\n\tprivate async upsertMaterializedRecord(\n\t\ttxOrDb: PostgresJsDatabase,\n\t\ttableName: string,\n\t\trecordId: string,\n\t\trecordData: Record<string, unknown>,\n\t\tfieldNames: string[],\n\t\tcollectionDef: { fields: Record<string, import('@korajs/core').FieldDescriptor> },\n\t\tcreatedAt: number,\n\t\tupdatedAt: number,\n\t): Promise<void> {\n\t\tconst allColumns = ['id', ...fieldNames, '_created_at', '_updated_at', '_deleted']\n\t\tconst values: unknown[] = [\n\t\t\trecordId,\n\t\t\t...fieldNames.map((f) => {\n\t\t\t\tconst descriptor = collectionDef.fields[f]\n\t\t\t\treturn descriptor\n\t\t\t\t\t? serializeFieldValue(recordData[f] ?? null, descriptor)\n\t\t\t\t\t: null\n\t\t\t}),\n\t\t\tcreatedAt,\n\t\t\tupdatedAt,\n\t\t\t0,\n\t\t]\n\n\t\tconst columnsSql = sql.raw(allColumns.join(', '))\n\t\tconst valuesSql = sql.join(\n\t\t\tvalues.map((v) => sql`${v}`),\n\t\t\tsql.raw(', '),\n\t\t)\n\t\tconst updateSet = sql.raw(\n\t\t\tallColumns.slice(1).map((c) => `${c} = excluded.${c}`).join(', '),\n\t\t)\n\n\t\tawait txOrDb.execute(\n\t\t\tsql`INSERT INTO ${sql.raw(tableName)} (${columnsSql}) VALUES (${valuesSql}) ON CONFLICT (id) DO UPDATE SET ${updateSet}`,\n\t\t)\n\t}\n\n\t/**\n\t * Backfill all materialized collection tables from the existing operation log.\n\t */\n\tprivate async backfillAllCollections(): Promise<void> {\n\t\tif (!this.schema) return\n\n\t\tfor (const collectionName of Object.keys(this.schema.collections)) {\n\t\t\tawait this.backfillCollection(collectionName)\n\t\t}\n\t}\n\n\t/**\n\t * Backfill a single collection's materialized table from operations.\n\t */\n\tprivate async backfillCollection(collectionName: string): Promise<void> {\n\t\tconst collectionDef = this.schema!.collections[collectionName]\n\t\tif (!collectionDef) return\n\n\t\tconst allOps = await this.db\n\t\t\t.select({\n\t\t\t\trecordId: pgOperations.recordId,\n\t\t\t\ttype: pgOperations.type,\n\t\t\t\tdata: pgOperations.data,\n\t\t\t\twallTime: pgOperations.wallTime,\n\t\t\t})\n\t\t\t.from(pgOperations)\n\t\t\t.where(eq(pgOperations.collection, collectionName))\n\t\t\t.orderBy(\n\t\t\t\tasc(pgOperations.wallTime),\n\t\t\t\tasc(pgOperations.logical),\n\t\t\t\tasc(pgOperations.sequenceNumber),\n\t\t\t)\n\n\t\tif (allOps.length === 0) return\n\n\t\t// Group by recordId\n\t\tconst grouped = new Map<string, typeof allOps>()\n\t\tfor (const op of allOps) {\n\t\t\tlet group = grouped.get(op.recordId)\n\t\t\tif (!group) {\n\t\t\t\tgroup = []\n\t\t\t\tgrouped.set(op.recordId, group)\n\t\t\t}\n\t\t\tgroup.push(op)\n\t\t}\n\n\t\tconst fieldNames = Object.keys(collectionDef.fields)\n\n\t\t// Rebuild each record\n\t\tfor (const [recordId, recordOps] of grouped) {\n\t\t\tconst parsedOps = recordOps.map((op) => ({\n\t\t\t\ttype: op.type,\n\t\t\t\tdata: op.data !== null ? JSON.parse(op.data) : null,\n\t\t\t}))\n\t\t\tconst recordData = replayOperationsForRecord(parsedOps)\n\n\t\t\tif (recordData) {\n\t\t\t\tconst createdAt = recordOps[0]!.wallTime\n\t\t\t\tconst updatedAt = recordOps[recordOps.length - 1]!.wallTime\n\t\t\t\tawait this.upsertMaterializedRecord(\n\t\t\t\t\tthis.db,\n\t\t\t\t\tcollectionName,\n\t\t\t\t\trecordId,\n\t\t\t\t\trecordData,\n\t\t\t\t\tfieldNames,\n\t\t\t\t\tcollectionDef,\n\t\t\t\t\tcreatedAt,\n\t\t\t\t\tupdatedAt,\n\t\t\t\t)\n\t\t\t} else {\n\t\t\t\tawait this.db.execute(\n\t\t\t\t\tsql`INSERT INTO ${sql.raw(collectionName)} (id, _deleted, _created_at, _updated_at) VALUES (${recordId}, 1, ${Date.now()}, ${Date.now()}) ON CONFLICT (id) DO UPDATE SET _deleted = 1, _updated_at = ${Date.now()}`,\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\t}\n\n\t// ---------------------------------------------------------------------------\n\t// Query building\n\t// ---------------------------------------------------------------------------\n\n\tprivate buildSelectQuery(\n\t\tcollection: string,\n\t\toptions?: CollectionQueryOptions,\n\t): SQL {\n\t\tconst whereClause = this.buildWhereClause(\n\t\t\toptions?.where ?? {},\n\t\t\toptions?.includeDeleted ?? false,\n\t\t)\n\n\t\tconst parts: SQL[] = [\n\t\t\tsql`SELECT * FROM ${sql.raw(collection)} WHERE ${whereClause}`,\n\t\t]\n\n\t\tif (options?.orderBy) {\n\t\t\tconst dir = options.orderDirection === 'desc' ? 'DESC' : 'ASC'\n\t\t\tparts.push(sql.raw(` ORDER BY ${options.orderBy} ${dir}`))\n\t\t}\n\n\t\tif (options?.limit !== undefined) {\n\t\t\tparts.push(sql` LIMIT ${options.limit}`)\n\t\t}\n\n\t\tif (options?.offset !== undefined) {\n\t\t\tparts.push(sql` OFFSET ${options.offset}`)\n\t\t}\n\n\t\treturn sql.join(parts, sql.raw(''))\n\t}\n\n\tprivate buildWhereClause(\n\t\twhere: Record<string, unknown>,\n\t\tincludeDeleted: boolean,\n\t): SQL {\n\t\tconst conditions: SQL[] = []\n\n\t\tif (!includeDeleted) {\n\t\t\tconditions.push(sql.raw('_deleted = 0'))\n\t\t}\n\n\t\tfor (const [key, value] of Object.entries(where)) {\n\t\t\tconditions.push(sql`${sql.raw(key)} = ${value}`)\n\t\t}\n\n\t\tif (conditions.length === 0) {\n\t\t\treturn sql.raw('1 = 1')\n\t\t}\n\n\t\treturn sql.join(conditions, sql.raw(' AND '))\n\t}\n\n\t// ---------------------------------------------------------------------------\n\t// Row deserialization\n\t// ---------------------------------------------------------------------------\n\n\tprivate deserializeRow(\n\t\trow: Record<string, unknown>,\n\t\tcollectionDef: { fields: Record<string, import('@korajs/core').FieldDescriptor> },\n\t): MaterializedRecord {\n\t\tconst record: MaterializedRecord = { id: row.id as string }\n\n\t\tfor (const [fieldName, descriptor] of Object.entries(collectionDef.fields)) {\n\t\t\tif (fieldName in row) {\n\t\t\t\trecord[fieldName] = deserializeFieldValue(row[fieldName], descriptor)\n\t\t\t}\n\t\t}\n\n\t\tif ('_created_at' in row) record._created_at = row._created_at\n\t\tif ('_updated_at' in row) record._updated_at = row._updated_at\n\n\t\treturn record\n\t}\n\n\t// ---------------------------------------------------------------------------\n\t// Fallback materialization (operation replay, no schema)\n\t// ---------------------------------------------------------------------------\n\n\tprivate async materializeFromOpsLog(collection: string): Promise<MaterializedRecord[]> {\n\t\tconst rows = await this.db\n\t\t\t.select()\n\t\t\t.from(pgOperations)\n\t\t\t.where(eq(pgOperations.collection, collection))\n\t\t\t.orderBy(\n\t\t\t\tasc(pgOperations.wallTime),\n\t\t\t\tasc(pgOperations.logical),\n\t\t\t\tasc(pgOperations.sequenceNumber),\n\t\t\t)\n\n\t\tconst records = new Map<string, Record<string, unknown>>()\n\t\tconst deleted = new Set<string>()\n\n\t\tfor (const row of rows) {\n\t\t\tconst recordId = row.recordId\n\t\t\tconst data = row.data !== null ? JSON.parse(row.data) : null\n\n\t\t\tswitch (row.type) {\n\t\t\t\tcase 'insert':\n\t\t\t\t\tif (data) {\n\t\t\t\t\t\trecords.set(recordId, { id: recordId, ...data })\n\t\t\t\t\t\tdeleted.delete(recordId)\n\t\t\t\t\t}\n\t\t\t\t\tbreak\n\t\t\t\tcase 'update':\n\t\t\t\t\tif (data) {\n\t\t\t\t\t\tconst existing = records.get(recordId) ?? { id: recordId }\n\t\t\t\t\t\trecords.set(recordId, { ...existing, ...data })\n\t\t\t\t\t\tdeleted.delete(recordId)\n\t\t\t\t\t}\n\t\t\t\t\tbreak\n\t\t\t\tcase 'delete':\n\t\t\t\t\tdeleted.add(recordId)\n\t\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\tfor (const id of deleted) {\n\t\t\trecords.delete(id)\n\t\t}\n\n\t\treturn Array.from(records.values()) as MaterializedRecord[]\n\t}\n\n\t// ---------------------------------------------------------------------------\n\t// Initialization\n\t// ---------------------------------------------------------------------------\n\n\tprivate async initialize(): Promise<void> {\n\t\tawait this.ensureTables()\n\n\t\t// Hydrate in-memory version vector cache\n\t\tconst rows = await this.db\n\t\t\t.select({\n\t\t\t\tnodeId: pgSyncState.nodeId,\n\t\t\t\tmaxSequenceNumber: pgSyncState.maxSequenceNumber,\n\t\t\t})\n\t\t\t.from(pgSyncState)\n\n\t\tfor (const row of rows) {\n\t\t\tthis.versionVector.set(row.nodeId, row.maxSequenceNumber)\n\t\t}\n\t}\n\n\tprivate async ensureTables(): Promise<void> {\n\t\tawait this.db.execute(sql`\n\t\t\tCREATE TABLE IF NOT EXISTS operations (\n\t\t\t\tid TEXT PRIMARY KEY,\n\t\t\t\tnode_id TEXT NOT NULL,\n\t\t\t\ttype TEXT NOT NULL,\n\t\t\t\tcollection TEXT NOT NULL,\n\t\t\t\trecord_id TEXT NOT NULL,\n\t\t\t\tdata TEXT,\n\t\t\t\tprevious_data TEXT,\n\t\t\t\twall_time BIGINT NOT NULL,\n\t\t\t\tlogical INTEGER NOT NULL,\n\t\t\t\ttimestamp_node_id TEXT NOT NULL,\n\t\t\t\tsequence_number INTEGER NOT NULL,\n\t\t\t\tcausal_deps TEXT NOT NULL DEFAULT '[]',\n\t\t\t\tschema_version INTEGER NOT NULL,\n\t\t\t\treceived_at BIGINT NOT NULL\n\t\t\t)\n\t\t`)\n\n\t\tawait this.db.execute(\n\t\t\tsql`CREATE INDEX IF NOT EXISTS idx_node_seq ON operations (node_id, sequence_number)`,\n\t\t)\n\t\tawait this.db.execute(\n\t\t\tsql`CREATE INDEX IF NOT EXISTS idx_collection ON operations (collection)`,\n\t\t)\n\t\tawait this.db.execute(\n\t\t\tsql`CREATE INDEX IF NOT EXISTS idx_received ON operations (received_at)`,\n\t\t)\n\t\t// Index for efficient per-record operation lookups during materialization\n\t\tawait this.db.execute(\n\t\t\tsql`CREATE INDEX IF NOT EXISTS idx_collection_record ON operations (collection, record_id)`,\n\t\t)\n\n\t\tawait this.db.execute(sql`\n\t\t\tCREATE TABLE IF NOT EXISTS sync_state (\n\t\t\t\tnode_id TEXT PRIMARY KEY,\n\t\t\t\tmax_sequence_number INTEGER NOT NULL,\n\t\t\t\tlast_seen_at BIGINT NOT NULL\n\t\t\t)\n\t\t`)\n\t}\n\n\t// ---------------------------------------------------------------------------\n\t// Operation serialization\n\t// ---------------------------------------------------------------------------\n\n\tprivate serializeOperation(\n\t\top: Operation,\n\t\treceivedAt: number,\n\t): typeof pgOperations.$inferInsert {\n\t\treturn {\n\t\t\tid: op.id,\n\t\t\tnodeId: op.nodeId,\n\t\t\ttype: op.type,\n\t\t\tcollection: op.collection,\n\t\t\trecordId: op.recordId,\n\t\t\tdata: op.data !== null ? JSON.stringify(op.data) : null,\n\t\t\tpreviousData: op.previousData !== null ? JSON.stringify(op.previousData) : null,\n\t\t\twallTime: op.timestamp.wallTime,\n\t\t\tlogical: op.timestamp.logical,\n\t\t\ttimestampNodeId: op.timestamp.nodeId,\n\t\t\tsequenceNumber: op.sequenceNumber,\n\t\t\tcausalDeps: JSON.stringify(op.causalDeps),\n\t\t\tschemaVersion: op.schemaVersion,\n\t\t\treceivedAt,\n\t\t}\n\t}\n\n\tprivate deserializeOperation(row: typeof pgOperations.$inferSelect): Operation {\n\t\treturn {\n\t\t\tid: row.id,\n\t\t\tnodeId: row.nodeId,\n\t\t\ttype: row.type as Operation['type'],\n\t\t\tcollection: row.collection,\n\t\t\trecordId: row.recordId,\n\t\t\tdata: row.data !== null ? JSON.parse(row.data) : null,\n\t\t\tpreviousData: row.previousData !== null ? JSON.parse(row.previousData) : null,\n\t\t\ttimestamp: {\n\t\t\t\twallTime: row.wallTime,\n\t\t\t\tlogical: row.logical,\n\t\t\t\tnodeId: row.timestampNodeId,\n\t\t\t},\n\t\t\tsequenceNumber: row.sequenceNumber,\n\t\t\tcausalDeps: JSON.parse(row.causalDeps),\n\t\t\tschemaVersion: row.schemaVersion,\n\t\t}\n\t}\n\n\t// ---------------------------------------------------------------------------\n\t// Assertions\n\t// ---------------------------------------------------------------------------\n\n\tprivate assertOpen(): void {\n\t\tif (this.closed) {\n\t\t\tthrow new Error('PostgresServerStore is closed')\n\t\t}\n\t}\n\n\tprivate assertSchema(): void {\n\t\tif (!this.schema) {\n\t\t\tthrow new Error(\n\t\t\t\t'Schema not set. Call setSchema() before using queryCollection/findRecord/countCollection.',\n\t\t\t)\n\t\t}\n\t}\n\n\tprivate assertCollection(collection: string): void {\n\t\tif (!this.schema!.collections[collection]) {\n\t\t\tthrow new Error(\n\t\t\t\t`Unknown collection \"${collection}\". Available: ${Object.keys(this.schema!.collections).join(', ')}`,\n\t\t\t)\n\t\t}\n\t}\n}\n\n/**\n * Creates a PostgresServerStore from a PostgreSQL connection string.\n */\nexport async function createPostgresServerStore(options: {\n\tconnectionString: string\n\tnodeId?: string\n}): Promise<PostgresServerStore> {\n\tconst { postgresClient, drizzleFn } = await loadPostgresDeps()\n\tconst client = postgresClient(options.connectionString)\n\tconst db = drizzleFn(client)\n\n\treturn new PostgresServerStore(db, options.nodeId)\n}\n\nasync function loadPostgresDeps(): Promise<{\n\tpostgresClient: (connectionString: string) => unknown\n\tdrizzleFn: (client: unknown) => PostgresJsDatabase\n}> {\n\ttry {\n\t\tconst dynamicImport = new Function('specifier', 'return import(specifier)') as (\n\t\t\tspecifier: string,\n\t\t) => Promise<unknown>\n\n\t\tconst postgresMod = (await dynamicImport('postgres')) as { default: (cs: string) => unknown }\n\t\tconst drizzleMod = (await dynamicImport('drizzle-orm/postgres-js')) as {\n\t\t\tdrizzle: (client: unknown) => PostgresJsDatabase\n\t\t}\n\n\t\treturn {\n\t\t\tpostgresClient: postgresMod.default,\n\t\t\tdrizzleFn: drizzleMod.drizzle,\n\t\t}\n\t} catch {\n\t\tthrow new Error(\n\t\t\t'PostgreSQL backend requires the \"postgres\" package. Install it in your project dependencies.',\n\t\t)\n\t}\n}\n","import { bigint, index, integer, pgTable, text } from 'drizzle-orm/pg-core'\n\n/**\n * Drizzle schema for the Kora sync server's PostgreSQL database.\n *\n * Two tables:\n * - `pgOperations` — the append-only operation log (content-addressed by id)\n * - `pgSyncState` — tracks the max sequence number seen per node (version vector)\n *\n * Column structure mirrors the SQLite drizzle-schema.ts but uses pgTable.\n */\n\nexport const pgOperations = pgTable(\n\t'operations',\n\t{\n\t\tid: text('id').primaryKey(),\n\t\tnodeId: text('node_id').notNull(),\n\t\ttype: text('type').notNull(),\n\t\tcollection: text('collection').notNull(),\n\t\trecordId: text('record_id').notNull(),\n\t\tdata: text('data'), // JSON-serialized, null for deletes\n\t\tpreviousData: text('previous_data'), // JSON-serialized, null for insert/delete\n\t\twallTime: bigint('wall_time', { mode: 'number' }).notNull(),\n\t\tlogical: integer('logical').notNull(),\n\t\ttimestampNodeId: text('timestamp_node_id').notNull(),\n\t\tsequenceNumber: integer('sequence_number').notNull(),\n\t\tcausalDeps: text('causal_deps').notNull().default('[]'), // JSON array of op IDs\n\t\tschemaVersion: integer('schema_version').notNull(),\n\t\treceivedAt: bigint('received_at', { mode: 'number' }).notNull(),\n\t},\n\t(table) => ({\n\t\tnodeSeqIdx: index('idx_pg_node_seq').on(table.nodeId, table.sequenceNumber),\n\t\tcollectionIdx: index('idx_pg_collection').on(table.collection),\n\t\treceivedIdx: index('idx_pg_received').on(table.receivedAt),\n\t}),\n)\n\nexport const pgSyncState = pgTable('sync_state', {\n\tnodeId: text('node_id').primaryKey(),\n\tmaxSequenceNumber: integer('max_sequence_number').notNull(),\n\tlastSeenAt: bigint('last_seen_at', { mode: 'number' }).notNull(),\n})\n","import { createRequire } from 'node:module'\nimport type { Operation, SchemaDefinition, VersionVector } from '@korajs/core'\nimport { generateUUIDv7 } from '@korajs/core'\nimport type { ApplyResult } from '@korajs/sync'\nimport type { SQL } from 'drizzle-orm'\nimport { and, asc, between, count, eq, sql } from 'drizzle-orm'\nimport type { BetterSQLite3Database } from 'drizzle-orm/better-sqlite3'\nimport { operations, syncState } from './drizzle-schema'\nimport {\n\tdeserializeFieldValue,\n\tgenerateAllCollectionDDL,\n\treplayOperationsForRecord,\n\tserializeFieldValue,\n\tvalidateFieldName,\n} from './materialization'\nimport type { CollectionQueryOptions, MaterializedRecord, ServerStore } from './server-store'\n\n// better-sqlite3 is a native CJS addon that cannot be loaded via ESM import().\n// createRequire provides a CJS require() that works in both ESM and CJS contexts.\n// tsup's shims option ensures import.meta.url is available in CJS builds.\nconst esmRequire = createRequire(import.meta.url)\n\n/**\n * SQLite-backed server store using Drizzle ORM.\n * Persists operations and version vectors to a real database file,\n * surviving process restarts.\n *\n * When a schema is set via setSchema(), also maintains materialized\n * collection tables for efficient indexed queries (dual-write).\n */\nexport class SqliteServerStore implements ServerStore {\n\tprivate readonly nodeId: string\n\tprivate readonly db: BetterSQLite3Database\n\tprivate schema: SchemaDefinition | null = null\n\tprivate closed = false\n\n\tconstructor(db: BetterSQLite3Database, nodeId?: string) {\n\t\tthis.db = db\n\t\tthis.nodeId = nodeId ?? generateUUIDv7()\n\t\tthis.ensureTables()\n\t}\n\n\tgetVersionVector(): VersionVector {\n\t\tthis.assertOpen()\n\t\tconst rows = this.db.select().from(syncState).all()\n\t\tconst vv: VersionVector = new Map()\n\t\tfor (const row of rows) {\n\t\t\tvv.set(row.nodeId, row.maxSequenceNumber)\n\t\t}\n\t\treturn vv\n\t}\n\n\tgetNodeId(): string {\n\t\treturn this.nodeId\n\t}\n\n\tasync setSchema(schema: SchemaDefinition): Promise<void> {\n\t\tthis.assertOpen()\n\t\tthis.schema = schema\n\n\t\t// Generate and execute DDL for all collection tables\n\t\tconst ddlStatements = generateAllCollectionDDL(schema, 'sqlite')\n\t\tfor (const stmt of ddlStatements) {\n\t\t\tif (stmt.startsWith('--kora:safe-alter')) {\n\t\t\t\tconst alterSql = stmt.replace('--kora:safe-alter\\n', '')\n\t\t\t\ttry {\n\t\t\t\t\tthis.db.run(sql.raw(alterSql))\n\t\t\t\t} catch (e) {\n\t\t\t\t\t// Ignore \"duplicate column\" errors from safe ALTER TABLE.\n\t\t\t\t\t// Drizzle wraps SQLite errors, so check both outer message and cause.\n\t\t\t\t\tconst msg = e instanceof Error ? e.message : ''\n\t\t\t\t\tconst causeMsg =\n\t\t\t\t\t\te instanceof Error && e.cause instanceof Error ? e.cause.message : ''\n\t\t\t\t\tif (\n\t\t\t\t\t\t!msg.includes('duplicate column') &&\n\t\t\t\t\t\t!causeMsg.includes('duplicate column')\n\t\t\t\t\t) {\n\t\t\t\t\t\tthrow e\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tthis.db.run(sql.raw(stmt))\n\t\t\t}\n\t\t}\n\n\t\t// Backfill materialized tables from existing operations\n\t\tawait this.backfillAllCollections()\n\t}\n\n\tasync applyRemoteOperation(op: Operation): Promise<ApplyResult> {\n\t\tthis.assertOpen()\n\n\t\tconst now = Date.now()\n\t\tconst row = this.serializeOperation(op, now)\n\n\t\t// Use a transaction for atomicity: insert op + update version vector + materialize\n\t\tconst result = this.db.transaction((tx) => {\n\t\t\t// Content-addressed dedup via onConflictDoNothing\n\t\t\tconst insertResult = tx\n\t\t\t\t.insert(operations)\n\t\t\t\t.values(row)\n\t\t\t\t.onConflictDoNothing({ target: operations.id })\n\t\t\t\t.run()\n\n\t\t\tif (insertResult.changes === 0) {\n\t\t\t\treturn 'duplicate' as const\n\t\t\t}\n\n\t\t\t// Advance version vector: upsert with MAX to ensure monotonic progress\n\t\t\ttx.insert(syncState)\n\t\t\t\t.values({\n\t\t\t\t\tnodeId: op.nodeId,\n\t\t\t\t\tmaxSequenceNumber: op.sequenceNumber,\n\t\t\t\t\tlastSeenAt: now,\n\t\t\t\t})\n\t\t\t\t.onConflictDoUpdate({\n\t\t\t\t\ttarget: syncState.nodeId,\n\t\t\t\t\tset: {\n\t\t\t\t\t\tmaxSequenceNumber: sql`MAX(${syncState.maxSequenceNumber}, ${op.sequenceNumber})`,\n\t\t\t\t\t\tlastSeenAt: sql`${now}`,\n\t\t\t\t\t},\n\t\t\t\t})\n\t\t\t\t.run()\n\n\t\t\t// Dual-write: update materialized collection table if schema is set\n\t\t\tif (this.schema && this.schema.collections[op.collection]) {\n\t\t\t\tthis.rebuildMaterializedRecord(tx, op.collection, op.recordId)\n\t\t\t}\n\n\t\t\treturn 'applied' as const\n\t\t})\n\n\t\treturn result\n\t}\n\n\tasync getOperationRange(nodeId: string, fromSeq: number, toSeq: number): Promise<Operation[]> {\n\t\tthis.assertOpen()\n\n\t\tconst rows = this.db\n\t\t\t.select()\n\t\t\t.from(operations)\n\t\t\t.where(and(eq(operations.nodeId, nodeId), between(operations.sequenceNumber, fromSeq, toSeq)))\n\t\t\t.orderBy(asc(operations.sequenceNumber))\n\t\t\t.all()\n\n\t\treturn rows.map((row) => this.deserializeOperation(row))\n\t}\n\n\tasync getOperationCount(): Promise<number> {\n\t\tthis.assertOpen()\n\n\t\tconst result = this.db.select({ value: count() }).from(operations).all()\n\t\treturn result[0]?.value ?? 0\n\t}\n\n\tasync materializeCollection(collection: string): Promise<MaterializedRecord[]> {\n\t\tthis.assertOpen()\n\n\t\t// Fast path: if schema is set, read directly from the materialized table\n\t\tif (this.schema && this.schema.collections[collection]) {\n\t\t\treturn this.queryCollection(collection)\n\t\t}\n\n\t\t// Fallback: replay operations (legacy path when schema is not set)\n\t\treturn this.materializeFromOpsLog(collection)\n\t}\n\n\tasync queryCollection(\n\t\tcollection: string,\n\t\toptions?: CollectionQueryOptions,\n\t): Promise<MaterializedRecord[]> {\n\t\tthis.assertOpen()\n\t\tthis.assertSchema()\n\t\tthis.assertCollection(collection)\n\n\t\tconst collectionDef = this.schema!.collections[collection]!\n\n\t\t// Validate field names in options\n\t\tif (options?.where) {\n\t\t\tfor (const key of Object.keys(options.where)) {\n\t\t\t\tvalidateFieldName(collection, key, this.schema!)\n\t\t\t}\n\t\t}\n\t\tif (options?.orderBy) {\n\t\t\tvalidateFieldName(collection, options.orderBy, this.schema!)\n\t\t}\n\n\t\tconst query = this.buildSelectQuery(collection, options)\n\t\tconst rows = this.db.all<Record<string, unknown>>(query)\n\n\t\treturn rows.map((row) => this.deserializeRow(row, collectionDef))\n\t}\n\n\tasync findRecord(collection: string, id: string): Promise<MaterializedRecord | null> {\n\t\tthis.assertOpen()\n\t\tthis.assertSchema()\n\t\tthis.assertCollection(collection)\n\n\t\tconst collectionDef = this.schema!.collections[collection]!\n\t\tconst query = sql`SELECT * FROM ${sql.raw(collection)} WHERE id = ${id} AND _deleted = 0`\n\t\tconst rows = this.db.all<Record<string, unknown>>(query)\n\n\t\tif (rows.length === 0) return null\n\t\treturn this.deserializeRow(rows[0]!, collectionDef)\n\t}\n\n\tasync countCollection(collection: string, where?: Record<string, unknown>): Promise<number> {\n\t\tthis.assertOpen()\n\t\tthis.assertSchema()\n\t\tthis.assertCollection(collection)\n\n\t\tif (where) {\n\t\t\tfor (const key of Object.keys(where)) {\n\t\t\t\tvalidateFieldName(collection, key, this.schema!)\n\t\t\t}\n\t\t}\n\n\t\tconst whereClause = this.buildWhereClause(where ?? {}, false)\n\t\tconst query = sql`SELECT COUNT(*) as cnt FROM ${sql.raw(collection)} WHERE ${whereClause}`\n\t\tconst rows = this.db.all<{ cnt: number }>(query)\n\t\treturn rows[0]?.cnt ?? 0\n\t}\n\n\tasync close(): Promise<void> {\n\t\tthis.closed = true\n\t}\n\n\t// ---------------------------------------------------------------------------\n\t// Materialization internals\n\t// ---------------------------------------------------------------------------\n\n\t/**\n\t * Rebuild a single record in the materialized collection table by replaying\n\t * all operations for that record. Called within the applyRemoteOperation\n\t * transaction for atomic dual-write.\n\t */\n\tprivate rebuildMaterializedRecord(\n\t\ttxOrDb: BetterSQLite3Database,\n\t\tcollection: string,\n\t\trecordId: string,\n\t): void {\n\t\tconst collectionDef = this.schema!.collections[collection]\n\t\tif (!collectionDef) return\n\n\t\t// Fetch all ops for this specific record, ordered by HLC\n\t\tconst ops = txOrDb\n\t\t\t.select({\n\t\t\t\ttype: operations.type,\n\t\t\t\tdata: operations.data,\n\t\t\t\twallTime: operations.wallTime,\n\t\t\t})\n\t\t\t.from(operations)\n\t\t\t.where(\n\t\t\t\tand(\n\t\t\t\t\teq(operations.collection, collection),\n\t\t\t\t\teq(operations.recordId, recordId),\n\t\t\t\t),\n\t\t\t)\n\t\t\t.orderBy(asc(operations.wallTime), asc(operations.logical), asc(operations.sequenceNumber))\n\t\t\t.all()\n\n\t\t// Replay to get current state\n\t\tconst parsedOps = ops.map((op) => ({\n\t\t\ttype: op.type,\n\t\t\tdata: op.data !== null ? JSON.parse(op.data) : null,\n\t\t}))\n\t\tconst recordData = replayOperationsForRecord(parsedOps)\n\n\t\tconst fieldNames = Object.keys(collectionDef.fields)\n\n\t\tif (recordData) {\n\t\t\t// Compute timestamps from operations\n\t\t\tconst createdAt = ops.length > 0 ? ops[0]!.wallTime : Date.now()\n\t\t\tconst updatedAt = ops.length > 0 ? ops[ops.length - 1]!.wallTime : Date.now()\n\n\t\t\tthis.upsertMaterializedRecord(\n\t\t\t\ttxOrDb,\n\t\t\t\tcollection,\n\t\t\t\trecordId,\n\t\t\t\trecordData,\n\t\t\t\tfieldNames,\n\t\t\t\tcollectionDef,\n\t\t\t\tcreatedAt,\n\t\t\t\tupdatedAt,\n\t\t\t)\n\t\t} else {\n\t\t\t// Record was deleted — soft-delete in materialized table\n\t\t\ttxOrDb.run(\n\t\t\t\tsql`UPDATE ${sql.raw(collection)} SET _deleted = 1, _updated_at = ${Date.now()} WHERE id = ${recordId}`,\n\t\t\t)\n\t\t}\n\t}\n\n\t/**\n\t * UPSERT a record into the materialized collection table.\n\t * Uses INSERT ... ON CONFLICT (id) DO UPDATE SET for atomic upsert.\n\t */\n\tprivate upsertMaterializedRecord(\n\t\ttxOrDb: BetterSQLite3Database,\n\t\ttableName: string,\n\t\trecordId: string,\n\t\trecordData: Record<string, unknown>,\n\t\tfieldNames: string[],\n\t\tcollectionDef: { fields: Record<string, import('@korajs/core').FieldDescriptor> },\n\t\tcreatedAt: number,\n\t\tupdatedAt: number,\n\t): void {\n\t\tconst allColumns = ['id', ...fieldNames, '_created_at', '_updated_at', '_deleted']\n\t\tconst values: unknown[] = [\n\t\t\trecordId,\n\t\t\t...fieldNames.map((f) => {\n\t\t\t\tconst descriptor = collectionDef.fields[f]\n\t\t\t\treturn descriptor\n\t\t\t\t\t? serializeFieldValue(recordData[f] ?? null, descriptor)\n\t\t\t\t\t: null\n\t\t\t}),\n\t\t\tcreatedAt,\n\t\t\tupdatedAt,\n\t\t\t0, // _deleted = false\n\t\t]\n\n\t\tconst columnsSql = sql.raw(allColumns.join(', '))\n\t\tconst valuesSql = sql.join(\n\t\t\tvalues.map((v) => sql`${v}`),\n\t\t\tsql.raw(', '),\n\t\t)\n\t\tconst updateSet = sql.raw(\n\t\t\tallColumns.slice(1).map((c) => `${c} = excluded.${c}`).join(', '),\n\t\t)\n\n\t\ttxOrDb.run(\n\t\t\tsql`INSERT INTO ${sql.raw(tableName)} (${columnsSql}) VALUES (${valuesSql}) ON CONFLICT (id) DO UPDATE SET ${updateSet}`,\n\t\t)\n\t}\n\n\t/**\n\t * Backfill all materialized collection tables from the existing operation log.\n\t * Called when setSchema() is invoked and operations already exist.\n\t */\n\tprivate async backfillAllCollections(): Promise<void> {\n\t\tif (!this.schema) return\n\n\t\tfor (const collectionName of Object.keys(this.schema.collections)) {\n\t\t\tthis.backfillCollection(collectionName)\n\t\t}\n\t}\n\n\t/**\n\t * Backfill a single collection's materialized table from operations.\n\t */\n\tprivate backfillCollection(collectionName: string): void {\n\t\tconst collectionDef = this.schema!.collections[collectionName]\n\t\tif (!collectionDef) return\n\n\t\t// Fetch all ops for this collection, ordered by HLC\n\t\tconst allOps = this.db\n\t\t\t.select({\n\t\t\t\trecordId: operations.recordId,\n\t\t\t\ttype: operations.type,\n\t\t\t\tdata: operations.data,\n\t\t\t\twallTime: operations.wallTime,\n\t\t\t})\n\t\t\t.from(operations)\n\t\t\t.where(eq(operations.collection, collectionName))\n\t\t\t.orderBy(asc(operations.wallTime), asc(operations.logical), asc(operations.sequenceNumber))\n\t\t\t.all()\n\n\t\tif (allOps.length === 0) return\n\n\t\t// Group by recordId\n\t\tconst grouped = new Map<string, typeof allOps>()\n\t\tfor (const op of allOps) {\n\t\t\tlet group = grouped.get(op.recordId)\n\t\t\tif (!group) {\n\t\t\t\tgroup = []\n\t\t\t\tgrouped.set(op.recordId, group)\n\t\t\t}\n\t\t\tgroup.push(op)\n\t\t}\n\n\t\t// Rebuild each record inside a single transaction for efficiency\n\t\tconst fieldNames = Object.keys(collectionDef.fields)\n\t\tthis.db.transaction((tx) => {\n\t\t\tfor (const [recordId, recordOps] of grouped) {\n\t\t\t\tconst parsedOps = recordOps.map((op) => ({\n\t\t\t\t\ttype: op.type,\n\t\t\t\t\tdata: op.data !== null ? JSON.parse(op.data) : null,\n\t\t\t\t}))\n\t\t\t\tconst recordData = replayOperationsForRecord(parsedOps)\n\n\t\t\t\tif (recordData) {\n\t\t\t\t\tconst createdAt = recordOps[0]!.wallTime\n\t\t\t\t\tconst updatedAt = recordOps[recordOps.length - 1]!.wallTime\n\t\t\t\t\tthis.upsertMaterializedRecord(\n\t\t\t\t\t\ttx,\n\t\t\t\t\t\tcollectionName,\n\t\t\t\t\t\trecordId,\n\t\t\t\t\t\trecordData,\n\t\t\t\t\t\tfieldNames,\n\t\t\t\t\t\tcollectionDef,\n\t\t\t\t\t\tcreatedAt,\n\t\t\t\t\t\tupdatedAt,\n\t\t\t\t\t)\n\t\t\t\t} else {\n\t\t\t\t\ttx.run(\n\t\t\t\t\t\tsql`INSERT INTO ${sql.raw(collectionName)} (id, _deleted, _created_at, _updated_at) VALUES (${recordId}, 1, ${Date.now()}, ${Date.now()}) ON CONFLICT (id) DO UPDATE SET _deleted = 1, _updated_at = ${Date.now()}`,\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t}\n\n\t// ---------------------------------------------------------------------------\n\t// Query building\n\t// ---------------------------------------------------------------------------\n\n\tprivate buildSelectQuery(\n\t\tcollection: string,\n\t\toptions?: CollectionQueryOptions,\n\t): SQL {\n\t\tconst whereClause = this.buildWhereClause(\n\t\t\toptions?.where ?? {},\n\t\t\toptions?.includeDeleted ?? false,\n\t\t)\n\n\t\tconst parts: SQL[] = [\n\t\t\tsql`SELECT * FROM ${sql.raw(collection)} WHERE ${whereClause}`,\n\t\t]\n\n\t\tif (options?.orderBy) {\n\t\t\tconst dir = options.orderDirection === 'desc' ? 'DESC' : 'ASC'\n\t\t\tparts.push(sql.raw(` ORDER BY ${options.orderBy} ${dir}`))\n\t\t}\n\n\t\tif (options?.limit !== undefined) {\n\t\t\tparts.push(sql` LIMIT ${options.limit}`)\n\t\t}\n\n\t\tif (options?.offset !== undefined) {\n\t\t\tparts.push(sql` OFFSET ${options.offset}`)\n\t\t}\n\n\t\treturn sql.join(parts, sql.raw(''))\n\t}\n\n\tprivate buildWhereClause(\n\t\twhere: Record<string, unknown>,\n\t\tincludeDeleted: boolean,\n\t): SQL {\n\t\tconst conditions: SQL[] = []\n\n\t\tif (!includeDeleted) {\n\t\t\tconditions.push(sql.raw('_deleted = 0'))\n\t\t}\n\n\t\tfor (const [key, value] of Object.entries(where)) {\n\t\t\tconditions.push(sql`${sql.raw(key)} = ${value}`)\n\t\t}\n\n\t\tif (conditions.length === 0) {\n\t\t\treturn sql.raw('1 = 1')\n\t\t}\n\n\t\treturn sql.join(conditions, sql.raw(' AND '))\n\t}\n\n\t// ---------------------------------------------------------------------------\n\t// Row deserialization\n\t// ---------------------------------------------------------------------------\n\n\tprivate deserializeRow(\n\t\trow: Record<string, unknown>,\n\t\tcollectionDef: { fields: Record<string, import('@korajs/core').FieldDescriptor> },\n\t): MaterializedRecord {\n\t\tconst record: MaterializedRecord = { id: row.id as string }\n\n\t\tfor (const [fieldName, descriptor] of Object.entries(collectionDef.fields)) {\n\t\t\tif (fieldName in row) {\n\t\t\t\trecord[fieldName] = deserializeFieldValue(row[fieldName], descriptor)\n\t\t\t}\n\t\t}\n\n\t\t// Include metadata fields\n\t\tif ('_created_at' in row) record._created_at = row._created_at\n\t\tif ('_updated_at' in row) record._updated_at = row._updated_at\n\n\t\treturn record\n\t}\n\n\t// ---------------------------------------------------------------------------\n\t// Fallback materialization (operation replay, no schema)\n\t// ---------------------------------------------------------------------------\n\n\tprivate materializeFromOpsLog(collection: string): MaterializedRecord[] {\n\t\tconst rows = this.db\n\t\t\t.select()\n\t\t\t.from(operations)\n\t\t\t.where(eq(operations.collection, collection))\n\t\t\t.orderBy(asc(operations.wallTime), asc(operations.logical), asc(operations.sequenceNumber))\n\t\t\t.all()\n\n\t\tconst records = new Map<string, Record<string, unknown>>()\n\t\tconst deleted = new Set<string>()\n\n\t\tfor (const row of rows) {\n\t\t\tconst recordId = row.recordId\n\t\t\tconst data = row.data !== null ? JSON.parse(row.data) : null\n\n\t\t\tswitch (row.type) {\n\t\t\t\tcase 'insert':\n\t\t\t\t\tif (data) {\n\t\t\t\t\t\trecords.set(recordId, { id: recordId, ...data })\n\t\t\t\t\t\tdeleted.delete(recordId)\n\t\t\t\t\t}\n\t\t\t\t\tbreak\n\t\t\t\tcase 'update':\n\t\t\t\t\tif (data) {\n\t\t\t\t\t\tconst existing = records.get(recordId) ?? { id: recordId }\n\t\t\t\t\t\trecords.set(recordId, { ...existing, ...data })\n\t\t\t\t\t\tdeleted.delete(recordId)\n\t\t\t\t\t}\n\t\t\t\t\tbreak\n\t\t\t\tcase 'delete':\n\t\t\t\t\tdeleted.add(recordId)\n\t\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\tfor (const id of deleted) {\n\t\t\trecords.delete(id)\n\t\t}\n\n\t\treturn Array.from(records.values()) as MaterializedRecord[]\n\t}\n\n\t// ---------------------------------------------------------------------------\n\t// Table setup\n\t// ---------------------------------------------------------------------------\n\n\t/**\n\t * Create the operations and sync_state tables if they don't exist.\n\t */\n\tprivate ensureTables(): void {\n\t\tthis.db.run(sql`\n\t\t\tCREATE TABLE IF NOT EXISTS operations (\n\t\t\t\tid TEXT PRIMARY KEY,\n\t\t\t\tnode_id TEXT NOT NULL,\n\t\t\t\ttype TEXT NOT NULL,\n\t\t\t\tcollection TEXT NOT NULL,\n\t\t\t\trecord_id TEXT NOT NULL,\n\t\t\t\tdata TEXT,\n\t\t\t\tprevious_data TEXT,\n\t\t\t\twall_time INTEGER NOT NULL,\n\t\t\t\tlogical INTEGER NOT NULL,\n\t\t\t\ttimestamp_node_id TEXT NOT NULL,\n\t\t\t\tsequence_number INTEGER NOT NULL,\n\t\t\t\tcausal_deps TEXT NOT NULL DEFAULT '[]',\n\t\t\t\tschema_version INTEGER NOT NULL,\n\t\t\t\treceived_at INTEGER NOT NULL\n\t\t\t)\n\t\t`)\n\n\t\tthis.db.run(sql`\n\t\t\tCREATE INDEX IF NOT EXISTS idx_node_seq ON operations (node_id, sequence_number)\n\t\t`)\n\n\t\tthis.db.run(sql`\n\t\t\tCREATE INDEX IF NOT EXISTS idx_collection ON operations (collection)\n\t\t`)\n\n\t\tthis.db.run(sql`\n\t\t\tCREATE INDEX IF NOT EXISTS idx_received ON operations (received_at)\n\t\t`)\n\n\t\t// Index for efficient per-record operation lookups during materialization\n\t\tthis.db.run(sql`\n\t\t\tCREATE INDEX IF NOT EXISTS idx_collection_record ON operations (collection, record_id)\n\t\t`)\n\n\t\tthis.db.run(sql`\n\t\t\tCREATE TABLE IF NOT EXISTS sync_state (\n\t\t\t\tnode_id TEXT PRIMARY KEY,\n\t\t\t\tmax_sequence_number INTEGER NOT NULL,\n\t\t\t\tlast_seen_at INTEGER NOT NULL\n\t\t\t)\n\t\t`)\n\t}\n\n\t// ---------------------------------------------------------------------------\n\t// Operation serialization\n\t// ---------------------------------------------------------------------------\n\n\tprivate serializeOperation(\n\t\top: Operation,\n\t\treceivedAt: number,\n\t): typeof operations.$inferInsert {\n\t\treturn {\n\t\t\tid: op.id,\n\t\t\tnodeId: op.nodeId,\n\t\t\ttype: op.type,\n\t\t\tcollection: op.collection,\n\t\t\trecordId: op.recordId,\n\t\t\tdata: op.data !== null ? JSON.stringify(op.data) : null,\n\t\t\tpreviousData: op.previousData !== null ? JSON.stringify(op.previousData) : null,\n\t\t\twallTime: op.timestamp.wallTime,\n\t\t\tlogical: op.timestamp.logical,\n\t\t\ttimestampNodeId: op.timestamp.nodeId,\n\t\t\tsequenceNumber: op.sequenceNumber,\n\t\t\tcausalDeps: JSON.stringify(op.causalDeps),\n\t\t\tschemaVersion: op.schemaVersion,\n\t\t\treceivedAt,\n\t\t}\n\t}\n\n\tprivate deserializeOperation(row: typeof operations.$inferSelect): Operation {\n\t\treturn {\n\t\t\tid: row.id,\n\t\t\tnodeId: row.nodeId,\n\t\t\ttype: row.type as Operation['type'],\n\t\t\tcollection: row.collection,\n\t\t\trecordId: row.recordId,\n\t\t\tdata: row.data !== null ? JSON.parse(row.data) : null,\n\t\t\tpreviousData: row.previousData !== null ? JSON.parse(row.previousData) : null,\n\t\t\ttimestamp: {\n\t\t\t\twallTime: row.wallTime,\n\t\t\t\tlogical: row.logical,\n\t\t\t\tnodeId: row.timestampNodeId,\n\t\t\t},\n\t\t\tsequenceNumber: row.sequenceNumber,\n\t\t\tcausalDeps: JSON.parse(row.causalDeps),\n\t\t\tschemaVersion: row.schemaVersion,\n\t\t}\n\t}\n\n\t// ---------------------------------------------------------------------------\n\t// Assertions\n\t// ---------------------------------------------------------------------------\n\n\tprivate assertOpen(): void {\n\t\tif (this.closed) {\n\t\t\tthrow new Error('SqliteServerStore is closed')\n\t\t}\n\t}\n\n\tprivate assertSchema(): void {\n\t\tif (!this.schema) {\n\t\t\tthrow new Error(\n\t\t\t\t'Schema not set. Call setSchema() before using queryCollection/findRecord/countCollection.',\n\t\t\t)\n\t\t}\n\t}\n\n\tprivate assertCollection(collection: string): void {\n\t\tif (!this.schema!.collections[collection]) {\n\t\t\tthrow new Error(\n\t\t\t\t`Unknown collection \"${collection}\". Available: ${Object.keys(this.schema!.collections).join(', ')}`,\n\t\t\t)\n\t\t}\n\t}\n}\n\n/**\n * Creates a SqliteServerStore with a file-backed or in-memory database.\n * Handles database creation, Drizzle wrapping, and table setup.\n *\n * @param options - Configuration options\n * @param options.filename - Path to SQLite database file. Defaults to ':memory:' for testing.\n * @param options.nodeId - Server node ID. Auto-generated if not provided.\n * @returns A ready-to-use SqliteServerStore\n *\n * @example\n * ```typescript\n * import { createSqliteServerStore } from '@korajs/server'\n *\n * const store = createSqliteServerStore({ filename: './kora-server.db' })\n *\n * // Optional: enable materialized collection tables for fast queries\n * await store.setSchema(mySchema)\n *\n * const server = createKoraServer({ store, port: 3001 })\n * ```\n */\nexport function createSqliteServerStore(options: {\n\tfilename?: string\n\tnodeId?: string\n}): SqliteServerStore {\n\t// better-sqlite3 is a native CJS addon — use esmRequire (from createRequire)\n\t// so this works in both ESM and CJS contexts.\n\tconst Database = esmRequire('better-sqlite3')\n\tconst { drizzle } = esmRequire('drizzle-orm/better-sqlite3')\n\n\tconst filename = options.filename ?? ':memory:'\n\tconst sqlite = new Database(filename)\n\n\t// Enable WAL mode for better concurrent read/write performance\n\tsqlite.pragma('journal_mode = WAL')\n\n\tconst db = drizzle(sqlite)\n\treturn new SqliteServerStore(db, options.nodeId)\n}\n","import { index, integer, sqliteTable, text } from 'drizzle-orm/sqlite-core'\n\n/**\n * Drizzle schema for the Kora sync server's SQLite database.\n *\n * Two tables:\n * - `operations` — the append-only operation log (content-addressed by id)\n * - `syncState` — tracks the max sequence number seen per node (version vector)\n */\n\nexport const operations = sqliteTable(\n\t'operations',\n\t{\n\t\tid: text('id').primaryKey(),\n\t\tnodeId: text('node_id').notNull(),\n\t\ttype: text('type').notNull(),\n\t\tcollection: text('collection').notNull(),\n\t\trecordId: text('record_id').notNull(),\n\t\tdata: text('data'), // JSON-serialized, null for deletes\n\t\tpreviousData: text('previous_data'), // JSON-serialized, null for insert/delete\n\t\twallTime: integer('wall_time').notNull(),\n\t\tlogical: integer('logical').notNull(),\n\t\ttimestampNodeId: text('timestamp_node_id').notNull(),\n\t\tsequenceNumber: integer('sequence_number').notNull(),\n\t\tcausalDeps: text('causal_deps').notNull().default('[]'), // JSON array of op IDs\n\t\tschemaVersion: integer('schema_version').notNull(),\n\t\treceivedAt: integer('received_at').notNull(),\n\t},\n\t(table) => ({\n\t\tnodeSeqIdx: index('idx_node_seq').on(table.nodeId, table.sequenceNumber),\n\t\tcollectionIdx: index('idx_collection').on(table.collection),\n\t\treceivedIdx: index('idx_received').on(table.receivedAt),\n\t}),\n)\n\nexport const syncState = sqliteTable('sync_state', {\n\tnodeId: text('node_id').primaryKey(),\n\tmaxSequenceNumber: integer('max_sequence_number').notNull(),\n\tlastSeenAt: integer('last_seen_at').notNull(),\n})\n","import { SyncError } from '@korajs/core'\nimport type { MessageSerializer } from '@korajs/sync'\nimport type {\n\tServerCloseHandler,\n\tServerErrorHandler,\n\tServerMessageHandler,\n\tServerTransport,\n} from './server-transport'\n\nexport interface HttpPollResponse {\n\tstatus: 200 | 204 | 304 | 410\n\tbody?: string | Uint8Array\n\theaders?: Record<string, string>\n}\n\ninterface QueuedMessage {\n\tetag: string\n\tcontentType: string\n\tpayload: string | Uint8Array\n}\n\n/**\n * Server-side transport for HTTP long-polling clients.\n *\n * Incoming client messages are pushed via POST, while outbound server\n * messages are pulled via GET long-poll requests.\n */\nexport class HttpServerTransport implements ServerTransport {\n\tprivate readonly serializer: MessageSerializer\n\n\tprivate messageHandler: ServerMessageHandler | null = null\n\tprivate closeHandler: ServerCloseHandler | null = null\n\tprivate errorHandler: ServerErrorHandler | null = null\n\n\tprivate connected = true\n\tprivate nextSequence = 1\n\tprivate readonly queue: QueuedMessage[] = []\n\n\tconstructor(serializer: MessageSerializer) {\n\t\tthis.serializer = serializer\n\t}\n\n\tsend(message: import('@korajs/sync').SyncMessage): void {\n\t\tif (!this.connected) return\n\n\t\tconst encoded = this.serializer.encode(message)\n\t\tconst isBinary = encoded instanceof Uint8Array\n\t\tthis.queue.push({\n\t\t\tetag: this.makeEtag(this.nextSequence++),\n\t\t\tcontentType: isBinary ? 'application/x-protobuf' : 'application/json',\n\t\t\tpayload: encoded,\n\t\t})\n\t}\n\n\tonMessage(handler: ServerMessageHandler): void {\n\t\tthis.messageHandler = handler\n\t}\n\n\tonClose(handler: ServerCloseHandler): void {\n\t\tthis.closeHandler = handler\n\t}\n\n\tonError(handler: ServerErrorHandler): void {\n\t\tthis.errorHandler = handler\n\t}\n\n\tisConnected(): boolean {\n\t\treturn this.connected\n\t}\n\n\tclose(code = 1000, reason = 'transport closed'): void {\n\t\tif (!this.connected) return\n\t\tthis.connected = false\n\t\tthis.queue.length = 0\n\t\tthis.closeHandler?.(code, reason)\n\t}\n\n\treceive(payload: string | Uint8Array): void {\n\t\tif (!this.connected) {\n\t\t\tthrow new SyncError('HTTP server transport is closed')\n\t\t}\n\n\t\ttry {\n\t\t\tconst message = this.serializer.decode(payload)\n\t\t\tthis.messageHandler?.(message)\n\t\t} catch (error) {\n\t\t\tthis.errorHandler?.(error instanceof Error ? error : new Error(String(error)))\n\t\t}\n\t}\n\n\tpoll(ifNoneMatch?: string): HttpPollResponse {\n\t\tif (!this.connected) {\n\t\t\treturn { status: 410 }\n\t\t}\n\n\t\tconst next = this.queue[0]\n\t\tif (!next) {\n\t\t\treturn { status: 204 }\n\t\t}\n\n\t\tif (ifNoneMatch && ifNoneMatch === next.etag) {\n\t\t\treturn {\n\t\t\t\tstatus: 304,\n\t\t\t\theaders: { etag: next.etag },\n\t\t\t}\n\t\t}\n\n\t\tthis.queue.shift()\n\t\treturn {\n\t\t\tstatus: 200,\n\t\t\tbody: next.payload,\n\t\t\theaders: {\n\t\t\t\t'content-type': next.contentType,\n\t\t\t\tetag: next.etag,\n\t\t\t},\n\t\t}\n\t}\n\n\tprivate makeEtag(sequence: number): string {\n\t\treturn `W/\"${sequence}\"`\n\t}\n}\n","import { SyncError } from '@korajs/core'\nimport type { SyncMessage } from '@korajs/sync'\nimport { JsonMessageSerializer } from '@korajs/sync'\nimport type { MessageSerializer } from '@korajs/sync'\nimport type {\n\tServerCloseHandler,\n\tServerErrorHandler,\n\tServerMessageHandler,\n\tServerTransport,\n} from './server-transport'\n\n/** WebSocket ready states (mirrors ws constants) */\nconst WS_OPEN = 1\n\n/**\n * Minimal interface for a ws.WebSocket instance.\n * Allows dependency injection for testing without importing ws directly.\n */\nexport interface WsWebSocket {\n\treadyState: number\n\tsend(data: string | Uint8Array, callback?: (err?: Error) => void): void\n\tclose(code?: number, reason?: string): void\n\ton(event: string, listener: (...args: unknown[]) => void): void\n\tremoveAllListeners(): void\n}\n\n/**\n * Options for WsServerTransport.\n */\nexport interface WsServerTransportOptions {\n\t/** Message serializer. Defaults to JsonMessageSerializer. */\n\tserializer?: MessageSerializer\n}\n\n/**\n * Server-side transport wrapping a ws.WebSocket connection.\n * Created for each incoming client connection.\n */\nexport class WsServerTransport implements ServerTransport {\n\tprivate readonly ws: WsWebSocket\n\tprivate readonly serializer: MessageSerializer\n\tprivate messageHandler: ServerMessageHandler | null = null\n\tprivate closeHandler: ServerCloseHandler | null = null\n\tprivate errorHandler: ServerErrorHandler | null = null\n\n\tconstructor(ws: WsWebSocket, options?: WsServerTransportOptions) {\n\t\tthis.ws = ws\n\t\tthis.serializer = options?.serializer ?? new JsonMessageSerializer()\n\t\tthis.setupListeners()\n\t}\n\n\tsend(message: SyncMessage): void {\n\t\tif (this.ws.readyState !== WS_OPEN) {\n\t\t\tthrow new SyncError('Cannot send message: WebSocket is not open', {\n\t\t\t\treadyState: this.ws.readyState,\n\t\t\t\tmessageType: message.type,\n\t\t\t})\n\t\t}\n\n\t\tconst encoded = this.serializer.encode(message)\n\t\tthis.ws.send(encoded)\n\t}\n\n\tonMessage(handler: ServerMessageHandler): void {\n\t\tthis.messageHandler = handler\n\t}\n\n\tonClose(handler: ServerCloseHandler): void {\n\t\tthis.closeHandler = handler\n\t}\n\n\tonError(handler: ServerErrorHandler): void {\n\t\tthis.errorHandler = handler\n\t}\n\n\tisConnected(): boolean {\n\t\treturn this.ws.readyState === WS_OPEN\n\t}\n\n\tclose(code?: number, reason?: string): void {\n\t\tthis.ws.close(code ?? 1000, reason ?? 'server closing')\n\t}\n\n\tprivate setupListeners(): void {\n\t\tthis.ws.on('message', (data: unknown) => {\n\t\t\ttry {\n\t\t\t\tif (\n\t\t\t\t\ttypeof data !== 'string' &&\n\t\t\t\t\t!(data instanceof Uint8Array) &&\n\t\t\t\t\t!(data instanceof ArrayBuffer)\n\t\t\t\t) {\n\t\t\t\t\tthrow new SyncError('Unsupported WebSocket payload type', {\n\t\t\t\t\t\tpayloadType: typeof data,\n\t\t\t\t\t})\n\t\t\t\t}\n\n\t\t\t\tconst decoded = this.serializer.decode(data)\n\t\t\t\tthis.messageHandler?.(decoded)\n\t\t\t} catch (err) {\n\t\t\t\tthis.errorHandler?.(err instanceof Error ? err : new Error(String(err)))\n\t\t\t}\n\t\t})\n\n\t\tthis.ws.on('close', (code: unknown, reason: unknown) => {\n\t\t\tthis.closeHandler?.(Number(code) || 1006, String(reason || 'connection closed'))\n\t\t})\n\n\t\tthis.ws.on('error', (err: unknown) => {\n\t\t\tthis.errorHandler?.(err instanceof Error ? err : new Error(String(err)))\n\t\t})\n\t}\n}\n","import type { KoraEventEmitter, Operation } from '@korajs/core'\nimport { SyncError, generateUUIDv7 } from '@korajs/core'\nimport { topologicalSort } from '@korajs/core/internal'\nimport type {\n\tHandshakeMessage,\n\tMessageSerializer,\n\tOperationBatchMessage,\n\tSyncMessage,\n\tWireFormat,\n} from '@korajs/sync'\nimport {\n\tNegotiatedMessageSerializer,\n\tversionVectorToWire,\n\twireToVersionVector,\n} from '@korajs/sync'\nimport type { ServerStore } from '../store/server-store'\nimport { operationMatchesScopes } from '../scopes/server-scope-filter'\nimport type { ServerTransport } from '../transport/server-transport'\nimport type { AuthContext, AuthProvider } from '../types'\n\nconst DEFAULT_BATCH_SIZE = 100\nconst DEFAULT_SCHEMA_VERSION = 1\n\n/**\n * Possible states for a client session.\n */\nexport type SessionState = 'connected' | 'authenticated' | 'syncing' | 'streaming' | 'closed'\n\n/**\n * Callback invoked when a session has new operations to relay to other sessions.\n */\nexport type RelayCallback = (sourceSessionId: string, operations: Operation[]) => void\n\n/**\n * Options for creating a ClientSession.\n */\nexport interface ClientSessionOptions {\n\t/** Unique session identifier */\n\tsessionId: string\n\t/** Transport for this client connection */\n\ttransport: ServerTransport\n\t/** Server-side operation store */\n\tstore: ServerStore\n\t/** Authentication provider (optional) */\n\tauth?: AuthProvider\n\t/** Message serializer */\n\tserializer?: MessageSerializer\n\t/** Event emitter for DevTools integration */\n\temitter?: KoraEventEmitter\n\t/** Max operations per sync batch */\n\tbatchSize?: number\n\t/** Schema version the server expects */\n\tschemaVersion?: number\n\t/** Called when this session has operations to relay to other sessions */\n\tonRelay?: RelayCallback\n\t/** Called when this session closes */\n\tonClose?: (sessionId: string) => void\n}\n\n/**\n * Handles the sync protocol for a single connected client.\n *\n * Lifecycle: connected → (authenticated) → syncing → streaming → closed\n *\n * The session:\n * 1. Receives a handshake from the client\n * 2. Authenticates if an AuthProvider is configured\n * 3. Sends back a HandshakeResponse with the server's version vector\n * 4. Computes and sends the server's delta to the client (paginated)\n * 5. Processes incoming operation batches from the client\n * 6. Transitions to streaming for real-time bidirectional sync\n * 7. Relays new operations to other sessions via the RelayCallback\n */\nexport class ClientSession {\n\tprivate state: SessionState = 'connected'\n\tprivate clientNodeId: string | null = null\n\tprivate authContext: AuthContext | null = null\n\n\tprivate readonly sessionId: string\n\tprivate readonly transport: ServerTransport\n\tprivate readonly store: ServerStore\n\tprivate readonly auth: AuthProvider | null\n\tprivate readonly serializer: MessageSerializer\n\tprivate readonly emitter: KoraEventEmitter | null\n\tprivate readonly batchSize: number\n\tprivate readonly schemaVersion: number\n\tprivate readonly onRelay: RelayCallback | null\n\tprivate readonly onClose: ((sessionId: string) => void) | null\n\n\tconstructor(options: ClientSessionOptions) {\n\t\tthis.sessionId = options.sessionId\n\t\tthis.transport = options.transport\n\t\tthis.store = options.store\n\t\tthis.auth = options.auth ?? null\n\t\tthis.serializer = options.serializer ?? new NegotiatedMessageSerializer('json')\n\t\tthis.emitter = options.emitter ?? null\n\t\tthis.batchSize = options.batchSize ?? DEFAULT_BATCH_SIZE\n\t\tthis.schemaVersion = options.schemaVersion ?? DEFAULT_SCHEMA_VERSION\n\t\tthis.onRelay = options.onRelay ?? null\n\t\tthis.onClose = options.onClose ?? null\n\t}\n\n\t/**\n\t * Start handling messages from the client transport.\n\t */\n\tstart(): void {\n\t\tthis.transport.onMessage((msg) => this.handleMessage(msg))\n\t\tthis.transport.onClose((_code, _reason) => this.handleTransportClose())\n\t\tthis.transport.onError((_err) => {\n\t\t\t// Transport errors during active session cause close\n\t\t\tif (this.state !== 'closed') {\n\t\t\t\tthis.handleTransportClose()\n\t\t\t}\n\t\t})\n\t}\n\n\t/**\n\t * Relay operations from another session to this client.\n\t * Only relays if the session is in streaming state and transport is connected.\n\t */\n\trelayOperations(operations: Operation[]): void {\n\t\tif (this.state !== 'streaming' || !this.transport.isConnected()) return\n\t\tif (operations.length === 0) return\n\n\t\tconst visibleOperations = operations.filter((op) =>\n\t\t\toperationMatchesScopes(op, this.authContext?.scopes),\n\t\t)\n\t\tif (visibleOperations.length === 0) return\n\n\t\tconst serializedOps = visibleOperations.map((op) => this.serializer.encodeOperation(op))\n\t\tconst msg: SyncMessage = {\n\t\t\ttype: 'operation-batch',\n\t\t\tmessageId: generateUUIDv7(),\n\t\t\toperations: serializedOps,\n\t\t\tisFinal: true,\n\t\t\tbatchIndex: 0,\n\t\t}\n\t\tthis.transport.send(msg)\n\t}\n\n\t/**\n\t * Close this session.\n\t */\n\tclose(reason?: string): void {\n\t\tif (this.state === 'closed') return\n\t\tthis.state = 'closed'\n\n\t\tif (this.transport.isConnected()) {\n\t\t\tthis.transport.close(1000, reason ?? 'session closed')\n\t\t}\n\n\t\tthis.onClose?.(this.sessionId)\n\t}\n\n\t// --- Getters ---\n\n\tgetState(): SessionState {\n\t\treturn this.state\n\t}\n\n\tgetSessionId(): string {\n\t\treturn this.sessionId\n\t}\n\n\tgetClientNodeId(): string | null {\n\t\treturn this.clientNodeId\n\t}\n\n\tgetAuthContext(): AuthContext | null {\n\t\treturn this.authContext\n\t}\n\n\tisStreaming(): boolean {\n\t\treturn this.state === 'streaming'\n\t}\n\n\t// --- Private protocol handlers ---\n\n\tprivate handleMessage(message: SyncMessage): void {\n\t\tswitch (message.type) {\n\t\t\tcase 'handshake':\n\t\t\t\tthis.handleHandshake(message)\n\t\t\t\tbreak\n\t\t\tcase 'operation-batch':\n\t\t\t\tthis.handleOperationBatch(message)\n\t\t\t\tbreak\n\t\t\t// Acknowledgments from clients are noted but no action needed on server\n\t\t\tcase 'acknowledgment':\n\t\t\t\tbreak\n\t\t\tcase 'error':\n\t\t\t\tbreak\n\t\t}\n\t}\n\n\tprivate async handleHandshake(msg: HandshakeMessage): Promise<void> {\n\t\t// Only accept handshake in 'connected' state (prevent duplicate handshakes)\n\t\tif (this.state !== 'connected') {\n\t\t\tthis.sendError('DUPLICATE_HANDSHAKE', 'Handshake already completed', false)\n\t\t\treturn\n\t\t}\n\n\t\tthis.clientNodeId = msg.nodeId\n\n\t\t// Authenticate if provider is configured\n\t\tif (this.auth) {\n\t\t\tconst token = msg.authToken ?? ''\n\t\t\tconst context = await this.auth.authenticate(token)\n\t\t\tif (!context) {\n\t\t\t\tthis.sendError('AUTH_FAILED', 'Authentication failed', false)\n\t\t\t\tthis.close('authentication failed')\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.authContext = context\n\t\t\tthis.state = 'authenticated'\n\t\t}\n\n\t\t// Send handshake response with server's version vector\n\t\tconst serverVector = this.store.getVersionVector()\n\t\tconst selectedWireFormat = selectWireFormat(msg.supportedWireFormats)\n\t\tthis.setSerializerWireFormat(selectedWireFormat)\n\t\tconst response: SyncMessage = {\n\t\t\ttype: 'handshake-response',\n\t\t\tmessageId: generateUUIDv7(),\n\t\t\tnodeId: this.store.getNodeId(),\n\t\t\tversionVector: versionVectorToWire(serverVector),\n\t\t\tschemaVersion: this.schemaVersion,\n\t\t\taccepted: true,\n\t\t\tselectedWireFormat,\n\t\t}\n\t\tthis.transport.send(response)\n\n\t\tthis.emitter?.emit({ type: 'sync:connected', nodeId: msg.nodeId })\n\n\t\t// Transition to syncing and send delta\n\t\tthis.state = 'syncing'\n\t\tconst clientVector = wireToVersionVector(msg.versionVector)\n\t\tawait this.sendDelta(clientVector)\n\n\t\t// Transition to streaming after delta is sent\n\t\tthis.state = 'streaming'\n\t}\n\n\tprivate async handleOperationBatch(msg: OperationBatchMessage): Promise<void> {\n\t\tconst operations = msg.operations.map((s) => this.serializer.decodeOperation(s))\n\t\tconst applied: Operation[] = []\n\n\t\tfor (const op of operations) {\n\t\t\tif (!operationMatchesScopes(op, this.authContext?.scopes)) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tconst result = await this.store.applyRemoteOperation(op)\n\t\t\tif (result === 'applied') {\n\t\t\t\tapplied.push(op)\n\t\t\t}\n\t\t}\n\n\t\tif (operations.length > 0) {\n\t\t\tthis.emitter?.emit({\n\t\t\t\ttype: 'sync:received',\n\t\t\t\toperations,\n\t\t\t\tbatchSize: operations.length,\n\t\t\t})\n\t\t}\n\n\t\t// Send acknowledgment\n\t\tconst lastOp = operations[operations.length - 1]\n\t\tconst ack: SyncMessage = {\n\t\t\ttype: 'acknowledgment',\n\t\t\tmessageId: generateUUIDv7(),\n\t\t\tacknowledgedMessageId: msg.messageId,\n\t\t\tlastSequenceNumber: lastOp ? lastOp.sequenceNumber : 0,\n\t\t}\n\t\tthis.transport.send(ack)\n\n\t\t// Relay only newly applied operations to other sessions\n\t\tif (applied.length > 0) {\n\t\t\tthis.onRelay?.(this.sessionId, applied)\n\t\t}\n\t}\n\n\tprivate async sendDelta(clientVector: Map<string, number>): Promise<void> {\n\t\tconst serverVector = this.store.getVersionVector()\n\t\tconst missing: Operation[] = []\n\n\t\tfor (const [nodeId, serverSeq] of serverVector) {\n\t\t\tconst clientSeq = clientVector.get(nodeId) ?? 0\n\t\t\tif (serverSeq > clientSeq) {\n\t\t\t\tconst ops = await this.store.getOperationRange(nodeId, clientSeq + 1, serverSeq)\n\t\t\t\tconst visible = ops.filter((op) => operationMatchesScopes(op, this.authContext?.scopes))\n\t\t\t\tmissing.push(...visible)\n\t\t\t}\n\t\t}\n\n\t\tif (missing.length === 0) {\n\t\t\t// Send empty final batch to signal delta is complete\n\t\t\tconst emptyBatch: SyncMessage = {\n\t\t\t\ttype: 'operation-batch',\n\t\t\t\tmessageId: generateUUIDv7(),\n\t\t\t\toperations: [],\n\t\t\t\tisFinal: true,\n\t\t\t\tbatchIndex: 0,\n\t\t\t}\n\t\t\tthis.transport.send(emptyBatch)\n\t\t\treturn\n\t\t}\n\n\t\t// Sort causally and paginate\n\t\tconst sorted = topologicalSort(missing)\n\t\tconst totalBatches = Math.ceil(sorted.length / this.batchSize)\n\n\t\tfor (let i = 0; i < totalBatches; i++) {\n\t\t\tconst start = i * this.batchSize\n\t\t\tconst batchOps = sorted.slice(start, start + this.batchSize)\n\t\t\tconst serializedOps = batchOps.map((op) => this.serializer.encodeOperation(op))\n\n\t\t\tconst batchMsg: SyncMessage = {\n\t\t\t\ttype: 'operation-batch',\n\t\t\t\tmessageId: generateUUIDv7(),\n\t\t\t\toperations: serializedOps,\n\t\t\t\tisFinal: i === totalBatches - 1,\n\t\t\t\tbatchIndex: i,\n\t\t\t}\n\t\t\tthis.transport.send(batchMsg)\n\n\t\t\tthis.emitter?.emit({\n\t\t\t\ttype: 'sync:sent',\n\t\t\t\toperations: batchOps,\n\t\t\t\tbatchSize: batchOps.length,\n\t\t\t})\n\t\t}\n\t}\n\n\tprivate sendError(code: string, message: string, retriable: boolean): void {\n\t\tconst errorMsg: SyncMessage = {\n\t\t\ttype: 'error',\n\t\t\tmessageId: generateUUIDv7(),\n\t\t\tcode,\n\t\t\tmessage,\n\t\t\tretriable,\n\t\t}\n\t\tthis.transport.send(errorMsg)\n\t}\n\n\tprivate setSerializerWireFormat(format: WireFormat): void {\n\t\tif (typeof this.serializer.setWireFormat === 'function') {\n\t\t\tthis.serializer.setWireFormat(format)\n\t\t}\n\t}\n\n\tprivate handleTransportClose(): void {\n\t\tif (this.state === 'closed') return\n\t\tthis.state = 'closed'\n\t\tthis.emitter?.emit({ type: 'sync:disconnected', reason: 'transport closed' })\n\t\tthis.onClose?.(this.sessionId)\n\t}\n}\n\nfunction selectWireFormat(supportedWireFormats?: WireFormat[]): WireFormat {\n\tif (supportedWireFormats?.includes('protobuf')) {\n\t\treturn 'protobuf'\n\t}\n\n\treturn 'json'\n}\n","import type { Operation } from '@korajs/core'\n\n/**\n * Per-collection scope map from auth context.\n */\nexport type ScopeMap = Record<string, Record<string, unknown>>\n\n/**\n * Returns true if an operation is visible to a session based on its scopes.\n *\n * Rules:\n * - No scopes configured => visible\n * - Collection missing from scope map => hidden\n * - All scoped field/value pairs must match the operation snapshot\n */\nexport function operationMatchesScopes(op: Operation, scopes: ScopeMap | undefined): boolean {\n\tif (!scopes) return true\n\n\tconst collectionScope = scopes[op.collection]\n\tif (!collectionScope) return false\n\n\tconst snapshot = buildSnapshot(op)\n\tif (!snapshot) return false\n\n\tfor (const [field, expected] of Object.entries(collectionScope)) {\n\t\tif (snapshot[field] !== expected) {\n\t\t\treturn false\n\t\t}\n\t}\n\n\treturn true\n}\n\nfunction buildSnapshot(op: Operation): Record<string, unknown> | null {\n\tconst previous = asRecord(op.previousData)\n\tconst next = asRecord(op.data)\n\n\tif (!previous && !next) return null\n\n\treturn {\n\t\t...(previous ?? {}),\n\t\t...(next ?? {}),\n\t}\n}\n\nfunction asRecord(value: unknown): Record<string, unknown> | null {\n\tif (typeof value !== 'object' || value === null || Array.isArray(value)) {\n\t\treturn null\n\t}\n\n\treturn value as Record<string, unknown>\n}\n","import type { KoraEventEmitter, Operation } from '@korajs/core'\nimport { SyncError, generateUUIDv7 } from '@korajs/core'\nimport type { MessageSerializer } from '@korajs/sync'\nimport { JsonMessageSerializer } from '@korajs/sync'\nimport { ClientSession } from '../session/client-session'\nimport type { ServerStore } from '../store/server-store'\nimport { HttpServerTransport } from '../transport/http-server-transport'\nimport type { ServerTransport } from '../transport/server-transport'\nimport { WsServerTransport } from '../transport/ws-server-transport'\nimport type {\n\tAuthProvider,\n\tHttpSyncRequest,\n\tHttpSyncResponse,\n\tKoraSyncServerConfig,\n\tServerStatus,\n} from '../types'\n\nconst DEFAULT_MAX_CONNECTIONS = 0 // unlimited\nconst DEFAULT_BATCH_SIZE = 100\nconst DEFAULT_SCHEMA_VERSION = 1\nconst DEFAULT_HOST = '0.0.0.0'\nconst DEFAULT_PATH = '/'\n\n/**\n * Minimal interface for a ws.WebSocketServer instance.\n * Allows dependency injection for testing without importing ws directly.\n */\nexport interface WsServerLike {\n\ton(event: string, listener: (...args: unknown[]) => void): void\n\tclose(callback?: (err?: Error) => void): void\n\taddress(): { port: number } | string | null\n}\n\n/**\n * Constructor type for creating a WebSocket server.\n */\nexport type WsServerConstructor = new (options: {\n\tport?: number\n\thost?: string\n\tpath?: string\n}) => WsServerLike\n\n/**\n * Self-hosted sync server. Accepts WebSocket connections from clients,\n * handles the sync protocol, stores operations, and relays changes\n * between connected clients.\n *\n * Two modes of operation:\n * 1. **Standalone**: Call `start()` with a port — creates its own WebSocket server.\n * 2. **Attach**: Call `handleConnection(transport)` — attach to an existing HTTP server.\n */\nexport class KoraSyncServer {\n\tprivate readonly store: ServerStore\n\tprivate readonly auth: AuthProvider | null\n\tprivate readonly serializer: MessageSerializer\n\tprivate readonly emitter: KoraEventEmitter | null\n\tprivate readonly maxConnections: number\n\tprivate readonly batchSize: number\n\tprivate readonly schemaVersion: number\n\tprivate readonly port: number | undefined\n\tprivate readonly host: string\n\tprivate readonly path: string\n\n\tprivate readonly sessions = new Map<string, ClientSession>()\n\tprivate readonly httpClients = new Map<string, { sessionId: string; transport: HttpServerTransport }>()\n\tprivate readonly httpSessionToClient = new Map<string, string>()\n\tprivate wsServer: WsServerLike | null = null\n\tprivate running = false\n\n\tconstructor(config: KoraSyncServerConfig) {\n\t\tthis.store = config.store\n\t\tthis.auth = config.auth ?? null\n\t\tthis.serializer = config.serializer ?? new JsonMessageSerializer()\n\t\tthis.emitter = config.emitter ?? null\n\t\tthis.maxConnections = config.maxConnections ?? DEFAULT_MAX_CONNECTIONS\n\t\tthis.batchSize = config.batchSize ?? DEFAULT_BATCH_SIZE\n\t\tthis.schemaVersion = config.schemaVersion ?? DEFAULT_SCHEMA_VERSION\n\t\tthis.port = config.port\n\t\tthis.host = config.host ?? DEFAULT_HOST\n\t\tthis.path = config.path ?? DEFAULT_PATH\n\t}\n\n\t/**\n\t * Start the WebSocket server in standalone mode.\n\t *\n\t * @param wsServerImpl - Optional WebSocket server constructor for testing\n\t */\n\tasync start(wsServerImpl?: WsServerConstructor): Promise<void> {\n\t\tif (this.running) {\n\t\t\tthrow new SyncError('Server is already running', { port: this.port })\n\t\t}\n\n\t\tif (!wsServerImpl && this.port === undefined) {\n\t\t\tthrow new SyncError(\n\t\t\t\t'Port is required for standalone mode. Provide port in config or use handleConnection() for attach mode.',\n\t\t\t\t{},\n\t\t\t)\n\t\t}\n\n\t\tif (wsServerImpl) {\n\t\t\tthis.wsServer = new wsServerImpl({\n\t\t\t\tport: this.port,\n\t\t\t\thost: this.host,\n\t\t\t\tpath: this.path,\n\t\t\t})\n\t\t} else {\n\t\t\t// Dynamic import of ws — only needed in standalone mode\n\t\t\tconst { WebSocketServer } = await import('ws')\n\t\t\tthis.wsServer = new WebSocketServer({\n\t\t\t\tport: this.port,\n\t\t\t\thost: this.host,\n\t\t\t\tpath: this.path,\n\t\t\t})\n\t\t}\n\n\t\tthis.wsServer.on('connection', (ws: unknown) => {\n\t\t\tconst transport = new WsServerTransport(\n\t\t\t\tws as import('../transport/ws-server-transport').WsWebSocket,\n\t\t\t\t{\n\t\t\t\t\tserializer: this.serializer,\n\t\t\t\t},\n\t\t\t)\n\t\t\tthis.handleConnection(transport)\n\t\t})\n\n\t\tthis.running = true\n\t}\n\n\t/**\n\t * Stop the server. Closes all sessions and the WebSocket server.\n\t */\n\tasync stop(): Promise<void> {\n\t\t// Close all active sessions (works in both standalone and attach mode)\n\t\tfor (const session of this.sessions.values()) {\n\t\t\tsession.close('server shutting down')\n\t\t}\n\t\tthis.sessions.clear()\n\t\tthis.httpClients.clear()\n\t\tthis.httpSessionToClient.clear()\n\n\t\t// Close WebSocket server (standalone mode only)\n\t\tif (this.wsServer) {\n\t\t\tawait new Promise<void>((resolve) => {\n\t\t\t\tthis.wsServer?.close(() => resolve())\n\t\t\t})\n\t\t\tthis.wsServer = null\n\t\t}\n\n\t\tthis.running = false\n\t}\n\n\t/**\n\t * Handle one HTTP sync request for a long-polling client.\n\t *\n\t * A stable `clientId` identifies the logical connection across requests.\n\t */\n\tasync handleHttpRequest(request: HttpSyncRequest): Promise<HttpSyncResponse> {\n\t\tif (!request.clientId || request.clientId.trim().length === 0) {\n\t\t\treturn { status: 400 }\n\t\t}\n\n\t\tconst client = this.getOrCreateHttpClient(request.clientId)\n\n\t\tif (request.method === 'POST') {\n\t\t\tif (request.body === undefined) {\n\t\t\t\treturn { status: 400 }\n\t\t\t}\n\n\t\t\tconst payload = normalizeHttpBody(request.body, request.contentType)\n\t\t\tclient.transport.receive(payload)\n\t\t\treturn { status: 202 }\n\t\t}\n\n\t\tif (request.method === 'GET') {\n\t\t\tconst polled = client.transport.poll(request.ifNoneMatch)\n\t\t\treturn {\n\t\t\t\tstatus: polled.status,\n\t\t\t\tbody: polled.body,\n\t\t\t\theaders: polled.headers,\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\tstatus: 405,\n\t\t\theaders: { allow: 'GET, POST' },\n\t\t}\n\t}\n\n\t/**\n\t * Handle an incoming client connection (attach mode).\n\t * Creates a new ClientSession for the transport.\n\t *\n\t * @param transport - The server transport for the new connection\n\t * @returns The session ID\n\t */\n\thandleConnection(transport: ServerTransport): string {\n\t\t// Check max connections\n\t\tif (this.maxConnections > 0 && this.sessions.size >= this.maxConnections) {\n\t\t\ttransport.send({\n\t\t\t\ttype: 'error',\n\t\t\t\tmessageId: generateUUIDv7(),\n\t\t\t\tcode: 'MAX_CONNECTIONS',\n\t\t\t\tmessage: `Server has reached maximum connections (${this.maxConnections})`,\n\t\t\t\tretriable: true,\n\t\t\t})\n\t\t\ttransport.close(4029, 'max connections reached')\n\t\t\tthrow new SyncError('Maximum connections reached', {\n\t\t\t\tcurrent: this.sessions.size,\n\t\t\t\tmax: this.maxConnections,\n\t\t\t})\n\t\t}\n\n\t\tconst sessionId = generateUUIDv7()\n\n\t\tconst session = new ClientSession({\n\t\t\tsessionId,\n\t\t\ttransport,\n\t\t\tstore: this.store,\n\t\t\tauth: this.auth ?? undefined,\n\t\t\tserializer: this.serializer,\n\t\t\temitter: this.emitter ?? undefined,\n\t\t\tbatchSize: this.batchSize,\n\t\t\tschemaVersion: this.schemaVersion,\n\t\t\tonRelay: (sourceSessionId, operations) => {\n\t\t\t\tthis.handleRelay(sourceSessionId, operations)\n\t\t\t},\n\t\t\tonClose: (sid) => {\n\t\t\t\tthis.handleSessionClose(sid)\n\t\t\t},\n\t\t})\n\n\t\tthis.sessions.set(sessionId, session)\n\t\tsession.start()\n\n\t\treturn sessionId\n\t}\n\n\t/**\n\t * Get the current server status.\n\t */\n\tasync getStatus(): Promise<ServerStatus> {\n\t\treturn {\n\t\t\trunning: this.running,\n\t\t\tconnectedClients: this.sessions.size,\n\t\t\tport: this.port ?? null,\n\t\t\ttotalOperations: await this.store.getOperationCount(),\n\t\t}\n\t}\n\n\t/**\n\t * Get the number of currently connected clients.\n\t */\n\tgetConnectionCount(): number {\n\t\treturn this.sessions.size\n\t}\n\n\t// --- Private ---\n\n\tprivate handleRelay(sourceSessionId: string, operations: Operation[]): void {\n\t\tfor (const [sessionId, session] of this.sessions) {\n\t\t\tif (sessionId === sourceSessionId) continue\n\t\t\tsession.relayOperations(operations)\n\t\t}\n\t}\n\n\tprivate handleSessionClose(sessionId: string): void {\n\t\tthis.sessions.delete(sessionId)\n\n\t\tconst clientId = this.httpSessionToClient.get(sessionId)\n\t\tif (clientId) {\n\t\t\tthis.httpSessionToClient.delete(sessionId)\n\t\t\tthis.httpClients.delete(clientId)\n\t\t}\n\t}\n\n\tprivate getOrCreateHttpClient(clientId: string): { sessionId: string; transport: HttpServerTransport } {\n\t\tconst existing = this.httpClients.get(clientId)\n\t\tif (existing) {\n\t\t\treturn existing\n\t\t}\n\n\t\tconst transport = new HttpServerTransport(this.serializer)\n\t\tconst sessionId = this.handleConnection(transport)\n\t\tconst client = { sessionId, transport }\n\n\t\tthis.httpClients.set(clientId, client)\n\t\tthis.httpSessionToClient.set(sessionId, clientId)\n\n\t\treturn client\n\t}\n}\n\nfunction normalizeHttpBody(body: string | Uint8Array, contentType?: string): string | Uint8Array {\n\tif (body instanceof Uint8Array) {\n\t\treturn body\n\t}\n\n\tif (contentType?.includes('application/x-protobuf')) {\n\t\treturn new TextEncoder().encode(body)\n\t}\n\n\treturn body\n}\n","import type { AuthContext, AuthProvider } from '../types'\n\n/**\n * Auth provider that accepts all connections.\n * Returns a default anonymous context for any token.\n * Useful for development and testing.\n */\nexport class NoAuthProvider implements AuthProvider {\n\tasync authenticate(_token: string): Promise<AuthContext> {\n\t\treturn { userId: 'anonymous' }\n\t}\n}\n","import type { AuthContext, AuthProvider } from '../types'\n\n/**\n * Options for creating a TokenAuthProvider.\n */\nexport interface TokenAuthProviderOptions {\n\t/**\n\t * Validate a token and return an AuthContext if valid, or null if rejected.\n\t * This is where you implement your auth logic (JWT verification, database lookup, etc.).\n\t */\n\tvalidate: (token: string) => Promise<AuthContext | null>\n}\n\n/**\n * Token-based auth provider that delegates validation to a user-provided function.\n *\n * @example\n * ```typescript\n * const auth = new TokenAuthProvider({\n * validate: async (token) => {\n * const user = await verifyJWT(token)\n * return user ? { userId: user.id } : null\n * }\n * })\n * ```\n */\nexport class TokenAuthProvider implements AuthProvider {\n\tprivate readonly validate: (token: string) => Promise<AuthContext | null>\n\n\tconstructor(options: TokenAuthProviderOptions) {\n\t\tthis.validate = options.validate\n\t}\n\n\tasync authenticate(token: string): Promise<AuthContext | null> {\n\t\treturn this.validate(token)\n\t}\n}\n","import type { AuthContext, AuthProvider } from '../types'\n\n/**\n * Validates a Kora auth JWT and returns identity claims.\n * This interface matches the signature of TokenManager.validateToken()\n * from @korajs/auth without requiring a direct import.\n */\ninterface TokenValidator {\n\tvalidateToken(token: string): {\n\t\tsub: string\n\t\tdev: string\n\t\ttype: string\n\t} | null\n}\n\n/**\n * Looks up a user by ID. Returns null if the user doesn't exist.\n * This interface matches InMemoryUserStore.findById() from @korajs/auth\n * without requiring a direct import.\n */\ninterface UserLookup {\n\tfindById(userId: string): Promise<{\n\t\tid: string\n\t\temail: string\n\t\tname: string\n\t} | null>\n}\n\n/**\n * Optional device touch callback for updating last-seen timestamps.\n */\ninterface DeviceToucher {\n\ttouchDevice(deviceId: string): Promise<void>\n}\n\n/**\n * Configuration for creating a KoraAuthProvider.\n */\nexport interface KoraAuthProviderOptions {\n\t/**\n\t * Token validator that verifies JWT signatures and returns claims.\n\t * Typically a `TokenManager` instance from `@korajs/auth/server`.\n\t */\n\ttokenValidator: TokenValidator\n\n\t/**\n\t * User lookup for verifying the user still exists.\n\t * Typically an `InMemoryUserStore` instance from `@korajs/auth/server`.\n\t */\n\tuserLookup: UserLookup\n\n\t/**\n\t * Optional device tracker for updating last-seen timestamps.\n\t * Typically the same `InMemoryUserStore` if it implements `touchDevice`.\n\t */\n\tdeviceTracker?: DeviceToucher\n\n\t/**\n\t * Optional scope resolver. Called with the user ID to determine\n\t * which collections/records the user can sync.\n\t */\n\tresolveScopes?: (userId: string) => Promise<Record<string, Record<string, unknown>>>\n}\n\n/**\n * Auth provider that bridges `@korajs/auth` token management with the\n * sync server's authentication layer.\n *\n * Validates access tokens issued by `@korajs/auth`'s `TokenManager`,\n * verifies the user still exists, and optionally computes per-user\n * sync scopes. This is the recommended way to connect @korajs/auth\n * to @korajs/server.\n *\n * @example\n * ```typescript\n * import { TokenManager, InMemoryUserStore } from '@korajs/auth/server'\n * import { KoraAuthProvider, KoraSyncServer } from '@korajs/server'\n *\n * const tokenManager = new TokenManager({ secret: 'my-secret' })\n * const userStore = new InMemoryUserStore()\n *\n * const auth = new KoraAuthProvider({\n * tokenValidator: tokenManager,\n * userLookup: userStore,\n * deviceTracker: userStore,\n * resolveScopes: async (userId) => ({\n * forms: { userId },\n * responses: { formOwnerId: userId },\n * }),\n * })\n *\n * const server = new KoraSyncServer({ store, auth })\n * ```\n */\nexport class KoraAuthProvider implements AuthProvider {\n\tprivate readonly tokenValidator: TokenValidator\n\tprivate readonly userLookup: UserLookup\n\tprivate readonly deviceTracker: DeviceToucher | undefined\n\tprivate readonly resolveScopes:\n\t\t| ((userId: string) => Promise<Record<string, Record<string, unknown>>>)\n\t\t| undefined\n\n\tconstructor(options: KoraAuthProviderOptions) {\n\t\tthis.tokenValidator = options.tokenValidator\n\t\tthis.userLookup = options.userLookup\n\t\tthis.deviceTracker = options.deviceTracker\n\t\tthis.resolveScopes = options.resolveScopes\n\t}\n\n\tasync authenticate(token: string): Promise<AuthContext | null> {\n\t\t// Validate the JWT signature and expiration\n\t\tconst payload = this.tokenValidator.validateToken(token)\n\t\tif (payload === null) {\n\t\t\treturn null\n\t\t}\n\n\t\t// Only accept access tokens for sync authentication\n\t\tif (payload.type !== 'access') {\n\t\t\treturn null\n\t\t}\n\n\t\t// Verify the user still exists (may have been deleted since token was issued)\n\t\tconst user = await this.userLookup.findById(payload.sub)\n\t\tif (user === null) {\n\t\t\treturn null\n\t\t}\n\n\t\t// Update device last-seen timestamp\n\t\tif (this.deviceTracker) {\n\t\t\tawait this.deviceTracker.touchDevice(payload.dev)\n\t\t}\n\n\t\t// Compute sync scopes if a resolver is configured\n\t\tconst scopes = this.resolveScopes\n\t\t\t? await this.resolveScopes(payload.sub)\n\t\t\t: undefined\n\n\t\treturn {\n\t\t\tuserId: payload.sub,\n\t\t\tscopes,\n\t\t\tmetadata: {\n\t\t\t\tdeviceId: payload.dev,\n\t\t\t\temail: user.email,\n\t\t\t\tname: user.name,\n\t\t\t},\n\t\t}\n\t}\n}\n","import type { KoraSyncServerConfig } from '../types'\nimport { KoraSyncServer } from './kora-sync-server'\n\n/**\n * Factory function to create a KoraSyncServer.\n *\n * @param config - Server configuration\n * @returns A new KoraSyncServer instance\n *\n * @example\n * ```typescript\n * const server = createKoraServer({\n * store: new MemoryServerStore(),\n * port: 3000,\n * })\n * await server.start()\n * ```\n */\nexport function createKoraServer(config: KoraSyncServerConfig): KoraSyncServer {\n\treturn new KoraSyncServer(config)\n}\n","import type { ServerStore } from '../store/server-store'\nimport type { KoraSyncServerConfig } from '../types'\nimport { KoraSyncServer } from './kora-sync-server'\nimport { WsServerTransport } from '../transport/ws-server-transport'\n\n/**\n * Configuration for the production server that serves both\n * static files and WebSocket sync on a single port.\n */\nexport interface ProductionServerConfig {\n\t/** Server-side operation store */\n\tstore: ServerStore\n\t/** Port to listen on. Defaults to 3001 or process.env.PORT. */\n\tport?: number\n\t/** Directory containing built static files. Defaults to './dist'. */\n\tstaticDir?: string\n\t/** WebSocket sync path. Defaults to '/kora-sync'. */\n\tsyncPath?: string\n\t/** Additional KoraSyncServer options */\n\tsyncOptions?: Omit<KoraSyncServerConfig, 'store' | 'port' | 'host' | 'path'>\n}\n\n/**\n * A production server handle returned by createProductionServer.\n */\nexport interface ProductionServer {\n\t/** Start listening. Returns the URL the server is available at. */\n\tstart(): Promise<string>\n\t/** Stop the server gracefully. */\n\tstop(): Promise<void>\n}\n\n// MIME types for static file serving\nconst MIME_TYPES: Record<string, string> = {\n\t'.html': 'text/html',\n\t'.js': 'text/javascript',\n\t'.css': 'text/css',\n\t'.json': 'application/json',\n\t'.png': 'image/png',\n\t'.jpg': 'image/jpeg',\n\t'.svg': 'image/svg+xml',\n\t'.ico': 'image/x-icon',\n\t'.wasm': 'application/wasm',\n\t'.woff': 'font/woff',\n\t'.woff2': 'font/woff2',\n\t'.map': 'application/json',\n}\n\n/**\n * Creates a production server that serves both static files and WebSocket sync\n * on a single port. This is the recommended way to deploy a Kora app — one port\n * means one tunnel (ngrok, cloudflared) handles everything.\n *\n * @param config - Production server configuration\n * @returns A ProductionServer instance\n *\n * @example\n * ```typescript\n * import { createProductionServer, createSqliteServerStore } from '@korajs/server'\n *\n * const server = createProductionServer({\n * store: createSqliteServerStore({ filename: './kora-server.db' }),\n * })\n *\n * const url = await server.start()\n * console.log(`App running at ${url}`)\n * ```\n */\nexport function createProductionServer(config: ProductionServerConfig): ProductionServer {\n\tconst port = config.port ?? (Number(process.env.PORT) || 3001)\n\tconst staticDir = config.staticDir ?? './dist'\n\tconst syncPath = config.syncPath ?? '/kora-sync'\n\n\tconst syncServer = new KoraSyncServer({\n\t\tstore: config.store,\n\t\t...config.syncOptions,\n\t})\n\n\tlet httpServer: import('node:http').Server | null = null\n\n\treturn {\n\t\tasync start(): Promise<string> {\n\t\t\tconst { createServer } = await import('node:http')\n\t\t\tconst { createReadStream, existsSync, statSync } = await import('node:fs')\n\t\t\tconst { extname, join, resolve } = await import('node:path')\n\t\t\tconst { WebSocketServer } = await import('ws')\n\n\t\t\tconst distDir = resolve(staticDir)\n\n\t\t\thttpServer = createServer((req, res) => {\n\t\t\t\t// COOP/COEP headers required for SharedArrayBuffer (OPFS persistence)\n\t\t\t\tres.setHeader('Cross-Origin-Opener-Policy', 'same-origin')\n\t\t\t\tres.setHeader('Cross-Origin-Embedder-Policy', 'require-corp')\n\n\t\t\t\tconst url = new URL(req.url || '/', `http://${req.headers.host}`)\n\n\t\t\t\t// Health check endpoint (required by AWS ALB/ECS/Lightsail, GCP, etc.)\n\t\t\t\tif (url.pathname === '/health') {\n\t\t\t\t\tres.writeHead(200, { 'Content-Type': 'application/json' })\n\t\t\t\t\tres.end(JSON.stringify({ status: 'ok', timestamp: Date.now() }))\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\tlet filePath = join(distDir, url.pathname)\n\n\t\t\t\t// SPA fallback: serve index.html for non-file routes\n\t\t\t\tif (!extname(filePath)) {\n\t\t\t\t\tconst indexPath = join(filePath, 'index.html')\n\t\t\t\t\tif (existsSync(indexPath)) {\n\t\t\t\t\t\tfilePath = indexPath\n\t\t\t\t\t} else {\n\t\t\t\t\t\tfilePath = join(distDir, 'index.html')\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (!existsSync(filePath)) {\n\t\t\t\t\tfilePath = join(distDir, 'index.html')\n\t\t\t\t}\n\n\t\t\t\ttry {\n\t\t\t\t\tconst stat = statSync(filePath)\n\t\t\t\t\tif (stat.isDirectory()) {\n\t\t\t\t\t\tfilePath = join(filePath, 'index.html')\n\t\t\t\t\t}\n\t\t\t\t} catch {\n\t\t\t\t\tfilePath = join(distDir, 'index.html')\n\t\t\t\t}\n\n\t\t\t\tif (!existsSync(filePath)) {\n\t\t\t\t\tres.writeHead(404)\n\t\t\t\t\tres.end('Not Found')\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\tconst ext = extname(filePath)\n\t\t\t\tconst contentType = MIME_TYPES[ext] || 'application/octet-stream'\n\t\t\t\tres.writeHead(200, { 'Content-Type': contentType })\n\t\t\t\tcreateReadStream(filePath).pipe(res)\n\t\t\t})\n\n\t\t\tconst wss = new WebSocketServer({ noServer: true })\n\n\t\t\thttpServer.on('upgrade', (req, socket, head) => {\n\t\t\t\tconst url = new URL(req.url || '/', `http://${req.headers.host}`)\n\t\t\t\tif (url.pathname === syncPath) {\n\t\t\t\t\twss.handleUpgrade(req, socket, head, (ws) => {\n\t\t\t\t\t\tconst transport = new WsServerTransport(ws)\n\t\t\t\t\t\tsyncServer.handleConnection(transport)\n\t\t\t\t\t})\n\t\t\t\t} else {\n\t\t\t\t\tsocket.destroy()\n\t\t\t\t}\n\t\t\t})\n\n\t\t\treturn new Promise<string>((resolve) => {\n\t\t\t\thttpServer!.listen(port, '0.0.0.0', () => {\n\t\t\t\t\tresolve(`http://localhost:${port}`)\n\t\t\t\t})\n\t\t\t})\n\t\t},\n\n\t\tasync stop(): Promise<void> {\n\t\t\tawait syncServer.stop()\n\t\t\tif (httpServer) {\n\t\t\t\tawait new Promise<void>((resolve) => {\n\t\t\t\t\thttpServer!.close(() => resolve())\n\t\t\t\t})\n\t\t\t\thttpServer = null\n\t\t\t}\n\t\t},\n\t}\n}\n"],"mappings":"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","names":["count","generateUUIDv7","generateUUIDv7","generateUUIDv7","and","asc","between","count","eq","sql","index","integer","text","generateUUIDv7","sql","and","eq","between","asc","count","SyncError","generateUUIDv7","operations","generateUUIDv7","SyncError","generateUUIDv7","JsonMessageSerializer","DEFAULT_BATCH_SIZE","DEFAULT_SCHEMA_VERSION","JsonMessageSerializer","SyncError","generateUUIDv7","operations","resolve"]}
|
|
1
|
+
{"version":3,"sources":["../src/store/memory-server-store.ts","../src/store/materialization.ts","../src/store/postgres-server-store.ts","../src/store/drizzle-pg-schema.ts","../src/store/sqlite-server-store.ts","../src/store/drizzle-schema.ts","../src/transport/http-server-transport.ts","../src/transport/ws-server-transport.ts","../src/session/client-session.ts","../src/scopes/server-scope-filter.ts","../src/server/kora-sync-server.ts","../src/awareness/awareness-relay.ts","../src/auth/no-auth.ts","../src/auth/token-auth.ts","../src/auth/kora-auth-provider.ts","../src/auth/mixed-auth-provider.ts","../src/server/create-server.ts","../src/server/production-server.ts"],"sourcesContent":["import type { Operation, SchemaDefinition, VersionVector } from '@korajs/core'\nimport { generateUUIDv7 } from '@korajs/core'\nimport type { ApplyResult } from '@korajs/sync'\nimport {\n\tdeserializeFieldValue,\n\treplayOperationsForRecord,\n\tserializeFieldValue,\n\tvalidateFieldName,\n} from './materialization'\nimport type { CollectionQueryOptions, MaterializedRecord, ServerStore } from './server-store'\n\n/**\n * In-memory server store for testing and quick prototyping.\n * Not suitable for production — data does not survive process restart.\n *\n * When a schema is set via setSchema(), maintains materialized records\n * in-memory for efficient queries.\n */\nexport class MemoryServerStore implements ServerStore {\n\tprivate readonly nodeId: string\n\tprivate readonly operations: Operation[] = []\n\tprivate readonly operationIndex = new Map<string, Operation>()\n\tprivate readonly versionVector: Map<string, number> = new Map()\n\tprivate schema: SchemaDefinition | null = null\n\n\t/** Materialized records: collection -> recordId -> record data */\n\tprivate readonly materializedRecords = new Map<string, Map<string, MaterializedRecord>>()\n\n\tprivate closed = false\n\n\tconstructor(nodeId?: string) {\n\t\tthis.nodeId = nodeId ?? generateUUIDv7()\n\t}\n\n\tgetVersionVector(): VersionVector {\n\t\treturn new Map(this.versionVector)\n\t}\n\n\tgetNodeId(): string {\n\t\treturn this.nodeId\n\t}\n\n\tasync setSchema(schema: SchemaDefinition): Promise<void> {\n\t\tthis.assertOpen()\n\t\tthis.schema = schema\n\n\t\t// Initialize collection maps\n\t\tfor (const collectionName of Object.keys(schema.collections)) {\n\t\t\tif (!this.materializedRecords.has(collectionName)) {\n\t\t\t\tthis.materializedRecords.set(collectionName, new Map())\n\t\t\t}\n\t\t}\n\n\t\t// Backfill from existing operations\n\t\tthis.backfillAllCollections()\n\t}\n\n\tasync applyRemoteOperation(op: Operation): Promise<ApplyResult> {\n\t\tthis.assertOpen()\n\n\t\t// Content-addressed dedup: same id = same content\n\t\tif (this.operationIndex.has(op.id)) {\n\t\t\treturn 'duplicate'\n\t\t}\n\n\t\tthis.operations.push(op)\n\t\tthis.operationIndex.set(op.id, op)\n\n\t\t// Advance version vector\n\t\tconst currentSeq = this.versionVector.get(op.nodeId) ?? 0\n\t\tif (op.sequenceNumber > currentSeq) {\n\t\t\tthis.versionVector.set(op.nodeId, op.sequenceNumber)\n\t\t}\n\n\t\t// Dual-write: update materialized records if schema is set\n\t\tif (this.schema?.collections[op.collection]) {\n\t\t\tthis.rebuildMaterializedRecord(op.collection, op.recordId)\n\t\t}\n\n\t\treturn 'applied'\n\t}\n\n\tasync getOperationRange(nodeId: string, fromSeq: number, toSeq: number): Promise<Operation[]> {\n\t\tthis.assertOpen()\n\n\t\treturn this.operations\n\t\t\t.filter(\n\t\t\t\t(op) => op.nodeId === nodeId && op.sequenceNumber >= fromSeq && op.sequenceNumber <= toSeq,\n\t\t\t)\n\t\t\t.sort((a, b) => a.sequenceNumber - b.sequenceNumber)\n\t}\n\n\tasync getOperationCount(): Promise<number> {\n\t\tthis.assertOpen()\n\t\treturn this.operations.length\n\t}\n\n\tasync materializeCollection(collection: string): Promise<MaterializedRecord[]> {\n\t\tthis.assertOpen()\n\n\t\t// Fast path: if schema is set, read from materialized records\n\t\tif (this.schema?.collections[collection]) {\n\t\t\treturn this.queryCollection(collection)\n\t\t}\n\n\t\t// Fallback: replay operations\n\t\treturn this.materializeFromOps(collection)\n\t}\n\n\tasync queryCollection(\n\t\tcollection: string,\n\t\toptions?: CollectionQueryOptions,\n\t): Promise<MaterializedRecord[]> {\n\t\tthis.assertOpen()\n\t\tthis.assertSchema()\n\t\tthis.assertCollection(collection)\n\n\t\t// Validate field names\n\t\tconst schema = this.schema as SchemaDefinition\n\t\tif (options?.where) {\n\t\t\tfor (const key of Object.keys(options.where)) {\n\t\t\t\tvalidateFieldName(collection, key, schema)\n\t\t\t}\n\t\t}\n\t\tif (options?.orderBy) {\n\t\t\tvalidateFieldName(collection, options.orderBy, schema)\n\t\t}\n\n\t\tconst collectionMap = this.materializedRecords.get(collection)\n\t\tif (!collectionMap) return []\n\n\t\t// Get all non-deleted records\n\t\tlet records = Array.from(collectionMap.values()).filter((r) => {\n\t\t\tif (!options?.includeDeleted && r._deleted === 1) return false\n\t\t\treturn true\n\t\t})\n\n\t\t// Apply WHERE filters\n\t\tif (options?.where) {\n\t\t\tfor (const [key, value] of Object.entries(options.where)) {\n\t\t\t\trecords = records.filter((r) => r[key] === value)\n\t\t\t}\n\t\t}\n\n\t\t// Apply ORDER BY\n\t\tif (options?.orderBy) {\n\t\t\tconst field = options.orderBy\n\t\t\tconst dir = options.orderDirection === 'desc' ? -1 : 1\n\t\t\trecords.sort((a, b) => {\n\t\t\t\tconst aVal = a[field]\n\t\t\t\tconst bVal = b[field]\n\t\t\t\tif (aVal === bVal) return 0\n\t\t\t\tif (aVal === null || aVal === undefined) return 1\n\t\t\t\tif (bVal === null || bVal === undefined) return -1\n\t\t\t\treturn aVal < bVal ? -1 * dir : 1 * dir\n\t\t\t})\n\t\t}\n\n\t\t// Apply OFFSET\n\t\tif (options?.offset !== undefined) {\n\t\t\trecords = records.slice(options.offset)\n\t\t}\n\n\t\t// Apply LIMIT\n\t\tif (options?.limit !== undefined) {\n\t\t\trecords = records.slice(0, options.limit)\n\t\t}\n\n\t\t// Return clean copies without internal fields\n\t\treturn records.map((r) => {\n\t\t\tconst clean: MaterializedRecord = { id: r.id }\n\t\t\tconst collectionDef = (this.schema as SchemaDefinition).collections[\n\t\t\t\tcollection\n\t\t\t] as NonNullable<SchemaDefinition['collections'][string]>\n\t\t\tfor (const fieldName of Object.keys(collectionDef.fields)) {\n\t\t\t\tif (fieldName in r) {\n\t\t\t\t\tclean[fieldName] = r[fieldName]\n\t\t\t\t}\n\t\t\t}\n\t\t\tif ('_created_at' in r) clean._created_at = r._created_at\n\t\t\tif ('_updated_at' in r) clean._updated_at = r._updated_at\n\t\t\treturn clean\n\t\t})\n\t}\n\n\tasync findRecord(collection: string, id: string): Promise<MaterializedRecord | null> {\n\t\tthis.assertOpen()\n\t\tthis.assertSchema()\n\t\tthis.assertCollection(collection)\n\n\t\tconst collectionMap = this.materializedRecords.get(collection)\n\t\tif (!collectionMap) return null\n\n\t\tconst record = collectionMap.get(id)\n\t\tif (!record || record._deleted === 1) return null\n\n\t\t// Return clean copy\n\t\tconst clean: MaterializedRecord = { id: record.id }\n\t\tconst collectionDef = (this.schema as SchemaDefinition).collections[collection] as NonNullable<\n\t\t\tSchemaDefinition['collections'][string]\n\t\t>\n\t\tfor (const fieldName of Object.keys(collectionDef.fields)) {\n\t\t\tif (fieldName in record) {\n\t\t\t\tclean[fieldName] = record[fieldName]\n\t\t\t}\n\t\t}\n\t\tif ('_created_at' in record) clean._created_at = record._created_at\n\t\tif ('_updated_at' in record) clean._updated_at = record._updated_at\n\t\treturn clean\n\t}\n\n\tasync countCollection(collection: string, where?: Record<string, unknown>): Promise<number> {\n\t\tthis.assertOpen()\n\t\tthis.assertSchema()\n\t\tthis.assertCollection(collection)\n\n\t\tconst schema = this.schema as SchemaDefinition\n\t\tif (where) {\n\t\t\tfor (const key of Object.keys(where)) {\n\t\t\t\tvalidateFieldName(collection, key, schema)\n\t\t\t}\n\t\t}\n\n\t\tconst collectionMap = this.materializedRecords.get(collection)\n\t\tif (!collectionMap) return 0\n\n\t\tlet count = 0\n\t\tfor (const record of collectionMap.values()) {\n\t\t\tif (record._deleted === 1) continue\n\t\t\tif (where) {\n\t\t\t\tlet matches = true\n\t\t\t\tfor (const [key, value] of Object.entries(where)) {\n\t\t\t\t\tif (record[key] !== value) {\n\t\t\t\t\t\tmatches = false\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (!matches) continue\n\t\t\t}\n\t\t\tcount++\n\t\t}\n\t\treturn count\n\t}\n\n\tasync close(): Promise<void> {\n\t\tthis.closed = true\n\t}\n\n\t// --- Testing helpers (not on interface) ---\n\n\t/**\n\t * Get all stored operations (for test assertions).\n\t */\n\tgetAllOperations(): Operation[] {\n\t\treturn [...this.operations]\n\t}\n\n\t// ---------------------------------------------------------------------------\n\t// Materialization internals\n\t// ---------------------------------------------------------------------------\n\n\tprivate rebuildMaterializedRecord(collection: string, recordId: string): void {\n\t\tconst collectionDef = this.schema?.collections[collection]\n\t\tif (!collectionDef) return\n\n\t\t// Get or create collection map\n\t\tlet collectionMap = this.materializedRecords.get(collection)\n\t\tif (!collectionMap) {\n\t\t\tcollectionMap = new Map()\n\t\t\tthis.materializedRecords.set(collection, collectionMap)\n\t\t}\n\n\t\t// Get all ops for this record in HLC order\n\t\tconst recordOps = this.operations\n\t\t\t.filter((op) => op.collection === collection && op.recordId === recordId)\n\t\t\t.sort((a, b) => {\n\t\t\t\tif (a.timestamp.wallTime !== b.timestamp.wallTime)\n\t\t\t\t\treturn a.timestamp.wallTime - b.timestamp.wallTime\n\t\t\t\tif (a.timestamp.logical !== b.timestamp.logical)\n\t\t\t\t\treturn a.timestamp.logical - b.timestamp.logical\n\t\t\t\treturn a.sequenceNumber - b.sequenceNumber\n\t\t\t})\n\n\t\tconst parsedOps = recordOps.map((op) => ({\n\t\t\ttype: op.type,\n\t\t\tdata: op.data,\n\t\t}))\n\t\tconst recordData = replayOperationsForRecord(parsedOps)\n\n\t\tif (recordData) {\n\t\t\tconst createdAt =\n\t\t\t\trecordOps.length > 0 ? (recordOps[0] as Operation).timestamp.wallTime : Date.now()\n\t\t\tconst updatedAt =\n\t\t\t\trecordOps.length > 0\n\t\t\t\t\t? (recordOps[recordOps.length - 1] as Operation).timestamp.wallTime\n\t\t\t\t\t: Date.now()\n\n\t\t\tconst materialized: MaterializedRecord = {\n\t\t\t\tid: recordId,\n\t\t\t\t...recordData,\n\t\t\t\t_created_at: createdAt,\n\t\t\t\t_updated_at: updatedAt,\n\t\t\t\t_deleted: 0,\n\t\t\t}\n\t\t\tcollectionMap.set(recordId, materialized)\n\t\t} else {\n\t\t\t// Record was deleted\n\t\t\tconst existing = collectionMap.get(recordId)\n\t\t\tif (existing) {\n\t\t\t\texisting._deleted = 1\n\t\t\t\texisting._updated_at = Date.now()\n\t\t\t} else {\n\t\t\t\tcollectionMap.set(recordId, {\n\t\t\t\t\tid: recordId,\n\t\t\t\t\t_deleted: 1,\n\t\t\t\t\t_created_at: Date.now(),\n\t\t\t\t\t_updated_at: Date.now(),\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate backfillAllCollections(): void {\n\t\tif (!this.schema) return\n\n\t\t// Get all unique (collection, recordId) pairs\n\t\tconst recordKeys = new Set<string>()\n\t\tfor (const op of this.operations) {\n\t\t\tif (this.schema.collections[op.collection]) {\n\t\t\t\trecordKeys.add(`${op.collection}:::${op.recordId}`)\n\t\t\t}\n\t\t}\n\n\t\tfor (const key of recordKeys) {\n\t\t\tconst [collection, recordId] = key.split(':::') as [string, string]\n\t\t\tthis.rebuildMaterializedRecord(collection, recordId)\n\t\t}\n\t}\n\n\t// ---------------------------------------------------------------------------\n\t// Fallback materialization (no schema)\n\t// ---------------------------------------------------------------------------\n\n\tprivate materializeFromOps(collection: string): MaterializedRecord[] {\n\t\tconst collectionOps = this.operations\n\t\t\t.filter((op) => op.collection === collection)\n\t\t\t.sort((a, b) => {\n\t\t\t\tif (a.timestamp.wallTime !== b.timestamp.wallTime)\n\t\t\t\t\treturn a.timestamp.wallTime - b.timestamp.wallTime\n\t\t\t\tif (a.timestamp.logical !== b.timestamp.logical)\n\t\t\t\t\treturn a.timestamp.logical - b.timestamp.logical\n\t\t\t\treturn a.sequenceNumber - b.sequenceNumber\n\t\t\t})\n\n\t\tconst records = new Map<string, Record<string, unknown>>()\n\t\tconst deleted = new Set<string>()\n\n\t\tfor (const op of collectionOps) {\n\t\t\tswitch (op.type) {\n\t\t\t\tcase 'insert':\n\t\t\t\t\tif (op.data) {\n\t\t\t\t\t\trecords.set(op.recordId, { id: op.recordId, ...op.data })\n\t\t\t\t\t\tdeleted.delete(op.recordId)\n\t\t\t\t\t}\n\t\t\t\t\tbreak\n\t\t\t\tcase 'update':\n\t\t\t\t\tif (op.data) {\n\t\t\t\t\t\tconst existing = records.get(op.recordId) ?? { id: op.recordId }\n\t\t\t\t\t\trecords.set(op.recordId, { ...existing, ...op.data })\n\t\t\t\t\t\tdeleted.delete(op.recordId)\n\t\t\t\t\t}\n\t\t\t\t\tbreak\n\t\t\t\tcase 'delete':\n\t\t\t\t\tdeleted.add(op.recordId)\n\t\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\tfor (const id of deleted) {\n\t\t\trecords.delete(id)\n\t\t}\n\n\t\treturn Array.from(records.values()) as MaterializedRecord[]\n\t}\n\n\t// ---------------------------------------------------------------------------\n\t// Assertions\n\t// ---------------------------------------------------------------------------\n\n\tprivate assertOpen(): void {\n\t\tif (this.closed) {\n\t\t\tthrow new Error('MemoryServerStore is closed')\n\t\t}\n\t}\n\n\tprivate assertSchema(): void {\n\t\tif (!this.schema) {\n\t\t\tthrow new Error(\n\t\t\t\t'Schema not set. Call setSchema() before using queryCollection/findRecord/countCollection.',\n\t\t\t)\n\t\t}\n\t}\n\n\tprivate assertCollection(collection: string): void {\n\t\tconst schema = this.schema as SchemaDefinition\n\t\tif (!schema.collections[collection]) {\n\t\t\tthrow new Error(\n\t\t\t\t`Unknown collection \"${collection}\". Available: ${Object.keys(schema.collections).join(', ')}`,\n\t\t\t)\n\t\t}\n\t}\n}\n","import type { CollectionDefinition, FieldDescriptor, SchemaDefinition } from '@korajs/core'\n\n/**\n * SQL dialect for DDL generation.\n * SQLite and PostgreSQL differ in some column types.\n */\nexport type SqlDialect = 'sqlite' | 'postgres'\n\n/**\n * Map a Kora field kind to its SQL column type for the given dialect.\n */\nfunction fieldTypeToSql(descriptor: FieldDescriptor, dialect: SqlDialect): string {\n\tswitch (descriptor.kind) {\n\t\tcase 'string':\n\t\t\treturn 'TEXT'\n\t\tcase 'number':\n\t\t\treturn dialect === 'postgres' ? 'DOUBLE PRECISION' : 'REAL'\n\t\tcase 'boolean':\n\t\t\treturn 'INTEGER'\n\t\tcase 'enum':\n\t\t\treturn 'TEXT'\n\t\tcase 'timestamp':\n\t\t\treturn dialect === 'postgres' ? 'BIGINT' : 'INTEGER'\n\t\tcase 'array':\n\t\t\treturn dialect === 'postgres' ? 'JSONB' : 'TEXT'\n\t\tcase 'richtext':\n\t\t\treturn dialect === 'postgres' ? 'BYTEA' : 'BLOB'\n\t}\n}\n\nfunction sqlDefaultLiteral(value: unknown): string {\n\tif (value === null) return 'NULL'\n\tif (typeof value === 'string') return `'${value}'`\n\tif (typeof value === 'number') return String(value)\n\tif (typeof value === 'boolean') return value ? '1' : '0'\n\treturn `'${JSON.stringify(value)}'`\n}\n\n/**\n * Generate DDL statements for creating a materialized collection table.\n * Includes CREATE TABLE, safe ALTER TABLE for schema evolution, and indexes.\n *\n * @param name - Collection/table name\n * @param collection - Collection definition from the schema\n * @param dialect - SQL dialect ('sqlite' or 'postgres')\n * @returns Array of DDL SQL strings\n */\nexport function generateCollectionDDL(\n\tname: string,\n\tcollection: CollectionDefinition,\n\tdialect: SqlDialect,\n): string[] {\n\tconst statements: string[] = []\n\tconst columns: string[] = ['id TEXT PRIMARY KEY NOT NULL']\n\n\tfor (const [fieldName, descriptor] of Object.entries(collection.fields)) {\n\t\tconst sqlType = fieldTypeToSql(descriptor, dialect)\n\t\tlet colDef = `${fieldName} ${sqlType}`\n\t\tif (descriptor.defaultValue !== undefined) {\n\t\t\tcolDef += ` DEFAULT ${sqlDefaultLiteral(descriptor.defaultValue)}`\n\t\t}\n\t\tif (descriptor.kind === 'enum' && descriptor.enumValues) {\n\t\t\tconst values = descriptor.enumValues.map((v) => `'${v}'`).join(', ')\n\t\t\tcolDef += ` CHECK (${fieldName} IN (${values}))`\n\t\t}\n\t\tcolumns.push(colDef)\n\t}\n\n\tconst tsType = dialect === 'postgres' ? 'BIGINT' : 'INTEGER'\n\tcolumns.push(`_created_at ${tsType} NOT NULL DEFAULT 0`)\n\tcolumns.push(`_updated_at ${tsType} NOT NULL DEFAULT 0`)\n\tcolumns.push('_deleted INTEGER NOT NULL DEFAULT 0')\n\n\tstatements.push(`CREATE TABLE IF NOT EXISTS ${name} (\\n ${columns.join(',\\n ')}\\n)`)\n\n\t// Safe ALTER TABLE for adding new columns to existing tables\n\tfor (const [fieldName, descriptor] of Object.entries(collection.fields)) {\n\t\tconst sqlType = fieldTypeToSql(descriptor, dialect)\n\t\tlet colDef = `${fieldName} ${sqlType}`\n\t\tif (descriptor.defaultValue !== undefined) {\n\t\t\tcolDef += ` DEFAULT ${sqlDefaultLiteral(descriptor.defaultValue)}`\n\t\t}\n\t\tstatements.push(`--kora:safe-alter\\nALTER TABLE ${name} ADD COLUMN ${colDef}`)\n\t}\n\n\t// User-defined indexes from schema\n\tfor (const indexField of collection.indexes) {\n\t\tstatements.push(\n\t\t\t`CREATE INDEX IF NOT EXISTS idx_${name}_${indexField} ON ${name} (${indexField})`,\n\t\t)\n\t}\n\n\t// Always index _deleted for efficient soft-delete filtering\n\tstatements.push(`CREATE INDEX IF NOT EXISTS idx_${name}__deleted ON ${name} (_deleted)`)\n\n\treturn statements\n}\n\n/**\n * Generate all collection table DDL from a full schema.\n */\nexport function generateAllCollectionDDL(schema: SchemaDefinition, dialect: SqlDialect): string[] {\n\tconst statements: string[] = []\n\tfor (const [name, collection] of Object.entries(schema.collections)) {\n\t\tstatements.push(...generateCollectionDDL(name, collection, dialect))\n\t}\n\treturn statements\n}\n\n/**\n * Replay a list of operations (must be sorted by HLC order) to produce\n * the current state of a single record.\n *\n * Returns the record field data (without `id`) or null if the record was deleted\n * or never inserted.\n */\nexport function replayOperationsForRecord(\n\tops: Array<{ type: string; data: Record<string, unknown> | null }>,\n): Record<string, unknown> | null {\n\tlet record: Record<string, unknown> | null = null\n\tlet deleted = false\n\n\tfor (const op of ops) {\n\t\tswitch (op.type) {\n\t\t\tcase 'insert':\n\t\t\t\tif (op.data) {\n\t\t\t\t\trecord = { ...op.data }\n\t\t\t\t\tdeleted = false\n\t\t\t\t}\n\t\t\t\tbreak\n\t\t\tcase 'update':\n\t\t\t\tif (op.data) {\n\t\t\t\t\trecord = { ...(record ?? {}), ...op.data }\n\t\t\t\t\tdeleted = false\n\t\t\t\t}\n\t\t\t\tbreak\n\t\t\tcase 'delete':\n\t\t\t\tdeleted = true\n\t\t\t\tbreak\n\t\t}\n\t}\n\n\treturn deleted ? null : record\n}\n\n/**\n * Serialize a field value for SQL storage.\n * Arrays become JSON strings, booleans become 0/1, etc.\n */\nexport function serializeFieldValue(value: unknown, descriptor: FieldDescriptor): unknown {\n\tif (value === null || value === undefined) return null\n\tswitch (descriptor.kind) {\n\t\tcase 'array':\n\t\t\treturn typeof value === 'string' ? value : JSON.stringify(value)\n\t\tcase 'boolean':\n\t\t\treturn value ? 1 : 0\n\t\tdefault:\n\t\t\treturn value\n\t}\n}\n\n/**\n * Deserialize a field value from SQL storage back to JavaScript types.\n */\nexport function deserializeFieldValue(value: unknown, descriptor: FieldDescriptor): unknown {\n\tif (value === null || value === undefined) return null\n\tswitch (descriptor.kind) {\n\t\tcase 'array':\n\t\t\treturn typeof value === 'string' ? JSON.parse(value) : value\n\t\tcase 'boolean':\n\t\t\treturn value === 1 || value === true\n\t\tdefault:\n\t\t\treturn value\n\t}\n}\n\n/**\n * Validate that a field name is a valid column in the given collection schema.\n * Includes system fields (id, _created_at, _updated_at, _deleted).\n */\nexport function validateFieldName(\n\tcollectionName: string,\n\tfieldName: string,\n\tschema: SchemaDefinition,\n): void {\n\tconst collection = schema.collections[collectionName]\n\tif (!collection) {\n\t\tthrow new Error(`Unknown collection: ${collectionName}`)\n\t}\n\tconst validFields = new Set([\n\t\t'id',\n\t\t'_created_at',\n\t\t'_updated_at',\n\t\t'_deleted',\n\t\t...Object.keys(collection.fields),\n\t])\n\tif (!validFields.has(fieldName)) {\n\t\tthrow new Error(\n\t\t\t`Invalid field name \"${fieldName}\" for collection \"${collectionName}\". ` +\n\t\t\t\t`Valid fields: ${Array.from(validFields).join(', ')}`,\n\t\t)\n\t}\n}\n","import type { Operation, SchemaDefinition, VersionVector } from '@korajs/core'\nimport { generateUUIDv7 } from '@korajs/core'\nimport type { ApplyResult } from '@korajs/sync'\nimport type { SQL } from 'drizzle-orm'\nimport { and, asc, between, count, eq, sql } from 'drizzle-orm'\nimport type { PostgresJsDatabase } from 'drizzle-orm/postgres-js'\nimport { pgOperations, pgSyncState } from './drizzle-pg-schema'\nimport {\n\tdeserializeFieldValue,\n\tgenerateAllCollectionDDL,\n\treplayOperationsForRecord,\n\tserializeFieldValue,\n\tvalidateFieldName,\n} from './materialization'\nimport type { CollectionQueryOptions, MaterializedRecord, ServerStore } from './server-store'\n\n/**\n * PostgreSQL-backed server store using Drizzle ORM.\n * All reads and writes go through Drizzle's typed query builder.\n *\n * When a schema is set via setSchema(), also maintains materialized\n * collection tables for efficient indexed queries (dual-write).\n */\nexport class PostgresServerStore implements ServerStore {\n\tprivate readonly nodeId: string\n\tprivate readonly db: PostgresJsDatabase\n\tprivate readonly versionVector: VersionVector = new Map()\n\tprivate readonly ready: Promise<void>\n\tprivate schema: SchemaDefinition | null = null\n\tprivate closed = false\n\n\tconstructor(db: PostgresJsDatabase, nodeId?: string) {\n\t\tthis.db = db\n\t\tthis.nodeId = nodeId ?? generateUUIDv7()\n\t\tthis.ready = this.initialize()\n\t}\n\n\tgetVersionVector(): VersionVector {\n\t\tthis.assertOpen()\n\t\treturn new Map(this.versionVector)\n\t}\n\n\tgetNodeId(): string {\n\t\treturn this.nodeId\n\t}\n\n\tasync setSchema(schema: SchemaDefinition): Promise<void> {\n\t\tthis.assertOpen()\n\t\tawait this.ready\n\t\tthis.schema = schema\n\n\t\t// Generate and execute DDL for all collection tables\n\t\tconst ddlStatements = generateAllCollectionDDL(schema, 'postgres')\n\t\tfor (const stmt of ddlStatements) {\n\t\t\tif (stmt.startsWith('--kora:safe-alter')) {\n\t\t\t\tconst alterSql = stmt.replace('--kora:safe-alter\\n', '')\n\t\t\t\ttry {\n\t\t\t\t\tawait this.db.execute(sql.raw(alterSql))\n\t\t\t\t} catch (e) {\n\t\t\t\t\t// Ignore \"already exists\" errors from safe ALTER TABLE.\n\t\t\t\t\t// Drizzle wraps the actual DB error in e.cause, so check both.\n\t\t\t\t\tconst msg = e instanceof Error ? e.message : ''\n\t\t\t\t\tconst causeMsg = e instanceof Error && e.cause instanceof Error ? e.cause.message : ''\n\t\t\t\t\tif (\n\t\t\t\t\t\t!msg.includes('already exists') &&\n\t\t\t\t\t\t!msg.includes('duplicate column') &&\n\t\t\t\t\t\t!causeMsg.includes('already exists') &&\n\t\t\t\t\t\t!causeMsg.includes('duplicate column')\n\t\t\t\t\t) {\n\t\t\t\t\t\tthrow e\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tawait this.db.execute(sql.raw(stmt))\n\t\t\t}\n\t\t}\n\n\t\t// Backfill materialized tables from existing operations\n\t\tawait this.backfillAllCollections()\n\t}\n\n\tasync applyRemoteOperation(op: Operation): Promise<ApplyResult> {\n\t\tthis.assertOpen()\n\t\tawait this.ready\n\n\t\t// Content-addressed dedup check\n\t\tconst existing = await this.db\n\t\t\t.select({ id: pgOperations.id })\n\t\t\t.from(pgOperations)\n\t\t\t.where(eq(pgOperations.id, op.id))\n\t\t\t.limit(1)\n\n\t\tif (existing.length > 0) {\n\t\t\treturn 'duplicate'\n\t\t}\n\n\t\tconst now = Date.now()\n\t\tconst row = this.serializeOperation(op, now)\n\n\t\tawait this.db.transaction(async (tx) => {\n\t\t\t// Insert operation with dedup\n\t\t\tawait tx.insert(pgOperations).values(row).onConflictDoNothing({ target: pgOperations.id })\n\n\t\t\t// Upsert version vector: advance max sequence number with GREATEST\n\t\t\tawait tx\n\t\t\t\t.insert(pgSyncState)\n\t\t\t\t.values({\n\t\t\t\t\tnodeId: op.nodeId,\n\t\t\t\t\tmaxSequenceNumber: op.sequenceNumber,\n\t\t\t\t\tlastSeenAt: now,\n\t\t\t\t})\n\t\t\t\t.onConflictDoUpdate({\n\t\t\t\t\ttarget: pgSyncState.nodeId,\n\t\t\t\t\tset: {\n\t\t\t\t\t\tmaxSequenceNumber: sql`GREATEST(${pgSyncState.maxSequenceNumber}, ${op.sequenceNumber})`,\n\t\t\t\t\t\tlastSeenAt: sql`${now}`,\n\t\t\t\t\t},\n\t\t\t\t})\n\n\t\t\t// Dual-write: update materialized collection table if schema is set\n\t\t\tif (this.schema?.collections[op.collection]) {\n\t\t\t\tawait this.rebuildMaterializedRecord(tx, op.collection, op.recordId)\n\t\t\t}\n\t\t})\n\n\t\t// Update in-memory version vector cache\n\t\tconst currentMax = this.versionVector.get(op.nodeId) ?? 0\n\t\tif (op.sequenceNumber > currentMax) {\n\t\t\tthis.versionVector.set(op.nodeId, op.sequenceNumber)\n\t\t}\n\n\t\treturn 'applied'\n\t}\n\n\tasync getOperationRange(nodeId: string, fromSeq: number, toSeq: number): Promise<Operation[]> {\n\t\tthis.assertOpen()\n\t\tawait this.ready\n\n\t\tconst rows = await this.db\n\t\t\t.select()\n\t\t\t.from(pgOperations)\n\t\t\t.where(\n\t\t\t\tand(eq(pgOperations.nodeId, nodeId), between(pgOperations.sequenceNumber, fromSeq, toSeq)),\n\t\t\t)\n\t\t\t.orderBy(asc(pgOperations.sequenceNumber))\n\n\t\treturn rows.map((row) => this.deserializeOperation(row))\n\t}\n\n\tasync getOperationCount(): Promise<number> {\n\t\tthis.assertOpen()\n\t\tawait this.ready\n\n\t\tconst result = await this.db.select({ value: count() }).from(pgOperations)\n\t\treturn result[0]?.value ?? 0\n\t}\n\n\tasync materializeCollection(collection: string): Promise<MaterializedRecord[]> {\n\t\tthis.assertOpen()\n\t\tawait this.ready\n\n\t\t// Fast path: if schema is set, read directly from the materialized table\n\t\tif (this.schema?.collections[collection]) {\n\t\t\treturn this.queryCollection(collection)\n\t\t}\n\n\t\t// Fallback: replay operations (legacy path when schema is not set)\n\t\treturn this.materializeFromOpsLog(collection)\n\t}\n\n\tasync queryCollection(\n\t\tcollection: string,\n\t\toptions?: CollectionQueryOptions,\n\t): Promise<MaterializedRecord[]> {\n\t\tthis.assertOpen()\n\t\tawait this.ready\n\t\tthis.assertSchema()\n\t\tthis.assertCollection(collection)\n\n\t\tconst schema = this.schema as SchemaDefinition\n\t\tconst collectionDef = schema.collections[collection] as NonNullable<\n\t\t\tSchemaDefinition['collections'][string]\n\t\t>\n\n\t\t// Validate field names in options\n\t\tif (options?.where) {\n\t\t\tfor (const key of Object.keys(options.where)) {\n\t\t\t\tvalidateFieldName(collection, key, schema)\n\t\t\t}\n\t\t}\n\t\tif (options?.orderBy) {\n\t\t\tvalidateFieldName(collection, options.orderBy, schema)\n\t\t}\n\n\t\tconst query = this.buildSelectQuery(collection, options)\n\t\tconst rows = (await this.db.execute(query)) as unknown as Record<string, unknown>[]\n\n\t\treturn rows.map((row) => this.deserializeRow(row, collectionDef))\n\t}\n\n\tasync findRecord(collection: string, id: string): Promise<MaterializedRecord | null> {\n\t\tthis.assertOpen()\n\t\tawait this.ready\n\t\tthis.assertSchema()\n\t\tthis.assertCollection(collection)\n\n\t\tconst schema = this.schema as SchemaDefinition\n\t\tconst collectionDef = schema.collections[collection] as NonNullable<\n\t\t\tSchemaDefinition['collections'][string]\n\t\t>\n\t\tconst query = sql`SELECT * FROM ${sql.raw(collection)} WHERE id = ${id} AND _deleted = 0`\n\t\tconst rows = (await this.db.execute(query)) as unknown as Record<string, unknown>[]\n\n\t\tif (rows.length === 0) return null\n\t\treturn this.deserializeRow(rows[0] as Record<string, unknown>, collectionDef)\n\t}\n\n\tasync countCollection(collection: string, where?: Record<string, unknown>): Promise<number> {\n\t\tthis.assertOpen()\n\t\tawait this.ready\n\t\tthis.assertSchema()\n\t\tthis.assertCollection(collection)\n\n\t\tconst schema = this.schema as SchemaDefinition\n\t\tif (where) {\n\t\t\tfor (const key of Object.keys(where)) {\n\t\t\t\tvalidateFieldName(collection, key, schema)\n\t\t\t}\n\t\t}\n\n\t\tconst whereClause = this.buildWhereClause(where ?? {}, false)\n\t\tconst query = sql`SELECT COUNT(*) as cnt FROM ${sql.raw(collection)} WHERE ${whereClause}`\n\t\tconst rows = (await this.db.execute(query)) as unknown as Array<{ cnt: number | string }>\n\t\tconst cnt = rows[0]?.cnt\n\t\treturn typeof cnt === 'string' ? Number.parseInt(cnt, 10) : (cnt ?? 0)\n\t}\n\n\tasync close(): Promise<void> {\n\t\tthis.closed = true\n\t}\n\n\t// ---------------------------------------------------------------------------\n\t// Materialization internals\n\t// ---------------------------------------------------------------------------\n\n\t/**\n\t * Rebuild a single record in the materialized collection table by replaying\n\t * all operations for that record.\n\t */\n\tprivate async rebuildMaterializedRecord(\n\t\ttxOrDb: PostgresJsDatabase,\n\t\tcollection: string,\n\t\trecordId: string,\n\t): Promise<void> {\n\t\tconst collectionDef = this.schema?.collections[collection]\n\t\tif (!collectionDef) return\n\n\t\t// Fetch all ops for this specific record, ordered by HLC\n\t\tconst ops = await txOrDb\n\t\t\t.select({\n\t\t\t\ttype: pgOperations.type,\n\t\t\t\tdata: pgOperations.data,\n\t\t\t\twallTime: pgOperations.wallTime,\n\t\t\t})\n\t\t\t.from(pgOperations)\n\t\t\t.where(and(eq(pgOperations.collection, collection), eq(pgOperations.recordId, recordId)))\n\t\t\t.orderBy(\n\t\t\t\tasc(pgOperations.wallTime),\n\t\t\t\tasc(pgOperations.logical),\n\t\t\t\tasc(pgOperations.sequenceNumber),\n\t\t\t)\n\n\t\t// Replay to get current state\n\t\tconst parsedOps = ops.map((op) => ({\n\t\t\ttype: op.type,\n\t\t\tdata: op.data !== null ? JSON.parse(op.data) : null,\n\t\t}))\n\t\tconst recordData = replayOperationsForRecord(parsedOps)\n\n\t\tconst fieldNames = Object.keys(collectionDef.fields)\n\n\t\tif (recordData) {\n\t\t\tconst createdAt = ops.length > 0 ? (ops[0] as (typeof ops)[0]).wallTime : Date.now()\n\t\t\tconst updatedAt =\n\t\t\t\tops.length > 0 ? (ops[ops.length - 1] as (typeof ops)[0]).wallTime : Date.now()\n\n\t\t\tawait this.upsertMaterializedRecord(\n\t\t\t\ttxOrDb,\n\t\t\t\tcollection,\n\t\t\t\trecordId,\n\t\t\t\trecordData,\n\t\t\t\tfieldNames,\n\t\t\t\tcollectionDef,\n\t\t\t\tcreatedAt,\n\t\t\t\tupdatedAt,\n\t\t\t)\n\t\t} else {\n\t\t\tawait txOrDb.execute(\n\t\t\t\tsql`UPDATE ${sql.raw(collection)} SET _deleted = 1, _updated_at = ${Date.now()} WHERE id = ${recordId}`,\n\t\t\t)\n\t\t}\n\t}\n\n\t/**\n\t * UPSERT a record into the materialized collection table.\n\t */\n\tprivate async upsertMaterializedRecord(\n\t\ttxOrDb: PostgresJsDatabase,\n\t\ttableName: string,\n\t\trecordId: string,\n\t\trecordData: Record<string, unknown>,\n\t\tfieldNames: string[],\n\t\tcollectionDef: { fields: Record<string, import('@korajs/core').FieldDescriptor> },\n\t\tcreatedAt: number,\n\t\tupdatedAt: number,\n\t): Promise<void> {\n\t\tconst allColumns = ['id', ...fieldNames, '_created_at', '_updated_at', '_deleted']\n\t\tconst values: unknown[] = [\n\t\t\trecordId,\n\t\t\t...fieldNames.map((f) => {\n\t\t\t\tconst descriptor = collectionDef.fields[f]\n\t\t\t\treturn descriptor ? serializeFieldValue(recordData[f] ?? null, descriptor) : null\n\t\t\t}),\n\t\t\tcreatedAt,\n\t\t\tupdatedAt,\n\t\t\t0,\n\t\t]\n\n\t\tconst columnsSql = sql.raw(allColumns.join(', '))\n\t\tconst valuesSql = sql.join(\n\t\t\tvalues.map((v) => sql`${v}`),\n\t\t\tsql.raw(', '),\n\t\t)\n\t\tconst updateSet = sql.raw(\n\t\t\tallColumns\n\t\t\t\t.slice(1)\n\t\t\t\t.map((c) => `${c} = excluded.${c}`)\n\t\t\t\t.join(', '),\n\t\t)\n\n\t\tawait txOrDb.execute(\n\t\t\tsql`INSERT INTO ${sql.raw(tableName)} (${columnsSql}) VALUES (${valuesSql}) ON CONFLICT (id) DO UPDATE SET ${updateSet}`,\n\t\t)\n\t}\n\n\t/**\n\t * Backfill all materialized collection tables from the existing operation log.\n\t */\n\tprivate async backfillAllCollections(): Promise<void> {\n\t\tif (!this.schema) return\n\n\t\tfor (const collectionName of Object.keys(this.schema.collections)) {\n\t\t\tawait this.backfillCollection(collectionName)\n\t\t}\n\t}\n\n\t/**\n\t * Backfill a single collection's materialized table from operations.\n\t */\n\tprivate async backfillCollection(collectionName: string): Promise<void> {\n\t\tconst collectionDef = this.schema?.collections[collectionName]\n\t\tif (!collectionDef) return\n\n\t\tconst allOps = await this.db\n\t\t\t.select({\n\t\t\t\trecordId: pgOperations.recordId,\n\t\t\t\ttype: pgOperations.type,\n\t\t\t\tdata: pgOperations.data,\n\t\t\t\twallTime: pgOperations.wallTime,\n\t\t\t})\n\t\t\t.from(pgOperations)\n\t\t\t.where(eq(pgOperations.collection, collectionName))\n\t\t\t.orderBy(\n\t\t\t\tasc(pgOperations.wallTime),\n\t\t\t\tasc(pgOperations.logical),\n\t\t\t\tasc(pgOperations.sequenceNumber),\n\t\t\t)\n\n\t\tif (allOps.length === 0) return\n\n\t\t// Group by recordId\n\t\tconst grouped = new Map<string, typeof allOps>()\n\t\tfor (const op of allOps) {\n\t\t\tlet group = grouped.get(op.recordId)\n\t\t\tif (!group) {\n\t\t\t\tgroup = []\n\t\t\t\tgrouped.set(op.recordId, group)\n\t\t\t}\n\t\t\tgroup.push(op)\n\t\t}\n\n\t\tconst fieldNames = Object.keys(collectionDef.fields)\n\n\t\t// Rebuild each record\n\t\tfor (const [recordId, recordOps] of grouped) {\n\t\t\tconst parsedOps = recordOps.map((op) => ({\n\t\t\t\ttype: op.type,\n\t\t\t\tdata: op.data !== null ? JSON.parse(op.data) : null,\n\t\t\t}))\n\t\t\tconst recordData = replayOperationsForRecord(parsedOps)\n\n\t\t\tif (recordData) {\n\t\t\t\tconst createdAt = (recordOps[0] as (typeof recordOps)[0]).wallTime\n\t\t\t\tconst updatedAt = (recordOps[recordOps.length - 1] as (typeof recordOps)[0]).wallTime\n\t\t\t\tawait this.upsertMaterializedRecord(\n\t\t\t\t\tthis.db,\n\t\t\t\t\tcollectionName,\n\t\t\t\t\trecordId,\n\t\t\t\t\trecordData,\n\t\t\t\t\tfieldNames,\n\t\t\t\t\tcollectionDef,\n\t\t\t\t\tcreatedAt,\n\t\t\t\t\tupdatedAt,\n\t\t\t\t)\n\t\t\t} else {\n\t\t\t\tawait this.db.execute(\n\t\t\t\t\tsql`INSERT INTO ${sql.raw(collectionName)} (id, _deleted, _created_at, _updated_at) VALUES (${recordId}, 1, ${Date.now()}, ${Date.now()}) ON CONFLICT (id) DO UPDATE SET _deleted = 1, _updated_at = ${Date.now()}`,\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\t}\n\n\t// ---------------------------------------------------------------------------\n\t// Query building\n\t// ---------------------------------------------------------------------------\n\n\tprivate buildSelectQuery(collection: string, options?: CollectionQueryOptions): SQL {\n\t\tconst whereClause = this.buildWhereClause(\n\t\t\toptions?.where ?? {},\n\t\t\toptions?.includeDeleted ?? false,\n\t\t)\n\n\t\tconst parts: SQL[] = [sql`SELECT * FROM ${sql.raw(collection)} WHERE ${whereClause}`]\n\n\t\tif (options?.orderBy) {\n\t\t\tconst dir = options.orderDirection === 'desc' ? 'DESC' : 'ASC'\n\t\t\tparts.push(sql.raw(` ORDER BY ${options.orderBy} ${dir}`))\n\t\t}\n\n\t\tif (options?.limit !== undefined) {\n\t\t\tparts.push(sql` LIMIT ${options.limit}`)\n\t\t}\n\n\t\tif (options?.offset !== undefined) {\n\t\t\tparts.push(sql` OFFSET ${options.offset}`)\n\t\t}\n\n\t\treturn sql.join(parts, sql.raw(''))\n\t}\n\n\tprivate buildWhereClause(where: Record<string, unknown>, includeDeleted: boolean): SQL {\n\t\tconst conditions: SQL[] = []\n\n\t\tif (!includeDeleted) {\n\t\t\tconditions.push(sql.raw('_deleted = 0'))\n\t\t}\n\n\t\tfor (const [key, value] of Object.entries(where)) {\n\t\t\tconditions.push(sql`${sql.raw(key)} = ${value}`)\n\t\t}\n\n\t\tif (conditions.length === 0) {\n\t\t\treturn sql.raw('1 = 1')\n\t\t}\n\n\t\treturn sql.join(conditions, sql.raw(' AND '))\n\t}\n\n\t// ---------------------------------------------------------------------------\n\t// Row deserialization\n\t// ---------------------------------------------------------------------------\n\n\tprivate deserializeRow(\n\t\trow: Record<string, unknown>,\n\t\tcollectionDef: { fields: Record<string, import('@korajs/core').FieldDescriptor> },\n\t): MaterializedRecord {\n\t\tconst record: MaterializedRecord = { id: row.id as string }\n\n\t\tfor (const [fieldName, descriptor] of Object.entries(collectionDef.fields)) {\n\t\t\tif (fieldName in row) {\n\t\t\t\trecord[fieldName] = deserializeFieldValue(row[fieldName], descriptor)\n\t\t\t}\n\t\t}\n\n\t\tif ('_created_at' in row) record._created_at = row._created_at\n\t\tif ('_updated_at' in row) record._updated_at = row._updated_at\n\n\t\treturn record\n\t}\n\n\t// ---------------------------------------------------------------------------\n\t// Fallback materialization (operation replay, no schema)\n\t// ---------------------------------------------------------------------------\n\n\tprivate async materializeFromOpsLog(collection: string): Promise<MaterializedRecord[]> {\n\t\tconst rows = await this.db\n\t\t\t.select()\n\t\t\t.from(pgOperations)\n\t\t\t.where(eq(pgOperations.collection, collection))\n\t\t\t.orderBy(\n\t\t\t\tasc(pgOperations.wallTime),\n\t\t\t\tasc(pgOperations.logical),\n\t\t\t\tasc(pgOperations.sequenceNumber),\n\t\t\t)\n\n\t\tconst records = new Map<string, Record<string, unknown>>()\n\t\tconst deleted = new Set<string>()\n\n\t\tfor (const row of rows) {\n\t\t\tconst recordId = row.recordId\n\t\t\tconst data = row.data !== null ? JSON.parse(row.data) : null\n\n\t\t\tswitch (row.type) {\n\t\t\t\tcase 'insert':\n\t\t\t\t\tif (data) {\n\t\t\t\t\t\trecords.set(recordId, { id: recordId, ...data })\n\t\t\t\t\t\tdeleted.delete(recordId)\n\t\t\t\t\t}\n\t\t\t\t\tbreak\n\t\t\t\tcase 'update':\n\t\t\t\t\tif (data) {\n\t\t\t\t\t\tconst existing = records.get(recordId) ?? { id: recordId }\n\t\t\t\t\t\trecords.set(recordId, { ...existing, ...data })\n\t\t\t\t\t\tdeleted.delete(recordId)\n\t\t\t\t\t}\n\t\t\t\t\tbreak\n\t\t\t\tcase 'delete':\n\t\t\t\t\tdeleted.add(recordId)\n\t\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\tfor (const id of deleted) {\n\t\t\trecords.delete(id)\n\t\t}\n\n\t\treturn Array.from(records.values()) as MaterializedRecord[]\n\t}\n\n\t// ---------------------------------------------------------------------------\n\t// Initialization\n\t// ---------------------------------------------------------------------------\n\n\tprivate async initialize(): Promise<void> {\n\t\tawait this.ensureTables()\n\n\t\t// Hydrate in-memory version vector cache\n\t\tconst rows = await this.db\n\t\t\t.select({\n\t\t\t\tnodeId: pgSyncState.nodeId,\n\t\t\t\tmaxSequenceNumber: pgSyncState.maxSequenceNumber,\n\t\t\t})\n\t\t\t.from(pgSyncState)\n\n\t\tfor (const row of rows) {\n\t\t\tthis.versionVector.set(row.nodeId, row.maxSequenceNumber)\n\t\t}\n\t}\n\n\tprivate async ensureTables(): Promise<void> {\n\t\tawait this.db.execute(sql`\n\t\t\tCREATE TABLE IF NOT EXISTS operations (\n\t\t\t\tid TEXT PRIMARY KEY,\n\t\t\t\tnode_id TEXT NOT NULL,\n\t\t\t\ttype TEXT NOT NULL,\n\t\t\t\tcollection TEXT NOT NULL,\n\t\t\t\trecord_id TEXT NOT NULL,\n\t\t\t\tdata TEXT,\n\t\t\t\tprevious_data TEXT,\n\t\t\t\twall_time BIGINT NOT NULL,\n\t\t\t\tlogical INTEGER NOT NULL,\n\t\t\t\ttimestamp_node_id TEXT NOT NULL,\n\t\t\t\tsequence_number INTEGER NOT NULL,\n\t\t\t\tcausal_deps TEXT NOT NULL DEFAULT '[]',\n\t\t\t\tschema_version INTEGER NOT NULL,\n\t\t\t\treceived_at BIGINT NOT NULL\n\t\t\t)\n\t\t`)\n\n\t\tawait this.db.execute(\n\t\t\tsql`CREATE INDEX IF NOT EXISTS idx_node_seq ON operations (node_id, sequence_number)`,\n\t\t)\n\t\tawait this.db.execute(sql`CREATE INDEX IF NOT EXISTS idx_collection ON operations (collection)`)\n\t\tawait this.db.execute(sql`CREATE INDEX IF NOT EXISTS idx_received ON operations (received_at)`)\n\t\t// Index for efficient per-record operation lookups during materialization\n\t\tawait this.db.execute(\n\t\t\tsql`CREATE INDEX IF NOT EXISTS idx_collection_record ON operations (collection, record_id)`,\n\t\t)\n\n\t\tawait this.db.execute(sql`\n\t\t\tCREATE TABLE IF NOT EXISTS sync_state (\n\t\t\t\tnode_id TEXT PRIMARY KEY,\n\t\t\t\tmax_sequence_number INTEGER NOT NULL,\n\t\t\t\tlast_seen_at BIGINT NOT NULL\n\t\t\t)\n\t\t`)\n\t}\n\n\t// ---------------------------------------------------------------------------\n\t// Operation serialization\n\t// ---------------------------------------------------------------------------\n\n\tprivate serializeOperation(op: Operation, receivedAt: number): typeof pgOperations.$inferInsert {\n\t\treturn {\n\t\t\tid: op.id,\n\t\t\tnodeId: op.nodeId,\n\t\t\ttype: op.type,\n\t\t\tcollection: op.collection,\n\t\t\trecordId: op.recordId,\n\t\t\tdata: op.data !== null ? JSON.stringify(op.data) : null,\n\t\t\tpreviousData: op.previousData !== null ? JSON.stringify(op.previousData) : null,\n\t\t\twallTime: op.timestamp.wallTime,\n\t\t\tlogical: op.timestamp.logical,\n\t\t\ttimestampNodeId: op.timestamp.nodeId,\n\t\t\tsequenceNumber: op.sequenceNumber,\n\t\t\tcausalDeps: JSON.stringify(op.causalDeps),\n\t\t\tschemaVersion: op.schemaVersion,\n\t\t\treceivedAt,\n\t\t}\n\t}\n\n\tprivate deserializeOperation(row: typeof pgOperations.$inferSelect): Operation {\n\t\treturn {\n\t\t\tid: row.id,\n\t\t\tnodeId: row.nodeId,\n\t\t\ttype: row.type as Operation['type'],\n\t\t\tcollection: row.collection,\n\t\t\trecordId: row.recordId,\n\t\t\tdata: row.data !== null ? JSON.parse(row.data) : null,\n\t\t\tpreviousData: row.previousData !== null ? JSON.parse(row.previousData) : null,\n\t\t\ttimestamp: {\n\t\t\t\twallTime: row.wallTime,\n\t\t\t\tlogical: row.logical,\n\t\t\t\tnodeId: row.timestampNodeId,\n\t\t\t},\n\t\t\tsequenceNumber: row.sequenceNumber,\n\t\t\tcausalDeps: JSON.parse(row.causalDeps),\n\t\t\tschemaVersion: row.schemaVersion,\n\t\t}\n\t}\n\n\t// ---------------------------------------------------------------------------\n\t// Assertions\n\t// ---------------------------------------------------------------------------\n\n\tprivate assertOpen(): void {\n\t\tif (this.closed) {\n\t\t\tthrow new Error('PostgresServerStore is closed')\n\t\t}\n\t}\n\n\tprivate assertSchema(): void {\n\t\tif (!this.schema) {\n\t\t\tthrow new Error(\n\t\t\t\t'Schema not set. Call setSchema() before using queryCollection/findRecord/countCollection.',\n\t\t\t)\n\t\t}\n\t}\n\n\tprivate assertCollection(collection: string): void {\n\t\tconst schema = this.schema as SchemaDefinition\n\t\tif (!schema.collections[collection]) {\n\t\t\tthrow new Error(\n\t\t\t\t`Unknown collection \"${collection}\". Available: ${Object.keys(schema.collections).join(', ')}`,\n\t\t\t)\n\t\t}\n\t}\n}\n\n/**\n * Creates a PostgresServerStore from a PostgreSQL connection string.\n */\nexport async function createPostgresServerStore(options: {\n\tconnectionString: string\n\tnodeId?: string\n}): Promise<PostgresServerStore> {\n\tconst { postgresClient, drizzleFn } = await loadPostgresDeps()\n\tconst client = postgresClient(options.connectionString)\n\tconst db = drizzleFn(client)\n\n\treturn new PostgresServerStore(db, options.nodeId)\n}\n\nasync function loadPostgresDeps(): Promise<{\n\tpostgresClient: (connectionString: string) => unknown\n\tdrizzleFn: (client: unknown) => PostgresJsDatabase\n}> {\n\ttry {\n\t\tconst dynamicImport = new Function('specifier', 'return import(specifier)') as (\n\t\t\tspecifier: string,\n\t\t) => Promise<unknown>\n\n\t\tconst postgresMod = (await dynamicImport('postgres')) as { default: (cs: string) => unknown }\n\t\tconst drizzleMod = (await dynamicImport('drizzle-orm/postgres-js')) as {\n\t\t\tdrizzle: (client: unknown) => PostgresJsDatabase\n\t\t}\n\n\t\treturn {\n\t\t\tpostgresClient: postgresMod.default,\n\t\t\tdrizzleFn: drizzleMod.drizzle,\n\t\t}\n\t} catch {\n\t\tthrow new Error(\n\t\t\t'PostgreSQL backend requires the \"postgres\" package. Install it in your project dependencies.',\n\t\t)\n\t}\n}\n","import { bigint, index, integer, pgTable, text } from 'drizzle-orm/pg-core'\n\n/**\n * Drizzle schema for the Kora sync server's PostgreSQL database.\n *\n * Two tables:\n * - `pgOperations` — the append-only operation log (content-addressed by id)\n * - `pgSyncState` — tracks the max sequence number seen per node (version vector)\n *\n * Column structure mirrors the SQLite drizzle-schema.ts but uses pgTable.\n */\n\nexport const pgOperations = pgTable(\n\t'operations',\n\t{\n\t\tid: text('id').primaryKey(),\n\t\tnodeId: text('node_id').notNull(),\n\t\ttype: text('type').notNull(),\n\t\tcollection: text('collection').notNull(),\n\t\trecordId: text('record_id').notNull(),\n\t\tdata: text('data'), // JSON-serialized, null for deletes\n\t\tpreviousData: text('previous_data'), // JSON-serialized, null for insert/delete\n\t\twallTime: bigint('wall_time', { mode: 'number' }).notNull(),\n\t\tlogical: integer('logical').notNull(),\n\t\ttimestampNodeId: text('timestamp_node_id').notNull(),\n\t\tsequenceNumber: integer('sequence_number').notNull(),\n\t\tcausalDeps: text('causal_deps').notNull().default('[]'), // JSON array of op IDs\n\t\tschemaVersion: integer('schema_version').notNull(),\n\t\treceivedAt: bigint('received_at', { mode: 'number' }).notNull(),\n\t},\n\t(table) => ({\n\t\tnodeSeqIdx: index('idx_pg_node_seq').on(table.nodeId, table.sequenceNumber),\n\t\tcollectionIdx: index('idx_pg_collection').on(table.collection),\n\t\treceivedIdx: index('idx_pg_received').on(table.receivedAt),\n\t}),\n)\n\nexport const pgSyncState = pgTable('sync_state', {\n\tnodeId: text('node_id').primaryKey(),\n\tmaxSequenceNumber: integer('max_sequence_number').notNull(),\n\tlastSeenAt: bigint('last_seen_at', { mode: 'number' }).notNull(),\n})\n","import { createRequire } from 'node:module'\nimport type { Operation, SchemaDefinition, VersionVector } from '@korajs/core'\nimport { generateUUIDv7 } from '@korajs/core'\nimport type { ApplyResult } from '@korajs/sync'\nimport type { SQL } from 'drizzle-orm'\nimport { and, asc, between, count, eq, sql } from 'drizzle-orm'\nimport type { BetterSQLite3Database } from 'drizzle-orm/better-sqlite3'\nimport { operations, syncState } from './drizzle-schema'\nimport {\n\tdeserializeFieldValue,\n\tgenerateAllCollectionDDL,\n\treplayOperationsForRecord,\n\tserializeFieldValue,\n\tvalidateFieldName,\n} from './materialization'\nimport type { CollectionQueryOptions, MaterializedRecord, ServerStore } from './server-store'\n\n// better-sqlite3 is a native CJS addon that cannot be loaded via ESM import().\n// createRequire provides a CJS require() that works in both ESM and CJS contexts.\n// tsup's shims option ensures import.meta.url is available in CJS builds.\nconst esmRequire = createRequire(import.meta.url)\n\n/**\n * SQLite-backed server store using Drizzle ORM.\n * Persists operations and version vectors to a real database file,\n * surviving process restarts.\n *\n * When a schema is set via setSchema(), also maintains materialized\n * collection tables for efficient indexed queries (dual-write).\n */\nexport class SqliteServerStore implements ServerStore {\n\tprivate readonly nodeId: string\n\tprivate readonly db: BetterSQLite3Database\n\tprivate schema: SchemaDefinition | null = null\n\tprivate closed = false\n\n\tconstructor(db: BetterSQLite3Database, nodeId?: string) {\n\t\tthis.db = db\n\t\tthis.nodeId = nodeId ?? generateUUIDv7()\n\t\tthis.ensureTables()\n\t}\n\n\tgetVersionVector(): VersionVector {\n\t\tthis.assertOpen()\n\t\tconst rows = this.db.select().from(syncState).all()\n\t\tconst vv: VersionVector = new Map()\n\t\tfor (const row of rows) {\n\t\t\tvv.set(row.nodeId, row.maxSequenceNumber)\n\t\t}\n\t\treturn vv\n\t}\n\n\tgetNodeId(): string {\n\t\treturn this.nodeId\n\t}\n\n\tasync setSchema(schema: SchemaDefinition): Promise<void> {\n\t\tthis.assertOpen()\n\t\tthis.schema = schema\n\n\t\t// Generate and execute DDL for all collection tables\n\t\tconst ddlStatements = generateAllCollectionDDL(schema, 'sqlite')\n\t\tfor (const stmt of ddlStatements) {\n\t\t\tif (stmt.startsWith('--kora:safe-alter')) {\n\t\t\t\tconst alterSql = stmt.replace('--kora:safe-alter\\n', '')\n\t\t\t\ttry {\n\t\t\t\t\tthis.db.run(sql.raw(alterSql))\n\t\t\t\t} catch (e) {\n\t\t\t\t\t// Ignore \"duplicate column\" errors from safe ALTER TABLE.\n\t\t\t\t\t// Drizzle wraps SQLite errors, so check both outer message and cause.\n\t\t\t\t\tconst msg = e instanceof Error ? e.message : ''\n\t\t\t\t\tconst causeMsg = e instanceof Error && e.cause instanceof Error ? e.cause.message : ''\n\t\t\t\t\tif (!msg.includes('duplicate column') && !causeMsg.includes('duplicate column')) {\n\t\t\t\t\t\tthrow e\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tthis.db.run(sql.raw(stmt))\n\t\t\t}\n\t\t}\n\n\t\t// Backfill materialized tables from existing operations\n\t\tawait this.backfillAllCollections()\n\t}\n\n\tasync applyRemoteOperation(op: Operation): Promise<ApplyResult> {\n\t\tthis.assertOpen()\n\n\t\tconst now = Date.now()\n\t\tconst row = this.serializeOperation(op, now)\n\n\t\t// Use a transaction for atomicity: insert op + update version vector + materialize\n\t\tconst result = this.db.transaction((tx) => {\n\t\t\t// Content-addressed dedup via onConflictDoNothing\n\t\t\tconst insertResult = tx\n\t\t\t\t.insert(operations)\n\t\t\t\t.values(row)\n\t\t\t\t.onConflictDoNothing({ target: operations.id })\n\t\t\t\t.run()\n\n\t\t\tif (insertResult.changes === 0) {\n\t\t\t\treturn 'duplicate' as const\n\t\t\t}\n\n\t\t\t// Advance version vector: upsert with MAX to ensure monotonic progress\n\t\t\ttx.insert(syncState)\n\t\t\t\t.values({\n\t\t\t\t\tnodeId: op.nodeId,\n\t\t\t\t\tmaxSequenceNumber: op.sequenceNumber,\n\t\t\t\t\tlastSeenAt: now,\n\t\t\t\t})\n\t\t\t\t.onConflictDoUpdate({\n\t\t\t\t\ttarget: syncState.nodeId,\n\t\t\t\t\tset: {\n\t\t\t\t\t\tmaxSequenceNumber: sql`MAX(${syncState.maxSequenceNumber}, ${op.sequenceNumber})`,\n\t\t\t\t\t\tlastSeenAt: sql`${now}`,\n\t\t\t\t\t},\n\t\t\t\t})\n\t\t\t\t.run()\n\n\t\t\t// Dual-write: update materialized collection table if schema is set\n\t\t\tif (this.schema?.collections[op.collection]) {\n\t\t\t\tthis.rebuildMaterializedRecord(tx, op.collection, op.recordId)\n\t\t\t}\n\n\t\t\treturn 'applied' as const\n\t\t})\n\n\t\treturn result\n\t}\n\n\tasync getOperationRange(nodeId: string, fromSeq: number, toSeq: number): Promise<Operation[]> {\n\t\tthis.assertOpen()\n\n\t\tconst rows = this.db\n\t\t\t.select()\n\t\t\t.from(operations)\n\t\t\t.where(and(eq(operations.nodeId, nodeId), between(operations.sequenceNumber, fromSeq, toSeq)))\n\t\t\t.orderBy(asc(operations.sequenceNumber))\n\t\t\t.all()\n\n\t\treturn rows.map((row) => this.deserializeOperation(row))\n\t}\n\n\tasync getOperationCount(): Promise<number> {\n\t\tthis.assertOpen()\n\n\t\tconst result = this.db.select({ value: count() }).from(operations).all()\n\t\treturn result[0]?.value ?? 0\n\t}\n\n\tasync materializeCollection(collection: string): Promise<MaterializedRecord[]> {\n\t\tthis.assertOpen()\n\n\t\t// Fast path: if schema is set, read directly from the materialized table\n\t\tif (this.schema?.collections[collection]) {\n\t\t\treturn this.queryCollection(collection)\n\t\t}\n\n\t\t// Fallback: replay operations (legacy path when schema is not set)\n\t\treturn this.materializeFromOpsLog(collection)\n\t}\n\n\tasync queryCollection(\n\t\tcollection: string,\n\t\toptions?: CollectionQueryOptions,\n\t): Promise<MaterializedRecord[]> {\n\t\tthis.assertOpen()\n\t\tthis.assertSchema()\n\t\tthis.assertCollection(collection)\n\n\t\tconst schema = this.schema as SchemaDefinition\n\t\tconst collectionDef = schema.collections[collection] as NonNullable<\n\t\t\tSchemaDefinition['collections'][string]\n\t\t>\n\n\t\t// Validate field names in options\n\t\tif (options?.where) {\n\t\t\tfor (const key of Object.keys(options.where)) {\n\t\t\t\tvalidateFieldName(collection, key, schema)\n\t\t\t}\n\t\t}\n\t\tif (options?.orderBy) {\n\t\t\tvalidateFieldName(collection, options.orderBy, schema)\n\t\t}\n\n\t\tconst query = this.buildSelectQuery(collection, options)\n\t\tconst rows = this.db.all<Record<string, unknown>>(query)\n\n\t\treturn rows.map((row) => this.deserializeRow(row, collectionDef))\n\t}\n\n\tasync findRecord(collection: string, id: string): Promise<MaterializedRecord | null> {\n\t\tthis.assertOpen()\n\t\tthis.assertSchema()\n\t\tthis.assertCollection(collection)\n\n\t\tconst schema = this.schema as SchemaDefinition\n\t\tconst collectionDef = schema.collections[collection] as NonNullable<\n\t\t\tSchemaDefinition['collections'][string]\n\t\t>\n\t\tconst query = sql`SELECT * FROM ${sql.raw(collection)} WHERE id = ${id} AND _deleted = 0`\n\t\tconst rows = this.db.all<Record<string, unknown>>(query)\n\n\t\tif (rows.length === 0) return null\n\t\treturn this.deserializeRow(rows[0] as Record<string, unknown>, collectionDef)\n\t}\n\n\tasync countCollection(collection: string, where?: Record<string, unknown>): Promise<number> {\n\t\tthis.assertOpen()\n\t\tthis.assertSchema()\n\t\tthis.assertCollection(collection)\n\n\t\tconst schema = this.schema as SchemaDefinition\n\t\tif (where) {\n\t\t\tfor (const key of Object.keys(where)) {\n\t\t\t\tvalidateFieldName(collection, key, schema)\n\t\t\t}\n\t\t}\n\n\t\tconst whereClause = this.buildWhereClause(where ?? {}, false)\n\t\tconst query = sql`SELECT COUNT(*) as cnt FROM ${sql.raw(collection)} WHERE ${whereClause}`\n\t\tconst rows = this.db.all<{ cnt: number }>(query)\n\t\treturn rows[0]?.cnt ?? 0\n\t}\n\n\tasync close(): Promise<void> {\n\t\tthis.closed = true\n\t}\n\n\t// ---------------------------------------------------------------------------\n\t// Materialization internals\n\t// ---------------------------------------------------------------------------\n\n\t/**\n\t * Rebuild a single record in the materialized collection table by replaying\n\t * all operations for that record. Called within the applyRemoteOperation\n\t * transaction for atomic dual-write.\n\t */\n\tprivate rebuildMaterializedRecord(\n\t\ttxOrDb: BetterSQLite3Database,\n\t\tcollection: string,\n\t\trecordId: string,\n\t): void {\n\t\tconst collectionDef = this.schema?.collections[collection]\n\t\tif (!collectionDef) return\n\n\t\t// Fetch all ops for this specific record, ordered by HLC\n\t\tconst ops = txOrDb\n\t\t\t.select({\n\t\t\t\ttype: operations.type,\n\t\t\t\tdata: operations.data,\n\t\t\t\twallTime: operations.wallTime,\n\t\t\t})\n\t\t\t.from(operations)\n\t\t\t.where(and(eq(operations.collection, collection), eq(operations.recordId, recordId)))\n\t\t\t.orderBy(asc(operations.wallTime), asc(operations.logical), asc(operations.sequenceNumber))\n\t\t\t.all()\n\n\t\t// Replay to get current state\n\t\tconst parsedOps = ops.map((op) => ({\n\t\t\ttype: op.type,\n\t\t\tdata: op.data !== null ? JSON.parse(op.data) : null,\n\t\t}))\n\t\tconst recordData = replayOperationsForRecord(parsedOps)\n\n\t\tconst fieldNames = Object.keys(collectionDef.fields)\n\n\t\tif (recordData) {\n\t\t\t// Compute timestamps from operations\n\t\t\tconst createdAt = ops.length > 0 ? (ops[0] as (typeof ops)[0]).wallTime : Date.now()\n\t\t\tconst updatedAt =\n\t\t\t\tops.length > 0 ? (ops[ops.length - 1] as (typeof ops)[0]).wallTime : Date.now()\n\n\t\t\tthis.upsertMaterializedRecord(\n\t\t\t\ttxOrDb,\n\t\t\t\tcollection,\n\t\t\t\trecordId,\n\t\t\t\trecordData,\n\t\t\t\tfieldNames,\n\t\t\t\tcollectionDef,\n\t\t\t\tcreatedAt,\n\t\t\t\tupdatedAt,\n\t\t\t)\n\t\t} else {\n\t\t\t// Record was deleted — soft-delete in materialized table\n\t\t\ttxOrDb.run(\n\t\t\t\tsql`UPDATE ${sql.raw(collection)} SET _deleted = 1, _updated_at = ${Date.now()} WHERE id = ${recordId}`,\n\t\t\t)\n\t\t}\n\t}\n\n\t/**\n\t * UPSERT a record into the materialized collection table.\n\t * Uses INSERT ... ON CONFLICT (id) DO UPDATE SET for atomic upsert.\n\t */\n\tprivate upsertMaterializedRecord(\n\t\ttxOrDb: BetterSQLite3Database,\n\t\ttableName: string,\n\t\trecordId: string,\n\t\trecordData: Record<string, unknown>,\n\t\tfieldNames: string[],\n\t\tcollectionDef: { fields: Record<string, import('@korajs/core').FieldDescriptor> },\n\t\tcreatedAt: number,\n\t\tupdatedAt: number,\n\t): void {\n\t\tconst allColumns = ['id', ...fieldNames, '_created_at', '_updated_at', '_deleted']\n\t\tconst values: unknown[] = [\n\t\t\trecordId,\n\t\t\t...fieldNames.map((f) => {\n\t\t\t\tconst descriptor = collectionDef.fields[f]\n\t\t\t\treturn descriptor ? serializeFieldValue(recordData[f] ?? null, descriptor) : null\n\t\t\t}),\n\t\t\tcreatedAt,\n\t\t\tupdatedAt,\n\t\t\t0, // _deleted = false\n\t\t]\n\n\t\tconst columnsSql = sql.raw(allColumns.join(', '))\n\t\tconst valuesSql = sql.join(\n\t\t\tvalues.map((v) => sql`${v}`),\n\t\t\tsql.raw(', '),\n\t\t)\n\t\tconst updateSet = sql.raw(\n\t\t\tallColumns\n\t\t\t\t.slice(1)\n\t\t\t\t.map((c) => `${c} = excluded.${c}`)\n\t\t\t\t.join(', '),\n\t\t)\n\n\t\ttxOrDb.run(\n\t\t\tsql`INSERT INTO ${sql.raw(tableName)} (${columnsSql}) VALUES (${valuesSql}) ON CONFLICT (id) DO UPDATE SET ${updateSet}`,\n\t\t)\n\t}\n\n\t/**\n\t * Backfill all materialized collection tables from the existing operation log.\n\t * Called when setSchema() is invoked and operations already exist.\n\t */\n\tprivate async backfillAllCollections(): Promise<void> {\n\t\tif (!this.schema) return\n\n\t\tfor (const collectionName of Object.keys(this.schema.collections)) {\n\t\t\tthis.backfillCollection(collectionName)\n\t\t}\n\t}\n\n\t/**\n\t * Backfill a single collection's materialized table from operations.\n\t */\n\tprivate backfillCollection(collectionName: string): void {\n\t\tconst collectionDef = this.schema?.collections[collectionName]\n\t\tif (!collectionDef) return\n\n\t\t// Fetch all ops for this collection, ordered by HLC\n\t\tconst allOps = this.db\n\t\t\t.select({\n\t\t\t\trecordId: operations.recordId,\n\t\t\t\ttype: operations.type,\n\t\t\t\tdata: operations.data,\n\t\t\t\twallTime: operations.wallTime,\n\t\t\t})\n\t\t\t.from(operations)\n\t\t\t.where(eq(operations.collection, collectionName))\n\t\t\t.orderBy(asc(operations.wallTime), asc(operations.logical), asc(operations.sequenceNumber))\n\t\t\t.all()\n\n\t\tif (allOps.length === 0) return\n\n\t\t// Group by recordId\n\t\tconst grouped = new Map<string, typeof allOps>()\n\t\tfor (const op of allOps) {\n\t\t\tlet group = grouped.get(op.recordId)\n\t\t\tif (!group) {\n\t\t\t\tgroup = []\n\t\t\t\tgrouped.set(op.recordId, group)\n\t\t\t}\n\t\t\tgroup.push(op)\n\t\t}\n\n\t\t// Rebuild each record inside a single transaction for efficiency\n\t\tconst fieldNames = Object.keys(collectionDef.fields)\n\t\tthis.db.transaction((tx) => {\n\t\t\tfor (const [recordId, recordOps] of grouped) {\n\t\t\t\tconst parsedOps = recordOps.map((op) => ({\n\t\t\t\t\ttype: op.type,\n\t\t\t\t\tdata: op.data !== null ? JSON.parse(op.data) : null,\n\t\t\t\t}))\n\t\t\t\tconst recordData = replayOperationsForRecord(parsedOps)\n\n\t\t\t\tif (recordData) {\n\t\t\t\t\tconst createdAt = (recordOps[0] as (typeof recordOps)[0]).wallTime\n\t\t\t\t\tconst updatedAt = (recordOps[recordOps.length - 1] as (typeof recordOps)[0]).wallTime\n\t\t\t\t\tthis.upsertMaterializedRecord(\n\t\t\t\t\t\ttx,\n\t\t\t\t\t\tcollectionName,\n\t\t\t\t\t\trecordId,\n\t\t\t\t\t\trecordData,\n\t\t\t\t\t\tfieldNames,\n\t\t\t\t\t\tcollectionDef,\n\t\t\t\t\t\tcreatedAt,\n\t\t\t\t\t\tupdatedAt,\n\t\t\t\t\t)\n\t\t\t\t} else {\n\t\t\t\t\ttx.run(\n\t\t\t\t\t\tsql`INSERT INTO ${sql.raw(collectionName)} (id, _deleted, _created_at, _updated_at) VALUES (${recordId}, 1, ${Date.now()}, ${Date.now()}) ON CONFLICT (id) DO UPDATE SET _deleted = 1, _updated_at = ${Date.now()}`,\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t}\n\n\t// ---------------------------------------------------------------------------\n\t// Query building\n\t// ---------------------------------------------------------------------------\n\n\tprivate buildSelectQuery(collection: string, options?: CollectionQueryOptions): SQL {\n\t\tconst whereClause = this.buildWhereClause(\n\t\t\toptions?.where ?? {},\n\t\t\toptions?.includeDeleted ?? false,\n\t\t)\n\n\t\tconst parts: SQL[] = [sql`SELECT * FROM ${sql.raw(collection)} WHERE ${whereClause}`]\n\n\t\tif (options?.orderBy) {\n\t\t\tconst dir = options.orderDirection === 'desc' ? 'DESC' : 'ASC'\n\t\t\tparts.push(sql.raw(` ORDER BY ${options.orderBy} ${dir}`))\n\t\t}\n\n\t\tif (options?.limit !== undefined) {\n\t\t\tparts.push(sql` LIMIT ${options.limit}`)\n\t\t}\n\n\t\tif (options?.offset !== undefined) {\n\t\t\tparts.push(sql` OFFSET ${options.offset}`)\n\t\t}\n\n\t\treturn sql.join(parts, sql.raw(''))\n\t}\n\n\tprivate buildWhereClause(where: Record<string, unknown>, includeDeleted: boolean): SQL {\n\t\tconst conditions: SQL[] = []\n\n\t\tif (!includeDeleted) {\n\t\t\tconditions.push(sql.raw('_deleted = 0'))\n\t\t}\n\n\t\tfor (const [key, value] of Object.entries(where)) {\n\t\t\tconditions.push(sql`${sql.raw(key)} = ${value}`)\n\t\t}\n\n\t\tif (conditions.length === 0) {\n\t\t\treturn sql.raw('1 = 1')\n\t\t}\n\n\t\treturn sql.join(conditions, sql.raw(' AND '))\n\t}\n\n\t// ---------------------------------------------------------------------------\n\t// Row deserialization\n\t// ---------------------------------------------------------------------------\n\n\tprivate deserializeRow(\n\t\trow: Record<string, unknown>,\n\t\tcollectionDef: { fields: Record<string, import('@korajs/core').FieldDescriptor> },\n\t): MaterializedRecord {\n\t\tconst record: MaterializedRecord = { id: row.id as string }\n\n\t\tfor (const [fieldName, descriptor] of Object.entries(collectionDef.fields)) {\n\t\t\tif (fieldName in row) {\n\t\t\t\trecord[fieldName] = deserializeFieldValue(row[fieldName], descriptor)\n\t\t\t}\n\t\t}\n\n\t\t// Include metadata fields\n\t\tif ('_created_at' in row) record._created_at = row._created_at\n\t\tif ('_updated_at' in row) record._updated_at = row._updated_at\n\n\t\treturn record\n\t}\n\n\t// ---------------------------------------------------------------------------\n\t// Fallback materialization (operation replay, no schema)\n\t// ---------------------------------------------------------------------------\n\n\tprivate materializeFromOpsLog(collection: string): MaterializedRecord[] {\n\t\tconst rows = this.db\n\t\t\t.select()\n\t\t\t.from(operations)\n\t\t\t.where(eq(operations.collection, collection))\n\t\t\t.orderBy(asc(operations.wallTime), asc(operations.logical), asc(operations.sequenceNumber))\n\t\t\t.all()\n\n\t\tconst records = new Map<string, Record<string, unknown>>()\n\t\tconst deleted = new Set<string>()\n\n\t\tfor (const row of rows) {\n\t\t\tconst recordId = row.recordId\n\t\t\tconst data = row.data !== null ? JSON.parse(row.data) : null\n\n\t\t\tswitch (row.type) {\n\t\t\t\tcase 'insert':\n\t\t\t\t\tif (data) {\n\t\t\t\t\t\trecords.set(recordId, { id: recordId, ...data })\n\t\t\t\t\t\tdeleted.delete(recordId)\n\t\t\t\t\t}\n\t\t\t\t\tbreak\n\t\t\t\tcase 'update':\n\t\t\t\t\tif (data) {\n\t\t\t\t\t\tconst existing = records.get(recordId) ?? { id: recordId }\n\t\t\t\t\t\trecords.set(recordId, { ...existing, ...data })\n\t\t\t\t\t\tdeleted.delete(recordId)\n\t\t\t\t\t}\n\t\t\t\t\tbreak\n\t\t\t\tcase 'delete':\n\t\t\t\t\tdeleted.add(recordId)\n\t\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\tfor (const id of deleted) {\n\t\t\trecords.delete(id)\n\t\t}\n\n\t\treturn Array.from(records.values()) as MaterializedRecord[]\n\t}\n\n\t// ---------------------------------------------------------------------------\n\t// Table setup\n\t// ---------------------------------------------------------------------------\n\n\t/**\n\t * Create the operations and sync_state tables if they don't exist.\n\t */\n\tprivate ensureTables(): void {\n\t\tthis.db.run(sql`\n\t\t\tCREATE TABLE IF NOT EXISTS operations (\n\t\t\t\tid TEXT PRIMARY KEY,\n\t\t\t\tnode_id TEXT NOT NULL,\n\t\t\t\ttype TEXT NOT NULL,\n\t\t\t\tcollection TEXT NOT NULL,\n\t\t\t\trecord_id TEXT NOT NULL,\n\t\t\t\tdata TEXT,\n\t\t\t\tprevious_data TEXT,\n\t\t\t\twall_time INTEGER NOT NULL,\n\t\t\t\tlogical INTEGER NOT NULL,\n\t\t\t\ttimestamp_node_id TEXT NOT NULL,\n\t\t\t\tsequence_number INTEGER NOT NULL,\n\t\t\t\tcausal_deps TEXT NOT NULL DEFAULT '[]',\n\t\t\t\tschema_version INTEGER NOT NULL,\n\t\t\t\treceived_at INTEGER NOT NULL\n\t\t\t)\n\t\t`)\n\n\t\tthis.db.run(sql`\n\t\t\tCREATE INDEX IF NOT EXISTS idx_node_seq ON operations (node_id, sequence_number)\n\t\t`)\n\n\t\tthis.db.run(sql`\n\t\t\tCREATE INDEX IF NOT EXISTS idx_collection ON operations (collection)\n\t\t`)\n\n\t\tthis.db.run(sql`\n\t\t\tCREATE INDEX IF NOT EXISTS idx_received ON operations (received_at)\n\t\t`)\n\n\t\t// Index for efficient per-record operation lookups during materialization\n\t\tthis.db.run(sql`\n\t\t\tCREATE INDEX IF NOT EXISTS idx_collection_record ON operations (collection, record_id)\n\t\t`)\n\n\t\tthis.db.run(sql`\n\t\t\tCREATE TABLE IF NOT EXISTS sync_state (\n\t\t\t\tnode_id TEXT PRIMARY KEY,\n\t\t\t\tmax_sequence_number INTEGER NOT NULL,\n\t\t\t\tlast_seen_at INTEGER NOT NULL\n\t\t\t)\n\t\t`)\n\t}\n\n\t// ---------------------------------------------------------------------------\n\t// Operation serialization\n\t// ---------------------------------------------------------------------------\n\n\tprivate serializeOperation(op: Operation, receivedAt: number): typeof operations.$inferInsert {\n\t\treturn {\n\t\t\tid: op.id,\n\t\t\tnodeId: op.nodeId,\n\t\t\ttype: op.type,\n\t\t\tcollection: op.collection,\n\t\t\trecordId: op.recordId,\n\t\t\tdata: op.data !== null ? JSON.stringify(op.data) : null,\n\t\t\tpreviousData: op.previousData !== null ? JSON.stringify(op.previousData) : null,\n\t\t\twallTime: op.timestamp.wallTime,\n\t\t\tlogical: op.timestamp.logical,\n\t\t\ttimestampNodeId: op.timestamp.nodeId,\n\t\t\tsequenceNumber: op.sequenceNumber,\n\t\t\tcausalDeps: JSON.stringify(op.causalDeps),\n\t\t\tschemaVersion: op.schemaVersion,\n\t\t\treceivedAt,\n\t\t}\n\t}\n\n\tprivate deserializeOperation(row: typeof operations.$inferSelect): Operation {\n\t\treturn {\n\t\t\tid: row.id,\n\t\t\tnodeId: row.nodeId,\n\t\t\ttype: row.type as Operation['type'],\n\t\t\tcollection: row.collection,\n\t\t\trecordId: row.recordId,\n\t\t\tdata: row.data !== null ? JSON.parse(row.data) : null,\n\t\t\tpreviousData: row.previousData !== null ? JSON.parse(row.previousData) : null,\n\t\t\ttimestamp: {\n\t\t\t\twallTime: row.wallTime,\n\t\t\t\tlogical: row.logical,\n\t\t\t\tnodeId: row.timestampNodeId,\n\t\t\t},\n\t\t\tsequenceNumber: row.sequenceNumber,\n\t\t\tcausalDeps: JSON.parse(row.causalDeps),\n\t\t\tschemaVersion: row.schemaVersion,\n\t\t}\n\t}\n\n\t// ---------------------------------------------------------------------------\n\t// Assertions\n\t// ---------------------------------------------------------------------------\n\n\tprivate assertOpen(): void {\n\t\tif (this.closed) {\n\t\t\tthrow new Error('SqliteServerStore is closed')\n\t\t}\n\t}\n\n\tprivate assertSchema(): void {\n\t\tif (!this.schema) {\n\t\t\tthrow new Error(\n\t\t\t\t'Schema not set. Call setSchema() before using queryCollection/findRecord/countCollection.',\n\t\t\t)\n\t\t}\n\t}\n\n\tprivate assertCollection(collection: string): void {\n\t\tconst schema = this.schema as SchemaDefinition\n\t\tif (!schema.collections[collection]) {\n\t\t\tthrow new Error(\n\t\t\t\t`Unknown collection \"${collection}\". Available: ${Object.keys(schema.collections).join(', ')}`,\n\t\t\t)\n\t\t}\n\t}\n}\n\n/**\n * Creates a SqliteServerStore with a file-backed or in-memory database.\n * Handles database creation, Drizzle wrapping, and table setup.\n *\n * @param options - Configuration options\n * @param options.filename - Path to SQLite database file. Defaults to ':memory:' for testing.\n * @param options.nodeId - Server node ID. Auto-generated if not provided.\n * @returns A ready-to-use SqliteServerStore\n *\n * @example\n * ```typescript\n * import { createSqliteServerStore } from '@korajs/server'\n *\n * const store = createSqliteServerStore({ filename: './kora-server.db' })\n *\n * // Optional: enable materialized collection tables for fast queries\n * await store.setSchema(mySchema)\n *\n * const server = createKoraServer({ store, port: 3001 })\n * ```\n */\nexport function createSqliteServerStore(options: {\n\tfilename?: string\n\tnodeId?: string\n}): SqliteServerStore {\n\t// better-sqlite3 is a native CJS addon — use esmRequire (from createRequire)\n\t// so this works in both ESM and CJS contexts.\n\tconst Database = esmRequire('better-sqlite3')\n\tconst { drizzle } = esmRequire('drizzle-orm/better-sqlite3')\n\n\tconst filename = options.filename ?? ':memory:'\n\tconst sqlite = new Database(filename)\n\n\t// Enable WAL mode for better concurrent read/write performance\n\tsqlite.pragma('journal_mode = WAL')\n\n\tconst db = drizzle(sqlite)\n\treturn new SqliteServerStore(db, options.nodeId)\n}\n","import { index, integer, sqliteTable, text } from 'drizzle-orm/sqlite-core'\n\n/**\n * Drizzle schema for the Kora sync server's SQLite database.\n *\n * Two tables:\n * - `operations` — the append-only operation log (content-addressed by id)\n * - `syncState` — tracks the max sequence number seen per node (version vector)\n */\n\nexport const operations = sqliteTable(\n\t'operations',\n\t{\n\t\tid: text('id').primaryKey(),\n\t\tnodeId: text('node_id').notNull(),\n\t\ttype: text('type').notNull(),\n\t\tcollection: text('collection').notNull(),\n\t\trecordId: text('record_id').notNull(),\n\t\tdata: text('data'), // JSON-serialized, null for deletes\n\t\tpreviousData: text('previous_data'), // JSON-serialized, null for insert/delete\n\t\twallTime: integer('wall_time').notNull(),\n\t\tlogical: integer('logical').notNull(),\n\t\ttimestampNodeId: text('timestamp_node_id').notNull(),\n\t\tsequenceNumber: integer('sequence_number').notNull(),\n\t\tcausalDeps: text('causal_deps').notNull().default('[]'), // JSON array of op IDs\n\t\tschemaVersion: integer('schema_version').notNull(),\n\t\treceivedAt: integer('received_at').notNull(),\n\t},\n\t(table) => ({\n\t\tnodeSeqIdx: index('idx_node_seq').on(table.nodeId, table.sequenceNumber),\n\t\tcollectionIdx: index('idx_collection').on(table.collection),\n\t\treceivedIdx: index('idx_received').on(table.receivedAt),\n\t}),\n)\n\nexport const syncState = sqliteTable('sync_state', {\n\tnodeId: text('node_id').primaryKey(),\n\tmaxSequenceNumber: integer('max_sequence_number').notNull(),\n\tlastSeenAt: integer('last_seen_at').notNull(),\n})\n","import { SyncError } from '@korajs/core'\nimport type { MessageSerializer } from '@korajs/sync'\nimport type {\n\tServerCloseHandler,\n\tServerErrorHandler,\n\tServerMessageHandler,\n\tServerTransport,\n} from './server-transport'\n\nexport interface HttpPollResponse {\n\tstatus: 200 | 204 | 304 | 410\n\tbody?: string | Uint8Array\n\theaders?: Record<string, string>\n}\n\ninterface QueuedMessage {\n\tetag: string\n\tcontentType: string\n\tpayload: string | Uint8Array\n}\n\n/**\n * Server-side transport for HTTP long-polling clients.\n *\n * Incoming client messages are pushed via POST, while outbound server\n * messages are pulled via GET long-poll requests.\n */\nexport class HttpServerTransport implements ServerTransport {\n\tprivate readonly serializer: MessageSerializer\n\n\tprivate messageHandler: ServerMessageHandler | null = null\n\tprivate closeHandler: ServerCloseHandler | null = null\n\tprivate errorHandler: ServerErrorHandler | null = null\n\n\tprivate connected = true\n\tprivate nextSequence = 1\n\tprivate readonly queue: QueuedMessage[] = []\n\n\tconstructor(serializer: MessageSerializer) {\n\t\tthis.serializer = serializer\n\t}\n\n\tsend(message: import('@korajs/sync').SyncMessage): void {\n\t\tif (!this.connected) return\n\n\t\tconst encoded = this.serializer.encode(message)\n\t\tconst isBinary = encoded instanceof Uint8Array\n\t\tthis.queue.push({\n\t\t\tetag: this.makeEtag(this.nextSequence++),\n\t\t\tcontentType: isBinary ? 'application/x-protobuf' : 'application/json',\n\t\t\tpayload: encoded,\n\t\t})\n\t}\n\n\tonMessage(handler: ServerMessageHandler): void {\n\t\tthis.messageHandler = handler\n\t}\n\n\tonClose(handler: ServerCloseHandler): void {\n\t\tthis.closeHandler = handler\n\t}\n\n\tonError(handler: ServerErrorHandler): void {\n\t\tthis.errorHandler = handler\n\t}\n\n\tisConnected(): boolean {\n\t\treturn this.connected\n\t}\n\n\tclose(code = 1000, reason = 'transport closed'): void {\n\t\tif (!this.connected) return\n\t\tthis.connected = false\n\t\tthis.queue.length = 0\n\t\tthis.closeHandler?.(code, reason)\n\t}\n\n\treceive(payload: string | Uint8Array): void {\n\t\tif (!this.connected) {\n\t\t\tthrow new SyncError('HTTP server transport is closed')\n\t\t}\n\n\t\ttry {\n\t\t\tconst message = this.serializer.decode(payload)\n\t\t\tthis.messageHandler?.(message)\n\t\t} catch (error) {\n\t\t\tthis.errorHandler?.(error instanceof Error ? error : new Error(String(error)))\n\t\t}\n\t}\n\n\tpoll(ifNoneMatch?: string): HttpPollResponse {\n\t\tif (!this.connected) {\n\t\t\treturn { status: 410 }\n\t\t}\n\n\t\tconst next = this.queue[0]\n\t\tif (!next) {\n\t\t\treturn { status: 204 }\n\t\t}\n\n\t\tif (ifNoneMatch && ifNoneMatch === next.etag) {\n\t\t\treturn {\n\t\t\t\tstatus: 304,\n\t\t\t\theaders: { etag: next.etag },\n\t\t\t}\n\t\t}\n\n\t\tthis.queue.shift()\n\t\treturn {\n\t\t\tstatus: 200,\n\t\t\tbody: next.payload,\n\t\t\theaders: {\n\t\t\t\t'content-type': next.contentType,\n\t\t\t\tetag: next.etag,\n\t\t\t},\n\t\t}\n\t}\n\n\tprivate makeEtag(sequence: number): string {\n\t\treturn `W/\"${sequence}\"`\n\t}\n}\n","import { SyncError } from '@korajs/core'\nimport type { SyncMessage } from '@korajs/sync'\nimport { JsonMessageSerializer } from '@korajs/sync'\nimport type { MessageSerializer } from '@korajs/sync'\nimport type {\n\tServerCloseHandler,\n\tServerErrorHandler,\n\tServerMessageHandler,\n\tServerTransport,\n} from './server-transport'\n\n/** WebSocket ready states (mirrors ws constants) */\nconst WS_OPEN = 1\n\n/**\n * Minimal interface for a ws.WebSocket instance.\n * Allows dependency injection for testing without importing ws directly.\n */\nexport interface WsWebSocket {\n\treadyState: number\n\tsend(data: string | Uint8Array, callback?: (err?: Error) => void): void\n\tclose(code?: number, reason?: string): void\n\ton(event: string, listener: (...args: unknown[]) => void): void\n\tremoveAllListeners(): void\n}\n\n/**\n * Options for WsServerTransport.\n */\nexport interface WsServerTransportOptions {\n\t/** Message serializer. Defaults to JsonMessageSerializer. */\n\tserializer?: MessageSerializer\n}\n\n/**\n * Server-side transport wrapping a ws.WebSocket connection.\n * Created for each incoming client connection.\n */\nexport class WsServerTransport implements ServerTransport {\n\tprivate readonly ws: WsWebSocket\n\tprivate readonly serializer: MessageSerializer\n\tprivate messageHandler: ServerMessageHandler | null = null\n\tprivate closeHandler: ServerCloseHandler | null = null\n\tprivate errorHandler: ServerErrorHandler | null = null\n\n\tconstructor(ws: WsWebSocket, options?: WsServerTransportOptions) {\n\t\tthis.ws = ws\n\t\tthis.serializer = options?.serializer ?? new JsonMessageSerializer()\n\t\tthis.setupListeners()\n\t}\n\n\tsend(message: SyncMessage): void {\n\t\tif (this.ws.readyState !== WS_OPEN) {\n\t\t\tthrow new SyncError('Cannot send message: WebSocket is not open', {\n\t\t\t\treadyState: this.ws.readyState,\n\t\t\t\tmessageType: message.type,\n\t\t\t})\n\t\t}\n\n\t\tconst encoded = this.serializer.encode(message)\n\t\tthis.ws.send(encoded)\n\t}\n\n\tonMessage(handler: ServerMessageHandler): void {\n\t\tthis.messageHandler = handler\n\t}\n\n\tonClose(handler: ServerCloseHandler): void {\n\t\tthis.closeHandler = handler\n\t}\n\n\tonError(handler: ServerErrorHandler): void {\n\t\tthis.errorHandler = handler\n\t}\n\n\tisConnected(): boolean {\n\t\treturn this.ws.readyState === WS_OPEN\n\t}\n\n\tclose(code?: number, reason?: string): void {\n\t\tthis.ws.close(code ?? 1000, reason ?? 'server closing')\n\t}\n\n\tprivate setupListeners(): void {\n\t\tthis.ws.on('message', (data: unknown) => {\n\t\t\ttry {\n\t\t\t\tif (\n\t\t\t\t\ttypeof data !== 'string' &&\n\t\t\t\t\t!(data instanceof Uint8Array) &&\n\t\t\t\t\t!(data instanceof ArrayBuffer)\n\t\t\t\t) {\n\t\t\t\t\tthrow new SyncError('Unsupported WebSocket payload type', {\n\t\t\t\t\t\tpayloadType: typeof data,\n\t\t\t\t\t})\n\t\t\t\t}\n\n\t\t\t\tconst decoded = this.serializer.decode(data)\n\t\t\t\tthis.messageHandler?.(decoded)\n\t\t\t} catch (err) {\n\t\t\t\tthis.errorHandler?.(err instanceof Error ? err : new Error(String(err)))\n\t\t\t}\n\t\t})\n\n\t\tthis.ws.on('close', (code: unknown, reason: unknown) => {\n\t\t\tthis.closeHandler?.(Number(code) || 1006, String(reason || 'connection closed'))\n\t\t})\n\n\t\tthis.ws.on('error', (err: unknown) => {\n\t\t\tthis.errorHandler?.(err instanceof Error ? err : new Error(String(err)))\n\t\t})\n\t}\n}\n","import type { KoraEventEmitter, Operation } from '@korajs/core'\nimport { SyncError, generateUUIDv7 } from '@korajs/core'\nimport { topologicalSort } from '@korajs/core/internal'\nimport type {\n\tAwarenessUpdateMessage,\n\tHandshakeMessage,\n\tMessageSerializer,\n\tOperationBatchMessage,\n\tSyncMessage,\n\tWireFormat,\n} from '@korajs/sync'\nimport { NegotiatedMessageSerializer, versionVectorToWire, wireToVersionVector } from '@korajs/sync'\nimport { operationMatchesScopes } from '../scopes/server-scope-filter'\nimport type { ServerStore } from '../store/server-store'\nimport type { ServerTransport } from '../transport/server-transport'\nimport type { AuthContext, AuthProvider } from '../types'\n\nconst DEFAULT_BATCH_SIZE = 100\nconst DEFAULT_SCHEMA_VERSION = 1\n\n/**\n * Possible states for a client session.\n */\nexport type SessionState = 'connected' | 'authenticated' | 'syncing' | 'streaming' | 'closed'\n\n/**\n * Callback invoked when a session has new operations to relay to other sessions.\n */\nexport type RelayCallback = (sourceSessionId: string, operations: Operation[]) => void\n\n/**\n * Callback invoked when a session receives an awareness update to relay to other sessions.\n */\nexport type AwarenessRelayCallback = (\n\tsourceSessionId: string,\n\tmessage: AwarenessUpdateMessage,\n) => void\n\n/**\n * Options for creating a ClientSession.\n */\nexport interface ClientSessionOptions {\n\t/** Unique session identifier */\n\tsessionId: string\n\t/** Transport for this client connection */\n\ttransport: ServerTransport\n\t/** Server-side operation store */\n\tstore: ServerStore\n\t/** Authentication provider (optional) */\n\tauth?: AuthProvider\n\t/** Message serializer */\n\tserializer?: MessageSerializer\n\t/** Event emitter for DevTools integration */\n\temitter?: KoraEventEmitter\n\t/** Max operations per sync batch */\n\tbatchSize?: number\n\t/** Schema version the server expects */\n\tschemaVersion?: number\n\t/** Called when this session has operations to relay to other sessions */\n\tonRelay?: RelayCallback\n\t/** Called when this session receives an awareness update to broadcast */\n\tonAwarenessUpdate?: AwarenessRelayCallback\n\t/** Called when this session closes */\n\tonClose?: (sessionId: string) => void\n}\n\n/**\n * Handles the sync protocol for a single connected client.\n *\n * Lifecycle: connected → (authenticated) → syncing → streaming → closed\n *\n * The session:\n * 1. Receives a handshake from the client\n * 2. Authenticates if an AuthProvider is configured\n * 3. Sends back a HandshakeResponse with the server's version vector\n * 4. Computes and sends the server's delta to the client (paginated)\n * 5. Processes incoming operation batches from the client\n * 6. Transitions to streaming for real-time bidirectional sync\n * 7. Relays new operations to other sessions via the RelayCallback\n */\nexport class ClientSession {\n\tprivate state: SessionState = 'connected'\n\tprivate clientNodeId: string | null = null\n\tprivate authContext: AuthContext | null = null\n\n\tprivate readonly sessionId: string\n\tprivate readonly transport: ServerTransport\n\tprivate readonly store: ServerStore\n\tprivate readonly auth: AuthProvider | null\n\tprivate readonly serializer: MessageSerializer\n\tprivate readonly emitter: KoraEventEmitter | null\n\tprivate readonly batchSize: number\n\tprivate readonly schemaVersion: number\n\tprivate readonly onRelay: RelayCallback | null\n\tprivate readonly onAwarenessUpdate: AwarenessRelayCallback | null\n\tprivate readonly onClose: ((sessionId: string) => void) | null\n\n\tconstructor(options: ClientSessionOptions) {\n\t\tthis.sessionId = options.sessionId\n\t\tthis.transport = options.transport\n\t\tthis.store = options.store\n\t\tthis.auth = options.auth ?? null\n\t\tthis.serializer = options.serializer ?? new NegotiatedMessageSerializer('json')\n\t\tthis.emitter = options.emitter ?? null\n\t\tthis.batchSize = options.batchSize ?? DEFAULT_BATCH_SIZE\n\t\tthis.schemaVersion = options.schemaVersion ?? DEFAULT_SCHEMA_VERSION\n\t\tthis.onRelay = options.onRelay ?? null\n\t\tthis.onAwarenessUpdate = options.onAwarenessUpdate ?? null\n\t\tthis.onClose = options.onClose ?? null\n\t}\n\n\t/**\n\t * Start handling messages from the client transport.\n\t */\n\tstart(): void {\n\t\tthis.transport.onMessage((msg) => this.handleMessage(msg))\n\t\tthis.transport.onClose((_code, _reason) => this.handleTransportClose())\n\t\tthis.transport.onError((_err) => {\n\t\t\t// Transport errors during active session cause close\n\t\t\tif (this.state !== 'closed') {\n\t\t\t\tthis.handleTransportClose()\n\t\t\t}\n\t\t})\n\t}\n\n\t/**\n\t * Relay operations from another session to this client.\n\t * Only relays if the session is in streaming state and transport is connected.\n\t */\n\trelayOperations(operations: Operation[]): void {\n\t\tif (this.state !== 'streaming' || !this.transport.isConnected()) return\n\t\tif (operations.length === 0) return\n\n\t\tconst visibleOperations = operations.filter((op) =>\n\t\t\toperationMatchesScopes(op, this.authContext?.scopes),\n\t\t)\n\t\tif (visibleOperations.length === 0) return\n\n\t\tconst serializedOps = visibleOperations.map((op) => this.serializer.encodeOperation(op))\n\t\tconst msg: SyncMessage = {\n\t\t\ttype: 'operation-batch',\n\t\t\tmessageId: generateUUIDv7(),\n\t\t\toperations: serializedOps,\n\t\t\tisFinal: true,\n\t\t\tbatchIndex: 0,\n\t\t}\n\t\tthis.transport.send(msg)\n\t}\n\n\t/**\n\t * Close this session.\n\t */\n\tclose(reason?: string): void {\n\t\tif (this.state === 'closed') return\n\t\tthis.state = 'closed'\n\n\t\tif (this.transport.isConnected()) {\n\t\t\tthis.transport.close(1000, reason ?? 'session closed')\n\t\t}\n\n\t\tthis.onClose?.(this.sessionId)\n\t}\n\n\t// --- Getters ---\n\n\tgetState(): SessionState {\n\t\treturn this.state\n\t}\n\n\tgetSessionId(): string {\n\t\treturn this.sessionId\n\t}\n\n\tgetClientNodeId(): string | null {\n\t\treturn this.clientNodeId\n\t}\n\n\tgetAuthContext(): AuthContext | null {\n\t\treturn this.authContext\n\t}\n\n\tisStreaming(): boolean {\n\t\treturn this.state === 'streaming'\n\t}\n\n\t/**\n\t * Get the transport for this session.\n\t * Used by the awareness relay to send messages to this client.\n\t */\n\tgetTransport(): ServerTransport {\n\t\treturn this.transport\n\t}\n\n\t// --- Private protocol handlers ---\n\n\tprivate handleMessage(message: SyncMessage): void {\n\t\tswitch (message.type) {\n\t\t\tcase 'handshake':\n\t\t\t\tthis.handleHandshake(message)\n\t\t\t\tbreak\n\t\t\tcase 'operation-batch':\n\t\t\t\tthis.handleOperationBatch(message)\n\t\t\t\tbreak\n\t\t\t// Acknowledgments from clients are noted but no action needed on server\n\t\t\tcase 'acknowledgment':\n\t\t\t\tbreak\n\t\t\tcase 'error':\n\t\t\t\tbreak\n\t\t\tcase 'awareness-update':\n\t\t\t\tthis.handleAwarenessUpdate(message)\n\t\t\t\tbreak\n\t\t}\n\t}\n\n\tprivate async handleHandshake(msg: HandshakeMessage): Promise<void> {\n\t\t// Only accept handshake in 'connected' state (prevent duplicate handshakes)\n\t\tif (this.state !== 'connected') {\n\t\t\tthis.sendError('DUPLICATE_HANDSHAKE', 'Handshake already completed', false)\n\t\t\treturn\n\t\t}\n\n\t\tthis.clientNodeId = msg.nodeId\n\n\t\t// Authenticate if provider is configured\n\t\tif (this.auth) {\n\t\t\tconst token = msg.authToken ?? ''\n\t\t\tconst context = await this.auth.authenticate(token)\n\t\t\tif (!context) {\n\t\t\t\tthis.sendError('AUTH_FAILED', 'Authentication failed', false)\n\t\t\t\tthis.close('authentication failed')\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.authContext = context\n\t\t\tthis.state = 'authenticated'\n\t\t}\n\n\t\t// Merge handshake sync scopes with auth scopes.\n\t\t// Auth scopes take precedence (server-controlled).\n\t\t// Handshake scopes provide client-requested filtering.\n\t\tif (msg.syncScope) {\n\t\t\tconst mergedScopes = { ...msg.syncScope }\n\t\t\tif (this.authContext?.scopes) {\n\t\t\t\t// Auth scopes override handshake scopes per-collection\n\t\t\t\tfor (const [collection, authScope] of Object.entries(this.authContext.scopes)) {\n\t\t\t\t\tmergedScopes[collection] = { ...(mergedScopes[collection] ?? {}), ...authScope }\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (this.authContext) {\n\t\t\t\tthis.authContext = { ...this.authContext, scopes: mergedScopes }\n\t\t\t} else {\n\t\t\t\t// No auth provider, but scope was provided in handshake\n\t\t\t\tthis.authContext = { userId: msg.nodeId, scopes: mergedScopes }\n\t\t\t}\n\t\t}\n\n\t\t// Send handshake response with server's version vector and accepted scope\n\t\tconst serverVector = this.store.getVersionVector()\n\t\tconst selectedWireFormat = selectWireFormat(msg.supportedWireFormats)\n\t\tthis.setSerializerWireFormat(selectedWireFormat)\n\t\tconst response: SyncMessage = {\n\t\t\ttype: 'handshake-response',\n\t\t\tmessageId: generateUUIDv7(),\n\t\t\tnodeId: this.store.getNodeId(),\n\t\t\tversionVector: versionVectorToWire(serverVector),\n\t\t\tschemaVersion: this.schemaVersion,\n\t\t\taccepted: true,\n\t\t\tselectedWireFormat,\n\t\t\t// Confirm the accepted scope so the client knows what data will be synced.\n\t\t\t// This may differ from what the client requested if auth scopes are narrower.\n\t\t\t...(this.authContext?.scopes ? { acceptedScope: this.authContext.scopes } : {}),\n\t\t}\n\t\tthis.transport.send(response)\n\n\t\tthis.emitter?.emit({ type: 'sync:connected', nodeId: msg.nodeId })\n\n\t\t// Transition to syncing and send delta\n\t\tthis.state = 'syncing'\n\t\tconst clientVector = wireToVersionVector(msg.versionVector)\n\t\tawait this.sendDelta(clientVector)\n\n\t\t// Transition to streaming after delta is sent\n\t\tthis.state = 'streaming'\n\t}\n\n\tprivate async handleOperationBatch(msg: OperationBatchMessage): Promise<void> {\n\t\tconst operations = msg.operations.map((s) => this.serializer.decodeOperation(s))\n\t\tconst applied: Operation[] = []\n\t\tconst rejected: Operation[] = []\n\n\t\tfor (const op of operations) {\n\t\t\tif (!operationMatchesScopes(op, this.authContext?.scopes)) {\n\t\t\t\trejected.push(op)\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tconst result = await this.store.applyRemoteOperation(op)\n\t\t\tif (result === 'applied') {\n\t\t\t\tapplied.push(op)\n\t\t\t}\n\t\t}\n\n\t\t// Send scope violation errors for rejected operations so the client\n\t\t// knows its writes were rejected rather than silently dropped.\n\t\tif (rejected.length > 0) {\n\t\t\tfor (const op of rejected) {\n\t\t\t\tthis.sendError(\n\t\t\t\t\t'SCOPE_VIOLATION',\n\t\t\t\t\t`Operation \"${op.id}\" in collection \"${op.collection}\" is outside the client's sync scope`,\n\t\t\t\t\tfalse,\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\n\t\tif (operations.length > 0) {\n\t\t\tthis.emitter?.emit({\n\t\t\t\ttype: 'sync:received',\n\t\t\t\toperations,\n\t\t\t\tbatchSize: operations.length,\n\t\t\t})\n\t\t}\n\n\t\t// Send acknowledgment\n\t\tconst lastOp = operations[operations.length - 1]\n\t\tconst ack: SyncMessage = {\n\t\t\ttype: 'acknowledgment',\n\t\t\tmessageId: generateUUIDv7(),\n\t\t\tacknowledgedMessageId: msg.messageId,\n\t\t\tlastSequenceNumber: lastOp ? lastOp.sequenceNumber : 0,\n\t\t}\n\t\tthis.transport.send(ack)\n\n\t\t// Relay only newly applied operations to other sessions\n\t\tif (applied.length > 0) {\n\t\t\tthis.onRelay?.(this.sessionId, applied)\n\t\t}\n\t}\n\n\tprivate async sendDelta(clientVector: Map<string, number>): Promise<void> {\n\t\tconst serverVector = this.store.getVersionVector()\n\t\tconst missing: Operation[] = []\n\n\t\tfor (const [nodeId, serverSeq] of serverVector) {\n\t\t\tconst clientSeq = clientVector.get(nodeId) ?? 0\n\t\t\tif (serverSeq > clientSeq) {\n\t\t\t\tconst ops = await this.store.getOperationRange(nodeId, clientSeq + 1, serverSeq)\n\t\t\t\tconst visible = ops.filter((op) => operationMatchesScopes(op, this.authContext?.scopes))\n\t\t\t\tmissing.push(...visible)\n\t\t\t}\n\t\t}\n\n\t\tif (missing.length === 0) {\n\t\t\t// Send empty final batch to signal delta is complete\n\t\t\tconst emptyBatch: SyncMessage = {\n\t\t\t\ttype: 'operation-batch',\n\t\t\t\tmessageId: generateUUIDv7(),\n\t\t\t\toperations: [],\n\t\t\t\tisFinal: true,\n\t\t\t\tbatchIndex: 0,\n\t\t\t}\n\t\t\tthis.transport.send(emptyBatch)\n\t\t\treturn\n\t\t}\n\n\t\t// Sort causally and paginate\n\t\tconst sorted = topologicalSort(missing)\n\t\tconst totalBatches = Math.ceil(sorted.length / this.batchSize)\n\n\t\tfor (let i = 0; i < totalBatches; i++) {\n\t\t\tconst start = i * this.batchSize\n\t\t\tconst batchOps = sorted.slice(start, start + this.batchSize)\n\t\t\tconst serializedOps = batchOps.map((op) => this.serializer.encodeOperation(op))\n\n\t\t\tconst batchMsg: SyncMessage = {\n\t\t\t\ttype: 'operation-batch',\n\t\t\t\tmessageId: generateUUIDv7(),\n\t\t\t\toperations: serializedOps,\n\t\t\t\tisFinal: i === totalBatches - 1,\n\t\t\t\tbatchIndex: i,\n\t\t\t}\n\t\t\tthis.transport.send(batchMsg)\n\n\t\t\tthis.emitter?.emit({\n\t\t\t\ttype: 'sync:sent',\n\t\t\t\toperations: batchOps,\n\t\t\t\tbatchSize: batchOps.length,\n\t\t\t})\n\t\t}\n\t}\n\n\tprivate handleAwarenessUpdate(msg: AwarenessUpdateMessage): void {\n\t\t// Relay awareness updates to the server for broadcasting to other clients.\n\t\t// Awareness is purely ephemeral -- no persistence.\n\t\tthis.onAwarenessUpdate?.(this.sessionId, msg)\n\t}\n\n\tprivate sendError(code: string, message: string, retriable: boolean): void {\n\t\tconst errorMsg: SyncMessage = {\n\t\t\ttype: 'error',\n\t\t\tmessageId: generateUUIDv7(),\n\t\t\tcode,\n\t\t\tmessage,\n\t\t\tretriable,\n\t\t}\n\t\tthis.transport.send(errorMsg)\n\t}\n\n\tprivate setSerializerWireFormat(format: WireFormat): void {\n\t\tif (typeof this.serializer.setWireFormat === 'function') {\n\t\t\tthis.serializer.setWireFormat(format)\n\t\t}\n\t}\n\n\tprivate handleTransportClose(): void {\n\t\tif (this.state === 'closed') return\n\t\tthis.state = 'closed'\n\t\tthis.emitter?.emit({ type: 'sync:disconnected', reason: 'transport closed' })\n\t\tthis.onClose?.(this.sessionId)\n\t}\n}\n\nfunction selectWireFormat(supportedWireFormats?: WireFormat[]): WireFormat {\n\tif (supportedWireFormats?.includes('protobuf')) {\n\t\treturn 'protobuf'\n\t}\n\n\treturn 'json'\n}\n","import type { Operation } from '@korajs/core'\n\n/**\n * Per-collection scope map from auth context.\n */\nexport type ScopeMap = Record<string, Record<string, unknown>>\n\n/**\n * Returns true if an operation is visible to a session based on its scopes.\n *\n * Rules:\n * - No scopes configured => visible\n * - Collection missing from scope map => hidden\n * - All scoped field/value pairs must match the operation snapshot\n */\nexport function operationMatchesScopes(op: Operation, scopes: ScopeMap | undefined): boolean {\n\tif (!scopes) return true\n\n\tconst collectionScope = scopes[op.collection]\n\tif (!collectionScope) return false\n\n\tconst snapshot = buildSnapshot(op)\n\tif (!snapshot) return false\n\n\tfor (const [field, expected] of Object.entries(collectionScope)) {\n\t\tif (snapshot[field] !== expected) {\n\t\t\treturn false\n\t\t}\n\t}\n\n\treturn true\n}\n\nfunction buildSnapshot(op: Operation): Record<string, unknown> | null {\n\tconst previous = asRecord(op.previousData)\n\tconst next = asRecord(op.data)\n\n\tif (!previous && !next) return null\n\n\treturn {\n\t\t...(previous ?? {}),\n\t\t...(next ?? {}),\n\t}\n}\n\nfunction asRecord(value: unknown): Record<string, unknown> | null {\n\tif (typeof value !== 'object' || value === null || Array.isArray(value)) {\n\t\treturn null\n\t}\n\n\treturn value as Record<string, unknown>\n}\n","import type { KoraEventEmitter, Operation } from '@korajs/core'\nimport { SyncError, generateUUIDv7 } from '@korajs/core'\nimport type { AwarenessUpdateMessage, MessageSerializer } from '@korajs/sync'\nimport { JsonMessageSerializer } from '@korajs/sync'\nimport { AwarenessRelay } from '../awareness/awareness-relay'\nimport { ClientSession } from '../session/client-session'\nimport type { ServerStore } from '../store/server-store'\nimport { HttpServerTransport } from '../transport/http-server-transport'\nimport type { ServerTransport } from '../transport/server-transport'\nimport { WsServerTransport } from '../transport/ws-server-transport'\nimport type {\n\tAuthProvider,\n\tHttpSyncRequest,\n\tHttpSyncResponse,\n\tKoraSyncServerConfig,\n\tServerStatus,\n} from '../types'\n\nconst DEFAULT_MAX_CONNECTIONS = 0 // unlimited\nconst DEFAULT_BATCH_SIZE = 100\nconst DEFAULT_SCHEMA_VERSION = 1\nconst DEFAULT_HOST = '0.0.0.0'\nconst DEFAULT_PATH = '/'\n\n/**\n * Minimal interface for a ws.WebSocketServer instance.\n * Allows dependency injection for testing without importing ws directly.\n */\nexport interface WsServerLike {\n\ton(event: string, listener: (...args: unknown[]) => void): void\n\tclose(callback?: (err?: Error) => void): void\n\taddress(): { port: number } | string | null\n}\n\n/**\n * Constructor type for creating a WebSocket server.\n */\nexport type WsServerConstructor = new (options: {\n\tport?: number\n\thost?: string\n\tpath?: string\n}) => WsServerLike\n\n/**\n * Self-hosted sync server. Accepts WebSocket connections from clients,\n * handles the sync protocol, stores operations, and relays changes\n * between connected clients.\n *\n * Two modes of operation:\n * 1. **Standalone**: Call `start()` with a port — creates its own WebSocket server.\n * 2. **Attach**: Call `handleConnection(transport)` — attach to an existing HTTP server.\n */\nexport class KoraSyncServer {\n\tprivate readonly store: ServerStore\n\tprivate readonly auth: AuthProvider | null\n\tprivate readonly serializer: MessageSerializer\n\tprivate readonly emitter: KoraEventEmitter | null\n\tprivate readonly maxConnections: number\n\tprivate readonly batchSize: number\n\tprivate readonly schemaVersion: number\n\tprivate readonly port: number | undefined\n\tprivate readonly host: string\n\tprivate readonly path: string\n\n\tprivate readonly awarenessRelay = new AwarenessRelay()\n\tprivate readonly sessions = new Map<string, ClientSession>()\n\tprivate readonly httpClients = new Map<\n\t\tstring,\n\t\t{ sessionId: string; transport: HttpServerTransport }\n\t>()\n\tprivate readonly httpSessionToClient = new Map<string, string>()\n\tprivate wsServer: WsServerLike | null = null\n\tprivate running = false\n\n\tconstructor(config: KoraSyncServerConfig) {\n\t\tthis.store = config.store\n\t\tthis.auth = config.auth ?? null\n\t\tthis.serializer = config.serializer ?? new JsonMessageSerializer()\n\t\tthis.emitter = config.emitter ?? null\n\t\tthis.maxConnections = config.maxConnections ?? DEFAULT_MAX_CONNECTIONS\n\t\tthis.batchSize = config.batchSize ?? DEFAULT_BATCH_SIZE\n\t\tthis.schemaVersion = config.schemaVersion ?? DEFAULT_SCHEMA_VERSION\n\t\tthis.port = config.port\n\t\tthis.host = config.host ?? DEFAULT_HOST\n\t\tthis.path = config.path ?? DEFAULT_PATH\n\t}\n\n\t/**\n\t * Start the WebSocket server in standalone mode.\n\t *\n\t * @param wsServerImpl - Optional WebSocket server constructor for testing\n\t */\n\tasync start(wsServerImpl?: WsServerConstructor): Promise<void> {\n\t\tif (this.running) {\n\t\t\tthrow new SyncError('Server is already running', { port: this.port })\n\t\t}\n\n\t\tif (!wsServerImpl && this.port === undefined) {\n\t\t\tthrow new SyncError(\n\t\t\t\t'Port is required for standalone mode. Provide port in config or use handleConnection() for attach mode.',\n\t\t\t\t{},\n\t\t\t)\n\t\t}\n\n\t\tif (wsServerImpl) {\n\t\t\tthis.wsServer = new wsServerImpl({\n\t\t\t\tport: this.port,\n\t\t\t\thost: this.host,\n\t\t\t\tpath: this.path,\n\t\t\t})\n\t\t} else {\n\t\t\t// Dynamic import of ws — only needed in standalone mode\n\t\t\tconst { WebSocketServer } = await import('ws')\n\t\t\tthis.wsServer = new WebSocketServer({\n\t\t\t\tport: this.port,\n\t\t\t\thost: this.host,\n\t\t\t\tpath: this.path,\n\t\t\t})\n\t\t}\n\n\t\tthis.wsServer.on('connection', (ws: unknown) => {\n\t\t\tconst transport = new WsServerTransport(\n\t\t\t\tws as import('../transport/ws-server-transport').WsWebSocket,\n\t\t\t\t{\n\t\t\t\t\tserializer: this.serializer,\n\t\t\t\t},\n\t\t\t)\n\t\t\tthis.handleConnection(transport)\n\t\t})\n\n\t\tthis.running = true\n\t}\n\n\t/**\n\t * Stop the server. Closes all sessions and the WebSocket server.\n\t */\n\tasync stop(): Promise<void> {\n\t\t// Clean up awareness relay\n\t\tthis.awarenessRelay.clear()\n\n\t\t// Close all active sessions (works in both standalone and attach mode)\n\t\tfor (const session of this.sessions.values()) {\n\t\t\tsession.close('server shutting down')\n\t\t}\n\t\tthis.sessions.clear()\n\t\tthis.httpClients.clear()\n\t\tthis.httpSessionToClient.clear()\n\n\t\t// Close WebSocket server (standalone mode only)\n\t\tif (this.wsServer) {\n\t\t\tawait new Promise<void>((resolve) => {\n\t\t\t\tthis.wsServer?.close(() => resolve())\n\t\t\t})\n\t\t\tthis.wsServer = null\n\t\t}\n\n\t\tthis.running = false\n\t}\n\n\t/**\n\t * Handle one HTTP sync request for a long-polling client.\n\t *\n\t * A stable `clientId` identifies the logical connection across requests.\n\t */\n\tasync handleHttpRequest(request: HttpSyncRequest): Promise<HttpSyncResponse> {\n\t\tif (!request.clientId || request.clientId.trim().length === 0) {\n\t\t\treturn { status: 400 }\n\t\t}\n\n\t\tconst client = this.getOrCreateHttpClient(request.clientId)\n\n\t\tif (request.method === 'POST') {\n\t\t\tif (request.body === undefined) {\n\t\t\t\treturn { status: 400 }\n\t\t\t}\n\n\t\t\tconst payload = normalizeHttpBody(request.body, request.contentType)\n\t\t\tclient.transport.receive(payload)\n\t\t\treturn { status: 202 }\n\t\t}\n\n\t\tif (request.method === 'GET') {\n\t\t\tconst polled = client.transport.poll(request.ifNoneMatch)\n\t\t\treturn {\n\t\t\t\tstatus: polled.status,\n\t\t\t\tbody: polled.body,\n\t\t\t\theaders: polled.headers,\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\tstatus: 405,\n\t\t\theaders: { allow: 'GET, POST' },\n\t\t}\n\t}\n\n\t/**\n\t * Handle an incoming client connection (attach mode).\n\t * Creates a new ClientSession for the transport.\n\t *\n\t * @param transport - The server transport for the new connection\n\t * @returns The session ID\n\t */\n\thandleConnection(transport: ServerTransport): string {\n\t\t// Check max connections\n\t\tif (this.maxConnections > 0 && this.sessions.size >= this.maxConnections) {\n\t\t\ttransport.send({\n\t\t\t\ttype: 'error',\n\t\t\t\tmessageId: generateUUIDv7(),\n\t\t\t\tcode: 'MAX_CONNECTIONS',\n\t\t\t\tmessage: `Server has reached maximum connections (${this.maxConnections})`,\n\t\t\t\tretriable: true,\n\t\t\t})\n\t\t\ttransport.close(4029, 'max connections reached')\n\t\t\tthrow new SyncError('Maximum connections reached', {\n\t\t\t\tcurrent: this.sessions.size,\n\t\t\t\tmax: this.maxConnections,\n\t\t\t})\n\t\t}\n\n\t\tconst sessionId = generateUUIDv7()\n\n\t\tconst session = new ClientSession({\n\t\t\tsessionId,\n\t\t\ttransport,\n\t\t\tstore: this.store,\n\t\t\tauth: this.auth ?? undefined,\n\t\t\tserializer: this.serializer,\n\t\t\temitter: this.emitter ?? undefined,\n\t\t\tbatchSize: this.batchSize,\n\t\t\tschemaVersion: this.schemaVersion,\n\t\t\tonRelay: (sourceSessionId, operations) => {\n\t\t\t\tthis.handleRelay(sourceSessionId, operations)\n\t\t\t},\n\t\t\tonAwarenessUpdate: (sourceSessionId, message) => {\n\t\t\t\tthis.handleAwarenessRelay(sourceSessionId, message)\n\t\t\t},\n\t\t\tonClose: (sid) => {\n\t\t\t\tthis.handleSessionClose(sid)\n\t\t\t},\n\t\t})\n\n\t\tthis.sessions.set(sessionId, session)\n\t\tsession.start()\n\n\t\treturn sessionId\n\t}\n\n\t/**\n\t * Get the current server status.\n\t */\n\tasync getStatus(): Promise<ServerStatus> {\n\t\treturn {\n\t\t\trunning: this.running,\n\t\t\tconnectedClients: this.sessions.size,\n\t\t\tport: this.port ?? null,\n\t\t\ttotalOperations: await this.store.getOperationCount(),\n\t\t}\n\t}\n\n\t/**\n\t * Get the number of currently connected clients.\n\t */\n\tgetConnectionCount(): number {\n\t\treturn this.sessions.size\n\t}\n\n\t// --- Private ---\n\n\tprivate handleRelay(sourceSessionId: string, operations: Operation[]): void {\n\t\tfor (const [sessionId, session] of this.sessions) {\n\t\t\tif (sessionId === sourceSessionId) continue\n\t\t\tsession.relayOperations(operations)\n\t\t}\n\t}\n\n\tprivate handleSessionClose(sessionId: string): void {\n\t\t// Clean up awareness state for this session and notify remaining clients\n\t\tthis.awarenessRelay.removeClient(sessionId)\n\n\t\tthis.sessions.delete(sessionId)\n\n\t\tconst clientId = this.httpSessionToClient.get(sessionId)\n\t\tif (clientId) {\n\t\t\tthis.httpSessionToClient.delete(sessionId)\n\t\t\tthis.httpClients.delete(clientId)\n\t\t}\n\t}\n\n\tprivate handleAwarenessRelay(\n\t\tsourceSessionId: string,\n\t\tmessage: AwarenessUpdateMessage,\n\t): void {\n\t\t// Register client with awareness relay if not already done\n\t\tconst session = this.sessions.get(sourceSessionId)\n\t\tif (!session) return\n\n\t\tconst transport = session.getTransport()\n\t\tif (!this.awarenessRelay.getClientCount() || !transport) {\n\t\t\t// First awareness update from this client -- register\n\t\t}\n\t\tthis.awarenessRelay.addClient(sourceSessionId, message.clientId, transport)\n\t\tthis.awarenessRelay.handleUpdate(sourceSessionId, message)\n\t}\n\n\tprivate getOrCreateHttpClient(clientId: string): {\n\t\tsessionId: string\n\t\ttransport: HttpServerTransport\n\t} {\n\t\tconst existing = this.httpClients.get(clientId)\n\t\tif (existing) {\n\t\t\treturn existing\n\t\t}\n\n\t\tconst transport = new HttpServerTransport(this.serializer)\n\t\tconst sessionId = this.handleConnection(transport)\n\t\tconst client = { sessionId, transport }\n\n\t\tthis.httpClients.set(clientId, client)\n\t\tthis.httpSessionToClient.set(sessionId, clientId)\n\n\t\treturn client\n\t}\n}\n\nfunction normalizeHttpBody(body: string | Uint8Array, contentType?: string): string | Uint8Array {\n\tif (body instanceof Uint8Array) {\n\t\treturn body\n\t}\n\n\tif (contentType?.includes('application/x-protobuf')) {\n\t\treturn new TextEncoder().encode(body)\n\t}\n\n\treturn body\n}\n","import { generateUUIDv7 } from '@korajs/core'\nimport type { AwarenessStateWire, AwarenessUpdateMessage, SyncMessage } from '@korajs/sync'\nimport type { ServerTransport } from '../transport/server-transport'\n\n/**\n * Tracks a single client's awareness registration.\n */\ninterface AwarenessClient {\n\t/** Session ID for this client */\n\tsessionId: string\n\t/** Client-assigned awareness ID (numeric, unique per client) */\n\tclientId: number\n\t/** Transport for sending messages to this client */\n\ttransport: ServerTransport\n\t/** Current awareness state, if any */\n\tstate: AwarenessStateWire | null\n}\n\n/**\n * Server-side awareness relay. Broadcasts ephemeral awareness states\n * (cursor positions, user presence) between connected clients.\n *\n * Awareness data is never persisted. The relay simply forwards awareness\n * updates from one client to all other connected clients, and broadcasts\n * removal notifications when a client disconnects.\n */\nexport class AwarenessRelay {\n\tprivate readonly clients = new Map<string, AwarenessClient>()\n\n\t/**\n\t * Register a client for awareness broadcasting.\n\t *\n\t * @param sessionId - Unique session identifier\n\t * @param clientId - Client-assigned awareness ID\n\t * @param transport - Transport for sending messages to this client\n\t */\n\taddClient(sessionId: string, clientId: number, transport: ServerTransport): void {\n\t\tthis.clients.set(sessionId, {\n\t\t\tsessionId,\n\t\t\tclientId,\n\t\t\ttransport,\n\t\t\tstate: null,\n\t\t})\n\n\t\t// Send this client all existing awareness states so it catches up\n\t\tconst existingStates: Record<string, AwarenessStateWire | null> = {}\n\t\tlet hasStates = false\n\t\tfor (const [, client] of this.clients) {\n\t\t\tif (client.sessionId === sessionId) continue\n\t\t\tif (client.state) {\n\t\t\t\texistingStates[String(client.clientId)] = client.state\n\t\t\t\thasStates = true\n\t\t\t}\n\t\t}\n\n\t\tif (hasStates) {\n\t\t\tconst catchUpMsg: SyncMessage = {\n\t\t\t\ttype: 'awareness-update',\n\t\t\t\tmessageId: generateUUIDv7(),\n\t\t\t\tclientId: 0, // Server-sourced\n\t\t\t\tstates: existingStates,\n\t\t\t}\n\t\t\ttransport.send(catchUpMsg)\n\t\t}\n\t}\n\n\t/**\n\t * Remove a client and broadcast its removal to all remaining clients.\n\t *\n\t * @param sessionId - Session ID of the disconnecting client\n\t */\n\tremoveClient(sessionId: string): void {\n\t\tconst client = this.clients.get(sessionId)\n\t\tif (!client) return\n\n\t\tthis.clients.delete(sessionId)\n\n\t\t// Only broadcast removal if the client had an awareness state\n\t\tif (client.state === null) return\n\n\t\tconst removalStates: Record<string, AwarenessStateWire | null> = {\n\t\t\t[String(client.clientId)]: null,\n\t\t}\n\n\t\tconst msg: SyncMessage = {\n\t\t\ttype: 'awareness-update',\n\t\t\tmessageId: generateUUIDv7(),\n\t\t\tclientId: client.clientId,\n\t\t\tstates: removalStates,\n\t\t}\n\n\t\tthis.broadcastExcept(sessionId, msg)\n\t}\n\n\t/**\n\t * Handle an incoming awareness update from a client.\n\t * Stores the state and relays to all other connected clients.\n\t *\n\t * @param sessionId - Session ID of the sending client\n\t * @param message - The awareness update message\n\t */\n\thandleUpdate(sessionId: string, message: AwarenessUpdateMessage): void {\n\t\tconst sender = this.clients.get(sessionId)\n\t\tif (!sender) return\n\n\t\t// Update stored state for this client\n\t\tconst senderState = message.states[String(message.clientId)]\n\t\tif (senderState !== undefined) {\n\t\t\tsender.state = senderState\n\t\t}\n\n\t\t// Relay to all other clients\n\t\tthis.broadcastExcept(sessionId, message)\n\t}\n\n\t/**\n\t * Get the number of registered awareness clients.\n\t */\n\tgetClientCount(): number {\n\t\treturn this.clients.size\n\t}\n\n\t/**\n\t * Remove all clients and clear all state.\n\t */\n\tclear(): void {\n\t\tthis.clients.clear()\n\t}\n\n\t// --- Private ---\n\n\tprivate broadcastExcept(excludeSessionId: string, message: SyncMessage): void {\n\t\tfor (const [, client] of this.clients) {\n\t\t\tif (client.sessionId === excludeSessionId) continue\n\t\t\tif (!client.transport.isConnected()) continue\n\n\t\t\tclient.transport.send(message)\n\t\t}\n\t}\n}\n","import type { AuthContext, AuthProvider } from '../types'\n\n/**\n * Auth provider that accepts all connections.\n * Returns a default anonymous context for any token.\n * Useful for development and testing.\n */\nexport class NoAuthProvider implements AuthProvider {\n\tasync authenticate(_token: string): Promise<AuthContext> {\n\t\treturn { userId: 'anonymous' }\n\t}\n}\n","import type { AuthContext, AuthProvider } from '../types'\n\n/**\n * Options for creating a TokenAuthProvider.\n */\nexport interface TokenAuthProviderOptions {\n\t/**\n\t * Validate a token and return an AuthContext if valid, or null if rejected.\n\t * This is where you implement your auth logic (JWT verification, database lookup, etc.).\n\t */\n\tvalidate: (token: string) => Promise<AuthContext | null>\n}\n\n/**\n * Token-based auth provider that delegates validation to a user-provided function.\n *\n * @example\n * ```typescript\n * const auth = new TokenAuthProvider({\n * validate: async (token) => {\n * const user = await verifyJWT(token)\n * return user ? { userId: user.id } : null\n * }\n * })\n * ```\n */\nexport class TokenAuthProvider implements AuthProvider {\n\tprivate readonly validate: (token: string) => Promise<AuthContext | null>\n\n\tconstructor(options: TokenAuthProviderOptions) {\n\t\tthis.validate = options.validate\n\t}\n\n\tasync authenticate(token: string): Promise<AuthContext | null> {\n\t\treturn this.validate(token)\n\t}\n}\n","import type { AuthContext, AuthProvider } from '../types'\n\n/**\n * Validates a Kora auth JWT and returns identity claims.\n * This interface matches the signature of TokenManager.validateToken()\n * from @korajs/auth without requiring a direct import.\n */\ninterface TokenValidator {\n\tvalidateToken(token: string): {\n\t\tsub: string\n\t\tdev: string\n\t\ttype: string\n\t} | null\n}\n\n/**\n * Looks up a user by ID. Returns null if the user doesn't exist.\n * This interface matches InMemoryUserStore.findById() from @korajs/auth\n * without requiring a direct import.\n */\ninterface UserLookup {\n\tfindById(userId: string): Promise<{\n\t\tid: string\n\t\temail: string\n\t\tname: string\n\t} | null>\n}\n\n/**\n * Optional device touch callback for updating last-seen timestamps.\n */\ninterface DeviceToucher {\n\ttouchDevice(deviceId: string): Promise<void>\n}\n\n/**\n * Configuration for creating a KoraAuthProvider.\n */\nexport interface KoraAuthProviderOptions {\n\t/**\n\t * Token validator that verifies JWT signatures and returns claims.\n\t * Typically a `TokenManager` instance from `@korajs/auth/server`.\n\t */\n\ttokenValidator: TokenValidator\n\n\t/**\n\t * User lookup for verifying the user still exists.\n\t * Typically an `InMemoryUserStore` instance from `@korajs/auth/server`.\n\t */\n\tuserLookup: UserLookup\n\n\t/**\n\t * Optional device tracker for updating last-seen timestamps.\n\t * Typically the same `InMemoryUserStore` if it implements `touchDevice`.\n\t */\n\tdeviceTracker?: DeviceToucher\n\n\t/**\n\t * Optional scope resolver. Called with the user ID to determine\n\t * which collections/records the user can sync.\n\t */\n\tresolveScopes?: (userId: string) => Promise<Record<string, Record<string, unknown>>>\n}\n\n/**\n * Auth provider that bridges `@korajs/auth` token management with the\n * sync server's authentication layer.\n *\n * Validates access tokens issued by `@korajs/auth`'s `TokenManager`,\n * verifies the user still exists, and optionally computes per-user\n * sync scopes. This is the recommended way to connect @korajs/auth\n * to @korajs/server.\n *\n * @example\n * ```typescript\n * import { TokenManager, InMemoryUserStore } from '@korajs/auth/server'\n * import { KoraAuthProvider, KoraSyncServer } from '@korajs/server'\n *\n * const tokenManager = new TokenManager({ secret: 'my-secret' })\n * const userStore = new InMemoryUserStore()\n *\n * const auth = new KoraAuthProvider({\n * tokenValidator: tokenManager,\n * userLookup: userStore,\n * deviceTracker: userStore,\n * resolveScopes: async (userId) => ({\n * forms: { userId },\n * responses: { formOwnerId: userId },\n * }),\n * })\n *\n * const server = new KoraSyncServer({ store, auth })\n * ```\n */\nexport class KoraAuthProvider implements AuthProvider {\n\tprivate readonly tokenValidator: TokenValidator\n\tprivate readonly userLookup: UserLookup\n\tprivate readonly deviceTracker: DeviceToucher | undefined\n\tprivate readonly resolveScopes:\n\t\t| ((userId: string) => Promise<Record<string, Record<string, unknown>>>)\n\t\t| undefined\n\n\tconstructor(options: KoraAuthProviderOptions) {\n\t\tthis.tokenValidator = options.tokenValidator\n\t\tthis.userLookup = options.userLookup\n\t\tthis.deviceTracker = options.deviceTracker\n\t\tthis.resolveScopes = options.resolveScopes\n\t}\n\n\tasync authenticate(token: string): Promise<AuthContext | null> {\n\t\t// Validate the JWT signature and expiration\n\t\tconst payload = this.tokenValidator.validateToken(token)\n\t\tif (payload === null) {\n\t\t\treturn null\n\t\t}\n\n\t\t// Only accept access tokens for sync authentication\n\t\tif (payload.type !== 'access') {\n\t\t\treturn null\n\t\t}\n\n\t\t// Verify the user still exists (may have been deleted since token was issued)\n\t\tconst user = await this.userLookup.findById(payload.sub)\n\t\tif (user === null) {\n\t\t\treturn null\n\t\t}\n\n\t\t// Update device last-seen timestamp\n\t\tif (this.deviceTracker) {\n\t\t\tawait this.deviceTracker.touchDevice(payload.dev)\n\t\t}\n\n\t\t// Compute sync scopes if a resolver is configured\n\t\tconst scopes = this.resolveScopes ? await this.resolveScopes(payload.sub) : undefined\n\n\t\treturn {\n\t\t\tuserId: payload.sub,\n\t\t\tscopes,\n\t\t\tmetadata: {\n\t\t\t\tdeviceId: payload.dev,\n\t\t\t\temail: user.email,\n\t\t\t\tname: user.name,\n\t\t\t},\n\t\t}\n\t}\n}\n","import type { AuthContext, AuthProvider } from '../types'\n\n/**\n * Configuration for creating a MixedAuthProvider.\n */\nexport interface MixedAuthProviderOptions {\n\t/**\n\t * Primary auth provider that validates tokens from authenticated users.\n\t * Typically a `KoraAuthProvider`, `TokenAuthProvider`, or the result of\n\t * `authRoutes.toSyncAuthProvider()`.\n\t */\n\tprimary: AuthProvider\n\n\t/**\n\t * Scopes to apply to anonymous connections.\n\t * Each key is a collection name; the value is a filter object\n\t * (use `{}` for unrestricted access to that collection).\n\t *\n\t * @example\n\t * ```typescript\n\t * // Anonymous users can only sync the 'responses' collection\n\t * anonymousScopes: { responses: {} }\n\t *\n\t * // Anonymous users can read published forms\n\t * anonymousScopes: { forms: { status: 'published' } }\n\t * ```\n\t */\n\tanonymousScopes: Record<string, Record<string, unknown>>\n\n\t/**\n\t * Prefix for generated anonymous user IDs.\n\t * A unique suffix is appended to each connection.\n\t * @default 'anon'\n\t */\n\tanonymousPrefix?: string\n}\n\n/**\n * Auth provider that supports both authenticated and anonymous connections.\n *\n * When a client connects with a valid token, the primary auth provider\n * handles authentication normally. When a client connects without a token\n * (or with an invalid one), the connection is accepted as anonymous with\n * restricted sync scopes.\n *\n * This is the recommended pattern for apps that need public data access\n * alongside authenticated users — for example, a form builder where\n * authenticated users create forms but anyone can submit responses.\n *\n * @example\n * ```typescript\n * import { MixedAuthProvider, KoraAuthProvider } from '@korajs/server'\n *\n * const auth = new MixedAuthProvider({\n * primary: authRoutes.toSyncAuthProvider(),\n * anonymousScopes: {\n * // Anonymous users can only sync the 'responses' collection\n * responses: {},\n * },\n * })\n *\n * const server = new KoraSyncServer({ store, auth })\n * ```\n *\n * @example\n * ```typescript\n * // On the client, return an empty token for unauthenticated users:\n * const app = createApp({\n * schema,\n * sync: {\n * url: 'wss://my-server.com/kora',\n * auth: async () => ({\n * token: (await authClient.getAccessToken()) ?? '',\n * }),\n * },\n * })\n * ```\n */\nexport class MixedAuthProvider implements AuthProvider {\n\tprivate readonly primary: AuthProvider\n\tprivate readonly anonymousScopes: Record<string, Record<string, unknown>>\n\tprivate readonly anonymousPrefix: string\n\tprivate anonymousCounter = 0\n\n\tconstructor(options: MixedAuthProviderOptions) {\n\t\tthis.primary = options.primary\n\t\tthis.anonymousScopes = options.anonymousScopes\n\t\tthis.anonymousPrefix = options.anonymousPrefix ?? 'anon'\n\t}\n\n\tasync authenticate(token: string): Promise<AuthContext> {\n\t\t// Try authenticated path first when a token is provided\n\t\tif (token) {\n\t\t\tconst ctx = await this.primary.authenticate(token)\n\t\t\tif (ctx) return ctx\n\t\t}\n\n\t\t// Fall back to scoped anonymous access\n\t\tthis.anonymousCounter++\n\t\treturn {\n\t\t\tuserId: `${this.anonymousPrefix}-${Date.now()}-${this.anonymousCounter}`,\n\t\t\tscopes: this.anonymousScopes,\n\t\t}\n\t}\n}\n","import type { KoraSyncServerConfig } from '../types'\nimport { KoraSyncServer } from './kora-sync-server'\n\n/**\n * Factory function to create a KoraSyncServer.\n *\n * @param config - Server configuration\n * @returns A new KoraSyncServer instance\n *\n * @example\n * ```typescript\n * const server = createKoraServer({\n * store: new MemoryServerStore(),\n * port: 3000,\n * })\n * await server.start()\n * ```\n */\nexport function createKoraServer(config: KoraSyncServerConfig): KoraSyncServer {\n\treturn new KoraSyncServer(config)\n}\n","import type { ServerStore } from '../store/server-store'\nimport { WsServerTransport } from '../transport/ws-server-transport'\nimport type { KoraSyncServerConfig } from '../types'\nimport { KoraSyncServer } from './kora-sync-server'\n\n/**\n * Configuration for the production server that serves both\n * static files and WebSocket sync on a single port.\n */\nexport interface ProductionServerConfig {\n\t/** Server-side operation store */\n\tstore: ServerStore\n\t/** Port to listen on. Defaults to 3001 or process.env.PORT. */\n\tport?: number\n\t/** Directory containing built static files. Defaults to './dist'. */\n\tstaticDir?: string\n\t/** WebSocket sync path. Defaults to '/kora-sync'. */\n\tsyncPath?: string\n\t/** Additional KoraSyncServer options */\n\tsyncOptions?: Omit<KoraSyncServerConfig, 'store' | 'port' | 'host' | 'path'>\n}\n\n/**\n * A production server handle returned by createProductionServer.\n */\nexport interface ProductionServer {\n\t/** Start listening. Returns the URL the server is available at. */\n\tstart(): Promise<string>\n\t/** Stop the server gracefully. */\n\tstop(): Promise<void>\n}\n\n// MIME types for static file serving\nconst MIME_TYPES: Record<string, string> = {\n\t'.html': 'text/html',\n\t'.js': 'text/javascript',\n\t'.css': 'text/css',\n\t'.json': 'application/json',\n\t'.png': 'image/png',\n\t'.jpg': 'image/jpeg',\n\t'.svg': 'image/svg+xml',\n\t'.ico': 'image/x-icon',\n\t'.wasm': 'application/wasm',\n\t'.woff': 'font/woff',\n\t'.woff2': 'font/woff2',\n\t'.map': 'application/json',\n}\n\n/**\n * Creates a production server that serves both static files and WebSocket sync\n * on a single port. This is the recommended way to deploy a Kora app — one port\n * means one tunnel (ngrok, cloudflared) handles everything.\n *\n * @param config - Production server configuration\n * @returns A ProductionServer instance\n *\n * @example\n * ```typescript\n * import { createProductionServer, createSqliteServerStore } from '@korajs/server'\n *\n * const server = createProductionServer({\n * store: createSqliteServerStore({ filename: './kora-server.db' }),\n * })\n *\n * const url = await server.start()\n * console.log(`App running at ${url}`)\n * ```\n */\nexport function createProductionServer(config: ProductionServerConfig): ProductionServer {\n\tconst port = config.port ?? (Number(process.env.PORT) || 3001)\n\tconst staticDir = config.staticDir ?? './dist'\n\tconst syncPath = config.syncPath ?? '/kora-sync'\n\n\tconst syncServer = new KoraSyncServer({\n\t\tstore: config.store,\n\t\t...config.syncOptions,\n\t})\n\n\tlet httpServer: import('node:http').Server | null = null\n\n\treturn {\n\t\tasync start(): Promise<string> {\n\t\t\tconst { createServer } = await import('node:http')\n\t\t\tconst { createReadStream, existsSync, statSync } = await import('node:fs')\n\t\t\tconst { extname, join, resolve } = await import('node:path')\n\t\t\tconst { WebSocketServer } = await import('ws')\n\n\t\t\tconst distDir = resolve(staticDir)\n\n\t\t\thttpServer = createServer((req, res) => {\n\t\t\t\t// COOP/COEP headers required for SharedArrayBuffer (OPFS persistence)\n\t\t\t\tres.setHeader('Cross-Origin-Opener-Policy', 'same-origin')\n\t\t\t\tres.setHeader('Cross-Origin-Embedder-Policy', 'require-corp')\n\n\t\t\t\tconst url = new URL(req.url || '/', `http://${req.headers.host}`)\n\n\t\t\t\t// Health check endpoint (required by AWS ALB/ECS/Lightsail, GCP, etc.)\n\t\t\t\tif (url.pathname === '/health') {\n\t\t\t\t\tres.writeHead(200, { 'Content-Type': 'application/json' })\n\t\t\t\t\tres.end(JSON.stringify({ status: 'ok', timestamp: Date.now() }))\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\tlet filePath = join(distDir, url.pathname)\n\n\t\t\t\t// SPA fallback: serve index.html for non-file routes\n\t\t\t\tif (!extname(filePath)) {\n\t\t\t\t\tconst indexPath = join(filePath, 'index.html')\n\t\t\t\t\tif (existsSync(indexPath)) {\n\t\t\t\t\t\tfilePath = indexPath\n\t\t\t\t\t} else {\n\t\t\t\t\t\tfilePath = join(distDir, 'index.html')\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (!existsSync(filePath)) {\n\t\t\t\t\tfilePath = join(distDir, 'index.html')\n\t\t\t\t}\n\n\t\t\t\ttry {\n\t\t\t\t\tconst stat = statSync(filePath)\n\t\t\t\t\tif (stat.isDirectory()) {\n\t\t\t\t\t\tfilePath = join(filePath, 'index.html')\n\t\t\t\t\t}\n\t\t\t\t} catch {\n\t\t\t\t\tfilePath = join(distDir, 'index.html')\n\t\t\t\t}\n\n\t\t\t\tif (!existsSync(filePath)) {\n\t\t\t\t\tres.writeHead(404)\n\t\t\t\t\tres.end('Not Found')\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\tconst ext = extname(filePath)\n\t\t\t\tconst contentType = MIME_TYPES[ext] || 'application/octet-stream'\n\t\t\t\tres.writeHead(200, { 'Content-Type': contentType })\n\t\t\t\tcreateReadStream(filePath).pipe(res)\n\t\t\t})\n\n\t\t\tconst wss = new WebSocketServer({ noServer: true })\n\n\t\t\thttpServer.on('upgrade', (req, socket, head) => {\n\t\t\t\tconst url = new URL(req.url || '/', `http://${req.headers.host}`)\n\t\t\t\tif (url.pathname === syncPath) {\n\t\t\t\t\twss.handleUpgrade(req, socket, head, (ws) => {\n\t\t\t\t\t\tconst transport = new WsServerTransport(ws)\n\t\t\t\t\t\tsyncServer.handleConnection(transport)\n\t\t\t\t\t})\n\t\t\t\t} else {\n\t\t\t\t\tsocket.destroy()\n\t\t\t\t}\n\t\t\t})\n\n\t\t\treturn new Promise<string>((resolve) => {\n\t\t\t\thttpServer?.listen(port, '0.0.0.0', () => {\n\t\t\t\t\tresolve(`http://localhost:${port}`)\n\t\t\t\t})\n\t\t\t})\n\t\t},\n\n\t\tasync stop(): Promise<void> {\n\t\t\tawait syncServer.stop()\n\t\t\tif (httpServer) {\n\t\t\t\tawait new Promise<void>((resolve) => {\n\t\t\t\t\thttpServer?.close(() => resolve())\n\t\t\t\t})\n\t\t\t\thttpServer = null\n\t\t\t}\n\t\t},\n\t}\n}\n"],"mappings":"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","names":["count","generateUUIDv7","generateUUIDv7","generateUUIDv7","and","asc","between","count","eq","sql","index","integer","text","generateUUIDv7","sql","and","eq","between","asc","count","SyncError","generateUUIDv7","operations","generateUUIDv7","SyncError","generateUUIDv7","JsonMessageSerializer","generateUUIDv7","DEFAULT_BATCH_SIZE","DEFAULT_SCHEMA_VERSION","JsonMessageSerializer","SyncError","generateUUIDv7","operations","resolve"]}
|