@korajs/server 0.1.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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/store/memory-server-store.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/server/create-server.ts"],"sourcesContent":["// @korajs/server — public API\n// Every export here is a public API commitment. Be explicit.\n\n// === Types ===\nexport type {\n\tAuthContext,\n\tAuthProvider,\n\tHttpSyncRequest,\n\tHttpSyncResponse,\n\tKoraSyncServerConfig,\n\tServerStatus,\n} from './types'\n\nexport type { ServerStore } from './store/server-store'\n\nexport type {\n\tServerCloseHandler,\n\tServerErrorHandler,\n\tServerMessageHandler,\n\tServerTransport,\n} from './transport/server-transport'\n\nexport type {\n\tHttpPollResponse,\n} from './transport/http-server-transport'\n\nexport type {\n\tWsWebSocket,\n\tWsServerTransportOptions,\n} from './transport/ws-server-transport'\n\nexport type {\n\tClientSessionOptions,\n\tRelayCallback,\n\tSessionState,\n} from './session/client-session'\n\nexport type {\n\tWsServerConstructor,\n\tWsServerLike,\n} from './server/kora-sync-server'\n\nexport type { TokenAuthProviderOptions } from './auth/token-auth'\n\n// === Classes ===\nexport { MemoryServerStore } from './store/memory-server-store'\nexport { PostgresServerStore } from './store/postgres-server-store'\nexport { SqliteServerStore } from './store/sqlite-server-store'\nexport { HttpServerTransport } from './transport/http-server-transport'\nexport { WsServerTransport } from './transport/ws-server-transport'\nexport { ClientSession } from './session/client-session'\nexport { KoraSyncServer } from './server/kora-sync-server'\nexport { NoAuthProvider } from './auth/no-auth'\nexport { TokenAuthProvider } from './auth/token-auth'\n\n// === Factory Functions ===\nexport { createKoraServer } from './server/create-server'\nexport { createPostgresServerStore } from './store/postgres-server-store'\nexport { createSqliteServerStore } from './store/sqlite-server-store'\n","import type { Operation, VersionVector } from '@korajs/core'\nimport { generateUUIDv7 } from '@korajs/core'\nimport type { ApplyResult } from '@korajs/sync'\nimport type { 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 */\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 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 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\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 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\tprivate assertOpen(): void {\n\t\tif (this.closed) {\n\t\t\tthrow new Error('MemoryServerStore is closed')\n\t\t}\n\t}\n}\n","import type { Operation, VersionVector } from '@korajs/core'\nimport { generateUUIDv7 } from '@korajs/core'\nimport type { ApplyResult } from '@korajs/sync'\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 type { 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 * DDL stays as raw SQL via Drizzle's sql template (standard practice without drizzle-kit).\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 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 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\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 close(): Promise<void> {\n\t\tthis.closed = true\n\t}\n\n\tprivate async initialize(): Promise<void> {\n\t\tawait this.ensureTables()\n\n\t\t// Hydrate in-memory version vector cache via Drizzle query\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\t/**\n\t * Create tables if they don't exist.\n\t * Uses raw SQL via Drizzle's sql template — standard DDL practice without drizzle-kit.\n\t */\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 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\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\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 INTEGER NOT NULL\n\t\t\t)\n\t\t`)\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\tprivate assertOpen(): void {\n\t\tif (this.closed) {\n\t\t\tthrow new Error('PostgresServerStore is closed')\n\t\t}\n\t}\n}\n\n/**\n * Creates a PostgresServerStore from a PostgreSQL connection string.\n *\n * Uses runtime dynamic imports so projects that do not use PostgreSQL\n * do not need to install `postgres`. Wraps the postgres client with\n * Drizzle ORM for typed query building.\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 { 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: 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_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: integer('last_seen_at').notNull(),\n})\n","import type { Operation, VersionVector } from '@korajs/core'\nimport { generateUUIDv7 } from '@korajs/core'\nimport type { ApplyResult } from '@korajs/sync'\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 type { ServerStore } from './server-store'\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 */\nexport class SqliteServerStore implements ServerStore {\n\tprivate readonly nodeId: string\n\tprivate readonly db: BetterSQLite3Database\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 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\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\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 close(): Promise<void> {\n\t\tthis.closed = true\n\t}\n\n\t/**\n\t * Create the operations and sync_state tables if they don't exist.\n\t * Uses raw SQL via Drizzle's sql template — standard practice for DDL without drizzle-kit.\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\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\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\tprivate assertOpen(): void {\n\t\tif (this.closed) {\n\t\t\tthrow new Error('SqliteServerStore is closed')\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 * const server = createKoraServer({ store, port: 3001 })\n * ```\n */\nexport function createSqliteServerStore(options: {\n\tfilename?: string\n\tnodeId?: string\n}): SqliteServerStore {\n\t// Dynamic imports avoided — better-sqlite3 is synchronous and Node-only.\n\t// Consumer is responsible for having better-sqlite3 installed.\n\t// eslint-disable-next-line @typescript-eslint/no-require-imports\n\tconst Database = require('better-sqlite3')\n\tconst { drizzle } = require('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 { 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"],"mappings":"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","names":["import_core","import_core","import_drizzle_orm","import_core","import_core","import_core","import_sync","operations","import_core","import_sync","DEFAULT_BATCH_SIZE","DEFAULT_SCHEMA_VERSION","operations"]}