lakesync 0.1.8 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapter-types-DwsQGQS4.d.ts +94 -0
- package/dist/adapter.d.ts +23 -49
- package/dist/adapter.js +9 -4
- package/dist/analyst.js +1 -1
- package/dist/{base-poller-Bj9kX9dv.d.ts → base-poller-Y7ORYgUv.d.ts} +2 -0
- package/dist/catalogue.js +2 -2
- package/dist/{chunk-LDFFCG2K.js → chunk-4SG66H5K.js} +44 -31
- package/dist/chunk-4SG66H5K.js.map +1 -0
- package/dist/{chunk-LPWXOYNS.js → chunk-C4KD6YKP.js} +59 -43
- package/dist/chunk-C4KD6YKP.js.map +1 -0
- package/dist/{chunk-JI4C4R5H.js → chunk-FIIHPQMQ.js} +196 -118
- package/dist/chunk-FIIHPQMQ.js.map +1 -0
- package/dist/{chunk-TMLG32QV.js → chunk-U2NV4DUX.js} +2 -2
- package/dist/{chunk-QNITY4F6.js → chunk-XVP5DJJ7.js} +16 -13
- package/dist/{chunk-QNITY4F6.js.map → chunk-XVP5DJJ7.js.map} +1 -1
- package/dist/{chunk-KVSWLIJR.js → chunk-YHYBLU6W.js} +2 -2
- package/dist/{chunk-PYRS74YP.js → chunk-ZNY4DSFU.js} +16 -13
- package/dist/{chunk-PYRS74YP.js.map → chunk-ZNY4DSFU.js.map} +1 -1
- package/dist/{chunk-SSICS5KI.js → chunk-ZU7RC7CT.js} +2 -2
- package/dist/client.d.ts +28 -10
- package/dist/client.js +150 -29
- package/dist/client.js.map +1 -1
- package/dist/compactor.d.ts +1 -1
- package/dist/compactor.js +3 -3
- package/dist/connector-jira.d.ts +13 -3
- package/dist/connector-jira.js +6 -2
- package/dist/connector-salesforce.d.ts +13 -3
- package/dist/connector-salesforce.js +6 -2
- package/dist/{coordinator-NXy6tA0h.d.ts → coordinator-eGmZMnJ_.d.ts} +99 -16
- package/dist/create-poller-Cc2MGfhh.d.ts +55 -0
- package/dist/factory-DFfR-030.d.ts +33 -0
- package/dist/gateway-server.d.ts +398 -95
- package/dist/gateway-server.js +743 -56
- package/dist/gateway-server.js.map +1 -1
- package/dist/gateway.d.ts +14 -8
- package/dist/gateway.js +6 -5
- package/dist/index.d.ts +45 -73
- package/dist/index.js +5 -3
- package/dist/parquet.js +2 -2
- package/dist/proto.js +2 -2
- package/dist/react.d.ts +3 -3
- package/dist/{registry-BcspAtZI.d.ts → registry-Dd8JuW8T.d.ts} +1 -1
- package/dist/{request-handler-pUvL7ozF.d.ts → request-handler-B1I5xDOx.d.ts} +71 -27
- package/dist/{src-ROW4XLO7.js → src-WU7IBVC4.js} +6 -4
- package/dist/{types-BrcD1oJg.d.ts → types-D2C9jTbL.d.ts} +33 -23
- package/package.json +1 -1
- package/dist/auth-CAVutXzx.d.ts +0 -30
- package/dist/chunk-JI4C4R5H.js.map +0 -1
- package/dist/chunk-LDFFCG2K.js.map +0 -1
- package/dist/chunk-LPWXOYNS.js.map +0 -1
- package/dist/db-types-CfLMUBfW.d.ts +0 -29
- package/dist/src-B6NLV3FP.js +0 -27
- package/dist/src-ROW4XLO7.js.map +0 -1
- package/dist/src-ZRHKG42A.js +0 -25
- package/dist/src-ZRHKG42A.js.map +0 -1
- package/dist/types-DSC_EiwR.d.ts +0 -45
- /package/dist/{chunk-TMLG32QV.js.map → chunk-U2NV4DUX.js.map} +0 -0
- /package/dist/{chunk-KVSWLIJR.js.map → chunk-YHYBLU6W.js.map} +0 -0
- /package/dist/{chunk-SSICS5KI.js.map → chunk-ZU7RC7CT.js.map} +0 -0
- /package/dist/{src-B6NLV3FP.js.map → src-WU7IBVC4.js.map} +0 -0
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../gateway/src/action-dispatcher.ts","../../gateway/src/buffer.ts","../../gateway/src/config-store.ts","../../gateway/src/constants.ts","../../gateway/src/flush.ts","../../gateway/src/flush-coordinator.ts","../../gateway/src/source-registry.ts","../../gateway/src/gateway.ts","../../gateway/src/validation.ts","../../gateway/src/request-handler.ts","../../gateway/src/schema-manager.ts"],"sourcesContent":["import type {\n\tAction,\n\tActionDescriptor,\n\tActionDiscovery,\n\tActionExecutionError,\n\tActionHandler,\n\tActionPush,\n\tActionResponse,\n\tActionResult,\n\tActionValidationError,\n\tAuthContext,\n\tHLCTimestamp,\n\tResult,\n} from \"@lakesync/core\";\nimport { Err, Ok, validateAction } from \"@lakesync/core\";\n\n/** Default maximum number of cached action results. */\nconst DEFAULT_MAX_CACHE_SIZE = 10_000;\n\n/** Default TTL for idempotency cache entries (5 minutes). */\nconst DEFAULT_CACHE_TTL_MS = 5 * 60 * 1000;\n\n/** Configuration for ActionDispatcher caches. */\nexport interface ActionCacheConfig {\n\t/** Maximum number of entries in the executed actions set and idempotency map. */\n\tmaxSize?: number;\n\t/** Time-to-live for idempotency entries in milliseconds. */\n\tttlMs?: number;\n}\n\n/** Cached action result with a timestamp for TTL eviction. */\ninterface CachedResult {\n\tvalue: ActionResult | { actionId: string; code: string; message: string; retryable: boolean };\n\tcachedAt: number;\n}\n\n/**\n * Dispatches imperative actions to registered handlers.\n *\n * Manages idempotency via actionId deduplication and idempotencyKey mapping.\n * Caches are bounded by max size and TTL to prevent unbounded growth.\n * Completely decoupled from the HLC clock — takes a callback for timestamp generation.\n */\nexport class ActionDispatcher {\n\tprivate actionHandlers: Map<string, ActionHandler> = new Map();\n\tprivate executedActions: Set<string> = new Set();\n\tprivate idempotencyMap: Map<string, CachedResult> = new Map();\n\tprivate readonly maxCacheSize: number;\n\tprivate readonly cacheTtlMs: number;\n\n\tconstructor(handlers?: Record<string, ActionHandler>, cacheConfig?: ActionCacheConfig) {\n\t\tif (handlers) {\n\t\t\tfor (const [name, handler] of Object.entries(handlers)) {\n\t\t\t\tthis.actionHandlers.set(name, handler);\n\t\t\t}\n\t\t}\n\t\tthis.maxCacheSize = cacheConfig?.maxSize ?? DEFAULT_MAX_CACHE_SIZE;\n\t\tthis.cacheTtlMs = cacheConfig?.ttlMs ?? DEFAULT_CACHE_TTL_MS;\n\t}\n\n\t/**\n\t * Dispatch an action push to registered handlers.\n\t *\n\t * Iterates over actions, dispatches each to the registered ActionHandler\n\t * by connector name. Supports idempotency via actionId deduplication and\n\t * idempotencyKey mapping.\n\t *\n\t * @param msg - The action push containing one or more actions.\n\t * @param hlcNow - Callback to get the current server HLC timestamp.\n\t * @param context - Optional auth context for permission checks.\n\t * @returns A `Result` containing results for each action.\n\t */\n\tasync dispatch(\n\t\tmsg: ActionPush,\n\t\thlcNow: () => HLCTimestamp,\n\t\tcontext?: AuthContext,\n\t): Promise<Result<ActionResponse, ActionValidationError>> {\n\t\t// Sweep expired and over-limit entries before processing\n\t\tthis.evictStaleEntries();\n\n\t\tconst results: Array<\n\t\t\tActionResult | { actionId: string; code: string; message: string; retryable: boolean }\n\t\t> = [];\n\n\t\tfor (const action of msg.actions) {\n\t\t\t// Structural validation\n\t\t\tconst validation = validateAction(action);\n\t\t\tif (!validation.ok) {\n\t\t\t\treturn Err(validation.error);\n\t\t\t}\n\n\t\t\t// Idempotency — check actionId\n\t\t\tif (this.executedActions.has(action.actionId)) {\n\t\t\t\tconst cached = this.getCachedResult(action.actionId);\n\t\t\t\tif (cached) {\n\t\t\t\t\tresults.push(cached);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t// Already executed but no cached result — skip\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// Idempotency — check idempotencyKey\n\t\t\tif (action.idempotencyKey) {\n\t\t\t\tconst cached = this.getCachedResult(`idem:${action.idempotencyKey}`);\n\t\t\t\tif (cached) {\n\t\t\t\t\tresults.push(cached);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Resolve handler\n\t\t\tconst handler = this.actionHandlers.get(action.connector);\n\t\t\tif (!handler) {\n\t\t\t\tconst errorResult = {\n\t\t\t\t\tactionId: action.actionId,\n\t\t\t\t\tcode: \"ACTION_NOT_SUPPORTED\",\n\t\t\t\t\tmessage: `No action handler registered for connector \"${action.connector}\"`,\n\t\t\t\t\tretryable: false,\n\t\t\t\t};\n\t\t\t\tresults.push(errorResult);\n\t\t\t\tthis.cacheActionResult(action, errorResult);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// Check action type is supported\n\t\t\tconst supported = handler.supportedActions.some((d) => d.actionType === action.actionType);\n\t\t\tif (!supported) {\n\t\t\t\tconst errorResult = {\n\t\t\t\t\tactionId: action.actionId,\n\t\t\t\t\tcode: \"ACTION_NOT_SUPPORTED\",\n\t\t\t\t\tmessage: `Action type \"${action.actionType}\" not supported by connector \"${action.connector}\"`,\n\t\t\t\t\tretryable: false,\n\t\t\t\t};\n\t\t\t\tresults.push(errorResult);\n\t\t\t\tthis.cacheActionResult(action, errorResult);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// Execute\n\t\t\tconst execResult = await handler.executeAction(action, context);\n\t\t\tif (execResult.ok) {\n\t\t\t\tresults.push(execResult.value);\n\t\t\t\tthis.cacheActionResult(action, execResult.value);\n\t\t\t} else {\n\t\t\t\tconst err = execResult.error;\n\t\t\t\tconst errorResult = {\n\t\t\t\t\tactionId: action.actionId,\n\t\t\t\t\tcode: err.code,\n\t\t\t\t\tmessage: err.message,\n\t\t\t\t\tretryable: \"retryable\" in err ? (err as ActionExecutionError).retryable : false,\n\t\t\t\t};\n\t\t\t\tresults.push(errorResult);\n\t\t\t\t// Only cache non-retryable errors — retryable errors should be retried\n\t\t\t\tif (!errorResult.retryable) {\n\t\t\t\t\tthis.cacheActionResult(action, errorResult);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconst serverHlc = hlcNow();\n\t\treturn Ok({ results, serverHlc });\n\t}\n\n\t/**\n\t * Register a named action handler.\n\t *\n\t * @param name - Connector name (matches `Action.connector`).\n\t * @param handler - The action handler to register.\n\t */\n\tregisterHandler(name: string, handler: ActionHandler): void {\n\t\tthis.actionHandlers.set(name, handler);\n\t}\n\n\t/**\n\t * Unregister a named action handler.\n\t *\n\t * @param name - The connector name to remove.\n\t */\n\tunregisterHandler(name: string): void {\n\t\tthis.actionHandlers.delete(name);\n\t}\n\n\t/**\n\t * List all registered action handler names.\n\t *\n\t * @returns Array of registered connector names.\n\t */\n\tlistHandlers(): string[] {\n\t\treturn [...this.actionHandlers.keys()];\n\t}\n\n\t/**\n\t * Describe all registered action handlers and their supported actions.\n\t *\n\t * Returns a map of connector name to its {@link ActionDescriptor} array,\n\t * enabling frontend discovery of available actions.\n\t *\n\t * @returns An {@link ActionDiscovery} object listing connectors and their actions.\n\t */\n\tdescribe(): ActionDiscovery {\n\t\tconst connectors: Record<string, ActionDescriptor[]> = {};\n\t\tfor (const [name, handler] of this.actionHandlers) {\n\t\t\tconnectors[name] = handler.supportedActions;\n\t\t}\n\t\treturn { connectors };\n\t}\n\n\t/** Cache an action result for idempotency deduplication. */\n\tprivate cacheActionResult(\n\t\taction: Action,\n\t\tresult: ActionResult | { actionId: string; code: string; message: string; retryable: boolean },\n\t): void {\n\t\tconst entry: CachedResult = { value: result, cachedAt: Date.now() };\n\t\tthis.executedActions.add(action.actionId);\n\t\tthis.idempotencyMap.set(action.actionId, entry);\n\t\tif (action.idempotencyKey) {\n\t\t\tthis.idempotencyMap.set(`idem:${action.idempotencyKey}`, entry);\n\t\t}\n\t}\n\n\t/** Get a cached result if it exists and hasn't expired. */\n\tprivate getCachedResult(\n\t\tkey: string,\n\t):\n\t\t| ActionResult\n\t\t| { actionId: string; code: string; message: string; retryable: boolean }\n\t\t| undefined {\n\t\tconst entry = this.idempotencyMap.get(key);\n\t\tif (!entry) return undefined;\n\t\tif (Date.now() - entry.cachedAt > this.cacheTtlMs) {\n\t\t\tthis.idempotencyMap.delete(key);\n\t\t\treturn undefined;\n\t\t}\n\t\treturn entry.value;\n\t}\n\n\t/** Evict expired entries and trim to max size. */\n\tprivate evictStaleEntries(): void {\n\t\tconst now = Date.now();\n\n\t\t// Evict expired entries\n\t\tfor (const [key, entry] of this.idempotencyMap) {\n\t\t\tif (now - entry.cachedAt > this.cacheTtlMs) {\n\t\t\t\tthis.idempotencyMap.delete(key);\n\t\t\t\t// Also remove from executedActions if it's an actionId (not idem: prefixed)\n\t\t\t\tif (!key.startsWith(\"idem:\")) {\n\t\t\t\t\tthis.executedActions.delete(key);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Trim to max size — remove oldest entries first\n\t\tif (this.executedActions.size > this.maxCacheSize) {\n\t\t\tconst excess = this.executedActions.size - this.maxCacheSize;\n\t\t\tlet removed = 0;\n\t\t\tfor (const actionId of this.executedActions) {\n\t\t\t\tif (removed >= excess) break;\n\t\t\t\tthis.executedActions.delete(actionId);\n\t\t\t\tthis.idempotencyMap.delete(actionId);\n\t\t\t\tremoved++;\n\t\t\t}\n\t\t}\n\t}\n}\n","import type { HLCTimestamp, RowDelta, RowKey } from \"@lakesync/core\";\nimport { HLC, rowKey } from \"@lakesync/core\";\n\n/** Estimated base overhead per delta entry (metadata fields: deltaId, table, rowId, clientId, op + HLC bigint). */\nconst BASE_DELTA_OVERHEAD = 8 + 8 + 8 + 8 + 1;\n\n/**\n * Estimate the byte size of a single column value.\n * Uses type-aware heuristics as a proxy for in-memory size.\n */\nfunction estimateValueBytes(value: unknown): number {\n\tif (value === null || value === undefined) return 4;\n\tswitch (typeof value) {\n\t\tcase \"boolean\":\n\t\t\treturn 4;\n\t\tcase \"number\":\n\t\t\treturn 8;\n\t\tcase \"bigint\":\n\t\t\treturn 8;\n\t\tcase \"string\":\n\t\t\treturn (value as string).length * 2; // UTF-16\n\t\tdefault:\n\t\t\t// Objects, arrays — use JSON.stringify as proxy\n\t\t\ttry {\n\t\t\t\treturn JSON.stringify(value).length;\n\t\t\t} catch {\n\t\t\t\treturn 100; // fallback for circular refs etc.\n\t\t\t}\n\t}\n}\n\n/** Estimate the byte size of a RowDelta. */\nfunction estimateDeltaBytes(delta: RowDelta): number {\n\tlet bytes = BASE_DELTA_OVERHEAD;\n\tbytes += delta.deltaId.length;\n\tbytes += delta.table.length * 2;\n\tbytes += delta.rowId.length * 2;\n\tbytes += delta.clientId.length * 2;\n\tfor (const col of delta.columns) {\n\t\tbytes += col.column.length * 2; // column name\n\t\tbytes += estimateValueBytes(col.value); // column value\n\t}\n\treturn bytes;\n}\n\n/**\n * Dual-structure delta buffer.\n *\n * Maintains an append-only log for event streaming (pull) and flush,\n * plus a row-level index for O(1) conflict resolution lookups.\n */\nexport class DeltaBuffer {\n\tprivate log: RowDelta[] = [];\n\tprivate index: Map<RowKey, RowDelta> = new Map();\n\tprivate deltaIds = new Set<string>();\n\tprivate estimatedBytes = 0;\n\tprivate createdAt: number = Date.now();\n\tprivate tableBytes = new Map<string, number>();\n\tprivate tableLog = new Map<string, RowDelta[]>();\n\n\t/** Append a delta to the log and upsert the index (post-conflict-resolution). */\n\tappend(delta: RowDelta): void {\n\t\tthis.log.push(delta);\n\t\tconst key = rowKey(delta.table, delta.rowId);\n\t\tthis.index.set(key, delta);\n\t\tthis.deltaIds.add(delta.deltaId);\n\t\tconst bytes = estimateDeltaBytes(delta);\n\t\tthis.estimatedBytes += bytes;\n\t\t// Per-table tracking\n\t\tthis.tableBytes.set(delta.table, (this.tableBytes.get(delta.table) ?? 0) + bytes);\n\t\tconst tableEntries = this.tableLog.get(delta.table);\n\t\tif (tableEntries) {\n\t\t\ttableEntries.push(delta);\n\t\t} else {\n\t\t\tthis.tableLog.set(delta.table, [delta]);\n\t\t}\n\t}\n\n\t/** Get the current merged state for a row (for conflict resolution). */\n\tgetRow(key: RowKey): RowDelta | undefined {\n\t\treturn this.index.get(key);\n\t}\n\n\t/** Check if a delta with this ID already exists in the log (for idempotency). */\n\thasDelta(deltaId: string): boolean {\n\t\treturn this.deltaIds.has(deltaId);\n\t}\n\n\t/** Return change events from the log since a given HLC. */\n\tgetEventsSince(hlc: HLCTimestamp, limit: number): { deltas: RowDelta[]; hasMore: boolean } {\n\t\tlet lo = 0;\n\t\tlet hi = this.log.length;\n\t\twhile (lo < hi) {\n\t\t\tconst mid = (lo + hi) >>> 1;\n\t\t\tif (HLC.compare(this.log[mid]!.hlc, hlc) <= 0) {\n\t\t\t\tlo = mid + 1;\n\t\t\t} else {\n\t\t\t\thi = mid;\n\t\t\t}\n\t\t}\n\t\tconst hasMore = this.log.length - lo > limit;\n\t\treturn { deltas: this.log.slice(lo, lo + limit), hasMore };\n\t}\n\n\t/** Check if the buffer should be flushed based on size or age thresholds. */\n\tshouldFlush(config: { maxBytes: number; maxAgeMs: number }): boolean {\n\t\tif (this.log.length === 0) return false;\n\t\treturn this.estimatedBytes >= config.maxBytes || Date.now() - this.createdAt >= config.maxAgeMs;\n\t}\n\n\t/** Per-table buffer statistics. */\n\ttableStats(): Array<{ table: string; byteSize: number; deltaCount: number }> {\n\t\tconst stats: Array<{ table: string; byteSize: number; deltaCount: number }> = [];\n\t\tfor (const [table, bytes] of this.tableBytes) {\n\t\t\tstats.push({\n\t\t\t\ttable,\n\t\t\t\tbyteSize: bytes,\n\t\t\t\tdeltaCount: this.tableLog.get(table)?.length ?? 0,\n\t\t\t});\n\t\t}\n\t\treturn stats;\n\t}\n\n\t/** Drain only the specified table's deltas, leaving other tables intact. */\n\tdrainTable(table: string): RowDelta[] {\n\t\tconst tableDeltas = this.tableLog.get(table) ?? [];\n\t\tif (tableDeltas.length === 0) return [];\n\n\t\t// Remove from main log\n\t\tthis.log = this.log.filter((d) => d.table !== table);\n\n\t\t// Remove from index and deltaIds\n\t\tfor (const delta of tableDeltas) {\n\t\t\tthis.index.delete(rowKey(delta.table, delta.rowId));\n\t\t\tthis.deltaIds.delete(delta.deltaId);\n\t\t}\n\n\t\t// Adjust byte tracking\n\t\tconst tableByteSize = this.tableBytes.get(table) ?? 0;\n\t\tthis.estimatedBytes -= tableByteSize;\n\t\tthis.tableBytes.delete(table);\n\t\tthis.tableLog.delete(table);\n\n\t\treturn tableDeltas;\n\t}\n\n\t/**\n\t * Snapshot the current buffer state without clearing it.\n\t *\n\t * Useful for inspecting the buffer contents without draining.\n\t * Use {@link clear} separately after a successful flush for\n\t * transactional semantics.\n\t */\n\tsnapshot(): { entries: RowDelta[]; byteSize: number } {\n\t\treturn { entries: [...this.log], byteSize: this.estimatedBytes };\n\t}\n\n\t/** Clear all buffer state. */\n\tclear(): void {\n\t\tthis.log = [];\n\t\tthis.index.clear();\n\t\tthis.deltaIds.clear();\n\t\tthis.estimatedBytes = 0;\n\t\tthis.createdAt = Date.now();\n\t\tthis.tableBytes.clear();\n\t\tthis.tableLog.clear();\n\t}\n\n\t/** Drain the log for flush. Returns log entries and clears both structures. */\n\tdrain(): RowDelta[] {\n\t\tconst { entries } = this.snapshot();\n\t\tthis.clear();\n\t\treturn entries;\n\t}\n\n\t/** Number of log entries */\n\tget logSize(): number {\n\t\treturn this.log.length;\n\t}\n\n\t/** Number of unique rows in the index */\n\tget indexSize(): number {\n\t\treturn this.index.size;\n\t}\n\n\t/** Estimated byte size of the buffer */\n\tget byteSize(): number {\n\t\treturn this.estimatedBytes;\n\t}\n\n\t/** Average byte size per delta in the buffer (0 if empty). */\n\tget averageDeltaBytes(): number {\n\t\treturn this.log.length === 0 ? 0 : this.estimatedBytes / this.log.length;\n\t}\n}\n","import type { ConnectorConfig, SyncRulesConfig, TableSchema } from \"@lakesync/core\";\n\n/**\n * Platform-agnostic configuration storage interface.\n *\n * Implemented by MemoryConfigStore (tests, gateway-server) and\n * DurableStorageConfigStore (gateway-worker).\n */\nexport interface ConfigStore {\n\tgetSchema(gatewayId: string): Promise<TableSchema | undefined>;\n\tsetSchema(gatewayId: string, schema: TableSchema): Promise<void>;\n\tgetSyncRules(gatewayId: string): Promise<SyncRulesConfig | undefined>;\n\tsetSyncRules(gatewayId: string, rules: SyncRulesConfig): Promise<void>;\n\tgetConnectors(): Promise<Record<string, ConnectorConfig>>;\n\tsetConnectors(connectors: Record<string, ConnectorConfig>): Promise<void>;\n}\n\n/**\n * In-memory implementation of ConfigStore.\n * Used by tests and gateway-server.\n */\nexport class MemoryConfigStore implements ConfigStore {\n\tprivate schemas = new Map<string, TableSchema>();\n\tprivate syncRules = new Map<string, SyncRulesConfig>();\n\tprivate connectors: Record<string, ConnectorConfig> = {};\n\n\tasync getSchema(gatewayId: string): Promise<TableSchema | undefined> {\n\t\treturn this.schemas.get(gatewayId);\n\t}\n\n\tasync setSchema(gatewayId: string, schema: TableSchema): Promise<void> {\n\t\tthis.schemas.set(gatewayId, schema);\n\t}\n\n\tasync getSyncRules(gatewayId: string): Promise<SyncRulesConfig | undefined> {\n\t\treturn this.syncRules.get(gatewayId);\n\t}\n\n\tasync setSyncRules(gatewayId: string, rules: SyncRulesConfig): Promise<void> {\n\t\tthis.syncRules.set(gatewayId, rules);\n\t}\n\n\tasync getConnectors(): Promise<Record<string, ConnectorConfig>> {\n\t\treturn { ...this.connectors };\n\t}\n\n\tasync setConnectors(connectors: Record<string, ConnectorConfig>): Promise<void> {\n\t\tthis.connectors = { ...connectors };\n\t}\n}\n","import { COLUMN_TYPES } from \"@lakesync/core\";\n\n/** Maximum push payload size (1 MiB). */\nexport const MAX_PUSH_PAYLOAD_BYTES = 1_048_576;\n\n/** Maximum number of deltas allowed in a single push. */\nexport const MAX_DELTAS_PER_PUSH = 10_000;\n\n/** Maximum number of deltas returned in a single pull. */\nexport const MAX_PULL_LIMIT = 10_000;\n\n/** Default number of deltas returned in a pull when no limit is specified. */\nexport const DEFAULT_PULL_LIMIT = 100;\n\n/** Allowed column types for schema validation. Derived from core COLUMN_TYPES. */\nexport const VALID_COLUMN_TYPES: ReadonlySet<string> = new Set(COLUMN_TYPES);\n\n/** Default maximum buffer size before triggering flush (4 MiB). */\nexport const DEFAULT_MAX_BUFFER_BYTES = 4 * 1024 * 1024;\n\n/** Default maximum buffer age before triggering flush (30 seconds). */\nexport const DEFAULT_MAX_BUFFER_AGE_MS = 30_000;\n","import {\n\ttype DatabaseAdapter,\n\tisDatabaseAdapter,\n\tisMaterialisable,\n\ttype LakeAdapter,\n} from \"@lakesync/adapter\";\nimport {\n\tbuildPartitionSpec,\n\ttype DataFile,\n\tlakeSyncTableName,\n\ttype NessieCatalogueClient,\n\ttableSchemaToIceberg,\n} from \"@lakesync/catalogue\";\nimport {\n\tErr,\n\tFlushError,\n\tHLC,\n\ttype HLCTimestamp,\n\tOk,\n\ttype Result,\n\ttype RowDelta,\n\ttype TableSchema,\n\ttoError,\n} from \"@lakesync/core\";\nimport { writeDeltasToParquet } from \"@lakesync/parquet\";\nimport { bigintReplacer } from \"./json\";\nimport type { FlushEnvelope } from \"./types\";\n\n/** Configuration for flush operations. */\nexport interface FlushConfig {\n\tgatewayId: string;\n\tflushFormat?: \"json\" | \"parquet\";\n\ttableSchema?: TableSchema;\n\tcatalogue?: NessieCatalogueClient;\n}\n\n/** Dependencies injected into flush operations. */\nexport interface FlushDeps {\n\tadapter: LakeAdapter | DatabaseAdapter;\n\tconfig: FlushConfig;\n\trestoreEntries: (entries: RowDelta[]) => void;\n\tschemas?: ReadonlyArray<TableSchema>;\n}\n\n/** Find the min and max HLC in a non-empty array of deltas. */\nexport function hlcRange(entries: RowDelta[]): { min: HLCTimestamp; max: HLCTimestamp } {\n\tlet min = entries[0]!.hlc;\n\tlet max = entries[0]!.hlc;\n\tfor (let i = 1; i < entries.length; i++) {\n\t\tconst hlc = entries[i]!.hlc;\n\t\tif (HLC.compare(hlc, min) < 0) min = hlc;\n\t\tif (HLC.compare(hlc, max) > 0) max = hlc;\n\t}\n\treturn { min, max };\n}\n\n/**\n * Flush a set of entries to the configured adapter.\n *\n * Unifies both full-buffer flush and per-table flush. The `keyPrefix`\n * parameter, when provided, is prepended to the HLC range in the object key\n * (e.g. \"todos\" for per-table flush).\n */\nexport async function flushEntries(\n\tentries: RowDelta[],\n\tbyteSize: number,\n\tdeps: FlushDeps,\n\tkeyPrefix?: string,\n): Promise<Result<void, FlushError>> {\n\t// Database adapter path — batch INSERT deltas directly\n\tif (isDatabaseAdapter(deps.adapter)) {\n\t\ttry {\n\t\t\tconst result = await deps.adapter.insertDeltas(entries);\n\t\t\tif (!result.ok) {\n\t\t\t\tdeps.restoreEntries(entries);\n\t\t\t\treturn Err(new FlushError(`Database flush failed: ${result.error.message}`));\n\t\t\t}\n\n\t\t\t// Materialise after successful delta insertion (non-fatal)\n\t\t\tif (deps.schemas && deps.schemas.length > 0 && isMaterialisable(deps.adapter)) {\n\t\t\t\ttry {\n\t\t\t\t\tconst matResult = await deps.adapter.materialise(entries, deps.schemas);\n\t\t\t\t\tif (!matResult.ok) {\n\t\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t\t`[lakesync] Materialisation failed (${entries.length} deltas): ${matResult.error.message}`,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t} catch (error: unknown) {\n\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t`[lakesync] Materialisation error (${entries.length} deltas): ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn Ok(undefined);\n\t\t} catch (error: unknown) {\n\t\t\tdeps.restoreEntries(entries);\n\t\t\treturn Err(new FlushError(`Unexpected database flush failure: ${toError(error).message}`));\n\t\t}\n\t}\n\n\t// Lake adapter path — write to object storage as Parquet or JSON\n\ttry {\n\t\tconst { min, max } = hlcRange(entries);\n\t\tconst date = new Date().toISOString().split(\"T\")[0];\n\t\tconst prefix = keyPrefix ? `${keyPrefix}-` : \"\";\n\t\tlet objectKey: string;\n\t\tlet data: Uint8Array;\n\t\tlet contentType: string;\n\n\t\tif (deps.config.flushFormat === \"json\") {\n\t\t\tconst envelope: FlushEnvelope = {\n\t\t\t\tversion: 1,\n\t\t\t\tgatewayId: deps.config.gatewayId,\n\t\t\t\tcreatedAt: new Date().toISOString(),\n\t\t\t\thlcRange: { min, max },\n\t\t\t\tdeltaCount: entries.length,\n\t\t\t\tbyteSize,\n\t\t\t\tdeltas: entries,\n\t\t\t};\n\n\t\t\tobjectKey = `deltas/${date}/${deps.config.gatewayId}/${prefix}${min.toString()}-${max.toString()}.json`;\n\t\t\tdata = new TextEncoder().encode(JSON.stringify(envelope, bigintReplacer));\n\t\t\tcontentType = \"application/json\";\n\t\t} else {\n\t\t\t// Parquet path\n\t\t\tif (!deps.config.tableSchema) {\n\t\t\t\tdeps.restoreEntries(entries);\n\t\t\t\treturn Err(new FlushError(\"tableSchema required for Parquet flush\"));\n\t\t\t}\n\n\t\t\tconst parquetResult = await writeDeltasToParquet(entries, deps.config.tableSchema);\n\t\t\tif (!parquetResult.ok) {\n\t\t\t\tdeps.restoreEntries(entries);\n\t\t\t\treturn Err(parquetResult.error);\n\t\t\t}\n\n\t\t\tobjectKey = `deltas/${date}/${deps.config.gatewayId}/${prefix}${min.toString()}-${max.toString()}.parquet`;\n\t\t\tdata = parquetResult.value;\n\t\t\tcontentType = \"application/vnd.apache.parquet\";\n\t\t}\n\n\t\tconst result = await deps.adapter.putObject(objectKey, data, contentType);\n\t\tif (!result.ok) {\n\t\t\tdeps.restoreEntries(entries);\n\t\t\treturn Err(new FlushError(`Failed to write flush envelope: ${result.error.message}`));\n\t\t}\n\n\t\tif (deps.config.catalogue && deps.config.tableSchema) {\n\t\t\tawait commitToCatalogue(\n\t\t\t\tobjectKey,\n\t\t\t\tdata.byteLength,\n\t\t\t\tentries.length,\n\t\t\t\tdeps.config.catalogue,\n\t\t\t\tdeps.config.tableSchema,\n\t\t\t);\n\t\t}\n\n\t\treturn Ok(undefined);\n\t} catch (error: unknown) {\n\t\tdeps.restoreEntries(entries);\n\t\treturn Err(new FlushError(`Unexpected flush failure: ${toError(error).message}`));\n\t}\n}\n\n/**\n * Best-effort catalogue commit. Registers the flushed Parquet file\n * as an Iceberg snapshot via Nessie. Errors are logged but do not\n * fail the flush — the Parquet file is the source of truth.\n */\nexport async function commitToCatalogue(\n\tobjectKey: string,\n\tfileSizeInBytes: number,\n\trecordCount: number,\n\tcatalogue: NessieCatalogueClient,\n\tschema: TableSchema,\n): Promise<void> {\n\tconst { namespace, name } = lakeSyncTableName(schema.table);\n\tconst icebergSchema = tableSchemaToIceberg(schema);\n\tconst partitionSpec = buildPartitionSpec(icebergSchema);\n\n\t// Ensure namespace exists (idempotent)\n\tawait catalogue.createNamespace(namespace);\n\n\t// Ensure table exists (idempotent — catch 409)\n\tconst createResult = await catalogue.createTable(namespace, name, icebergSchema, partitionSpec);\n\tif (!createResult.ok && createResult.error.statusCode !== 409) {\n\t\treturn;\n\t}\n\n\t// Build DataFile reference\n\tconst dataFile: DataFile = {\n\t\tcontent: \"data\",\n\t\t\"file-path\": objectKey,\n\t\t\"file-format\": \"PARQUET\",\n\t\t\"record-count\": recordCount,\n\t\t\"file-size-in-bytes\": fileSizeInBytes,\n\t};\n\n\t// Append file to table snapshot\n\tconst appendResult = await catalogue.appendFiles(namespace, name, [dataFile]);\n\tif (!appendResult.ok && appendResult.error.statusCode === 409) {\n\t\t// On 409 conflict, retry once with fresh metadata\n\t\tawait catalogue.appendFiles(namespace, name, [dataFile]);\n\t}\n}\n","import type { DatabaseAdapter, LakeAdapter } from \"@lakesync/adapter\";\nimport { isDatabaseAdapter } from \"@lakesync/adapter\";\nimport { Err, FlushError, Ok, type Result, type RowDelta, type TableSchema } from \"@lakesync/core\";\nimport type { DeltaBuffer } from \"./buffer\";\nimport type { FlushConfig } from \"./flush\";\nimport { flushEntries } from \"./flush\";\n\n/** Dependencies for flush operations. */\nexport interface FlushCoordinatorDeps {\n\t/** Gateway configuration for flush. */\n\tconfig: FlushConfig;\n\t/** Table schemas for materialisation after flush. */\n\tschemas?: ReadonlyArray<TableSchema>;\n}\n\n/**\n * Coordinates flush operations from the buffer to the adapter.\n *\n * Owns the flushing state to prevent concurrent flushes and handles\n * entry restoration on failure.\n */\nexport class FlushCoordinator {\n\tprivate flushing = false;\n\n\t/** Whether a flush is currently in progress. */\n\tget isFlushing(): boolean {\n\t\treturn this.flushing;\n\t}\n\n\t/**\n\t * Flush all entries from the buffer to the adapter.\n\t *\n\t * Drains the buffer first, then writes to the adapter. On failure,\n\t * entries are restored to the buffer.\n\t */\n\tasync flush(\n\t\tbuffer: DeltaBuffer,\n\t\tadapter: LakeAdapter | DatabaseAdapter | null,\n\t\tdeps: FlushCoordinatorDeps,\n\t): Promise<Result<void, FlushError>> {\n\t\tif (this.flushing) {\n\t\t\treturn Err(new FlushError(\"Flush already in progress\"));\n\t\t}\n\t\tif (buffer.logSize === 0) {\n\t\t\treturn Ok(undefined);\n\t\t}\n\t\tif (!adapter) {\n\t\t\treturn Err(new FlushError(\"No adapter configured\"));\n\t\t}\n\n\t\tthis.flushing = true;\n\n\t\tconst byteSize = isDatabaseAdapter(adapter) ? 0 : buffer.byteSize;\n\t\tconst entries = buffer.drain();\n\t\tif (entries.length === 0) {\n\t\t\tthis.flushing = false;\n\t\t\treturn Ok(undefined);\n\t\t}\n\n\t\ttry {\n\t\t\treturn await flushEntries(entries, byteSize, {\n\t\t\t\tadapter,\n\t\t\t\tconfig: deps.config,\n\t\t\t\trestoreEntries: (e) => this.restoreEntries(buffer, e),\n\t\t\t\tschemas: deps.schemas,\n\t\t\t});\n\t\t} finally {\n\t\t\tthis.flushing = false;\n\t\t}\n\t}\n\n\t/**\n\t * Flush a single table's deltas from the buffer.\n\t *\n\t * Drains only the specified table's deltas and flushes them,\n\t * leaving other tables in the buffer.\n\t */\n\tasync flushTable(\n\t\ttable: string,\n\t\tbuffer: DeltaBuffer,\n\t\tadapter: LakeAdapter | DatabaseAdapter | null,\n\t\tdeps: FlushCoordinatorDeps,\n\t): Promise<Result<void, FlushError>> {\n\t\tif (this.flushing) {\n\t\t\treturn Err(new FlushError(\"Flush already in progress\"));\n\t\t}\n\t\tif (!adapter) {\n\t\t\treturn Err(new FlushError(\"No adapter configured\"));\n\t\t}\n\n\t\tconst entries = buffer.drainTable(table);\n\t\tif (entries.length === 0) {\n\t\t\treturn Ok(undefined);\n\t\t}\n\n\t\tthis.flushing = true;\n\n\t\ttry {\n\t\t\treturn await flushEntries(\n\t\t\t\tentries,\n\t\t\t\t0,\n\t\t\t\t{\n\t\t\t\t\tadapter,\n\t\t\t\t\tconfig: deps.config,\n\t\t\t\t\trestoreEntries: (e) => this.restoreEntries(buffer, e),\n\t\t\t\t\tschemas: deps.schemas,\n\t\t\t\t},\n\t\t\t\ttable,\n\t\t\t);\n\t\t} finally {\n\t\t\tthis.flushing = false;\n\t\t}\n\t}\n\n\t/** Restore drained entries back to the buffer for retry. */\n\tprivate restoreEntries(buffer: DeltaBuffer, entries: RowDelta[]): void {\n\t\tfor (const entry of entries) {\n\t\t\tbuffer.append(entry);\n\t\t}\n\t}\n}\n","import type { DatabaseAdapter } from \"@lakesync/adapter\";\n\n/**\n * Registry for named source adapters used in adapter-sourced pulls.\n *\n * Manages the mapping of source names to DatabaseAdapter instances,\n * decoupling source adapter management from the gateway.\n */\nexport class SourceRegistry {\n\tprivate sources: Map<string, DatabaseAdapter> = new Map();\n\n\tconstructor(initial?: Record<string, DatabaseAdapter>) {\n\t\tif (initial) {\n\t\t\tfor (const [name, adapter] of Object.entries(initial)) {\n\t\t\t\tthis.sources.set(name, adapter);\n\t\t\t}\n\t\t}\n\t}\n\n\t/** Register a named source adapter. */\n\tregister(name: string, adapter: DatabaseAdapter): void {\n\t\tthis.sources.set(name, adapter);\n\t}\n\n\t/** Unregister a named source adapter. */\n\tunregister(name: string): void {\n\t\tthis.sources.delete(name);\n\t}\n\n\t/** Get a source adapter by name, or undefined if not registered. */\n\tget(name: string): DatabaseAdapter | undefined {\n\t\treturn this.sources.get(name);\n\t}\n\n\t/** List all registered source adapter names. */\n\tlist(): string[] {\n\t\treturn [...this.sources.keys()];\n\t}\n}\n","import type { DatabaseAdapter, LakeAdapter } from \"@lakesync/adapter\";\nimport {\n\ttype ActionDiscovery,\n\ttype ActionHandler,\n\ttype ActionPush,\n\ttype ActionResponse,\n\ttype ActionValidationError,\n\ttype AdapterError,\n\tAdapterNotFoundError,\n\ttype AuthContext,\n\tBackpressureError,\n\ttype ClockDriftError,\n\tErr,\n\ttype FlushError,\n\tfilterDeltas,\n\tHLC,\n\ttype IngestTarget,\n\tOk,\n\ttype Result,\n\ttype RowDelta,\n\tresolveLWW,\n\trowKey,\n\ttype SchemaError,\n\ttype SyncPull,\n\ttype SyncPush,\n\ttype SyncResponse,\n\ttype SyncRulesContext,\n} from \"@lakesync/core\";\nimport { ActionDispatcher } from \"./action-dispatcher\";\nimport { DeltaBuffer } from \"./buffer\";\nimport { FlushCoordinator } from \"./flush-coordinator\";\nimport { SourceRegistry } from \"./source-registry\";\nimport type { GatewayConfig, HandlePushResult } from \"./types\";\n\nexport type { SyncPush, SyncPull, SyncResponse };\n\n/**\n * Sync gateway -- coordinates delta ingestion, conflict resolution, and flush.\n *\n * Thin facade composing DeltaBuffer, ActionDispatcher, SourceRegistry,\n * and FlushCoordinator. Public methods delegate to composed modules.\n */\nexport class SyncGateway implements IngestTarget {\n\tprivate hlc: HLC;\n\treadonly buffer: DeltaBuffer;\n\treadonly actions: ActionDispatcher;\n\tprivate config: GatewayConfig;\n\tprivate adapter: LakeAdapter | DatabaseAdapter | null;\n\tprivate readonly sources: SourceRegistry;\n\tprivate readonly flushCoordinator: FlushCoordinator;\n\n\tconstructor(config: GatewayConfig, adapter?: LakeAdapter | DatabaseAdapter) {\n\t\tthis.config = { sourceAdapters: {}, ...config };\n\t\tthis.hlc = new HLC();\n\t\tthis.buffer = new DeltaBuffer();\n\t\tthis.adapter = this.config.adapter ?? adapter ?? null;\n\t\tthis.actions = new ActionDispatcher(config.actionHandlers);\n\t\tthis.sources = new SourceRegistry(this.config.sourceAdapters);\n\t\tthis.flushCoordinator = new FlushCoordinator();\n\t}\n\n\t// -----------------------------------------------------------------------\n\t// Push — pipeline of validation steps then buffer append\n\t// -----------------------------------------------------------------------\n\n\t/**\n\t * Handle an incoming push from a client.\n\t *\n\t * Validates HLC drift, resolves conflicts via LWW, and appends to the buffer.\n\t *\n\t * @param msg - The push message containing client deltas.\n\t * @returns A `Result` with the new server HLC and accepted count,\n\t * or a `ClockDriftError` if the client clock is too far ahead.\n\t */\n\thandlePush(\n\t\tmsg: SyncPush,\n\t): Result<HandlePushResult, ClockDriftError | SchemaError | BackpressureError> {\n\t\t// Step 1: Check backpressure\n\t\tconst bpResult = this.checkBackpressure();\n\t\tif (!bpResult.ok) return bpResult;\n\n\t\tlet accepted = 0;\n\t\tconst ingested: RowDelta[] = [];\n\n\t\tfor (const delta of msg.deltas) {\n\t\t\t// Step 2: Filter duplicates\n\t\t\tif (this.buffer.hasDelta(delta.deltaId)) {\n\t\t\t\taccepted++;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// Step 3: Validate schema\n\t\t\tif (this.config.schemaManager) {\n\t\t\t\tconst schemaResult = this.config.schemaManager.validateDelta(delta);\n\t\t\t\tif (!schemaResult.ok) {\n\t\t\t\t\treturn Err(schemaResult.error);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Step 4: Validate HLC\n\t\t\tconst recvResult = this.hlc.recv(delta.hlc);\n\t\t\tif (!recvResult.ok) {\n\t\t\t\treturn Err(recvResult.error);\n\t\t\t}\n\n\t\t\t// Step 5: Resolve conflicts + append\n\t\t\tconst key = rowKey(delta.table, delta.rowId);\n\t\t\tconst existing = this.buffer.getRow(key);\n\n\t\t\tif (existing) {\n\t\t\t\tconst resolved = resolveLWW(existing, delta);\n\t\t\t\tif (resolved.ok) {\n\t\t\t\t\tthis.buffer.append(resolved.value);\n\t\t\t\t\tingested.push(resolved.value);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tthis.buffer.append(delta);\n\t\t\t\tingested.push(delta);\n\t\t\t}\n\n\t\t\taccepted++;\n\t\t}\n\n\t\tconst serverHlc = this.hlc.now();\n\t\treturn Ok({ serverHlc, accepted, deltas: ingested });\n\t}\n\n\t/** Check buffer backpressure. */\n\tprivate checkBackpressure(): Result<void, BackpressureError> {\n\t\tconst backpressureLimit = this.config.maxBackpressureBytes ?? this.config.maxBufferBytes * 2;\n\t\tif (this.buffer.byteSize >= backpressureLimit) {\n\t\t\treturn Err(\n\t\t\t\tnew BackpressureError(\n\t\t\t\t\t`Buffer backpressure exceeded (${this.buffer.byteSize} >= ${backpressureLimit} bytes)`,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\t\treturn Ok(undefined);\n\t}\n\n\t// -----------------------------------------------------------------------\n\t// Pull — delegates to buffer or source registry\n\t// -----------------------------------------------------------------------\n\n\t/**\n\t * Handle a pull request from a client.\n\t *\n\t * When `msg.source` is set, pulls deltas from the named source adapter\n\t * instead of the in-memory buffer. Otherwise, returns change events\n\t * from the log since the given HLC. When a {@link SyncRulesContext} is\n\t * provided, deltas are post-filtered by the client's bucket definitions\n\t * and JWT claims. The buffer path over-fetches (3x the requested limit)\n\t * and retries up to 5 times to fill the page.\n\t *\n\t * @param msg - The pull message specifying the cursor and limit.\n\t * @param context - Optional sync rules context for row-level filtering.\n\t * @returns A `Result` containing the matching deltas, server HLC, and pagination flag.\n\t */\n\thandlePull(\n\t\tmsg: SyncPull & { source: string },\n\t\tcontext?: SyncRulesContext,\n\t): Promise<Result<SyncResponse, AdapterNotFoundError | AdapterError>>;\n\thandlePull(msg: SyncPull, context?: SyncRulesContext): Result<SyncResponse, never>;\n\thandlePull(\n\t\tmsg: SyncPull,\n\t\tcontext?: SyncRulesContext,\n\t):\n\t\t| Promise<Result<SyncResponse, AdapterNotFoundError | AdapterError>>\n\t\t| Result<SyncResponse, never> {\n\t\tif (msg.source) {\n\t\t\treturn this.handleAdapterPull(msg, context);\n\t\t}\n\n\t\treturn this.handleBufferPull(msg, context);\n\t}\n\n\t/** Pull from the in-memory buffer (original path). */\n\tprivate handleBufferPull(msg: SyncPull, context?: SyncRulesContext): Result<SyncResponse, never> {\n\t\tif (!context) {\n\t\t\tconst { deltas, hasMore } = this.buffer.getEventsSince(msg.sinceHlc, msg.maxDeltas);\n\t\t\tconst serverHlc = this.hlc.now();\n\t\t\treturn Ok({ deltas, serverHlc, hasMore });\n\t\t}\n\n\t\t// Over-fetch and filter with bounded retry\n\t\tconst maxRetries = 5;\n\t\tconst overFetchMultiplier = 3;\n\t\tlet cursor = msg.sinceHlc;\n\t\tconst collected: RowDelta[] = [];\n\n\t\tfor (let attempt = 0; attempt < maxRetries; attempt++) {\n\t\t\tconst fetchLimit = msg.maxDeltas * overFetchMultiplier;\n\t\t\tconst { deltas: raw, hasMore: rawHasMore } = this.buffer.getEventsSince(cursor, fetchLimit);\n\n\t\t\tif (raw.length === 0) {\n\t\t\t\tconst serverHlc = this.hlc.now();\n\t\t\t\treturn Ok({ deltas: collected, serverHlc, hasMore: false });\n\t\t\t}\n\n\t\t\tconst filtered = filterDeltas(raw, context);\n\t\t\tcollected.push(...filtered);\n\n\t\t\tif (collected.length >= msg.maxDeltas) {\n\t\t\t\tconst trimmed = collected.slice(0, msg.maxDeltas);\n\t\t\t\tconst serverHlc = this.hlc.now();\n\t\t\t\treturn Ok({ deltas: trimmed, serverHlc, hasMore: true });\n\t\t\t}\n\n\t\t\tif (!rawHasMore) {\n\t\t\t\tconst serverHlc = this.hlc.now();\n\t\t\t\treturn Ok({ deltas: collected, serverHlc, hasMore: false });\n\t\t\t}\n\n\t\t\tcursor = raw[raw.length - 1]!.hlc;\n\t\t}\n\n\t\t// Exhausted retries — return what we have\n\t\tconst serverHlc = this.hlc.now();\n\t\tconst hasMore = collected.length >= msg.maxDeltas;\n\t\tconst trimmed = collected.slice(0, msg.maxDeltas);\n\t\treturn Ok({ deltas: trimmed, serverHlc, hasMore });\n\t}\n\n\t/** Pull from a named source adapter. */\n\tprivate async handleAdapterPull(\n\t\tmsg: SyncPull,\n\t\tcontext?: SyncRulesContext,\n\t): Promise<Result<SyncResponse, AdapterNotFoundError | AdapterError>> {\n\t\tconst adapter = this.sources.get(msg.source!);\n\t\tif (!adapter) {\n\t\t\treturn Err(new AdapterNotFoundError(`Source adapter \"${msg.source}\" not found`));\n\t\t}\n\n\t\tconst queryResult = await adapter.queryDeltasSince(msg.sinceHlc);\n\t\tif (!queryResult.ok) {\n\t\t\treturn Err(queryResult.error);\n\t\t}\n\n\t\tlet deltas = queryResult.value;\n\n\t\tif (context) {\n\t\t\tdeltas = filterDeltas(deltas, context);\n\t\t}\n\n\t\tconst hasMore = deltas.length > msg.maxDeltas;\n\t\tconst sliced = deltas.slice(0, msg.maxDeltas);\n\n\t\tconst serverHlc = this.hlc.now();\n\t\treturn Ok({ deltas: sliced, serverHlc, hasMore });\n\t}\n\n\t// -----------------------------------------------------------------------\n\t// Flush — delegates to FlushCoordinator\n\t// -----------------------------------------------------------------------\n\n\t/**\n\t * Flush the buffer to the configured adapter.\n\t *\n\t * Writes deltas as either a Parquet file (default) or a JSON\n\t * {@link FlushEnvelope} to the adapter, depending on\n\t * `config.flushFormat`. If the write fails, the buffer entries\n\t * are restored so they can be retried.\n\t *\n\t * @returns A `Result` indicating success or a `FlushError`.\n\t */\n\tasync flush(): Promise<Result<void, FlushError>> {\n\t\treturn this.flushCoordinator.flush(this.buffer, this.adapter, {\n\t\t\tconfig: {\n\t\t\t\tgatewayId: this.config.gatewayId,\n\t\t\t\tflushFormat: this.config.flushFormat,\n\t\t\t\ttableSchema: this.config.tableSchema,\n\t\t\t\tcatalogue: this.config.catalogue,\n\t\t\t},\n\t\t\tschemas: this.config.schemas,\n\t\t});\n\t}\n\n\t/**\n\t * Flush a single table's deltas from the buffer.\n\t *\n\t * Drains only the specified table's deltas and flushes them,\n\t * leaving other tables in the buffer.\n\t */\n\tasync flushTable(table: string): Promise<Result<void, FlushError>> {\n\t\treturn this.flushCoordinator.flushTable(table, this.buffer, this.adapter, {\n\t\t\tconfig: {\n\t\t\t\tgatewayId: this.config.gatewayId,\n\t\t\t\tflushFormat: this.config.flushFormat,\n\t\t\t\ttableSchema: this.config.tableSchema,\n\t\t\t\tcatalogue: this.config.catalogue,\n\t\t\t},\n\t\t\tschemas: this.config.schemas,\n\t\t});\n\t}\n\n\t// -----------------------------------------------------------------------\n\t// Actions — delegates to ActionDispatcher\n\t// -----------------------------------------------------------------------\n\n\t/** Handle an incoming action push from a client. */\n\tasync handleAction(\n\t\tmsg: ActionPush,\n\t\tcontext?: AuthContext,\n\t): Promise<Result<ActionResponse, ActionValidationError>> {\n\t\treturn this.actions.dispatch(msg, () => this.hlc.now(), context);\n\t}\n\n\t/** Register a named action handler. */\n\tregisterActionHandler(name: string, handler: ActionHandler): void {\n\t\tthis.actions.registerHandler(name, handler);\n\t}\n\n\t/** Unregister a named action handler. */\n\tunregisterActionHandler(name: string): void {\n\t\tthis.actions.unregisterHandler(name);\n\t}\n\n\t/** List all registered action handler names. */\n\tlistActionHandlers(): string[] {\n\t\treturn this.actions.listHandlers();\n\t}\n\n\t/** Describe all registered action handlers and their supported actions. */\n\tdescribeActions(): ActionDiscovery {\n\t\treturn this.actions.describe();\n\t}\n\n\t// -----------------------------------------------------------------------\n\t// Source adapters — delegates to SourceRegistry\n\t// -----------------------------------------------------------------------\n\n\t/**\n\t * Register a named source adapter for adapter-sourced pulls.\n\t *\n\t * @param name - Unique source name (used as the `source` parameter in pull requests).\n\t * @param adapter - The database adapter to register.\n\t */\n\tregisterSource(name: string, adapter: DatabaseAdapter): void {\n\t\tthis.sources.register(name, adapter);\n\t}\n\n\t/**\n\t * Unregister a named source adapter.\n\t *\n\t * @param name - The source name to remove.\n\t */\n\tunregisterSource(name: string): void {\n\t\tthis.sources.unregister(name);\n\t}\n\n\t/**\n\t * List all registered source adapter names.\n\t *\n\t * @returns Array of registered source adapter names.\n\t */\n\tlistSources(): string[] {\n\t\treturn this.sources.list();\n\t}\n\n\t// -----------------------------------------------------------------------\n\t// Buffer queries\n\t// -----------------------------------------------------------------------\n\n\t/** Get per-table buffer statistics. */\n\tget tableStats(): Array<{ table: string; byteSize: number; deltaCount: number }> {\n\t\treturn this.buffer.tableStats();\n\t}\n\n\t/**\n\t * Get tables that exceed the per-table budget.\n\t */\n\tgetTablesExceedingBudget(): string[] {\n\t\tconst budget = this.config.perTableBudgetBytes;\n\t\tif (!budget) return [];\n\t\treturn this.buffer\n\t\t\t.tableStats()\n\t\t\t.filter((s) => s.byteSize >= budget)\n\t\t\t.map((s) => s.table);\n\t}\n\n\t/** Check if the buffer should be flushed based on config thresholds. */\n\tshouldFlush(): boolean {\n\t\tlet effectiveMaxBytes = this.config.maxBufferBytes;\n\n\t\t// Reduce threshold for wide-column deltas\n\t\tconst adaptive = this.config.adaptiveBufferConfig;\n\t\tif (adaptive && this.buffer.averageDeltaBytes > adaptive.wideColumnThreshold) {\n\t\t\teffectiveMaxBytes = Math.floor(effectiveMaxBytes * adaptive.reductionFactor);\n\t\t}\n\n\t\treturn this.buffer.shouldFlush({\n\t\t\tmaxBytes: effectiveMaxBytes,\n\t\t\tmaxAgeMs: this.config.maxBufferAgeMs,\n\t\t});\n\t}\n\n\t/** Get buffer statistics for monitoring. */\n\tget bufferStats(): {\n\t\tlogSize: number;\n\t\tindexSize: number;\n\t\tbyteSize: number;\n\t} {\n\t\treturn {\n\t\t\tlogSize: this.buffer.logSize,\n\t\t\tindexSize: this.buffer.indexSize,\n\t\t\tbyteSize: this.buffer.byteSize,\n\t\t};\n\t}\n}\n","import type {\n\tActionPush,\n\tHLCTimestamp,\n\tResolvedClaims,\n\tSyncPull,\n\tSyncPush,\n\tSyncRulesConfig,\n\tSyncRulesContext,\n\tTableSchema,\n} from \"@lakesync/core\";\nimport { bigintReviver, Err, Ok, type Result } from \"@lakesync/core\";\nimport {\n\tDEFAULT_PULL_LIMIT,\n\tMAX_DELTAS_PER_PUSH,\n\tMAX_PULL_LIMIT,\n\tVALID_COLUMN_TYPES,\n} from \"./constants\";\n\n/** Validation error with HTTP status code. */\nexport interface RequestError {\n\tstatus: number;\n\tmessage: string;\n}\n\n/** Parse a JSON string, returning Err on invalid JSON. */\nexport function parseJson<T>(\n\traw: string,\n\treviver?: (key: string, value: unknown) => unknown,\n): Result<T, RequestError> {\n\ttry {\n\t\treturn Ok(JSON.parse(raw, reviver) as T);\n\t} catch {\n\t\treturn Err({ status: 400, message: \"Invalid JSON body\" });\n\t}\n}\n\n/**\n * Validate and parse a push request body.\n * Handles JSON parsing with bigint revival.\n */\nexport function validatePushBody(\n\traw: string,\n\theaderClientId?: string | null,\n): Result<SyncPush, RequestError> {\n\tconst parsed = parseJson<SyncPush>(raw, bigintReviver);\n\tif (!parsed.ok) return parsed;\n\tconst body = parsed.value;\n\n\tif (!body.clientId || !Array.isArray(body.deltas)) {\n\t\treturn Err({ status: 400, message: \"Missing required fields: clientId, deltas\" });\n\t}\n\n\tif (headerClientId && body.clientId !== headerClientId) {\n\t\treturn Err({\n\t\t\tstatus: 403,\n\t\t\tmessage: \"Client ID mismatch: push clientId does not match authenticated identity\",\n\t\t});\n\t}\n\n\tif (body.deltas.length > MAX_DELTAS_PER_PUSH) {\n\t\treturn Err({ status: 400, message: \"Too many deltas in a single push (max 10,000)\" });\n\t}\n\n\treturn Ok(body);\n}\n\n/**\n * Parse and validate pull query parameters.\n */\nexport function parsePullParams(params: {\n\tsince: string | null;\n\tclientId: string | null;\n\tlimit: string | null;\n\tsource: string | null;\n}): Result<SyncPull, RequestError> {\n\tif (!params.since || !params.clientId) {\n\t\treturn Err({ status: 400, message: \"Missing required query params: since, clientId\" });\n\t}\n\n\tlet sinceHlc: HLCTimestamp;\n\ttry {\n\t\tsinceHlc = BigInt(params.since) as HLCTimestamp;\n\t} catch {\n\t\treturn Err({\n\t\t\tstatus: 400,\n\t\t\tmessage: \"Invalid 'since' parameter \\u2014 must be a decimal integer\",\n\t\t});\n\t}\n\n\tconst rawLimit = params.limit ? Number.parseInt(params.limit, 10) : DEFAULT_PULL_LIMIT;\n\tif (Number.isNaN(rawLimit) || rawLimit < 1) {\n\t\treturn Err({\n\t\t\tstatus: 400,\n\t\t\tmessage: \"Invalid 'limit' parameter \\u2014 must be a positive integer\",\n\t\t});\n\t}\n\tconst maxDeltas = Math.min(rawLimit, MAX_PULL_LIMIT);\n\n\tconst msg: SyncPull = {\n\t\tclientId: params.clientId,\n\t\tsinceHlc,\n\t\tmaxDeltas,\n\t\t...(params.source ? { source: params.source } : {}),\n\t};\n\n\treturn Ok(msg);\n}\n\n/**\n * Validate and parse an action request body.\n */\nexport function validateActionBody(\n\traw: string,\n\theaderClientId?: string | null,\n): Result<ActionPush, RequestError> {\n\tconst parsed = parseJson<ActionPush>(raw, bigintReviver);\n\tif (!parsed.ok) return parsed;\n\tconst body = parsed.value;\n\n\tif (!body.clientId || !Array.isArray(body.actions)) {\n\t\treturn Err({ status: 400, message: \"Missing required fields: clientId, actions\" });\n\t}\n\n\tif (headerClientId && body.clientId !== headerClientId) {\n\t\treturn Err({\n\t\t\tstatus: 403,\n\t\t\tmessage: \"Client ID mismatch: action clientId does not match authenticated identity\",\n\t\t});\n\t}\n\n\treturn Ok(body);\n}\n\n/**\n * Validate a table schema body.\n */\nexport function validateSchemaBody(raw: string): Result<TableSchema, RequestError> {\n\tconst parsed = parseJson<TableSchema>(raw);\n\tif (!parsed.ok) return parsed;\n\tconst schema = parsed.value;\n\n\tif (!schema.table || !Array.isArray(schema.columns)) {\n\t\treturn Err({ status: 400, message: \"Missing required fields: table, columns\" });\n\t}\n\n\tfor (const col of schema.columns) {\n\t\tif (typeof col.name !== \"string\" || col.name.length === 0) {\n\t\t\treturn Err({ status: 400, message: \"Each column must have a non-empty 'name' string\" });\n\t\t}\n\t\tif (!VALID_COLUMN_TYPES.has(col.type)) {\n\t\t\treturn Err({\n\t\t\t\tstatus: 400,\n\t\t\t\tmessage: `Invalid column type \"${col.type}\" for column \"${col.name}\". Allowed: string, number, boolean, json, null`,\n\t\t\t});\n\t\t}\n\t}\n\n\tconst columnNames = new Set(schema.columns.map((c) => c.name));\n\n\t// Validate primaryKey\n\tif (schema.primaryKey !== undefined) {\n\t\tif (!Array.isArray(schema.primaryKey) || schema.primaryKey.length === 0) {\n\t\t\treturn Err({ status: 400, message: \"primaryKey must be a non-empty array of strings\" });\n\t\t}\n\t\tfor (const pk of schema.primaryKey) {\n\t\t\tif (typeof pk !== \"string\") {\n\t\t\t\treturn Err({ status: 400, message: \"primaryKey must be a non-empty array of strings\" });\n\t\t\t}\n\t\t\tif (pk !== \"row_id\" && !columnNames.has(pk)) {\n\t\t\t\treturn Err({\n\t\t\t\t\tstatus: 400,\n\t\t\t\t\tmessage: `primaryKey column \"${pk}\" must be \"row_id\" or exist in columns`,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\t// Validate softDelete\n\tif (schema.softDelete !== undefined && typeof schema.softDelete !== \"boolean\") {\n\t\treturn Err({ status: 400, message: \"softDelete must be a boolean\" });\n\t}\n\n\t// Validate externalIdColumn\n\tif (schema.externalIdColumn !== undefined) {\n\t\tif (typeof schema.externalIdColumn !== \"string\" || schema.externalIdColumn.length === 0) {\n\t\t\treturn Err({ status: 400, message: \"externalIdColumn must be a non-empty string\" });\n\t\t}\n\t\tif (!columnNames.has(schema.externalIdColumn)) {\n\t\t\treturn Err({\n\t\t\t\tstatus: 400,\n\t\t\t\tmessage: `externalIdColumn \"${schema.externalIdColumn}\" must exist in columns`,\n\t\t\t});\n\t\t}\n\t}\n\n\treturn Ok(schema);\n}\n\n/**\n * Map a gateway push error code to an HTTP status code.\n */\nexport function pushErrorToStatus(code: string): number {\n\tswitch (code) {\n\t\tcase \"CLOCK_DRIFT\":\n\t\t\treturn 409;\n\t\tcase \"SCHEMA_MISMATCH\":\n\t\t\treturn 422;\n\t\tcase \"BACKPRESSURE\":\n\t\t\treturn 503;\n\t\tdefault:\n\t\t\treturn 500;\n\t}\n}\n\n/**\n * Build a SyncRulesContext from rules and claims.\n * Returns undefined when no rules or empty buckets.\n */\nexport function buildSyncRulesContext(\n\trules: SyncRulesConfig | undefined,\n\tclaims: ResolvedClaims,\n): SyncRulesContext | undefined {\n\tif (!rules || rules.buckets.length === 0) {\n\t\treturn undefined;\n\t}\n\treturn { claims, rules };\n}\n","import type { HLCTimestamp, ResolvedClaims, RowDelta, SyncRulesConfig } from \"@lakesync/core\";\nimport {\n\tlistConnectorDescriptors,\n\tvalidateConnectorConfig,\n\tvalidateSyncRules,\n} from \"@lakesync/core\";\nimport type { ConfigStore } from \"./config-store\";\nimport type { SyncGateway } from \"./gateway\";\nimport {\n\tbuildSyncRulesContext,\n\tparseJson,\n\tparsePullParams,\n\tpushErrorToStatus,\n\tvalidateActionBody,\n\tvalidatePushBody,\n\tvalidateSchemaBody,\n} from \"./validation\";\n\n/** Result from a request handler, ready for platform-specific serialisation. */\nexport interface HandlerResult {\n\tstatus: number;\n\tbody: unknown;\n}\n\n/**\n * Handle a push request.\n *\n * @param gateway - The SyncGateway instance.\n * @param raw - The raw request body string.\n * @param headerClientId - Client ID from auth header (for mismatch check).\n * @param opts - Optional callbacks for persistence and broadcast.\n */\nexport function handlePushRequest(\n\tgateway: SyncGateway,\n\traw: string,\n\theaderClientId?: string | null,\n\topts?: {\n\t\t/** Persist deltas before processing (WAL-style). */\n\t\tpersistBatch?: (deltas: RowDelta[]) => void;\n\t\t/** Clear persisted deltas after successful push. */\n\t\tclearPersistence?: () => void;\n\t\t/** Broadcast deltas to connected clients. */\n\t\tbroadcastFn?: (\n\t\t\tdeltas: RowDelta[],\n\t\t\tserverHlc: HLCTimestamp,\n\t\t\texcludeClientId: string,\n\t\t) => void | Promise<void>;\n\t},\n): HandlerResult {\n\tconst validation = validatePushBody(raw, headerClientId);\n\tif (!validation.ok) {\n\t\treturn { status: validation.error.status, body: { error: validation.error.message } };\n\t}\n\n\tconst body = validation.value;\n\n\t// Persist before processing (WAL-style)\n\topts?.persistBatch?.(body.deltas);\n\n\tconst result = gateway.handlePush(body);\n\tif (!result.ok) {\n\t\treturn {\n\t\t\tstatus: pushErrorToStatus(result.error.code),\n\t\t\tbody: { error: result.error.message },\n\t\t};\n\t}\n\n\t// Clear persisted deltas on success\n\topts?.clearPersistence?.();\n\n\t// Broadcast to connected clients (fire and forget)\n\tif (opts?.broadcastFn && result.value.deltas.length > 0) {\n\t\topts.broadcastFn(result.value.deltas, result.value.serverHlc, body.clientId);\n\t}\n\n\treturn { status: 200, body: result.value };\n}\n\n/**\n * Handle a pull request.\n */\nexport async function handlePullRequest(\n\tgateway: SyncGateway,\n\tparams: {\n\t\tsince: string | null;\n\t\tclientId: string | null;\n\t\tlimit: string | null;\n\t\tsource: string | null;\n\t},\n\tclaims?: ResolvedClaims,\n\tsyncRules?: SyncRulesConfig,\n): Promise<HandlerResult> {\n\tconst validation = parsePullParams(params);\n\tif (!validation.ok) {\n\t\treturn { status: validation.error.status, body: { error: validation.error.message } };\n\t}\n\n\tconst msg = validation.value;\n\tconst context = buildSyncRulesContext(syncRules, claims ?? {});\n\n\tconst result = msg.source\n\t\t? await gateway.handlePull(\n\t\t\t\tmsg as import(\"@lakesync/core\").SyncPull & { source: string },\n\t\t\t\tcontext,\n\t\t\t)\n\t\t: gateway.handlePull(msg, context);\n\n\tif (!result.ok) {\n\t\tconst err = result.error;\n\t\tif (err.code === \"ADAPTER_NOT_FOUND\") {\n\t\t\treturn { status: 404, body: { error: err.message } };\n\t\t}\n\t\treturn { status: 500, body: { error: err.message } };\n\t}\n\n\treturn { status: 200, body: result.value };\n}\n\n/**\n * Handle an action request.\n */\nexport async function handleActionRequest(\n\tgateway: SyncGateway,\n\traw: string,\n\theaderClientId?: string | null,\n\tclaims?: ResolvedClaims,\n): Promise<HandlerResult> {\n\tconst validation = validateActionBody(raw, headerClientId);\n\tif (!validation.ok) {\n\t\treturn { status: validation.error.status, body: { error: validation.error.message } };\n\t}\n\n\tconst context = claims ? { claims } : undefined;\n\tconst result = await gateway.handleAction(validation.value, context);\n\n\tif (!result.ok) {\n\t\treturn { status: 400, body: { error: result.error.message } };\n\t}\n\n\treturn { status: 200, body: result.value };\n}\n\n/**\n * Handle a flush request.\n */\nexport async function handleFlushRequest(\n\tgateway: SyncGateway,\n\topts?: { clearPersistence?: () => void },\n): Promise<HandlerResult> {\n\tconst result = await gateway.flush();\n\tif (!result.ok) {\n\t\treturn { status: 500, body: { error: result.error.message } };\n\t}\n\n\topts?.clearPersistence?.();\n\treturn { status: 200, body: { flushed: true } };\n}\n\n/**\n * Handle saving a table schema.\n */\nexport async function handleSaveSchema(\n\traw: string,\n\tstore: ConfigStore,\n\tgatewayId: string,\n): Promise<HandlerResult> {\n\tconst validation = validateSchemaBody(raw);\n\tif (!validation.ok) {\n\t\treturn { status: validation.error.status, body: { error: validation.error.message } };\n\t}\n\n\tawait store.setSchema(gatewayId, validation.value);\n\treturn { status: 200, body: { saved: true } };\n}\n\n/**\n * Handle saving sync rules.\n */\nexport async function handleSaveSyncRules(\n\traw: string,\n\tstore: ConfigStore,\n\tgatewayId: string,\n): Promise<HandlerResult> {\n\tconst parsed = parseJson<unknown>(raw);\n\tif (!parsed.ok) {\n\t\treturn { status: parsed.error.status, body: { error: parsed.error.message } };\n\t}\n\tconst config = parsed.value;\n\n\tconst validation = validateSyncRules(config);\n\tif (!validation.ok) {\n\t\treturn { status: 400, body: { error: validation.error.message } };\n\t}\n\n\tawait store.setSyncRules(gatewayId, config as SyncRulesConfig);\n\treturn { status: 200, body: { saved: true } };\n}\n\n/**\n * Handle registering a connector.\n */\nexport async function handleRegisterConnector(\n\traw: string,\n\tstore: ConfigStore,\n): Promise<HandlerResult> {\n\tconst parsed = parseJson<unknown>(raw);\n\tif (!parsed.ok) {\n\t\treturn { status: parsed.error.status, body: { error: parsed.error.message } };\n\t}\n\tconst body = parsed.value;\n\n\tconst validation = validateConnectorConfig(body);\n\tif (!validation.ok) {\n\t\treturn { status: 400, body: { error: validation.error.message } };\n\t}\n\n\tconst config = validation.value;\n\tconst connectors = await store.getConnectors();\n\n\tif (connectors[config.name]) {\n\t\treturn { status: 409, body: { error: `Connector \"${config.name}\" already exists` } };\n\t}\n\n\tconnectors[config.name] = config;\n\tawait store.setConnectors(connectors);\n\n\treturn { status: 200, body: { registered: true, name: config.name } };\n}\n\n/**\n * Handle unregistering a connector.\n */\nexport async function handleUnregisterConnector(\n\tname: string,\n\tstore: ConfigStore,\n): Promise<HandlerResult> {\n\tconst connectors = await store.getConnectors();\n\n\tif (!connectors[name]) {\n\t\treturn { status: 404, body: { error: `Connector \"${name}\" not found` } };\n\t}\n\n\tdelete connectors[name];\n\tawait store.setConnectors(connectors);\n\n\treturn { status: 200, body: { unregistered: true, name } };\n}\n\n/**\n * Handle listing connectors.\n */\nexport async function handleListConnectors(store: ConfigStore): Promise<HandlerResult> {\n\tconst connectors = await store.getConnectors();\n\tconst list = Object.values(connectors).map((c) => ({\n\t\tname: c.name,\n\t\ttype: c.type,\n\t\thasIngest: c.ingest !== undefined,\n\t}));\n\n\treturn { status: 200, body: list };\n}\n\n/**\n * Handle listing available connector types (static metadata).\n */\nexport function handleListConnectorTypes(): HandlerResult {\n\treturn { status: 200, body: listConnectorDescriptors() };\n}\n\n/**\n * Handle metrics request.\n */\nexport function handleMetrics(\n\tgateway: SyncGateway,\n\textra?: Record<string, unknown>,\n): HandlerResult {\n\tconst stats = gateway.bufferStats;\n\treturn { status: 200, body: { ...stats, ...extra } };\n}\n","import { Err, Ok, type Result, type RowDelta, SchemaError, type TableSchema } from \"@lakesync/core\";\n\n/**\n * Manages schema versioning and validation for the gateway.\n *\n * Validates incoming deltas against the current schema and supports\n * safe schema evolution (adding nullable columns only).\n */\nexport class SchemaManager {\n\tprivate currentSchema: TableSchema;\n\tprivate version: number;\n\tprivate allowedColumns: Set<string>;\n\n\tconstructor(schema: TableSchema, version?: number) {\n\t\tthis.currentSchema = schema;\n\t\tthis.version = version ?? 1;\n\t\tthis.allowedColumns = new Set(schema.columns.map((c) => c.name));\n\t}\n\n\t/** Get the current schema and version. */\n\tgetSchema(): { schema: TableSchema; version: number } {\n\t\treturn { schema: this.currentSchema, version: this.version };\n\t}\n\n\t/**\n\t * Validate that a delta's columns are compatible with the current schema.\n\t *\n\t * Unknown columns result in a SchemaError. Missing columns are fine (sparse deltas).\n\t * DELETE ops with empty columns are always valid.\n\t */\n\tvalidateDelta(delta: RowDelta): Result<void, SchemaError> {\n\t\tif (delta.op === \"DELETE\" && delta.columns.length === 0) {\n\t\t\treturn Ok(undefined);\n\t\t}\n\n\t\tfor (const col of delta.columns) {\n\t\t\tif (!this.allowedColumns.has(col.column)) {\n\t\t\t\treturn Err(\n\t\t\t\t\tnew SchemaError(\n\t\t\t\t\t\t`Unknown column \"${col.column}\" in delta for table \"${delta.table}\". Schema version ${this.version} does not include this column.`,\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\treturn Ok(undefined);\n\t}\n\n\t/**\n\t * Evolve the schema by adding new nullable columns.\n\t *\n\t * Only adding columns is allowed. Removing columns or changing types\n\t * returns a SchemaError.\n\t */\n\tevolveSchema(newSchema: TableSchema): Result<{ version: number }, SchemaError> {\n\t\tif (newSchema.table !== this.currentSchema.table) {\n\t\t\treturn Err(new SchemaError(\"Cannot evolve schema: table name mismatch\"));\n\t\t}\n\n\t\tconst oldColumnMap = new Map(this.currentSchema.columns.map((c) => [c.name, c.type]));\n\t\tconst newColumnMap = new Map(newSchema.columns.map((c) => [c.name, c.type]));\n\n\t\t// Check for removed columns\n\t\tfor (const [name] of oldColumnMap) {\n\t\t\tif (!newColumnMap.has(name)) {\n\t\t\t\treturn Err(\n\t\t\t\t\tnew SchemaError(\n\t\t\t\t\t\t`Cannot remove column \"${name}\" — only adding nullable columns is supported`,\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\t// Check for type changes\n\t\tfor (const [name, oldType] of oldColumnMap) {\n\t\t\tconst newType = newColumnMap.get(name);\n\t\t\tif (newType && newType !== oldType) {\n\t\t\t\treturn Err(\n\t\t\t\t\tnew SchemaError(\n\t\t\t\t\t\t`Cannot change type of column \"${name}\" from \"${oldType}\" to \"${newType}\"`,\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\t// Apply evolution\n\t\tthis.currentSchema = newSchema;\n\t\tthis.version++;\n\t\tthis.allowedColumns = new Set(newSchema.columns.map((c) => c.name));\n\n\t\treturn Ok({ version: this.version });\n\t}\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiBA,IAAM,yBAAyB;AAG/B,IAAM,uBAAuB,IAAI,KAAK;AAuB/B,IAAM,mBAAN,MAAuB;AAAA,EACrB,iBAA6C,oBAAI,IAAI;AAAA,EACrD,kBAA+B,oBAAI,IAAI;AAAA,EACvC,iBAA4C,oBAAI,IAAI;AAAA,EAC3C;AAAA,EACA;AAAA,EAEjB,YAAY,UAA0C,aAAiC;AACtF,QAAI,UAAU;AACb,iBAAW,CAAC,MAAM,OAAO,KAAK,OAAO,QAAQ,QAAQ,GAAG;AACvD,aAAK,eAAe,IAAI,MAAM,OAAO;AAAA,MACtC;AAAA,IACD;AACA,SAAK,eAAe,aAAa,WAAW;AAC5C,SAAK,aAAa,aAAa,SAAS;AAAA,EACzC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAcA,MAAM,SACL,KACA,QACA,SACyD;AAEzD,SAAK,kBAAkB;AAEvB,UAAM,UAEF,CAAC;AAEL,eAAW,UAAU,IAAI,SAAS;AAEjC,YAAM,aAAa,eAAe,MAAM;AACxC,UAAI,CAAC,WAAW,IAAI;AACnB,eAAO,IAAI,WAAW,KAAK;AAAA,MAC5B;AAGA,UAAI,KAAK,gBAAgB,IAAI,OAAO,QAAQ,GAAG;AAC9C,cAAM,SAAS,KAAK,gBAAgB,OAAO,QAAQ;AACnD,YAAI,QAAQ;AACX,kBAAQ,KAAK,MAAM;AACnB;AAAA,QACD;AAEA;AAAA,MACD;AAGA,UAAI,OAAO,gBAAgB;AAC1B,cAAM,SAAS,KAAK,gBAAgB,QAAQ,OAAO,cAAc,EAAE;AACnE,YAAI,QAAQ;AACX,kBAAQ,KAAK,MAAM;AACnB;AAAA,QACD;AAAA,MACD;AAGA,YAAM,UAAU,KAAK,eAAe,IAAI,OAAO,SAAS;AACxD,UAAI,CAAC,SAAS;AACb,cAAM,cAAc;AAAA,UACnB,UAAU,OAAO;AAAA,UACjB,MAAM;AAAA,UACN,SAAS,+CAA+C,OAAO,SAAS;AAAA,UACxE,WAAW;AAAA,QACZ;AACA,gBAAQ,KAAK,WAAW;AACxB,aAAK,kBAAkB,QAAQ,WAAW;AAC1C;AAAA,MACD;AAGA,YAAM,YAAY,QAAQ,iBAAiB,KAAK,CAAC,MAAM,EAAE,eAAe,OAAO,UAAU;AACzF,UAAI,CAAC,WAAW;AACf,cAAM,cAAc;AAAA,UACnB,UAAU,OAAO;AAAA,UACjB,MAAM;AAAA,UACN,SAAS,gBAAgB,OAAO,UAAU,iCAAiC,OAAO,SAAS;AAAA,UAC3F,WAAW;AAAA,QACZ;AACA,gBAAQ,KAAK,WAAW;AACxB,aAAK,kBAAkB,QAAQ,WAAW;AAC1C;AAAA,MACD;AAGA,YAAM,aAAa,MAAM,QAAQ,cAAc,QAAQ,OAAO;AAC9D,UAAI,WAAW,IAAI;AAClB,gBAAQ,KAAK,WAAW,KAAK;AAC7B,aAAK,kBAAkB,QAAQ,WAAW,KAAK;AAAA,MAChD,OAAO;AACN,cAAM,MAAM,WAAW;AACvB,cAAM,cAAc;AAAA,UACnB,UAAU,OAAO;AAAA,UACjB,MAAM,IAAI;AAAA,UACV,SAAS,IAAI;AAAA,UACb,WAAW,eAAe,MAAO,IAA6B,YAAY;AAAA,QAC3E;AACA,gBAAQ,KAAK,WAAW;AAExB,YAAI,CAAC,YAAY,WAAW;AAC3B,eAAK,kBAAkB,QAAQ,WAAW;AAAA,QAC3C;AAAA,MACD;AAAA,IACD;AAEA,UAAM,YAAY,OAAO;AACzB,WAAO,GAAG,EAAE,SAAS,UAAU,CAAC;AAAA,EACjC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,gBAAgB,MAAc,SAA8B;AAC3D,SAAK,eAAe,IAAI,MAAM,OAAO;AAAA,EACtC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,kBAAkB,MAAoB;AACrC,SAAK,eAAe,OAAO,IAAI;AAAA,EAChC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,eAAyB;AACxB,WAAO,CAAC,GAAG,KAAK,eAAe,KAAK,CAAC;AAAA,EACtC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,WAA4B;AAC3B,UAAM,aAAiD,CAAC;AACxD,eAAW,CAAC,MAAM,OAAO,KAAK,KAAK,gBAAgB;AAClD,iBAAW,IAAI,IAAI,QAAQ;AAAA,IAC5B;AACA,WAAO,EAAE,WAAW;AAAA,EACrB;AAAA;AAAA,EAGQ,kBACP,QACA,QACO;AACP,UAAM,QAAsB,EAAE,OAAO,QAAQ,UAAU,KAAK,IAAI,EAAE;AAClE,SAAK,gBAAgB,IAAI,OAAO,QAAQ;AACxC,SAAK,eAAe,IAAI,OAAO,UAAU,KAAK;AAC9C,QAAI,OAAO,gBAAgB;AAC1B,WAAK,eAAe,IAAI,QAAQ,OAAO,cAAc,IAAI,KAAK;AAAA,IAC/D;AAAA,EACD;AAAA;AAAA,EAGQ,gBACP,KAIY;AACZ,UAAM,QAAQ,KAAK,eAAe,IAAI,GAAG;AACzC,QAAI,CAAC,MAAO,QAAO;AACnB,QAAI,KAAK,IAAI,IAAI,MAAM,WAAW,KAAK,YAAY;AAClD,WAAK,eAAe,OAAO,GAAG;AAC9B,aAAO;AAAA,IACR;AACA,WAAO,MAAM;AAAA,EACd;AAAA;AAAA,EAGQ,oBAA0B;AACjC,UAAM,MAAM,KAAK,IAAI;AAGrB,eAAW,CAAC,KAAK,KAAK,KAAK,KAAK,gBAAgB;AAC/C,UAAI,MAAM,MAAM,WAAW,KAAK,YAAY;AAC3C,aAAK,eAAe,OAAO,GAAG;AAE9B,YAAI,CAAC,IAAI,WAAW,OAAO,GAAG;AAC7B,eAAK,gBAAgB,OAAO,GAAG;AAAA,QAChC;AAAA,MACD;AAAA,IACD;AAGA,QAAI,KAAK,gBAAgB,OAAO,KAAK,cAAc;AAClD,YAAM,SAAS,KAAK,gBAAgB,OAAO,KAAK;AAChD,UAAI,UAAU;AACd,iBAAW,YAAY,KAAK,iBAAiB;AAC5C,YAAI,WAAW,OAAQ;AACvB,aAAK,gBAAgB,OAAO,QAAQ;AACpC,aAAK,eAAe,OAAO,QAAQ;AACnC;AAAA,MACD;AAAA,IACD;AAAA,EACD;AACD;;;ACpQA,IAAM,sBAAsB,IAAI,IAAI,IAAI,IAAI;AAM5C,SAAS,mBAAmB,OAAwB;AACnD,MAAI,UAAU,QAAQ,UAAU,OAAW,QAAO;AAClD,UAAQ,OAAO,OAAO;AAAA,IACrB,KAAK;AACJ,aAAO;AAAA,IACR,KAAK;AACJ,aAAO;AAAA,IACR,KAAK;AACJ,aAAO;AAAA,IACR,KAAK;AACJ,aAAQ,MAAiB,SAAS;AAAA;AAAA,IACnC;AAEC,UAAI;AACH,eAAO,KAAK,UAAU,KAAK,EAAE;AAAA,MAC9B,QAAQ;AACP,eAAO;AAAA,MACR;AAAA,EACF;AACD;AAGA,SAAS,mBAAmB,OAAyB;AACpD,MAAI,QAAQ;AACZ,WAAS,MAAM,QAAQ;AACvB,WAAS,MAAM,MAAM,SAAS;AAC9B,WAAS,MAAM,MAAM,SAAS;AAC9B,WAAS,MAAM,SAAS,SAAS;AACjC,aAAW,OAAO,MAAM,SAAS;AAChC,aAAS,IAAI,OAAO,SAAS;AAC7B,aAAS,mBAAmB,IAAI,KAAK;AAAA,EACtC;AACA,SAAO;AACR;AAQO,IAAM,cAAN,MAAkB;AAAA,EAChB,MAAkB,CAAC;AAAA,EACnB,QAA+B,oBAAI,IAAI;AAAA,EACvC,WAAW,oBAAI,IAAY;AAAA,EAC3B,iBAAiB;AAAA,EACjB,YAAoB,KAAK,IAAI;AAAA,EAC7B,aAAa,oBAAI,IAAoB;AAAA,EACrC,WAAW,oBAAI,IAAwB;AAAA;AAAA,EAG/C,OAAO,OAAuB;AAC7B,SAAK,IAAI,KAAK,KAAK;AACnB,UAAM,MAAM,OAAO,MAAM,OAAO,MAAM,KAAK;AAC3C,SAAK,MAAM,IAAI,KAAK,KAAK;AACzB,SAAK,SAAS,IAAI,MAAM,OAAO;AAC/B,UAAM,QAAQ,mBAAmB,KAAK;AACtC,SAAK,kBAAkB;AAEvB,SAAK,WAAW,IAAI,MAAM,QAAQ,KAAK,WAAW,IAAI,MAAM,KAAK,KAAK,KAAK,KAAK;AAChF,UAAM,eAAe,KAAK,SAAS,IAAI,MAAM,KAAK;AAClD,QAAI,cAAc;AACjB,mBAAa,KAAK,KAAK;AAAA,IACxB,OAAO;AACN,WAAK,SAAS,IAAI,MAAM,OAAO,CAAC,KAAK,CAAC;AAAA,IACvC;AAAA,EACD;AAAA;AAAA,EAGA,OAAO,KAAmC;AACzC,WAAO,KAAK,MAAM,IAAI,GAAG;AAAA,EAC1B;AAAA;AAAA,EAGA,SAAS,SAA0B;AAClC,WAAO,KAAK,SAAS,IAAI,OAAO;AAAA,EACjC;AAAA;AAAA,EAGA,eAAe,KAAmB,OAAyD;AAC1F,QAAI,KAAK;AACT,QAAI,KAAK,KAAK,IAAI;AAClB,WAAO,KAAK,IAAI;AACf,YAAM,MAAO,KAAK,OAAQ;AAC1B,UAAI,IAAI,QAAQ,KAAK,IAAI,GAAG,EAAG,KAAK,GAAG,KAAK,GAAG;AAC9C,aAAK,MAAM;AAAA,MACZ,OAAO;AACN,aAAK;AAAA,MACN;AAAA,IACD;AACA,UAAM,UAAU,KAAK,IAAI,SAAS,KAAK;AACvC,WAAO,EAAE,QAAQ,KAAK,IAAI,MAAM,IAAI,KAAK,KAAK,GAAG,QAAQ;AAAA,EAC1D;AAAA;AAAA,EAGA,YAAY,QAAyD;AACpE,QAAI,KAAK,IAAI,WAAW,EAAG,QAAO;AAClC,WAAO,KAAK,kBAAkB,OAAO,YAAY,KAAK,IAAI,IAAI,KAAK,aAAa,OAAO;AAAA,EACxF;AAAA;AAAA,EAGA,aAA6E;AAC5E,UAAM,QAAwE,CAAC;AAC/E,eAAW,CAAC,OAAO,KAAK,KAAK,KAAK,YAAY;AAC7C,YAAM,KAAK;AAAA,QACV;AAAA,QACA,UAAU;AAAA,QACV,YAAY,KAAK,SAAS,IAAI,KAAK,GAAG,UAAU;AAAA,MACjD,CAAC;AAAA,IACF;AACA,WAAO;AAAA,EACR;AAAA;AAAA,EAGA,WAAW,OAA2B;AACrC,UAAM,cAAc,KAAK,SAAS,IAAI,KAAK,KAAK,CAAC;AACjD,QAAI,YAAY,WAAW,EAAG,QAAO,CAAC;AAGtC,SAAK,MAAM,KAAK,IAAI,OAAO,CAAC,MAAM,EAAE,UAAU,KAAK;AAGnD,eAAW,SAAS,aAAa;AAChC,WAAK,MAAM,OAAO,OAAO,MAAM,OAAO,MAAM,KAAK,CAAC;AAClD,WAAK,SAAS,OAAO,MAAM,OAAO;AAAA,IACnC;AAGA,UAAM,gBAAgB,KAAK,WAAW,IAAI,KAAK,KAAK;AACpD,SAAK,kBAAkB;AACvB,SAAK,WAAW,OAAO,KAAK;AAC5B,SAAK,SAAS,OAAO,KAAK;AAE1B,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,WAAsD;AACrD,WAAO,EAAE,SAAS,CAAC,GAAG,KAAK,GAAG,GAAG,UAAU,KAAK,eAAe;AAAA,EAChE;AAAA;AAAA,EAGA,QAAc;AACb,SAAK,MAAM,CAAC;AACZ,SAAK,MAAM,MAAM;AACjB,SAAK,SAAS,MAAM;AACpB,SAAK,iBAAiB;AACtB,SAAK,YAAY,KAAK,IAAI;AAC1B,SAAK,WAAW,MAAM;AACtB,SAAK,SAAS,MAAM;AAAA,EACrB;AAAA;AAAA,EAGA,QAAoB;AACnB,UAAM,EAAE,QAAQ,IAAI,KAAK,SAAS;AAClC,SAAK,MAAM;AACX,WAAO;AAAA,EACR;AAAA;AAAA,EAGA,IAAI,UAAkB;AACrB,WAAO,KAAK,IAAI;AAAA,EACjB;AAAA;AAAA,EAGA,IAAI,YAAoB;AACvB,WAAO,KAAK,MAAM;AAAA,EACnB;AAAA;AAAA,EAGA,IAAI,WAAmB;AACtB,WAAO,KAAK;AAAA,EACb;AAAA;AAAA,EAGA,IAAI,oBAA4B;AAC/B,WAAO,KAAK,IAAI,WAAW,IAAI,IAAI,KAAK,iBAAiB,KAAK,IAAI;AAAA,EACnE;AACD;;;AC7KO,IAAM,oBAAN,MAA+C;AAAA,EAC7C,UAAU,oBAAI,IAAyB;AAAA,EACvC,YAAY,oBAAI,IAA6B;AAAA,EAC7C,aAA8C,CAAC;AAAA,EAEvD,MAAM,UAAU,WAAqD;AACpE,WAAO,KAAK,QAAQ,IAAI,SAAS;AAAA,EAClC;AAAA,EAEA,MAAM,UAAU,WAAmB,QAAoC;AACtE,SAAK,QAAQ,IAAI,WAAW,MAAM;AAAA,EACnC;AAAA,EAEA,MAAM,aAAa,WAAyD;AAC3E,WAAO,KAAK,UAAU,IAAI,SAAS;AAAA,EACpC;AAAA,EAEA,MAAM,aAAa,WAAmB,OAAuC;AAC5E,SAAK,UAAU,IAAI,WAAW,KAAK;AAAA,EACpC;AAAA,EAEA,MAAM,gBAA0D;AAC/D,WAAO,EAAE,GAAG,KAAK,WAAW;AAAA,EAC7B;AAAA,EAEA,MAAM,cAAc,YAA4D;AAC/E,SAAK,aAAa,EAAE,GAAG,WAAW;AAAA,EACnC;AACD;;;AC9CO,IAAM,yBAAyB;AAG/B,IAAM,sBAAsB;AAG5B,IAAM,iBAAiB;AAGvB,IAAM,qBAAqB;AAG3B,IAAM,qBAA0C,IAAI,IAAI,YAAY;AAGpE,IAAM,2BAA2B,IAAI,OAAO;AAG5C,IAAM,4BAA4B;;;ACwBlC,SAAS,SAAS,SAA+D;AACvF,MAAI,MAAM,QAAQ,CAAC,EAAG;AACtB,MAAI,MAAM,QAAQ,CAAC,EAAG;AACtB,WAAS,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK;AACxC,UAAM,MAAM,QAAQ,CAAC,EAAG;AACxB,QAAI,IAAI,QAAQ,KAAK,GAAG,IAAI,EAAG,OAAM;AACrC,QAAI,IAAI,QAAQ,KAAK,GAAG,IAAI,EAAG,OAAM;AAAA,EACtC;AACA,SAAO,EAAE,KAAK,IAAI;AACnB;AASA,eAAsB,aACrB,SACA,UACA,MACA,WACoC;AAEpC,MAAI,kBAAkB,KAAK,OAAO,GAAG;AACpC,QAAI;AACH,YAAM,SAAS,MAAM,KAAK,QAAQ,aAAa,OAAO;AACtD,UAAI,CAAC,OAAO,IAAI;AACf,aAAK,eAAe,OAAO;AAC3B,eAAO,IAAI,IAAI,WAAW,0BAA0B,OAAO,MAAM,OAAO,EAAE,CAAC;AAAA,MAC5E;AAGA,UAAI,KAAK,WAAW,KAAK,QAAQ,SAAS,KAAK,iBAAiB,KAAK,OAAO,GAAG;AAC9E,YAAI;AACH,gBAAM,YAAY,MAAM,KAAK,QAAQ,YAAY,SAAS,KAAK,OAAO;AACtE,cAAI,CAAC,UAAU,IAAI;AAClB,oBAAQ;AAAA,cACP,sCAAsC,QAAQ,MAAM,aAAa,UAAU,MAAM,OAAO;AAAA,YACzF;AAAA,UACD;AAAA,QACD,SAAS,OAAgB;AACxB,kBAAQ;AAAA,YACP,qCAAqC,QAAQ,MAAM,aAAa,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AAAA,UACvH;AAAA,QACD;AAAA,MACD;AAEA,aAAO,GAAG,MAAS;AAAA,IACpB,SAAS,OAAgB;AACxB,WAAK,eAAe,OAAO;AAC3B,aAAO,IAAI,IAAI,WAAW,sCAAsC,QAAQ,KAAK,EAAE,OAAO,EAAE,CAAC;AAAA,IAC1F;AAAA,EACD;AAGA,MAAI;AACH,UAAM,EAAE,KAAK,IAAI,IAAI,SAAS,OAAO;AACrC,UAAM,QAAO,oBAAI,KAAK,GAAE,YAAY,EAAE,MAAM,GAAG,EAAE,CAAC;AAClD,UAAM,SAAS,YAAY,GAAG,SAAS,MAAM;AAC7C,QAAI;AACJ,QAAI;AACJ,QAAI;AAEJ,QAAI,KAAK,OAAO,gBAAgB,QAAQ;AACvC,YAAM,WAA0B;AAAA,QAC/B,SAAS;AAAA,QACT,WAAW,KAAK,OAAO;AAAA,QACvB,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,QAClC,UAAU,EAAE,KAAK,IAAI;AAAA,QACrB,YAAY,QAAQ;AAAA,QACpB;AAAA,QACA,QAAQ;AAAA,MACT;AAEA,kBAAY,UAAU,IAAI,IAAI,KAAK,OAAO,SAAS,IAAI,MAAM,GAAG,IAAI,SAAS,CAAC,IAAI,IAAI,SAAS,CAAC;AAChG,aAAO,IAAI,YAAY,EAAE,OAAO,KAAK,UAAU,UAAU,cAAc,CAAC;AACxE,oBAAc;AAAA,IACf,OAAO;AAEN,UAAI,CAAC,KAAK,OAAO,aAAa;AAC7B,aAAK,eAAe,OAAO;AAC3B,eAAO,IAAI,IAAI,WAAW,wCAAwC,CAAC;AAAA,MACpE;AAEA,YAAM,gBAAgB,MAAM,qBAAqB,SAAS,KAAK,OAAO,WAAW;AACjF,UAAI,CAAC,cAAc,IAAI;AACtB,aAAK,eAAe,OAAO;AAC3B,eAAO,IAAI,cAAc,KAAK;AAAA,MAC/B;AAEA,kBAAY,UAAU,IAAI,IAAI,KAAK,OAAO,SAAS,IAAI,MAAM,GAAG,IAAI,SAAS,CAAC,IAAI,IAAI,SAAS,CAAC;AAChG,aAAO,cAAc;AACrB,oBAAc;AAAA,IACf;AAEA,UAAM,SAAS,MAAM,KAAK,QAAQ,UAAU,WAAW,MAAM,WAAW;AACxE,QAAI,CAAC,OAAO,IAAI;AACf,WAAK,eAAe,OAAO;AAC3B,aAAO,IAAI,IAAI,WAAW,mCAAmC,OAAO,MAAM,OAAO,EAAE,CAAC;AAAA,IACrF;AAEA,QAAI,KAAK,OAAO,aAAa,KAAK,OAAO,aAAa;AACrD,YAAM;AAAA,QACL;AAAA,QACA,KAAK;AAAA,QACL,QAAQ;AAAA,QACR,KAAK,OAAO;AAAA,QACZ,KAAK,OAAO;AAAA,MACb;AAAA,IACD;AAEA,WAAO,GAAG,MAAS;AAAA,EACpB,SAAS,OAAgB;AACxB,SAAK,eAAe,OAAO;AAC3B,WAAO,IAAI,IAAI,WAAW,6BAA6B,QAAQ,KAAK,EAAE,OAAO,EAAE,CAAC;AAAA,EACjF;AACD;AAOA,eAAsB,kBACrB,WACA,iBACA,aACA,WACA,QACgB;AAChB,QAAM,EAAE,WAAW,KAAK,IAAI,kBAAkB,OAAO,KAAK;AAC1D,QAAM,gBAAgB,qBAAqB,MAAM;AACjD,QAAM,gBAAgB,mBAAmB,aAAa;AAGtD,QAAM,UAAU,gBAAgB,SAAS;AAGzC,QAAM,eAAe,MAAM,UAAU,YAAY,WAAW,MAAM,eAAe,aAAa;AAC9F,MAAI,CAAC,aAAa,MAAM,aAAa,MAAM,eAAe,KAAK;AAC9D;AAAA,EACD;AAGA,QAAM,WAAqB;AAAA,IAC1B,SAAS;AAAA,IACT,aAAa;AAAA,IACb,eAAe;AAAA,IACf,gBAAgB;AAAA,IAChB,sBAAsB;AAAA,EACvB;AAGA,QAAM,eAAe,MAAM,UAAU,YAAY,WAAW,MAAM,CAAC,QAAQ,CAAC;AAC5E,MAAI,CAAC,aAAa,MAAM,aAAa,MAAM,eAAe,KAAK;AAE9D,UAAM,UAAU,YAAY,WAAW,MAAM,CAAC,QAAQ,CAAC;AAAA,EACxD;AACD;;;ACxLO,IAAM,mBAAN,MAAuB;AAAA,EACrB,WAAW;AAAA;AAAA,EAGnB,IAAI,aAAsB;AACzB,WAAO,KAAK;AAAA,EACb;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,MACL,QACA,SACA,MACoC;AACpC,QAAI,KAAK,UAAU;AAClB,aAAO,IAAI,IAAI,WAAW,2BAA2B,CAAC;AAAA,IACvD;AACA,QAAI,OAAO,YAAY,GAAG;AACzB,aAAO,GAAG,MAAS;AAAA,IACpB;AACA,QAAI,CAAC,SAAS;AACb,aAAO,IAAI,IAAI,WAAW,uBAAuB,CAAC;AAAA,IACnD;AAEA,SAAK,WAAW;AAEhB,UAAM,WAAW,kBAAkB,OAAO,IAAI,IAAI,OAAO;AACzD,UAAM,UAAU,OAAO,MAAM;AAC7B,QAAI,QAAQ,WAAW,GAAG;AACzB,WAAK,WAAW;AAChB,aAAO,GAAG,MAAS;AAAA,IACpB;AAEA,QAAI;AACH,aAAO,MAAM,aAAa,SAAS,UAAU;AAAA,QAC5C;AAAA,QACA,QAAQ,KAAK;AAAA,QACb,gBAAgB,CAAC,MAAM,KAAK,eAAe,QAAQ,CAAC;AAAA,QACpD,SAAS,KAAK;AAAA,MACf,CAAC;AAAA,IACF,UAAE;AACD,WAAK,WAAW;AAAA,IACjB;AAAA,EACD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,WACL,OACA,QACA,SACA,MACoC;AACpC,QAAI,KAAK,UAAU;AAClB,aAAO,IAAI,IAAI,WAAW,2BAA2B,CAAC;AAAA,IACvD;AACA,QAAI,CAAC,SAAS;AACb,aAAO,IAAI,IAAI,WAAW,uBAAuB,CAAC;AAAA,IACnD;AAEA,UAAM,UAAU,OAAO,WAAW,KAAK;AACvC,QAAI,QAAQ,WAAW,GAAG;AACzB,aAAO,GAAG,MAAS;AAAA,IACpB;AAEA,SAAK,WAAW;AAEhB,QAAI;AACH,aAAO,MAAM;AAAA,QACZ;AAAA,QACA;AAAA,QACA;AAAA,UACC;AAAA,UACA,QAAQ,KAAK;AAAA,UACb,gBAAgB,CAAC,MAAM,KAAK,eAAe,QAAQ,CAAC;AAAA,UACpD,SAAS,KAAK;AAAA,QACf;AAAA,QACA;AAAA,MACD;AAAA,IACD,UAAE;AACD,WAAK,WAAW;AAAA,IACjB;AAAA,EACD;AAAA;AAAA,EAGQ,eAAe,QAAqB,SAA2B;AACtE,eAAW,SAAS,SAAS;AAC5B,aAAO,OAAO,KAAK;AAAA,IACpB;AAAA,EACD;AACD;;;AChHO,IAAM,iBAAN,MAAqB;AAAA,EACnB,UAAwC,oBAAI,IAAI;AAAA,EAExD,YAAY,SAA2C;AACtD,QAAI,SAAS;AACZ,iBAAW,CAAC,MAAM,OAAO,KAAK,OAAO,QAAQ,OAAO,GAAG;AACtD,aAAK,QAAQ,IAAI,MAAM,OAAO;AAAA,MAC/B;AAAA,IACD;AAAA,EACD;AAAA;AAAA,EAGA,SAAS,MAAc,SAAgC;AACtD,SAAK,QAAQ,IAAI,MAAM,OAAO;AAAA,EAC/B;AAAA;AAAA,EAGA,WAAW,MAAoB;AAC9B,SAAK,QAAQ,OAAO,IAAI;AAAA,EACzB;AAAA;AAAA,EAGA,IAAI,MAA2C;AAC9C,WAAO,KAAK,QAAQ,IAAI,IAAI;AAAA,EAC7B;AAAA;AAAA,EAGA,OAAiB;AAChB,WAAO,CAAC,GAAG,KAAK,QAAQ,KAAK,CAAC;AAAA,EAC/B;AACD;;;ACIO,IAAM,cAAN,MAA0C;AAAA,EACxC;AAAA,EACC;AAAA,EACA;AAAA,EACD;AAAA,EACA;AAAA,EACS;AAAA,EACA;AAAA,EAEjB,YAAY,QAAuB,SAAyC;AAC3E,SAAK,SAAS,EAAE,gBAAgB,CAAC,GAAG,GAAG,OAAO;AAC9C,SAAK,MAAM,IAAI,IAAI;AACnB,SAAK,SAAS,IAAI,YAAY;AAC9B,SAAK,UAAU,KAAK,OAAO,WAAW,WAAW;AACjD,SAAK,UAAU,IAAI,iBAAiB,OAAO,cAAc;AACzD,SAAK,UAAU,IAAI,eAAe,KAAK,OAAO,cAAc;AAC5D,SAAK,mBAAmB,IAAI,iBAAiB;AAAA,EAC9C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAeA,WACC,KAC8E;AAE9E,UAAM,WAAW,KAAK,kBAAkB;AACxC,QAAI,CAAC,SAAS,GAAI,QAAO;AAEzB,QAAI,WAAW;AACf,UAAM,WAAuB,CAAC;AAE9B,eAAW,SAAS,IAAI,QAAQ;AAE/B,UAAI,KAAK,OAAO,SAAS,MAAM,OAAO,GAAG;AACxC;AACA;AAAA,MACD;AAGA,UAAI,KAAK,OAAO,eAAe;AAC9B,cAAM,eAAe,KAAK,OAAO,cAAc,cAAc,KAAK;AAClE,YAAI,CAAC,aAAa,IAAI;AACrB,iBAAO,IAAI,aAAa,KAAK;AAAA,QAC9B;AAAA,MACD;AAGA,YAAM,aAAa,KAAK,IAAI,KAAK,MAAM,GAAG;AAC1C,UAAI,CAAC,WAAW,IAAI;AACnB,eAAO,IAAI,WAAW,KAAK;AAAA,MAC5B;AAGA,YAAM,MAAM,OAAO,MAAM,OAAO,MAAM,KAAK;AAC3C,YAAM,WAAW,KAAK,OAAO,OAAO,GAAG;AAEvC,UAAI,UAAU;AACb,cAAM,WAAW,WAAW,UAAU,KAAK;AAC3C,YAAI,SAAS,IAAI;AAChB,eAAK,OAAO,OAAO,SAAS,KAAK;AACjC,mBAAS,KAAK,SAAS,KAAK;AAAA,QAC7B;AAAA,MACD,OAAO;AACN,aAAK,OAAO,OAAO,KAAK;AACxB,iBAAS,KAAK,KAAK;AAAA,MACpB;AAEA;AAAA,IACD;AAEA,UAAM,YAAY,KAAK,IAAI,IAAI;AAC/B,WAAO,GAAG,EAAE,WAAW,UAAU,QAAQ,SAAS,CAAC;AAAA,EACpD;AAAA;AAAA,EAGQ,oBAAqD;AAC5D,UAAM,oBAAoB,KAAK,OAAO,wBAAwB,KAAK,OAAO,iBAAiB;AAC3F,QAAI,KAAK,OAAO,YAAY,mBAAmB;AAC9C,aAAO;AAAA,QACN,IAAI;AAAA,UACH,iCAAiC,KAAK,OAAO,QAAQ,OAAO,iBAAiB;AAAA,QAC9E;AAAA,MACD;AAAA,IACD;AACA,WAAO,GAAG,MAAS;AAAA,EACpB;AAAA,EAyBA,WACC,KACA,SAG8B;AAC9B,QAAI,IAAI,QAAQ;AACf,aAAO,KAAK,kBAAkB,KAAK,OAAO;AAAA,IAC3C;AAEA,WAAO,KAAK,iBAAiB,KAAK,OAAO;AAAA,EAC1C;AAAA;AAAA,EAGQ,iBAAiB,KAAe,SAAyD;AAChG,QAAI,CAAC,SAAS;AACb,YAAM,EAAE,QAAQ,SAAAA,SAAQ,IAAI,KAAK,OAAO,eAAe,IAAI,UAAU,IAAI,SAAS;AAClF,YAAMC,aAAY,KAAK,IAAI,IAAI;AAC/B,aAAO,GAAG,EAAE,QAAQ,WAAAA,YAAW,SAAAD,SAAQ,CAAC;AAAA,IACzC;AAGA,UAAM,aAAa;AACnB,UAAM,sBAAsB;AAC5B,QAAI,SAAS,IAAI;AACjB,UAAM,YAAwB,CAAC;AAE/B,aAAS,UAAU,GAAG,UAAU,YAAY,WAAW;AACtD,YAAM,aAAa,IAAI,YAAY;AACnC,YAAM,EAAE,QAAQ,KAAK,SAAS,WAAW,IAAI,KAAK,OAAO,eAAe,QAAQ,UAAU;AAE1F,UAAI,IAAI,WAAW,GAAG;AACrB,cAAMC,aAAY,KAAK,IAAI,IAAI;AAC/B,eAAO,GAAG,EAAE,QAAQ,WAAW,WAAAA,YAAW,SAAS,MAAM,CAAC;AAAA,MAC3D;AAEA,YAAM,WAAW,aAAa,KAAK,OAAO;AAC1C,gBAAU,KAAK,GAAG,QAAQ;AAE1B,UAAI,UAAU,UAAU,IAAI,WAAW;AACtC,cAAMC,WAAU,UAAU,MAAM,GAAG,IAAI,SAAS;AAChD,cAAMD,aAAY,KAAK,IAAI,IAAI;AAC/B,eAAO,GAAG,EAAE,QAAQC,UAAS,WAAAD,YAAW,SAAS,KAAK,CAAC;AAAA,MACxD;AAEA,UAAI,CAAC,YAAY;AAChB,cAAMA,aAAY,KAAK,IAAI,IAAI;AAC/B,eAAO,GAAG,EAAE,QAAQ,WAAW,WAAAA,YAAW,SAAS,MAAM,CAAC;AAAA,MAC3D;AAEA,eAAS,IAAI,IAAI,SAAS,CAAC,EAAG;AAAA,IAC/B;AAGA,UAAM,YAAY,KAAK,IAAI,IAAI;AAC/B,UAAM,UAAU,UAAU,UAAU,IAAI;AACxC,UAAM,UAAU,UAAU,MAAM,GAAG,IAAI,SAAS;AAChD,WAAO,GAAG,EAAE,QAAQ,SAAS,WAAW,QAAQ,CAAC;AAAA,EAClD;AAAA;AAAA,EAGA,MAAc,kBACb,KACA,SACqE;AACrE,UAAM,UAAU,KAAK,QAAQ,IAAI,IAAI,MAAO;AAC5C,QAAI,CAAC,SAAS;AACb,aAAO,IAAI,IAAI,qBAAqB,mBAAmB,IAAI,MAAM,aAAa,CAAC;AAAA,IAChF;AAEA,UAAM,cAAc,MAAM,QAAQ,iBAAiB,IAAI,QAAQ;AAC/D,QAAI,CAAC,YAAY,IAAI;AACpB,aAAO,IAAI,YAAY,KAAK;AAAA,IAC7B;AAEA,QAAI,SAAS,YAAY;AAEzB,QAAI,SAAS;AACZ,eAAS,aAAa,QAAQ,OAAO;AAAA,IACtC;AAEA,UAAM,UAAU,OAAO,SAAS,IAAI;AACpC,UAAM,SAAS,OAAO,MAAM,GAAG,IAAI,SAAS;AAE5C,UAAM,YAAY,KAAK,IAAI,IAAI;AAC/B,WAAO,GAAG,EAAE,QAAQ,QAAQ,WAAW,QAAQ,CAAC;AAAA,EACjD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgBA,MAAM,QAA2C;AAChD,WAAO,KAAK,iBAAiB,MAAM,KAAK,QAAQ,KAAK,SAAS;AAAA,MAC7D,QAAQ;AAAA,QACP,WAAW,KAAK,OAAO;AAAA,QACvB,aAAa,KAAK,OAAO;AAAA,QACzB,aAAa,KAAK,OAAO;AAAA,QACzB,WAAW,KAAK,OAAO;AAAA,MACxB;AAAA,MACA,SAAS,KAAK,OAAO;AAAA,IACtB,CAAC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,WAAW,OAAkD;AAClE,WAAO,KAAK,iBAAiB,WAAW,OAAO,KAAK,QAAQ,KAAK,SAAS;AAAA,MACzE,QAAQ;AAAA,QACP,WAAW,KAAK,OAAO;AAAA,QACvB,aAAa,KAAK,OAAO;AAAA,QACzB,aAAa,KAAK,OAAO;AAAA,QACzB,WAAW,KAAK,OAAO;AAAA,MACxB;AAAA,MACA,SAAS,KAAK,OAAO;AAAA,IACtB,CAAC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,aACL,KACA,SACyD;AACzD,WAAO,KAAK,QAAQ,SAAS,KAAK,MAAM,KAAK,IAAI,IAAI,GAAG,OAAO;AAAA,EAChE;AAAA;AAAA,EAGA,sBAAsB,MAAc,SAA8B;AACjE,SAAK,QAAQ,gBAAgB,MAAM,OAAO;AAAA,EAC3C;AAAA;AAAA,EAGA,wBAAwB,MAAoB;AAC3C,SAAK,QAAQ,kBAAkB,IAAI;AAAA,EACpC;AAAA;AAAA,EAGA,qBAA+B;AAC9B,WAAO,KAAK,QAAQ,aAAa;AAAA,EAClC;AAAA;AAAA,EAGA,kBAAmC;AAClC,WAAO,KAAK,QAAQ,SAAS;AAAA,EAC9B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,eAAe,MAAc,SAAgC;AAC5D,SAAK,QAAQ,SAAS,MAAM,OAAO;AAAA,EACpC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,iBAAiB,MAAoB;AACpC,SAAK,QAAQ,WAAW,IAAI;AAAA,EAC7B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,cAAwB;AACvB,WAAO,KAAK,QAAQ,KAAK;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,IAAI,aAA6E;AAChF,WAAO,KAAK,OAAO,WAAW;AAAA,EAC/B;AAAA;AAAA;AAAA;AAAA,EAKA,2BAAqC;AACpC,UAAM,SAAS,KAAK,OAAO;AAC3B,QAAI,CAAC,OAAQ,QAAO,CAAC;AACrB,WAAO,KAAK,OACV,WAAW,EACX,OAAO,CAAC,MAAM,EAAE,YAAY,MAAM,EAClC,IAAI,CAAC,MAAM,EAAE,KAAK;AAAA,EACrB;AAAA;AAAA,EAGA,cAAuB;AACtB,QAAI,oBAAoB,KAAK,OAAO;AAGpC,UAAM,WAAW,KAAK,OAAO;AAC7B,QAAI,YAAY,KAAK,OAAO,oBAAoB,SAAS,qBAAqB;AAC7E,0BAAoB,KAAK,MAAM,oBAAoB,SAAS,eAAe;AAAA,IAC5E;AAEA,WAAO,KAAK,OAAO,YAAY;AAAA,MAC9B,UAAU;AAAA,MACV,UAAU,KAAK,OAAO;AAAA,IACvB,CAAC;AAAA,EACF;AAAA;AAAA,EAGA,IAAI,cAIF;AACD,WAAO;AAAA,MACN,SAAS,KAAK,OAAO;AAAA,MACrB,WAAW,KAAK,OAAO;AAAA,MACvB,UAAU,KAAK,OAAO;AAAA,IACvB;AAAA,EACD;AACD;;;AC/XO,SAAS,UACf,KACA,SAC0B;AAC1B,MAAI;AACH,WAAO,GAAG,KAAK,MAAM,KAAK,OAAO,CAAM;AAAA,EACxC,QAAQ;AACP,WAAO,IAAI,EAAE,QAAQ,KAAK,SAAS,oBAAoB,CAAC;AAAA,EACzD;AACD;AAMO,SAAS,iBACf,KACA,gBACiC;AACjC,QAAM,SAAS,UAAoB,KAAK,aAAa;AACrD,MAAI,CAAC,OAAO,GAAI,QAAO;AACvB,QAAM,OAAO,OAAO;AAEpB,MAAI,CAAC,KAAK,YAAY,CAAC,MAAM,QAAQ,KAAK,MAAM,GAAG;AAClD,WAAO,IAAI,EAAE,QAAQ,KAAK,SAAS,4CAA4C,CAAC;AAAA,EACjF;AAEA,MAAI,kBAAkB,KAAK,aAAa,gBAAgB;AACvD,WAAO,IAAI;AAAA,MACV,QAAQ;AAAA,MACR,SAAS;AAAA,IACV,CAAC;AAAA,EACF;AAEA,MAAI,KAAK,OAAO,SAAS,qBAAqB;AAC7C,WAAO,IAAI,EAAE,QAAQ,KAAK,SAAS,gDAAgD,CAAC;AAAA,EACrF;AAEA,SAAO,GAAG,IAAI;AACf;AAKO,SAAS,gBAAgB,QAKG;AAClC,MAAI,CAAC,OAAO,SAAS,CAAC,OAAO,UAAU;AACtC,WAAO,IAAI,EAAE,QAAQ,KAAK,SAAS,iDAAiD,CAAC;AAAA,EACtF;AAEA,MAAI;AACJ,MAAI;AACH,eAAW,OAAO,OAAO,KAAK;AAAA,EAC/B,QAAQ;AACP,WAAO,IAAI;AAAA,MACV,QAAQ;AAAA,MACR,SAAS;AAAA,IACV,CAAC;AAAA,EACF;AAEA,QAAM,WAAW,OAAO,QAAQ,OAAO,SAAS,OAAO,OAAO,EAAE,IAAI;AACpE,MAAI,OAAO,MAAM,QAAQ,KAAK,WAAW,GAAG;AAC3C,WAAO,IAAI;AAAA,MACV,QAAQ;AAAA,MACR,SAAS;AAAA,IACV,CAAC;AAAA,EACF;AACA,QAAM,YAAY,KAAK,IAAI,UAAU,cAAc;AAEnD,QAAM,MAAgB;AAAA,IACrB,UAAU,OAAO;AAAA,IACjB;AAAA,IACA;AAAA,IACA,GAAI,OAAO,SAAS,EAAE,QAAQ,OAAO,OAAO,IAAI,CAAC;AAAA,EAClD;AAEA,SAAO,GAAG,GAAG;AACd;AAKO,SAAS,mBACf,KACA,gBACmC;AACnC,QAAM,SAAS,UAAsB,KAAK,aAAa;AACvD,MAAI,CAAC,OAAO,GAAI,QAAO;AACvB,QAAM,OAAO,OAAO;AAEpB,MAAI,CAAC,KAAK,YAAY,CAAC,MAAM,QAAQ,KAAK,OAAO,GAAG;AACnD,WAAO,IAAI,EAAE,QAAQ,KAAK,SAAS,6CAA6C,CAAC;AAAA,EAClF;AAEA,MAAI,kBAAkB,KAAK,aAAa,gBAAgB;AACvD,WAAO,IAAI;AAAA,MACV,QAAQ;AAAA,MACR,SAAS;AAAA,IACV,CAAC;AAAA,EACF;AAEA,SAAO,GAAG,IAAI;AACf;AAKO,SAAS,mBAAmB,KAAgD;AAClF,QAAM,SAAS,UAAuB,GAAG;AACzC,MAAI,CAAC,OAAO,GAAI,QAAO;AACvB,QAAM,SAAS,OAAO;AAEtB,MAAI,CAAC,OAAO,SAAS,CAAC,MAAM,QAAQ,OAAO,OAAO,GAAG;AACpD,WAAO,IAAI,EAAE,QAAQ,KAAK,SAAS,0CAA0C,CAAC;AAAA,EAC/E;AAEA,aAAW,OAAO,OAAO,SAAS;AACjC,QAAI,OAAO,IAAI,SAAS,YAAY,IAAI,KAAK,WAAW,GAAG;AAC1D,aAAO,IAAI,EAAE,QAAQ,KAAK,SAAS,kDAAkD,CAAC;AAAA,IACvF;AACA,QAAI,CAAC,mBAAmB,IAAI,IAAI,IAAI,GAAG;AACtC,aAAO,IAAI;AAAA,QACV,QAAQ;AAAA,QACR,SAAS,wBAAwB,IAAI,IAAI,iBAAiB,IAAI,IAAI;AAAA,MACnE,CAAC;AAAA,IACF;AAAA,EACD;AAEA,QAAM,cAAc,IAAI,IAAI,OAAO,QAAQ,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC;AAG7D,MAAI,OAAO,eAAe,QAAW;AACpC,QAAI,CAAC,MAAM,QAAQ,OAAO,UAAU,KAAK,OAAO,WAAW,WAAW,GAAG;AACxE,aAAO,IAAI,EAAE,QAAQ,KAAK,SAAS,kDAAkD,CAAC;AAAA,IACvF;AACA,eAAW,MAAM,OAAO,YAAY;AACnC,UAAI,OAAO,OAAO,UAAU;AAC3B,eAAO,IAAI,EAAE,QAAQ,KAAK,SAAS,kDAAkD,CAAC;AAAA,MACvF;AACA,UAAI,OAAO,YAAY,CAAC,YAAY,IAAI,EAAE,GAAG;AAC5C,eAAO,IAAI;AAAA,UACV,QAAQ;AAAA,UACR,SAAS,sBAAsB,EAAE;AAAA,QAClC,CAAC;AAAA,MACF;AAAA,IACD;AAAA,EACD;AAGA,MAAI,OAAO,eAAe,UAAa,OAAO,OAAO,eAAe,WAAW;AAC9E,WAAO,IAAI,EAAE,QAAQ,KAAK,SAAS,+BAA+B,CAAC;AAAA,EACpE;AAGA,MAAI,OAAO,qBAAqB,QAAW;AAC1C,QAAI,OAAO,OAAO,qBAAqB,YAAY,OAAO,iBAAiB,WAAW,GAAG;AACxF,aAAO,IAAI,EAAE,QAAQ,KAAK,SAAS,8CAA8C,CAAC;AAAA,IACnF;AACA,QAAI,CAAC,YAAY,IAAI,OAAO,gBAAgB,GAAG;AAC9C,aAAO,IAAI;AAAA,QACV,QAAQ;AAAA,QACR,SAAS,qBAAqB,OAAO,gBAAgB;AAAA,MACtD,CAAC;AAAA,IACF;AAAA,EACD;AAEA,SAAO,GAAG,MAAM;AACjB;AAKO,SAAS,kBAAkB,MAAsB;AACvD,UAAQ,MAAM;AAAA,IACb,KAAK;AACJ,aAAO;AAAA,IACR,KAAK;AACJ,aAAO;AAAA,IACR,KAAK;AACJ,aAAO;AAAA,IACR;AACC,aAAO;AAAA,EACT;AACD;AAMO,SAAS,sBACf,OACA,QAC+B;AAC/B,MAAI,CAAC,SAAS,MAAM,QAAQ,WAAW,GAAG;AACzC,WAAO;AAAA,EACR;AACA,SAAO,EAAE,QAAQ,MAAM;AACxB;;;AClMO,SAAS,kBACf,SACA,KACA,gBACA,MAYgB;AAChB,QAAM,aAAa,iBAAiB,KAAK,cAAc;AACvD,MAAI,CAAC,WAAW,IAAI;AACnB,WAAO,EAAE,QAAQ,WAAW,MAAM,QAAQ,MAAM,EAAE,OAAO,WAAW,MAAM,QAAQ,EAAE;AAAA,EACrF;AAEA,QAAM,OAAO,WAAW;AAGxB,QAAM,eAAe,KAAK,MAAM;AAEhC,QAAM,SAAS,QAAQ,WAAW,IAAI;AACtC,MAAI,CAAC,OAAO,IAAI;AACf,WAAO;AAAA,MACN,QAAQ,kBAAkB,OAAO,MAAM,IAAI;AAAA,MAC3C,MAAM,EAAE,OAAO,OAAO,MAAM,QAAQ;AAAA,IACrC;AAAA,EACD;AAGA,QAAM,mBAAmB;AAGzB,MAAI,MAAM,eAAe,OAAO,MAAM,OAAO,SAAS,GAAG;AACxD,SAAK,YAAY,OAAO,MAAM,QAAQ,OAAO,MAAM,WAAW,KAAK,QAAQ;AAAA,EAC5E;AAEA,SAAO,EAAE,QAAQ,KAAK,MAAM,OAAO,MAAM;AAC1C;AAKA,eAAsB,kBACrB,SACA,QAMA,QACA,WACyB;AACzB,QAAM,aAAa,gBAAgB,MAAM;AACzC,MAAI,CAAC,WAAW,IAAI;AACnB,WAAO,EAAE,QAAQ,WAAW,MAAM,QAAQ,MAAM,EAAE,OAAO,WAAW,MAAM,QAAQ,EAAE;AAAA,EACrF;AAEA,QAAM,MAAM,WAAW;AACvB,QAAM,UAAU,sBAAsB,WAAW,UAAU,CAAC,CAAC;AAE7D,QAAM,SAAS,IAAI,SAChB,MAAM,QAAQ;AAAA,IACd;AAAA,IACA;AAAA,EACD,IACC,QAAQ,WAAW,KAAK,OAAO;AAElC,MAAI,CAAC,OAAO,IAAI;AACf,UAAM,MAAM,OAAO;AACnB,QAAI,IAAI,SAAS,qBAAqB;AACrC,aAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,IAAI,QAAQ,EAAE;AAAA,IACpD;AACA,WAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,IAAI,QAAQ,EAAE;AAAA,EACpD;AAEA,SAAO,EAAE,QAAQ,KAAK,MAAM,OAAO,MAAM;AAC1C;AAKA,eAAsB,oBACrB,SACA,KACA,gBACA,QACyB;AACzB,QAAM,aAAa,mBAAmB,KAAK,cAAc;AACzD,MAAI,CAAC,WAAW,IAAI;AACnB,WAAO,EAAE,QAAQ,WAAW,MAAM,QAAQ,MAAM,EAAE,OAAO,WAAW,MAAM,QAAQ,EAAE;AAAA,EACrF;AAEA,QAAM,UAAU,SAAS,EAAE,OAAO,IAAI;AACtC,QAAM,SAAS,MAAM,QAAQ,aAAa,WAAW,OAAO,OAAO;AAEnE,MAAI,CAAC,OAAO,IAAI;AACf,WAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,OAAO,MAAM,QAAQ,EAAE;AAAA,EAC7D;AAEA,SAAO,EAAE,QAAQ,KAAK,MAAM,OAAO,MAAM;AAC1C;AAKA,eAAsB,mBACrB,SACA,MACyB;AACzB,QAAM,SAAS,MAAM,QAAQ,MAAM;AACnC,MAAI,CAAC,OAAO,IAAI;AACf,WAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,OAAO,MAAM,QAAQ,EAAE;AAAA,EAC7D;AAEA,QAAM,mBAAmB;AACzB,SAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,SAAS,KAAK,EAAE;AAC/C;AAKA,eAAsB,iBACrB,KACA,OACA,WACyB;AACzB,QAAM,aAAa,mBAAmB,GAAG;AACzC,MAAI,CAAC,WAAW,IAAI;AACnB,WAAO,EAAE,QAAQ,WAAW,MAAM,QAAQ,MAAM,EAAE,OAAO,WAAW,MAAM,QAAQ,EAAE;AAAA,EACrF;AAEA,QAAM,MAAM,UAAU,WAAW,WAAW,KAAK;AACjD,SAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,KAAK,EAAE;AAC7C;AAKA,eAAsB,oBACrB,KACA,OACA,WACyB;AACzB,QAAM,SAAS,UAAmB,GAAG;AACrC,MAAI,CAAC,OAAO,IAAI;AACf,WAAO,EAAE,QAAQ,OAAO,MAAM,QAAQ,MAAM,EAAE,OAAO,OAAO,MAAM,QAAQ,EAAE;AAAA,EAC7E;AACA,QAAM,SAAS,OAAO;AAEtB,QAAM,aAAa,kBAAkB,MAAM;AAC3C,MAAI,CAAC,WAAW,IAAI;AACnB,WAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,WAAW,MAAM,QAAQ,EAAE;AAAA,EACjE;AAEA,QAAM,MAAM,aAAa,WAAW,MAAyB;AAC7D,SAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,KAAK,EAAE;AAC7C;AAKA,eAAsB,wBACrB,KACA,OACyB;AACzB,QAAM,SAAS,UAAmB,GAAG;AACrC,MAAI,CAAC,OAAO,IAAI;AACf,WAAO,EAAE,QAAQ,OAAO,MAAM,QAAQ,MAAM,EAAE,OAAO,OAAO,MAAM,QAAQ,EAAE;AAAA,EAC7E;AACA,QAAM,OAAO,OAAO;AAEpB,QAAM,aAAa,wBAAwB,IAAI;AAC/C,MAAI,CAAC,WAAW,IAAI;AACnB,WAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,WAAW,MAAM,QAAQ,EAAE;AAAA,EACjE;AAEA,QAAM,SAAS,WAAW;AAC1B,QAAM,aAAa,MAAM,MAAM,cAAc;AAE7C,MAAI,WAAW,OAAO,IAAI,GAAG;AAC5B,WAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,cAAc,OAAO,IAAI,mBAAmB,EAAE;AAAA,EACpF;AAEA,aAAW,OAAO,IAAI,IAAI;AAC1B,QAAM,MAAM,cAAc,UAAU;AAEpC,SAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,YAAY,MAAM,MAAM,OAAO,KAAK,EAAE;AACrE;AAKA,eAAsB,0BACrB,MACA,OACyB;AACzB,QAAM,aAAa,MAAM,MAAM,cAAc;AAE7C,MAAI,CAAC,WAAW,IAAI,GAAG;AACtB,WAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,cAAc,IAAI,cAAc,EAAE;AAAA,EACxE;AAEA,SAAO,WAAW,IAAI;AACtB,QAAM,MAAM,cAAc,UAAU;AAEpC,SAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,cAAc,MAAM,KAAK,EAAE;AAC1D;AAKA,eAAsB,qBAAqB,OAA4C;AACtF,QAAM,aAAa,MAAM,MAAM,cAAc;AAC7C,QAAM,OAAO,OAAO,OAAO,UAAU,EAAE,IAAI,CAAC,OAAO;AAAA,IAClD,MAAM,EAAE;AAAA,IACR,MAAM,EAAE;AAAA,IACR,WAAW,EAAE,WAAW;AAAA,EACzB,EAAE;AAEF,SAAO,EAAE,QAAQ,KAAK,MAAM,KAAK;AAClC;AAKO,SAAS,2BAA0C;AACzD,SAAO,EAAE,QAAQ,KAAK,MAAM,yBAAyB,EAAE;AACxD;AAKO,SAAS,cACf,SACA,OACgB;AAChB,QAAM,QAAQ,QAAQ;AACtB,SAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,GAAG,OAAO,GAAG,MAAM,EAAE;AACpD;;;AC9QO,IAAM,gBAAN,MAAoB;AAAA,EAClB;AAAA,EACA;AAAA,EACA;AAAA,EAER,YAAY,QAAqB,SAAkB;AAClD,SAAK,gBAAgB;AACrB,SAAK,UAAU,WAAW;AAC1B,SAAK,iBAAiB,IAAI,IAAI,OAAO,QAAQ,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC;AAAA,EAChE;AAAA;AAAA,EAGA,YAAsD;AACrD,WAAO,EAAE,QAAQ,KAAK,eAAe,SAAS,KAAK,QAAQ;AAAA,EAC5D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,cAAc,OAA4C;AACzD,QAAI,MAAM,OAAO,YAAY,MAAM,QAAQ,WAAW,GAAG;AACxD,aAAO,GAAG,MAAS;AAAA,IACpB;AAEA,eAAW,OAAO,MAAM,SAAS;AAChC,UAAI,CAAC,KAAK,eAAe,IAAI,IAAI,MAAM,GAAG;AACzC,eAAO;AAAA,UACN,IAAI;AAAA,YACH,mBAAmB,IAAI,MAAM,yBAAyB,MAAM,KAAK,qBAAqB,KAAK,OAAO;AAAA,UACnG;AAAA,QACD;AAAA,MACD;AAAA,IACD;AACA,WAAO,GAAG,MAAS;AAAA,EACpB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,aAAa,WAAkE;AAC9E,QAAI,UAAU,UAAU,KAAK,cAAc,OAAO;AACjD,aAAO,IAAI,IAAI,YAAY,2CAA2C,CAAC;AAAA,IACxE;AAEA,UAAM,eAAe,IAAI,IAAI,KAAK,cAAc,QAAQ,IAAI,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC;AACpF,UAAM,eAAe,IAAI,IAAI,UAAU,QAAQ,IAAI,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC;AAG3E,eAAW,CAAC,IAAI,KAAK,cAAc;AAClC,UAAI,CAAC,aAAa,IAAI,IAAI,GAAG;AAC5B,eAAO;AAAA,UACN,IAAI;AAAA,YACH,yBAAyB,IAAI;AAAA,UAC9B;AAAA,QACD;AAAA,MACD;AAAA,IACD;AAGA,eAAW,CAAC,MAAM,OAAO,KAAK,cAAc;AAC3C,YAAM,UAAU,aAAa,IAAI,IAAI;AACrC,UAAI,WAAW,YAAY,SAAS;AACnC,eAAO;AAAA,UACN,IAAI;AAAA,YACH,iCAAiC,IAAI,WAAW,OAAO,SAAS,OAAO;AAAA,UACxE;AAAA,QACD;AAAA,MACD;AAAA,IACD;AAGA,SAAK,gBAAgB;AACrB,SAAK;AACL,SAAK,iBAAiB,IAAI,IAAI,UAAU,QAAQ,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC;AAElE,WAAO,GAAG,EAAE,SAAS,KAAK,QAAQ,CAAC;AAAA,EACpC;AACD;","names":["hasMore","serverHlc","trimmed"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../core/src/result/errors.ts","../../core/src/action/errors.ts","../../core/src/action/generate-id.ts","../../core/src/action/types.ts","../../core/src/result/result.ts","../../core/src/action/validate.ts","../../core/src/auth.ts","../../core/src/hlc/hlc.ts","../../core/src/polling/chunked-pusher.ts","../../core/src/polling/pressure-manager.ts","../../core/src/polling/scheduler.ts","../../core/src/base-poller.ts","../../core/src/callback-push-target.ts","../../core/src/conflict/lww.ts","../../core/src/connector/action-handler.ts","../../core/src/connector/errors.ts","../../core/src/connector/registry.ts","../../core/src/connector/types.ts","../../core/src/connector/validate.ts","../../core/src/connector/schemas/bigquery.ts","../../core/src/connector/schemas/ingest.ts","../../core/src/connector/schemas/jira.ts","../../core/src/connector/schemas/mysql.ts","../../core/src/connector/schemas/postgres.ts","../../core/src/connector/schemas/salesforce.ts","../../core/src/connector/register-builtin.ts","../../core/src/create-poller.ts","../../core/src/delta/apply.ts","../../core/src/delta/extract.ts","../../core/src/delta/types.ts","../../core/src/json.ts","../../core/src/sync-rules/defaults.ts","../../core/src/sync-rules/errors.ts","../../core/src/sync-rules/evaluator.ts","../../core/src/validation/identifier.ts"],"sourcesContent":["/** Base error class for all LakeSync errors */\nexport class LakeSyncError extends Error {\n\treadonly code: string;\n\toverride readonly cause?: Error;\n\n\tconstructor(message: string, code: string, cause?: Error) {\n\t\tsuper(message);\n\t\tthis.name = this.constructor.name;\n\t\tthis.code = code;\n\t\tthis.cause = cause;\n\t}\n}\n\n/** Clock drift exceeds maximum allowed threshold */\nexport class ClockDriftError extends LakeSyncError {\n\tconstructor(message: string, cause?: Error) {\n\t\tsuper(message, \"CLOCK_DRIFT\", cause);\n\t}\n}\n\n/** Conflict resolution failure */\nexport class ConflictError extends LakeSyncError {\n\tconstructor(message: string, cause?: Error) {\n\t\tsuper(message, \"CONFLICT\", cause);\n\t}\n}\n\n/** Flush operation failure */\nexport class FlushError extends LakeSyncError {\n\tconstructor(message: string, cause?: Error) {\n\t\tsuper(message, \"FLUSH_FAILED\", cause);\n\t}\n}\n\n/** Schema mismatch or validation failure */\nexport class SchemaError extends LakeSyncError {\n\tconstructor(message: string, cause?: Error) {\n\t\tsuper(message, \"SCHEMA_MISMATCH\", cause);\n\t}\n}\n\n/** Lake adapter operation failure */\nexport class AdapterError extends LakeSyncError {\n\tconstructor(message: string, cause?: Error) {\n\t\tsuper(message, \"ADAPTER_ERROR\", cause);\n\t}\n}\n\n/** Named source adapter not found in gateway configuration */\nexport class AdapterNotFoundError extends LakeSyncError {\n\tconstructor(message: string, cause?: Error) {\n\t\tsuper(message, \"ADAPTER_NOT_FOUND\", cause);\n\t}\n}\n\n/** Buffer backpressure limit exceeded — push rejected to prevent OOM. */\nexport class BackpressureError extends LakeSyncError {\n\tconstructor(message: string, cause?: Error) {\n\t\tsuper(message, \"BACKPRESSURE\", cause);\n\t}\n}\n\n/** Coerce an unknown thrown value into an Error instance. */\nexport function toError(err: unknown): Error {\n\treturn err instanceof Error ? err : new Error(String(err));\n}\n","import { LakeSyncError } from \"../result/errors\";\n\n/** Error during action execution (may be retryable). */\nexport class ActionExecutionError extends LakeSyncError {\n\treadonly retryable: boolean;\n\n\tconstructor(message: string, retryable: boolean, cause?: Error) {\n\t\tsuper(message, \"ACTION_EXECUTION_ERROR\", cause);\n\t\tthis.retryable = retryable;\n\t}\n}\n\n/** The requested action type is not supported by the connector. */\nexport class ActionNotSupportedError extends LakeSyncError {\n\tconstructor(message: string, cause?: Error) {\n\t\tsuper(message, \"ACTION_NOT_SUPPORTED\", cause);\n\t}\n}\n\n/** Action payload failed structural validation. */\nexport class ActionValidationError extends LakeSyncError {\n\tconstructor(message: string, cause?: Error) {\n\t\tsuper(message, \"ACTION_VALIDATION_ERROR\", cause);\n\t}\n}\n","import stableStringify from \"fast-json-stable-stringify\";\nimport type { HLCTimestamp } from \"../hlc/types\";\n\n/**\n * Generate a deterministic action ID using SHA-256.\n *\n * Same pattern as `generateDeltaId` in `delta/extract.ts` — uses the\n * Web Crypto API for cross-runtime compatibility (Node, Bun, browsers).\n */\nexport async function generateActionId(params: {\n\tclientId: string;\n\thlc: HLCTimestamp;\n\tconnector: string;\n\tactionType: string;\n\tparams: Record<string, unknown>;\n}): Promise<string> {\n\tconst payload = stableStringify({\n\t\tclientId: params.clientId,\n\t\thlc: params.hlc.toString(),\n\t\tconnector: params.connector,\n\t\tactionType: params.actionType,\n\t\tparams: params.params,\n\t});\n\n\tconst data = new TextEncoder().encode(payload);\n\tconst hashBuffer = await crypto.subtle.digest(\"SHA-256\", data);\n\tconst bytes = new Uint8Array(hashBuffer);\n\n\tlet hex = \"\";\n\tfor (const b of bytes) {\n\t\thex += b.toString(16).padStart(2, \"0\");\n\t}\n\treturn hex;\n}\n","import type { ActionDescriptor } from \"../connector/action-handler\";\nimport type { HLCTimestamp } from \"../hlc/types\";\n\n/** Discovery response listing available connectors and their supported actions. */\nexport interface ActionDiscovery {\n\t/** Map of connector name to its supported action descriptors. */\n\tconnectors: Record<string, ActionDescriptor[]>;\n}\n\n/** An imperative action to execute against an external system. */\nexport interface Action {\n\t/** Unique action identifier (deterministic SHA-256 hash). */\n\tactionId: string;\n\t/** Client that initiated the action. */\n\tclientId: string;\n\t/** HLC timestamp when the action was created. */\n\thlc: HLCTimestamp;\n\t/** Target connector name (e.g. \"github\", \"slack\", \"linear\"). */\n\tconnector: string;\n\t/** Action type within the connector (e.g. \"create_pr\", \"send_message\"). */\n\tactionType: string;\n\t/** Action parameters — connector-specific payload. */\n\tparams: Record<string, unknown>;\n\t/** Optional idempotency key for at-most-once delivery. */\n\tidempotencyKey?: string;\n}\n\n/** Successful result of executing an action. */\nexport interface ActionResult {\n\t/** The action that was executed. */\n\tactionId: string;\n\t/** Result data returned by the connector. */\n\tdata: Record<string, unknown>;\n\t/** Server HLC after processing. */\n\tserverHlc: HLCTimestamp;\n}\n\n/** Error result of executing an action. */\nexport interface ActionErrorResult {\n\t/** The action that failed. */\n\tactionId: string;\n\t/** Error code. */\n\tcode: string;\n\t/** Human-readable error message. */\n\tmessage: string;\n\t/** Whether the client can retry this action. */\n\tretryable: boolean;\n}\n\n/** Batch of actions pushed by a client. */\nexport interface ActionPush {\n\t/** Client identifier. */\n\tclientId: string;\n\t/** Actions to execute. */\n\tactions: Action[];\n}\n\n/** Gateway response to an action push. */\nexport interface ActionResponse {\n\t/** Results for each action (success or error). */\n\tresults: Array<ActionResult | ActionErrorResult>;\n\t/** Server HLC after processing. */\n\tserverHlc: HLCTimestamp;\n}\n\n/** Type guard: check whether a result is an error. */\nexport function isActionError(\n\tresult: ActionResult | ActionErrorResult,\n): result is ActionErrorResult {\n\treturn \"code\" in result && \"retryable\" in result;\n}\n","import type { LakeSyncError } from \"./errors\";\n\n/** Discriminated union representing either success or failure */\nexport type Result<T, E = LakeSyncError> = { ok: true; value: T } | { ok: false; error: E };\n\n/** Create a successful Result */\nexport function Ok<T>(value: T): Result<T, never> {\n\treturn { ok: true, value };\n}\n\n/** Create a failed Result */\nexport function Err<E>(error: E): Result<never, E> {\n\treturn { ok: false, error };\n}\n\n/** Transform the success value of a Result */\nexport function mapResult<T, U, E>(result: Result<T, E>, fn: (value: T) => U): Result<U, E> {\n\tif (result.ok) {\n\t\treturn Ok(fn(result.value));\n\t}\n\treturn result;\n}\n\n/** Chain Result-returning operations */\nexport function flatMapResult<T, U, E>(\n\tresult: Result<T, E>,\n\tfn: (value: T) => Result<U, E>,\n): Result<U, E> {\n\tif (result.ok) {\n\t\treturn fn(result.value);\n\t}\n\treturn result;\n}\n\n/** Extract the value from a Result or throw the error */\nexport function unwrapOrThrow<T, E>(result: Result<T, E>): T {\n\tif (result.ok) {\n\t\treturn result.value;\n\t}\n\tthrow result.error;\n}\n\n/** Wrap a Promise into a Result */\nexport async function fromPromise<T>(promise: Promise<T>): Promise<Result<T, Error>> {\n\ttry {\n\t\tconst value = await promise;\n\t\treturn Ok(value);\n\t} catch (error) {\n\t\treturn Err(error instanceof Error ? error : new Error(String(error)));\n\t}\n}\n","import { Err, Ok, type Result } from \"../result/result\";\nimport { ActionValidationError } from \"./errors\";\nimport type { Action } from \"./types\";\n\n/**\n * Validate the structural integrity of an Action.\n *\n * Checks that all required fields are present and of the correct type.\n * Returns a `Result` so callers never need to catch.\n */\nexport function validateAction(action: unknown): Result<Action, ActionValidationError> {\n\tif (action === null || typeof action !== \"object\") {\n\t\treturn Err(new ActionValidationError(\"Action must be a non-null object\"));\n\t}\n\n\tconst a = action as Record<string, unknown>;\n\n\tif (typeof a.actionId !== \"string\" || a.actionId.length === 0) {\n\t\treturn Err(new ActionValidationError(\"actionId must be a non-empty string\"));\n\t}\n\n\tif (typeof a.clientId !== \"string\" || a.clientId.length === 0) {\n\t\treturn Err(new ActionValidationError(\"clientId must be a non-empty string\"));\n\t}\n\n\tif (typeof a.hlc !== \"bigint\") {\n\t\treturn Err(new ActionValidationError(\"hlc must be a bigint\"));\n\t}\n\n\tif (typeof a.connector !== \"string\" || a.connector.length === 0) {\n\t\treturn Err(new ActionValidationError(\"connector must be a non-empty string\"));\n\t}\n\n\tif (typeof a.actionType !== \"string\" || a.actionType.length === 0) {\n\t\treturn Err(new ActionValidationError(\"actionType must be a non-empty string\"));\n\t}\n\n\tif (a.params === null || typeof a.params !== \"object\" || Array.isArray(a.params)) {\n\t\treturn Err(new ActionValidationError(\"params must be a non-null object\"));\n\t}\n\n\tif (a.idempotencyKey !== undefined && typeof a.idempotencyKey !== \"string\") {\n\t\treturn Err(new ActionValidationError(\"idempotencyKey must be a string if provided\"));\n\t}\n\n\treturn Ok(action as Action);\n}\n","import { Err, Ok, type Result } from \"./result/result\";\n\n/**\n * Minimal Web Crypto typing for HMAC operations.\n * The core package uses `lib: [\"ES2022\"]` which doesn't include DOM types.\n * These declarations cover the methods we need without pulling in the full DOM lib.\n */\ninterface HmacSubtle {\n\timportKey(\n\t\tformat: \"raw\",\n\t\tkeyData: Uint8Array,\n\t\talgorithm: { name: string; hash: string },\n\t\textractable: boolean,\n\t\tusages: string[],\n\t): Promise<unknown>;\n\tverify(\n\t\talgorithm: string,\n\t\tkey: unknown,\n\t\tsignature: Uint8Array,\n\t\tdata: Uint8Array,\n\t): Promise<boolean>;\n}\n\n/** Claims extracted from a verified JWT token */\nexport interface AuthClaims {\n\t/** Client identifier (from JWT `sub` claim) */\n\tclientId: string;\n\t/** Authorised gateway ID (from JWT `gw` claim) */\n\tgatewayId: string;\n\t/** Role for route-level access control (from JWT `role` claim, defaults to \"client\") */\n\trole: string;\n\t/** Non-standard JWT claims for sync rule evaluation */\n\tcustomClaims: Record<string, string | string[]>;\n}\n\n/** Authentication error returned when JWT verification fails */\nexport class AuthError extends Error {\n\tconstructor(message: string) {\n\t\tsuper(message);\n\t\tthis.name = \"AuthError\";\n\t}\n}\n\n/** Expected JWT header for HMAC-SHA256 tokens */\ninterface JwtHeader {\n\talg: string;\n\ttyp: string;\n}\n\n/** JWT payload with required claims */\ninterface JwtPayload {\n\tsub?: string;\n\tgw?: string;\n\texp?: number;\n\t[key: string]: unknown;\n}\n\n/**\n * Decode a base64url-encoded string to a Uint8Array.\n * Handles the URL-safe alphabet (+/- replaced with -/_) and missing padding.\n */\nfunction base64urlDecode(input: string): Uint8Array {\n\t// Restore standard base64 characters and padding\n\tconst base64 = input.replace(/-/g, \"+\").replace(/_/g, \"/\");\n\tconst padded = base64.padEnd(base64.length + ((4 - (base64.length % 4)) % 4), \"=\");\n\tconst binary = atob(padded);\n\tconst bytes = new Uint8Array(binary.length);\n\tfor (let i = 0; i < binary.length; i++) {\n\t\tbytes[i] = binary.charCodeAt(i);\n\t}\n\treturn bytes;\n}\n\n/**\n * Parse a JSON string safely, returning null on failure.\n */\nfunction parseJson(text: string): unknown {\n\ttry {\n\t\treturn JSON.parse(text);\n\t} catch {\n\t\treturn null;\n\t}\n}\n\n/**\n * Verify a JWT token signed with HMAC-SHA256 and extract authentication claims.\n *\n * Uses the Web Crypto API exclusively (no external dependencies), making it\n * suitable for Cloudflare Workers and other edge runtimes.\n *\n * @param token - The raw JWT string (header.payload.signature)\n * @param secret - The HMAC-SHA256 secret key\n * @returns A Result containing AuthClaims on success, or AuthError on failure\n */\nexport async function verifyToken(\n\ttoken: string,\n\tsecret: string,\n): Promise<Result<AuthClaims, AuthError>> {\n\t// Split into three parts\n\tconst parts = token.split(\".\");\n\tif (parts.length !== 3) {\n\t\treturn Err(new AuthError(\"Malformed JWT: expected three dot-separated segments\"));\n\t}\n\n\tconst [headerB64, payloadB64, signatureB64] = parts;\n\tif (!headerB64 || !payloadB64 || !signatureB64) {\n\t\treturn Err(new AuthError(\"Malformed JWT: empty segment\"));\n\t}\n\n\t// Decode and verify header\n\tlet headerBytes: Uint8Array;\n\ttry {\n\t\theaderBytes = base64urlDecode(headerB64);\n\t} catch {\n\t\treturn Err(new AuthError(\"Malformed JWT: invalid base64url in header\"));\n\t}\n\n\tconst header = parseJson(new TextDecoder().decode(headerBytes)) as JwtHeader | null;\n\tif (!header || header.alg !== \"HS256\" || header.typ !== \"JWT\") {\n\t\treturn Err(new AuthError('Unsupported JWT: header must be {\"alg\":\"HS256\",\"typ\":\"JWT\"}'));\n\t}\n\n\t// Import the HMAC key via Web Crypto\n\tconst encoder = new TextEncoder();\n\tconst keyData = encoder.encode(secret);\n\n\tlet cryptoKey: unknown;\n\ttry {\n\t\tcryptoKey = await (crypto.subtle as unknown as HmacSubtle).importKey(\n\t\t\t\"raw\",\n\t\t\tkeyData,\n\t\t\t{ name: \"HMAC\", hash: \"SHA-256\" },\n\t\t\tfalse,\n\t\t\t[\"verify\"],\n\t\t);\n\t} catch {\n\t\treturn Err(new AuthError(\"Failed to import HMAC key\"));\n\t}\n\n\t// Verify signature\n\tlet signatureBytes: Uint8Array;\n\ttry {\n\t\tsignatureBytes = base64urlDecode(signatureB64);\n\t} catch {\n\t\treturn Err(new AuthError(\"Malformed JWT: invalid base64url in signature\"));\n\t}\n\n\tconst signingInput = encoder.encode(`${headerB64}.${payloadB64}`);\n\n\tlet valid: boolean;\n\ttry {\n\t\tvalid = await (crypto.subtle as unknown as HmacSubtle).verify(\n\t\t\t\"HMAC\",\n\t\t\tcryptoKey,\n\t\t\tsignatureBytes,\n\t\t\tsigningInput,\n\t\t);\n\t} catch {\n\t\treturn Err(new AuthError(\"Signature verification failed\"));\n\t}\n\n\tif (!valid) {\n\t\treturn Err(new AuthError(\"Invalid JWT signature\"));\n\t}\n\n\t// Decode payload\n\tlet payloadBytes: Uint8Array;\n\ttry {\n\t\tpayloadBytes = base64urlDecode(payloadB64);\n\t} catch {\n\t\treturn Err(new AuthError(\"Malformed JWT: invalid base64url in payload\"));\n\t}\n\n\tconst payload = parseJson(new TextDecoder().decode(payloadBytes)) as JwtPayload | null;\n\tif (!payload) {\n\t\treturn Err(new AuthError(\"Malformed JWT: payload is not valid JSON\"));\n\t}\n\n\t// Check expiry — exp claim is mandatory\n\tif (payload.exp === undefined || typeof payload.exp !== \"number\") {\n\t\treturn Err(new AuthError('Missing or invalid \"exp\" claim (expiry)'));\n\t}\n\tconst nowSeconds = Math.floor(Date.now() / 1000);\n\tif (payload.exp <= nowSeconds) {\n\t\treturn Err(new AuthError(\"JWT has expired\"));\n\t}\n\n\t// Extract required claims\n\tif (typeof payload.sub !== \"string\" || payload.sub.length === 0) {\n\t\treturn Err(new AuthError('Missing or invalid \"sub\" claim (clientId)'));\n\t}\n\n\tif (typeof payload.gw !== \"string\" || payload.gw.length === 0) {\n\t\treturn Err(new AuthError('Missing or invalid \"gw\" claim (gatewayId)'));\n\t}\n\n\t// Extract non-standard claims for sync rules evaluation\n\tconst standardClaims = new Set([\"sub\", \"gw\", \"exp\", \"iat\", \"iss\", \"aud\", \"role\"]);\n\tconst customClaims: Record<string, string | string[]> = {};\n\n\tfor (const [key, value] of Object.entries(payload)) {\n\t\tif (standardClaims.has(key)) continue;\n\t\tif (typeof value === \"string\") {\n\t\t\tcustomClaims[key] = value;\n\t\t} else if (Array.isArray(value) && value.every((v) => typeof v === \"string\")) {\n\t\t\tcustomClaims[key] = value as string[];\n\t\t}\n\t}\n\n\t// Always include `sub` in custom claims so sync rules can reference jwt:sub\n\tcustomClaims.sub = payload.sub;\n\n\t// Extract role claim (default to \"client\" if absent)\n\tconst role =\n\t\ttypeof payload.role === \"string\" && payload.role.length > 0 ? payload.role : \"client\";\n\n\treturn Ok({\n\t\tclientId: payload.sub,\n\t\tgatewayId: payload.gw,\n\t\trole,\n\t\tcustomClaims,\n\t});\n}\n","import { ClockDriftError, Err, Ok, type Result } from \"../result\";\nimport type { HLCTimestamp } from \"./types\";\n\n/**\n * Hybrid Logical Clock implementation.\n *\n * 64-bit layout: [48-bit wall clock ms][16-bit logical counter].\n * Maximum allowed clock drift: 5 seconds.\n *\n * The wall clock source is injectable for deterministic testing.\n */\nexport class HLC {\n\tprivate readonly wallClock: () => number;\n\tprivate counter = 0;\n\tprivate lastWall = 0;\n\n\t/** Maximum tolerated drift between local and remote physical clocks (ms). */\n\tstatic readonly MAX_DRIFT_MS = 5_000;\n\n\t/** Maximum value of the 16-bit logical counter. */\n\tstatic readonly MAX_COUNTER = 0xffff;\n\n\t/**\n\t * Create a new HLC instance.\n\t *\n\t * @param wallClock - Optional injectable clock source returning epoch ms.\n\t * Defaults to `Date.now`.\n\t */\n\tconstructor(wallClock?: () => number) {\n\t\tthis.wallClock = wallClock ?? (() => Date.now());\n\t}\n\n\t/**\n\t * Generate a new monotonically increasing HLC timestamp.\n\t *\n\t * The returned timestamp is guaranteed to be strictly greater than any\n\t * previously returned by this instance.\n\t */\n\tnow(): HLCTimestamp {\n\t\tconst physical = this.wallClock();\n\t\tconst wall = Math.max(physical, this.lastWall);\n\n\t\tif (wall === this.lastWall) {\n\t\t\tthis.counter++;\n\t\t\tif (this.counter > HLC.MAX_COUNTER) {\n\t\t\t\t// Counter overflow: advance wall by 1 ms and reset counter\n\t\t\t\tthis.lastWall = wall + 1;\n\t\t\t\tthis.counter = 0;\n\t\t\t}\n\t\t} else {\n\t\t\tthis.lastWall = wall;\n\t\t\tthis.counter = 0;\n\t\t}\n\n\t\treturn HLC.encode(this.lastWall, this.counter);\n\t}\n\n\t/**\n\t * Receive a remote HLC timestamp and advance the local clock.\n\t *\n\t * Returns `Err(ClockDriftError)` if the remote timestamp indicates\n\t * clock drift exceeding {@link MAX_DRIFT_MS}.\n\t *\n\t * @param remote - The HLC timestamp received from a remote node.\n\t * @returns A `Result` containing the new local HLC timestamp, or a\n\t * `ClockDriftError` if the remote clock is too far ahead.\n\t */\n\trecv(remote: HLCTimestamp): Result<HLCTimestamp, ClockDriftError> {\n\t\tconst { wall: remoteWall, counter: remoteCounter } = HLC.decode(remote);\n\t\tconst physical = this.wallClock();\n\t\tconst localWall = Math.max(physical, this.lastWall);\n\n\t\t// Check drift: compare remote wall against physical clock\n\t\tif (remoteWall - physical > HLC.MAX_DRIFT_MS) {\n\t\t\treturn Err(\n\t\t\t\tnew ClockDriftError(\n\t\t\t\t\t`Remote clock is ${remoteWall - physical}ms ahead (max drift: ${HLC.MAX_DRIFT_MS}ms)`,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\n\t\tif (remoteWall > localWall) {\n\t\t\tthis.lastWall = remoteWall;\n\t\t\tthis.counter = remoteCounter + 1;\n\t\t} else if (remoteWall === localWall) {\n\t\t\tthis.lastWall = localWall;\n\t\t\tthis.counter = Math.max(this.counter, remoteCounter) + 1;\n\t\t} else {\n\t\t\tthis.lastWall = localWall;\n\t\t\tthis.counter++;\n\t\t}\n\n\t\tif (this.counter > HLC.MAX_COUNTER) {\n\t\t\t// Counter overflow: advance wall by 1 ms and reset counter\n\t\t\tthis.lastWall = this.lastWall + 1;\n\t\t\tthis.counter = 0;\n\t\t}\n\n\t\treturn Ok(HLC.encode(this.lastWall, this.counter));\n\t}\n\n\t/**\n\t * Encode a wall clock value (ms) and logical counter into a 64-bit HLC timestamp.\n\t *\n\t * @param wall - Wall clock component in epoch milliseconds (48-bit).\n\t * @param counter - Logical counter component (16-bit, 0..65535).\n\t * @returns The encoded {@link HLCTimestamp}.\n\t */\n\tstatic encode(wall: number, counter: number): HLCTimestamp {\n\t\treturn ((BigInt(wall) << 16n) | BigInt(counter & 0xffff)) as HLCTimestamp;\n\t}\n\n\t/**\n\t * Decode an HLC timestamp into its wall clock (ms) and logical counter components.\n\t *\n\t * @param ts - The {@link HLCTimestamp} to decode.\n\t * @returns An object with `wall` (epoch ms) and `counter` (logical) fields.\n\t */\n\tstatic decode(ts: HLCTimestamp): { wall: number; counter: number } {\n\t\treturn {\n\t\t\twall: Number(ts >> 16n),\n\t\t\tcounter: Number(ts & 0xffffn),\n\t\t};\n\t}\n\n\t/**\n\t * Compare two HLC timestamps.\n\t *\n\t * @returns `-1` if `a < b`, `0` if `a === b`, `1` if `a > b`.\n\t */\n\tstatic compare(a: HLCTimestamp, b: HLCTimestamp): -1 | 0 | 1 {\n\t\tif (a < b) return -1;\n\t\tif (a > b) return 1;\n\t\treturn 0;\n\t}\n}\n","// ---------------------------------------------------------------------------\n// ChunkedPusher — chunks deltas and pushes to a target with backpressure retry\n// ---------------------------------------------------------------------------\n\nimport type { RowDelta, SyncPush } from \"../delta/types\";\nimport type { HLCTimestamp } from \"../hlc/types\";\nimport type { BackpressureError } from \"../result/errors\";\nimport type { Result } from \"../result/result\";\nimport type { PressureManager } from \"./pressure-manager\";\n\n/** Minimal interface for a push target (avoids depending on @lakesync/gateway). */\nexport interface PushTarget {\n\thandlePush(push: SyncPush): unknown;\n}\n\n/**\n * Manages chunked pushing of deltas to a {@link PushTarget}.\n * Handles backpressure retry (flush + retry once) when a\n * {@link PressureManager} is present.\n *\n * No runtime type checks — the PressureManager is either provided\n * at construction (target supports flush) or null.\n */\nexport class ChunkedPusher {\n\tprivate readonly target: PushTarget;\n\tprivate readonly clientId: string;\n\tprivate readonly chunkSize: number;\n\tprivate readonly pressure: PressureManager | null;\n\tprivate pendingDeltas: RowDelta[] = [];\n\n\tconstructor(config: {\n\t\ttarget: PushTarget;\n\t\tclientId: string;\n\t\tchunkSize: number;\n\t\tpressure: PressureManager | null;\n\t}) {\n\t\tthis.target = config.target;\n\t\tthis.clientId = config.clientId;\n\t\tthis.chunkSize = config.chunkSize;\n\t\tthis.pressure = config.pressure;\n\t}\n\n\t/**\n\t * Accumulate a single delta. When `chunkSize` is reached, the pending\n\t * deltas are automatically pushed (and flushed if needed).\n\t */\n\tasync accumulate(delta: RowDelta): Promise<void> {\n\t\tthis.pendingDeltas.push(delta);\n\t\tif (this.pendingDeltas.length >= this.chunkSize) {\n\t\t\tawait this.pushPendingChunk();\n\t\t}\n\t}\n\n\t/** Flush any remaining accumulated deltas. */\n\tasync flush(): Promise<void> {\n\t\tif (this.pendingDeltas.length > 0) {\n\t\t\tawait this.pushPendingChunk();\n\t\t}\n\t}\n\n\t/** Push deltas directly (single-shot, backward compat). */\n\tpushImmediate(deltas: RowDelta[]): void {\n\t\tif (deltas.length === 0) return;\n\t\tconst push: SyncPush = {\n\t\t\tclientId: this.clientId,\n\t\t\tdeltas,\n\t\t\tlastSeenHlc: 0n as HLCTimestamp,\n\t\t};\n\t\tthis.target.handlePush(push);\n\t}\n\n\tprivate async pushPendingChunk(): Promise<void> {\n\t\tconst chunk = this.pendingDeltas;\n\t\tthis.pendingDeltas = [];\n\t\tawait this.pushChunkWithFlush(chunk);\n\t}\n\n\tprivate async pushChunkWithFlush(chunk: RowDelta[]): Promise<void> {\n\t\tif (chunk.length === 0) return;\n\n\t\t// Pre-push: flush if pressure manager signals pressure\n\t\tif (this.pressure) {\n\t\t\tawait this.pressure.checkAndFlush();\n\t\t}\n\n\t\tconst push: SyncPush = {\n\t\t\tclientId: this.clientId,\n\t\t\tdeltas: chunk,\n\t\t\tlastSeenHlc: 0n as HLCTimestamp,\n\t\t};\n\n\t\tconst result = this.target.handlePush(push) as Result<unknown, BackpressureError> | undefined;\n\n\t\t// If handlePush returned a Result with backpressure, flush and retry once\n\t\tif (result && typeof result === \"object\" && \"ok\" in result && !result.ok) {\n\t\t\tif (this.pressure) {\n\t\t\t\tawait this.pressure.forceFlush();\n\t\t\t\tthis.target.handlePush(push);\n\t\t\t}\n\t\t}\n\t}\n}\n","// ---------------------------------------------------------------------------\n// PressureManager — monitors buffer pressure and triggers flushes\n// ---------------------------------------------------------------------------\n\nimport type { FlushError } from \"../result/errors\";\nimport type { Result } from \"../result/result\";\n\n/**\n * Target that supports flush and buffer inspection.\n * Implemented by SyncGateway so pollers can trigger flushes to relieve memory pressure.\n */\nexport interface FlushableTarget {\n\tflush(): Promise<Result<void, FlushError>>;\n\tshouldFlush(): boolean;\n\treadonly bufferStats: { logSize: number; indexSize: number; byteSize: number };\n}\n\n/**\n * Monitors buffer pressure on a {@link FlushableTarget} and triggers\n * flushes when thresholds are exceeded. Created at construction time\n * only when the target supports flushing — no runtime type checks needed.\n */\nexport class PressureManager {\n\tprivate readonly target: FlushableTarget;\n\tprivate readonly memoryBudgetBytes: number | undefined;\n\tprivate readonly flushThreshold: number;\n\n\tconstructor(config: {\n\t\ttarget: FlushableTarget;\n\t\tmemoryBudgetBytes?: number;\n\t\tflushThreshold?: number;\n\t}) {\n\t\tthis.target = config.target;\n\t\tthis.memoryBudgetBytes = config.memoryBudgetBytes;\n\t\tthis.flushThreshold = config.flushThreshold ?? 0.7;\n\t}\n\n\t/** Check buffer pressure and flush if thresholds are exceeded. */\n\tasync checkAndFlush(): Promise<void> {\n\t\tif (this.shouldFlush()) {\n\t\t\tawait this.target.flush();\n\t\t}\n\t}\n\n\t/** Force a flush regardless of current pressure. */\n\tasync forceFlush(): Promise<void> {\n\t\tawait this.target.flush();\n\t}\n\n\tprivate shouldFlush(): boolean {\n\t\tif (this.target.shouldFlush()) return true;\n\t\tif (this.memoryBudgetBytes != null) {\n\t\t\tconst threshold = Math.floor(this.memoryBudgetBytes * this.flushThreshold);\n\t\t\tif (this.target.bufferStats.byteSize >= threshold) return true;\n\t\t}\n\t\treturn false;\n\t}\n}\n","// ---------------------------------------------------------------------------\n// PollingScheduler — pure lifecycle management for periodic polling\n// ---------------------------------------------------------------------------\n\n/**\n * Manages the start/stop lifecycle and timer scheduling for a poll function.\n * Has no knowledge of deltas, gateways, or sync protocol.\n */\nexport class PollingScheduler {\n\tprivate readonly pollFn: () => Promise<void>;\n\tprivate readonly intervalMs: number;\n\tprivate timer: ReturnType<typeof setTimeout> | null = null;\n\tprivate running = false;\n\n\tconstructor(pollFn: () => Promise<void>, intervalMs: number) {\n\t\tthis.pollFn = pollFn;\n\t\tthis.intervalMs = intervalMs;\n\t}\n\n\t/** Start the polling loop. No-op if already running. */\n\tstart(): void {\n\t\tif (this.running) return;\n\t\tthis.running = true;\n\t\tthis.schedule();\n\t}\n\n\t/** Stop the polling loop. */\n\tstop(): void {\n\t\tthis.running = false;\n\t\tif (this.timer) {\n\t\t\tclearTimeout(this.timer);\n\t\t\tthis.timer = null;\n\t\t}\n\t}\n\n\t/** Whether the scheduler is currently running. */\n\tget isRunning(): boolean {\n\t\treturn this.running;\n\t}\n\n\t/** Execute a single poll cycle without the timer loop. */\n\tasync pollOnce(): Promise<void> {\n\t\treturn this.pollFn();\n\t}\n\n\tprivate schedule(): void {\n\t\tif (!this.running) return;\n\t\tthis.timer = setTimeout(async () => {\n\t\t\ttry {\n\t\t\t\tawait this.pollFn();\n\t\t\t} catch {\n\t\t\t\t// Swallow errors — a failed poll must never crash the server\n\t\t\t}\n\t\t\tthis.schedule();\n\t\t}, this.intervalMs);\n\t}\n}\n","// ---------------------------------------------------------------------------\n// BaseSourcePoller — shared lifecycle and push logic for source connectors\n// ---------------------------------------------------------------------------\n\nimport type { RowDelta } from \"./delta/types\";\nimport { HLC } from \"./hlc/hlc\";\nimport { ChunkedPusher, type PushTarget } from \"./polling/chunked-pusher\";\nimport { PressureManager } from \"./polling/pressure-manager\";\nimport { PollingScheduler } from \"./polling/scheduler\";\nimport type { FlushError } from \"./result/errors\";\nimport type { Result } from \"./result/result\";\n\n// Re-export PushTarget from its canonical location\nexport type { PushTarget } from \"./polling/chunked-pusher\";\n\n/**\n * Extended push target that supports flush and buffer inspection.\n * Implemented by SyncGateway so pollers can trigger flushes to relieve memory pressure.\n */\nexport interface IngestTarget extends PushTarget {\n\tflush(): Promise<Result<void, FlushError>>;\n\tshouldFlush(): boolean;\n\treadonly bufferStats: { logSize: number; indexSize: number; byteSize: number };\n}\n\n/** Type guard: returns true if the target supports flush/shouldFlush/bufferStats. */\nexport function isIngestTarget(target: PushTarget): target is IngestTarget {\n\treturn (\n\t\ttypeof (target as IngestTarget).flush === \"function\" &&\n\t\ttypeof (target as IngestTarget).shouldFlush === \"function\" &&\n\t\t\"bufferStats\" in target\n\t);\n}\n\n/** Memory configuration for the streaming accumulator. */\nexport interface PollerMemoryConfig {\n\t/** Number of deltas per push chunk (default 500). */\n\tchunkSize?: number;\n\t/** Approximate memory budget in bytes — triggers flush at 70% (default: no limit). */\n\tmemoryBudgetBytes?: number;\n\t/** Proportion of memoryBudgetBytes at which to trigger a flush (default 0.7). */\n\tflushThreshold?: number;\n}\n\nconst DEFAULT_CHUNK_SIZE = 500;\n\n/**\n * Base class for source pollers that poll an external API and push deltas\n * to a SyncGateway.\n *\n * Composes {@link PollingScheduler} (lifecycle), {@link ChunkedPusher}\n * (chunked push with backpressure), and {@link PressureManager}\n * (memory-budget flush decisions).\n */\nexport abstract class BaseSourcePoller {\n\tprotected readonly gateway: PushTarget;\n\tprotected readonly hlc: HLC;\n\tprotected readonly clientId: string;\n\n\tprivate readonly scheduler: PollingScheduler;\n\tprivate readonly pusher: ChunkedPusher;\n\n\tconstructor(config: {\n\t\tname: string;\n\t\tintervalMs: number;\n\t\tgateway: PushTarget;\n\t\tmemory?: PollerMemoryConfig;\n\t}) {\n\t\tthis.gateway = config.gateway;\n\t\tthis.hlc = new HLC();\n\t\tthis.clientId = `ingest:${config.name}`;\n\n\t\t// PressureManager is only created when the target supports flush —\n\t\t// decided once at construction, no runtime type checks in the push path\n\t\tconst pressure = isIngestTarget(config.gateway)\n\t\t\t? new PressureManager({\n\t\t\t\t\ttarget: config.gateway,\n\t\t\t\t\tmemoryBudgetBytes: config.memory?.memoryBudgetBytes,\n\t\t\t\t\tflushThreshold: config.memory?.flushThreshold,\n\t\t\t\t})\n\t\t\t: null;\n\n\t\tthis.pusher = new ChunkedPusher({\n\t\t\ttarget: config.gateway,\n\t\t\tclientId: this.clientId,\n\t\t\tchunkSize: config.memory?.chunkSize ?? DEFAULT_CHUNK_SIZE,\n\t\t\tpressure,\n\t\t});\n\n\t\tthis.scheduler = new PollingScheduler(() => this.poll(), config.intervalMs);\n\t}\n\n\t/** Start the polling loop. */\n\tstart(): void {\n\t\tthis.scheduler.start();\n\t}\n\n\t/** Stop the polling loop. */\n\tstop(): void {\n\t\tthis.scheduler.stop();\n\t}\n\n\t/** Whether the poller is currently running. */\n\tget isRunning(): boolean {\n\t\treturn this.scheduler.isRunning;\n\t}\n\n\t/** Execute a single poll cycle. Subclasses implement their specific polling logic. */\n\tabstract poll(): Promise<void>;\n\n\t/** Export cursor state as a JSON-serialisable object for external persistence. */\n\tabstract getCursorState(): Record<string, unknown>;\n\n\t/** Restore cursor state from a previously exported snapshot. */\n\tabstract setCursorState(state: Record<string, unknown>): void;\n\n\t/**\n\t * Execute a single poll cycle without the timer loop.\n\t * Convenience for serverless consumers who trigger polls manually.\n\t */\n\tasync pollOnce(): Promise<void> {\n\t\treturn this.scheduler.pollOnce();\n\t}\n\n\t/** Push collected deltas to the gateway (single-shot, backward compat). */\n\tprotected pushDeltas(deltas: RowDelta[]): void {\n\t\tthis.pusher.pushImmediate(deltas);\n\t}\n\n\t/**\n\t * Accumulate a single delta. When `chunkSize` is reached, the pending\n\t * deltas are automatically pushed (and flushed if needed).\n\t */\n\tprotected async accumulateDelta(delta: RowDelta): Promise<void> {\n\t\tawait this.pusher.accumulate(delta);\n\t}\n\n\t/** Flush any remaining accumulated deltas. Call at the end of `poll()`. */\n\tprotected async flushAccumulator(): Promise<void> {\n\t\tawait this.pusher.flush();\n\t}\n}\n","// ---------------------------------------------------------------------------\n// CallbackPushTarget — a PushTarget that delegates to a user-provided callback\n// ---------------------------------------------------------------------------\n\nimport type { PushTarget } from \"./base-poller\";\nimport type { SyncPush } from \"./delta/types\";\n\n/**\n * A simple PushTarget implementation that forwards every push to a\n * user-supplied callback. Useful for testing, logging, or lightweight\n * integrations where a full gateway is not required.\n */\nexport class CallbackPushTarget implements PushTarget {\n\tprivate readonly onPush: (push: SyncPush) => void | Promise<void>;\n\n\tconstructor(onPush: (push: SyncPush) => void | Promise<void>) {\n\t\tthis.onPush = onPush;\n\t}\n\n\thandlePush(push: SyncPush): void {\n\t\tthis.onPush(push);\n\t}\n}\n","import type { ColumnDelta, DeltaOp, RowDelta } from \"../delta/types\";\nimport { HLC } from \"../hlc/hlc\";\nimport { ConflictError } from \"../result/errors\";\nimport { Err, Ok, type Result } from \"../result/result\";\nimport type { ConflictResolver } from \"./resolver\";\n\n/**\n * Column-level Last-Write-Wins conflict resolver.\n *\n * For each column present in both deltas, the one with the higher HLC wins.\n * Equal HLC tiebreak: lexicographically higher clientId wins (deterministic).\n * Columns only present in one delta are always included in the result.\n */\nexport class LWWResolver implements ConflictResolver {\n\t/**\n\t * Resolve two conflicting deltas for the same row, returning the merged result.\n\t *\n\t * Rules:\n\t * - Both DELETE: the delta with the higher HLC (or clientId tiebreak) wins.\n\t * - One DELETE, one non-DELETE: the delta with the higher HLC wins.\n\t * If the DELETE wins, the row is tombstoned (empty columns).\n\t * If the non-DELETE wins, the row is resurrected.\n\t * - Both non-DELETE: columns are merged per-column using LWW semantics.\n\t *\n\t * @param local - The locally held delta for this row.\n\t * @param remote - The incoming remote delta for this row.\n\t * @returns A `Result` containing the resolved `RowDelta`, or a\n\t * `ConflictError` if the deltas refer to different tables/rows.\n\t */\n\tresolve(local: RowDelta, remote: RowDelta): Result<RowDelta, ConflictError> {\n\t\t// Validate same table + rowId\n\t\tif (local.table !== remote.table || local.rowId !== remote.rowId) {\n\t\t\treturn Err(\n\t\t\t\tnew ConflictError(\n\t\t\t\t\t`Cannot resolve conflict: mismatched table/rowId (${local.table}:${local.rowId} vs ${remote.table}:${remote.rowId})`,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\n\t\t// Determine which delta has higher HLC (for op-level decisions)\n\t\tconst winner = pickWinner(local, remote);\n\n\t\t// Both DELETE — winner takes all (no columns to merge)\n\t\tif (local.op === \"DELETE\" && remote.op === \"DELETE\") {\n\t\t\treturn Ok({ ...winner, columns: [] });\n\t\t}\n\n\t\t// One is DELETE\n\t\tif (local.op === \"DELETE\" || remote.op === \"DELETE\") {\n\t\t\tconst deleteDelta = local.op === \"DELETE\" ? local : remote;\n\t\t\tconst otherDelta = local.op === \"DELETE\" ? remote : local;\n\n\t\t\t// If the DELETE has higher/equal priority, tombstone wins\n\t\t\tif (deleteDelta === winner) {\n\t\t\t\treturn Ok({ ...deleteDelta, columns: [] });\n\t\t\t}\n\t\t\t// Otherwise the UPDATE/INSERT wins (resurrection)\n\t\t\treturn Ok({ ...otherDelta });\n\t\t}\n\n\t\t// Both are INSERT or UPDATE — merge columns\n\t\tconst mergedColumns = mergeColumns(local, remote);\n\n\t\t// Determine the resulting op: INSERT only if both are INSERT, otherwise UPDATE\n\t\tconst op: DeltaOp = local.op === \"INSERT\" && remote.op === \"INSERT\" ? \"INSERT\" : \"UPDATE\";\n\n\t\treturn Ok({\n\t\t\top,\n\t\t\ttable: local.table,\n\t\t\trowId: local.rowId,\n\t\t\tclientId: winner.clientId,\n\t\t\tcolumns: mergedColumns,\n\t\t\thlc: winner.hlc,\n\t\t\tdeltaId: winner.deltaId,\n\t\t});\n\t}\n}\n\n/**\n * Pick the winning delta based on HLC comparison with clientId tiebreak.\n *\n * @param local - The locally held delta.\n * @param remote - The incoming remote delta.\n * @returns The delta that wins the comparison.\n */\nfunction pickWinner(local: RowDelta, remote: RowDelta): RowDelta {\n\tconst cmp = HLC.compare(local.hlc, remote.hlc);\n\tif (cmp > 0) return local;\n\tif (cmp < 0) return remote;\n\t// Equal HLC — lexicographically higher clientId wins\n\treturn local.clientId > remote.clientId ? local : remote;\n}\n\n/**\n * Merge column-level changes from two non-DELETE deltas using LWW semantics.\n *\n * - Columns present in only one delta are included unconditionally.\n * - Columns present in both: the value from the delta with the higher HLC wins;\n * equal HLC uses lexicographic clientId tiebreak.\n *\n * @param local - The locally held delta.\n * @param remote - The incoming remote delta.\n * @returns The merged array of column deltas.\n */\nfunction mergeColumns(local: RowDelta, remote: RowDelta): ColumnDelta[] {\n\tconst localMap = new Map(local.columns.map((c) => [c.column, c]));\n\tconst remoteMap = new Map(remote.columns.map((c) => [c.column, c]));\n\tconst allColumns = new Set([...localMap.keys(), ...remoteMap.keys()]);\n\tconst winner = pickWinner(local, remote);\n\n\tconst merged: ColumnDelta[] = [];\n\n\tfor (const col of allColumns) {\n\t\tconst localCol = localMap.get(col);\n\t\tconst remoteCol = remoteMap.get(col);\n\n\t\tif (!remoteCol) {\n\t\t\tmerged.push(localCol!);\n\t\t} else if (!localCol) {\n\t\t\tmerged.push(remoteCol);\n\t\t} else {\n\t\t\t// Both have this column — winner takes it\n\t\t\tmerged.push(winner === local ? localCol : remoteCol);\n\t\t}\n\t}\n\n\treturn merged;\n}\n\nconst _singleton = new LWWResolver();\n\n/**\n * Convenience function — resolves two conflicting deltas using the\n * column-level Last-Write-Wins strategy.\n *\n * @param local - The locally held delta for this row.\n * @param remote - The incoming remote delta for this row.\n * @returns A `Result` containing the resolved `RowDelta`, or a\n * `ConflictError` if the deltas refer to different tables/rows.\n */\nexport function resolveLWW(local: RowDelta, remote: RowDelta): Result<RowDelta, ConflictError> {\n\treturn _singleton.resolve(local, remote);\n}\n","import type { ActionExecutionError, ActionNotSupportedError } from \"../action/errors\";\nimport type { Action, ActionResult } from \"../action/types\";\nimport type { Result } from \"../result/result\";\nimport type { ResolvedClaims } from \"../sync-rules/types\";\n\n/** Describes an action type supported by a connector. */\nexport interface ActionDescriptor {\n\t/** The action type identifier (e.g. \"create_pr\", \"send_message\"). */\n\tactionType: string;\n\t/** Human-readable description of what this action does. */\n\tdescription: string;\n\t/** Optional JSON Schema for the action's params. */\n\tparamsSchema?: Record<string, unknown>;\n}\n\n/** Authentication context passed to action handlers for permission checks. */\nexport interface AuthContext {\n\t/** Resolved JWT claims for resource-level permission checks. */\n\tclaims: ResolvedClaims;\n}\n\n/**\n * Interface for connectors that can execute imperative actions.\n *\n * Separate from `DatabaseAdapter` — not all connectors support actions\n * (e.g. S3 doesn't). A connector can implement `DatabaseAdapter` (read/write\n * data), `ActionHandler` (execute commands), or both.\n */\nexport interface ActionHandler {\n\t/** Descriptors for all action types this handler supports. */\n\treadonly supportedActions: ActionDescriptor[];\n\t/** Execute a single action against the external system. */\n\texecuteAction(\n\t\taction: Action,\n\t\tcontext?: AuthContext,\n\t): Promise<Result<ActionResult, ActionExecutionError | ActionNotSupportedError>>;\n}\n\n/** Type guard: check whether an object implements the ActionHandler interface. */\nexport function isActionHandler(obj: unknown): obj is ActionHandler {\n\tif (obj === null || typeof obj !== \"object\") return false;\n\tconst candidate = obj as Record<string, unknown>;\n\treturn Array.isArray(candidate.supportedActions) && typeof candidate.executeAction === \"function\";\n}\n","import { LakeSyncError } from \"../result/errors\";\n\n/** Connector configuration validation error. */\nexport class ConnectorValidationError extends LakeSyncError {\n\tconstructor(message: string, cause?: Error) {\n\t\tsuper(message, \"CONNECTOR_VALIDATION\", cause);\n\t}\n}\n","// ---------------------------------------------------------------------------\n// Connector Registry — machine-readable metadata for all connector types\n// ---------------------------------------------------------------------------\n\nimport type { TableSchema } from \"../delta/types\";\nimport type { ConnectorType } from \"./types\";\n\n/** Connector category — determines the ingest model. */\nexport type ConnectorCategory = \"database\" | \"api\";\n\n/**\n * Machine-readable descriptor for a connector type.\n *\n * Exposes enough metadata for a UI to render an \"Add Connector\" form\n * without hardcoding per-type config shapes.\n */\nexport interface ConnectorDescriptor {\n\t/** Connector type identifier (e.g. \"postgres\", \"jira\"). */\n\ttype: ConnectorType;\n\t/** Human-readable display name (e.g. \"PostgreSQL\"). */\n\tdisplayName: string;\n\t/** Short description of the connector. */\n\tdescription: string;\n\t/** Ingest model category. */\n\tcategory: ConnectorCategory;\n\t/** JSON Schema (draft-07) describing the connector-specific config object. */\n\tconfigSchema: Record<string, unknown>;\n\t/** JSON Schema (draft-07) describing the ingest configuration. */\n\tingestSchema: Record<string, unknown>;\n\t/** Output table schemas for API connectors. Null for database connectors. */\n\toutputTables: ReadonlyArray<TableSchema> | null;\n}\n\n// ---------------------------------------------------------------------------\n// ConnectorRegistry — immutable value created from a list of descriptors\n// ---------------------------------------------------------------------------\n\n/** Immutable registry of connector descriptors. */\nexport interface ConnectorRegistry {\n\t/** Look up a single descriptor by type. */\n\tget(type: string): ConnectorDescriptor | undefined;\n\t/** List all descriptors, sorted alphabetically by type. */\n\tlist(): ConnectorDescriptor[];\n\t/** Create a new registry with an additional or replaced descriptor. */\n\twith(descriptor: ConnectorDescriptor): ConnectorRegistry;\n\t/** Create a new registry with output schemas attached to a type. */\n\twithOutputSchemas(type: string, schemas: ReadonlyArray<TableSchema>): ConnectorRegistry;\n}\n\n/**\n * Create an immutable {@link ConnectorRegistry} from a list of descriptors.\n */\nexport function createConnectorRegistry(descriptors: ConnectorDescriptor[]): ConnectorRegistry {\n\tconst map = new Map<string, ConnectorDescriptor>();\n\tfor (const d of descriptors) {\n\t\tmap.set(d.type, d);\n\t}\n\treturn buildRegistry(map);\n}\n\nfunction buildRegistry(map: Map<string, ConnectorDescriptor>): ConnectorRegistry {\n\treturn {\n\t\tget(type: string): ConnectorDescriptor | undefined {\n\t\t\treturn map.get(type);\n\t\t},\n\t\tlist(): ConnectorDescriptor[] {\n\t\t\treturn [...map.values()].sort((a, b) => a.type.localeCompare(b.type));\n\t\t},\n\t\twith(descriptor: ConnectorDescriptor): ConnectorRegistry {\n\t\t\tconst next = new Map(map);\n\t\t\tnext.set(descriptor.type, descriptor);\n\t\t\treturn buildRegistry(next);\n\t\t},\n\t\twithOutputSchemas(type: string, schemas: ReadonlyArray<TableSchema>): ConnectorRegistry {\n\t\t\tconst existing = map.get(type);\n\t\t\tif (!existing) return buildRegistry(map);\n\t\t\tconst next = new Map(map);\n\t\t\tnext.set(type, { ...existing, outputTables: schemas });\n\t\t\treturn buildRegistry(next);\n\t\t},\n\t};\n}\n\n// ---------------------------------------------------------------------------\n// Module-level mutable registry (backwards compatibility)\n// ---------------------------------------------------------------------------\n\nconst descriptors = new Map<string, ConnectorDescriptor>();\n\n/**\n * Register (or replace) a connector descriptor in the global registry.\n *\n * Called at module load time by built-in registration and by connector\n * packages that need to attach output schemas.\n */\nexport function registerConnectorDescriptor(descriptor: ConnectorDescriptor): void {\n\tdescriptors.set(descriptor.type, descriptor);\n}\n\n/**\n * Attach output table schemas to an already-registered connector type.\n *\n * No-op if the type has not been registered yet — this allows connector\n * packages to be imported in any order relative to the core registration.\n */\nexport function registerOutputSchemas(type: string, schemas: ReadonlyArray<TableSchema>): void {\n\tconst existing = descriptors.get(type);\n\tif (!existing) return;\n\tdescriptors.set(type, { ...existing, outputTables: schemas });\n}\n\n/**\n * Look up a single connector descriptor by type.\n *\n * Returns `undefined` when the type is not registered.\n */\nexport function getConnectorDescriptor(type: string): ConnectorDescriptor | undefined {\n\treturn descriptors.get(type);\n}\n\n/**\n * List all registered connector descriptors, sorted alphabetically by type.\n */\nexport function listConnectorDescriptors(): ConnectorDescriptor[] {\n\treturn [...descriptors.values()].sort((a, b) => a.type.localeCompare(b.type));\n}\n","/** Supported connector types. */\nexport const CONNECTOR_TYPES = [\"postgres\", \"mysql\", \"bigquery\", \"jira\", \"salesforce\"] as const;\n\n/** Union of supported connector type strings. */\nexport type ConnectorType = (typeof CONNECTOR_TYPES)[number];\n\n/** Connection configuration for a PostgreSQL source. */\nexport interface PostgresConnectorConfig {\n\t/** PostgreSQL connection string (e.g. \"postgres://user:pass@host/db\"). */\n\tconnectionString: string;\n}\n\n/** Connection configuration for a MySQL source. */\nexport interface MySQLConnectorConfig {\n\t/** MySQL connection string (e.g. \"mysql://user:pass@host/db\"). */\n\tconnectionString: string;\n}\n\n/** Connection configuration for a BigQuery source. */\nexport interface BigQueryConnectorConfig {\n\t/** GCP project ID. */\n\tprojectId: string;\n\t/** BigQuery dataset name. */\n\tdataset: string;\n\t/** Path to service account JSON key file. Falls back to ADC when omitted. */\n\tkeyFilename?: string;\n\t/** Dataset location (default \"US\"). */\n\tlocation?: string;\n}\n\n/** Ingest table configuration — defines a single table to poll. */\nexport interface ConnectorIngestTable {\n\t/** Target table name in LakeSync. */\n\ttable: string;\n\t/** SQL query to poll (must return rowId + data columns). */\n\tquery: string;\n\t/** Primary key column name (default \"id\"). */\n\trowIdColumn?: string;\n\t/** Change detection strategy. */\n\tstrategy: { type: \"cursor\"; cursorColumn: string; lookbackMs?: number } | { type: \"diff\" };\n}\n\n/** Connection configuration for a Salesforce CRM source. */\nexport interface SalesforceConnectorConfig {\n\t/** Salesforce instance URL (e.g. \"https://mycompany.salesforce.com\"). */\n\tinstanceUrl: string;\n\t/** Connected App consumer key. */\n\tclientId: string;\n\t/** Connected App consumer secret. */\n\tclientSecret: string;\n\t/** Salesforce username. */\n\tusername: string;\n\t/** Salesforce password + security token concatenated. */\n\tpassword: string;\n\t/** REST API version (default \"v62.0\"). */\n\tapiVersion?: string;\n\t/** Use test.salesforce.com for auth (default false). */\n\tisSandbox?: boolean;\n\t/** Optional WHERE clause fragment appended to all SOQL queries. */\n\tsoqlFilter?: string;\n\t/** Whether to include Account objects (default true). */\n\tincludeAccounts?: boolean;\n\t/** Whether to include Contact objects (default true). */\n\tincludeContacts?: boolean;\n\t/** Whether to include Opportunity objects (default true). */\n\tincludeOpportunities?: boolean;\n\t/** Whether to include Lead objects (default true). */\n\tincludeLeads?: boolean;\n}\n\n/** Connection configuration for a Jira Cloud source. */\nexport interface JiraConnectorConfig {\n\t/** Jira Cloud domain (e.g. \"mycompany\" for mycompany.atlassian.net). */\n\tdomain: string;\n\t/** Email address for Basic auth. */\n\temail: string;\n\t/** API token paired with the email. */\n\tapiToken: string;\n\t/** Optional JQL filter to scope issue polling. */\n\tjql?: string;\n\t/** Whether to include comments (default true). */\n\tincludeComments?: boolean;\n\t/** Whether to include projects (default true). */\n\tincludeProjects?: boolean;\n}\n\n/** Optional ingest polling configuration attached to a connector. */\nexport interface ConnectorIngestConfig {\n\t/** Tables to poll for changes. */\n\ttables: ConnectorIngestTable[];\n\t/** Poll interval in milliseconds (default 10 000). */\n\tintervalMs?: number;\n\t/** Deltas per push chunk (default 500). */\n\tchunkSize?: number;\n\t/** Approximate memory budget in bytes — triggers flush at 70%. */\n\tmemoryBudgetBytes?: number;\n}\n\n/**\n * Configuration for a dynamically registered connector (data source).\n *\n * Discriminated union keyed on `type` — each variant carries exactly\n * its own connection config. No optional fields from other types.\n */\nexport type ConnectorConfig =\n\t| {\n\t\t\ttype: \"postgres\";\n\t\t\tname: string;\n\t\t\tpostgres: PostgresConnectorConfig;\n\t\t\tingest?: ConnectorIngestConfig;\n\t }\n\t| { type: \"mysql\"; name: string; mysql: MySQLConnectorConfig; ingest?: ConnectorIngestConfig }\n\t| {\n\t\t\ttype: \"bigquery\";\n\t\t\tname: string;\n\t\t\tbigquery: BigQueryConnectorConfig;\n\t\t\tingest?: ConnectorIngestConfig;\n\t }\n\t| { type: \"jira\"; name: string; jira: JiraConnectorConfig; ingest?: ConnectorIngestConfig }\n\t| {\n\t\t\ttype: \"salesforce\";\n\t\t\tname: string;\n\t\t\tsalesforce: SalesforceConnectorConfig;\n\t\t\tingest?: ConnectorIngestConfig;\n\t };\n","import { Err, Ok, type Result } from \"../result/result\";\nimport { ConnectorValidationError } from \"./errors\";\nimport { CONNECTOR_TYPES, type ConnectorConfig } from \"./types\";\n\nconst VALID_STRATEGIES = new Set([\"cursor\", \"diff\"]);\n\n// ---------------------------------------------------------------------------\n// Per-type validators\n// ---------------------------------------------------------------------------\n\nfunction validatePostgresConfig(\n\tobj: Record<string, unknown>,\n): Result<void, ConnectorValidationError> {\n\tconst pg = obj.postgres;\n\tif (typeof pg !== \"object\" || pg === null) {\n\t\treturn Err(\n\t\t\tnew ConnectorValidationError('Connector type \"postgres\" requires a postgres config object'),\n\t\t);\n\t}\n\tconst pgObj = pg as Record<string, unknown>;\n\tif (typeof pgObj.connectionString !== \"string\" || pgObj.connectionString.length === 0) {\n\t\treturn Err(\n\t\t\tnew ConnectorValidationError(\"Postgres connector requires a non-empty connectionString\"),\n\t\t);\n\t}\n\treturn Ok(undefined);\n}\n\nfunction validateMySQLConfig(obj: Record<string, unknown>): Result<void, ConnectorValidationError> {\n\tconst my = obj.mysql;\n\tif (typeof my !== \"object\" || my === null) {\n\t\treturn Err(\n\t\t\tnew ConnectorValidationError('Connector type \"mysql\" requires a mysql config object'),\n\t\t);\n\t}\n\tconst myObj = my as Record<string, unknown>;\n\tif (typeof myObj.connectionString !== \"string\" || myObj.connectionString.length === 0) {\n\t\treturn Err(\n\t\t\tnew ConnectorValidationError(\"MySQL connector requires a non-empty connectionString\"),\n\t\t);\n\t}\n\treturn Ok(undefined);\n}\n\nfunction validateBigQueryConfig(\n\tobj: Record<string, unknown>,\n): Result<void, ConnectorValidationError> {\n\tconst bq = obj.bigquery;\n\tif (typeof bq !== \"object\" || bq === null) {\n\t\treturn Err(\n\t\t\tnew ConnectorValidationError('Connector type \"bigquery\" requires a bigquery config object'),\n\t\t);\n\t}\n\tconst bqObj = bq as Record<string, unknown>;\n\tif (typeof bqObj.projectId !== \"string\" || bqObj.projectId.length === 0) {\n\t\treturn Err(new ConnectorValidationError(\"BigQuery connector requires a non-empty projectId\"));\n\t}\n\tif (typeof bqObj.dataset !== \"string\" || bqObj.dataset.length === 0) {\n\t\treturn Err(new ConnectorValidationError(\"BigQuery connector requires a non-empty dataset\"));\n\t}\n\treturn Ok(undefined);\n}\n\nfunction validateJiraConfig(obj: Record<string, unknown>): Result<void, ConnectorValidationError> {\n\tconst jira = obj.jira;\n\tif (typeof jira !== \"object\" || jira === null) {\n\t\treturn Err(new ConnectorValidationError('Connector type \"jira\" requires a jira config object'));\n\t}\n\tconst jiraObj = jira as Record<string, unknown>;\n\tif (typeof jiraObj.domain !== \"string\" || jiraObj.domain.length === 0) {\n\t\treturn Err(new ConnectorValidationError(\"Jira connector requires a non-empty domain\"));\n\t}\n\tif (typeof jiraObj.email !== \"string\" || jiraObj.email.length === 0) {\n\t\treturn Err(new ConnectorValidationError(\"Jira connector requires a non-empty email\"));\n\t}\n\tif (typeof jiraObj.apiToken !== \"string\" || jiraObj.apiToken.length === 0) {\n\t\treturn Err(new ConnectorValidationError(\"Jira connector requires a non-empty apiToken\"));\n\t}\n\treturn Ok(undefined);\n}\n\nfunction validateSalesforceConfig(\n\tobj: Record<string, unknown>,\n): Result<void, ConnectorValidationError> {\n\tconst sf = obj.salesforce;\n\tif (typeof sf !== \"object\" || sf === null) {\n\t\treturn Err(\n\t\t\tnew ConnectorValidationError(\n\t\t\t\t'Connector type \"salesforce\" requires a salesforce config object',\n\t\t\t),\n\t\t);\n\t}\n\tconst sfObj = sf as Record<string, unknown>;\n\tif (typeof sfObj.instanceUrl !== \"string\" || sfObj.instanceUrl.length === 0) {\n\t\treturn Err(\n\t\t\tnew ConnectorValidationError(\"Salesforce connector requires a non-empty instanceUrl\"),\n\t\t);\n\t}\n\tif (typeof sfObj.clientId !== \"string\" || sfObj.clientId.length === 0) {\n\t\treturn Err(new ConnectorValidationError(\"Salesforce connector requires a non-empty clientId\"));\n\t}\n\tif (typeof sfObj.clientSecret !== \"string\" || sfObj.clientSecret.length === 0) {\n\t\treturn Err(\n\t\t\tnew ConnectorValidationError(\"Salesforce connector requires a non-empty clientSecret\"),\n\t\t);\n\t}\n\tif (typeof sfObj.username !== \"string\" || sfObj.username.length === 0) {\n\t\treturn Err(new ConnectorValidationError(\"Salesforce connector requires a non-empty username\"));\n\t}\n\tif (typeof sfObj.password !== \"string\" || sfObj.password.length === 0) {\n\t\treturn Err(new ConnectorValidationError(\"Salesforce connector requires a non-empty password\"));\n\t}\n\treturn Ok(undefined);\n}\n\n// ---------------------------------------------------------------------------\n// Ingest validation\n// ---------------------------------------------------------------------------\n\nfunction validateIngestConfig(\n\tobj: Record<string, unknown>,\n\tconnectorType: string,\n): Result<void, ConnectorValidationError> {\n\tif (obj.ingest === undefined) return Ok(undefined);\n\n\tif (typeof obj.ingest !== \"object\" || obj.ingest === null) {\n\t\treturn Err(new ConnectorValidationError(\"Ingest config must be an object\"));\n\t}\n\n\tconst ingest = obj.ingest as Record<string, unknown>;\n\n\t// API-based connectors define tables internally — only validate intervalMs\n\tif (connectorType === \"jira\" || connectorType === \"salesforce\") {\n\t\tif (ingest.intervalMs !== undefined) {\n\t\t\tif (typeof ingest.intervalMs !== \"number\" || ingest.intervalMs < 1) {\n\t\t\t\treturn Err(new ConnectorValidationError(\"Ingest intervalMs must be a positive number\"));\n\t\t\t}\n\t\t}\n\t\treturn Ok(undefined);\n\t}\n\n\tif (!Array.isArray(ingest.tables) || ingest.tables.length === 0) {\n\t\treturn Err(new ConnectorValidationError(\"Ingest config must have a non-empty tables array\"));\n\t}\n\n\tfor (let i = 0; i < ingest.tables.length; i++) {\n\t\tconst table = ingest.tables[i] as Record<string, unknown>;\n\n\t\tif (typeof table !== \"object\" || table === null) {\n\t\t\treturn Err(new ConnectorValidationError(`Ingest table at index ${i} must be an object`));\n\t\t}\n\n\t\tif (typeof table.table !== \"string\" || (table.table as string).length === 0) {\n\t\t\treturn Err(\n\t\t\t\tnew ConnectorValidationError(`Ingest table at index ${i} must have a non-empty table name`),\n\t\t\t);\n\t\t}\n\n\t\tif (typeof table.query !== \"string\" || (table.query as string).length === 0) {\n\t\t\treturn Err(\n\t\t\t\tnew ConnectorValidationError(`Ingest table at index ${i} must have a non-empty query`),\n\t\t\t);\n\t\t}\n\n\t\tif (typeof table.strategy !== \"object\" || table.strategy === null) {\n\t\t\treturn Err(\n\t\t\t\tnew ConnectorValidationError(`Ingest table at index ${i} must have a strategy object`),\n\t\t\t);\n\t\t}\n\n\t\tconst strategy = table.strategy as Record<string, unknown>;\n\t\tif (!VALID_STRATEGIES.has(strategy.type as string)) {\n\t\t\treturn Err(\n\t\t\t\tnew ConnectorValidationError(\n\t\t\t\t\t`Ingest table at index ${i} strategy type must be \"cursor\" or \"diff\"`,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\n\t\tif (strategy.type === \"cursor\") {\n\t\t\tif (\n\t\t\t\ttypeof strategy.cursorColumn !== \"string\" ||\n\t\t\t\t(strategy.cursorColumn as string).length === 0\n\t\t\t) {\n\t\t\t\treturn Err(\n\t\t\t\t\tnew ConnectorValidationError(\n\t\t\t\t\t\t`Ingest table at index ${i} cursor strategy requires a non-empty cursorColumn`,\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\tif (ingest.intervalMs !== undefined) {\n\t\tif (typeof ingest.intervalMs !== \"number\" || ingest.intervalMs < 1) {\n\t\t\treturn Err(new ConnectorValidationError(\"Ingest intervalMs must be a positive number\"));\n\t\t}\n\t}\n\n\treturn Ok(undefined);\n}\n\n// ---------------------------------------------------------------------------\n// Main validator\n// ---------------------------------------------------------------------------\n\n/**\n * Validate a connector configuration for structural correctness.\n *\n * Checks:\n * - `name` is a non-empty string\n * - `type` is one of the supported connector types\n * - Type-specific config object is present and valid\n * - Optional ingest config has valid table definitions\n *\n * @param input - Raw input to validate.\n * @returns The validated {@link ConnectorConfig} or a validation error.\n */\nexport function validateConnectorConfig(\n\tinput: unknown,\n): Result<ConnectorConfig, ConnectorValidationError> {\n\tif (typeof input !== \"object\" || input === null) {\n\t\treturn Err(new ConnectorValidationError(\"Connector config must be an object\"));\n\t}\n\n\tconst obj = input as Record<string, unknown>;\n\n\t// --- name ---\n\tif (typeof obj.name !== \"string\" || obj.name.length === 0) {\n\t\treturn Err(new ConnectorValidationError(\"Connector name must be a non-empty string\"));\n\t}\n\n\t// --- type ---\n\tif (typeof obj.type !== \"string\" || !(CONNECTOR_TYPES as readonly string[]).includes(obj.type)) {\n\t\treturn Err(\n\t\t\tnew ConnectorValidationError(`Connector type must be one of: ${CONNECTOR_TYPES.join(\", \")}`),\n\t\t);\n\t}\n\n\tconst connectorType = obj.type as ConnectorConfig[\"type\"];\n\n\t// --- type-specific config (exhaustive switch) ---\n\tlet typeResult: Result<void, ConnectorValidationError>;\n\tswitch (connectorType) {\n\t\tcase \"postgres\":\n\t\t\ttypeResult = validatePostgresConfig(obj);\n\t\t\tbreak;\n\t\tcase \"mysql\":\n\t\t\ttypeResult = validateMySQLConfig(obj);\n\t\t\tbreak;\n\t\tcase \"bigquery\":\n\t\t\ttypeResult = validateBigQueryConfig(obj);\n\t\t\tbreak;\n\t\tcase \"jira\":\n\t\t\ttypeResult = validateJiraConfig(obj);\n\t\t\tbreak;\n\t\tcase \"salesforce\":\n\t\t\ttypeResult = validateSalesforceConfig(obj);\n\t\t\tbreak;\n\t}\n\n\tif (!typeResult.ok) return typeResult;\n\n\t// --- optional ingest config ---\n\tconst ingestResult = validateIngestConfig(obj, connectorType);\n\tif (!ingestResult.ok) return ingestResult;\n\n\treturn Ok(input as ConnectorConfig);\n}\n","/** JSON Schema (draft-07) for BigQuery connector configuration. */\nexport const BIGQUERY_CONFIG_SCHEMA: Record<string, unknown> = {\n\t$schema: \"http://json-schema.org/draft-07/schema#\",\n\ttype: \"object\",\n\tproperties: {\n\t\tprojectId: {\n\t\t\ttype: \"string\",\n\t\t\tdescription: \"GCP project ID.\",\n\t\t},\n\t\tdataset: {\n\t\t\ttype: \"string\",\n\t\t\tdescription: \"BigQuery dataset name.\",\n\t\t},\n\t\tkeyFilename: {\n\t\t\ttype: \"string\",\n\t\t\tdescription: \"Path to service account JSON key file. Falls back to ADC when omitted.\",\n\t\t},\n\t\tlocation: {\n\t\t\ttype: \"string\",\n\t\t\tdescription: 'Dataset location (default \"US\").',\n\t\t},\n\t},\n\trequired: [\"projectId\", \"dataset\"],\n\tadditionalProperties: false,\n};\n","/** JSON Schema (draft-07) for database connector ingest configuration. */\nexport const DATABASE_INGEST_SCHEMA: Record<string, unknown> = {\n\t$schema: \"http://json-schema.org/draft-07/schema#\",\n\ttype: \"object\",\n\tproperties: {\n\t\ttables: {\n\t\t\ttype: \"array\",\n\t\t\tdescription: \"Tables to poll for changes.\",\n\t\t\titems: {\n\t\t\t\ttype: \"object\",\n\t\t\t\tproperties: {\n\t\t\t\t\ttable: { type: \"string\", description: \"Target table name in LakeSync.\" },\n\t\t\t\t\tquery: {\n\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\tdescription: \"SQL query to poll (must return rowId + data columns).\",\n\t\t\t\t\t},\n\t\t\t\t\trowIdColumn: {\n\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\tdescription: 'Primary key column name (default \"id\").',\n\t\t\t\t\t},\n\t\t\t\t\tstrategy: {\n\t\t\t\t\t\toneOf: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\ttype: \"object\",\n\t\t\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\t\t\ttype: { const: \"cursor\" },\n\t\t\t\t\t\t\t\t\tcursorColumn: { type: \"string\" },\n\t\t\t\t\t\t\t\t\tlookbackMs: { type: \"number\" },\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\trequired: [\"type\", \"cursorColumn\"],\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\ttype: \"object\",\n\t\t\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\t\t\ttype: { const: \"diff\" },\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\trequired: [\"type\"],\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\trequired: [\"table\", \"query\", \"strategy\"],\n\t\t\t},\n\t\t},\n\t\tintervalMs: {\n\t\t\ttype: \"number\",\n\t\t\tdescription: \"Poll interval in milliseconds (default 10 000).\",\n\t\t},\n\t\tchunkSize: {\n\t\t\ttype: \"number\",\n\t\t\tdescription: \"Deltas per push chunk (default 500).\",\n\t\t},\n\t\tmemoryBudgetBytes: {\n\t\t\ttype: \"number\",\n\t\t\tdescription: \"Approximate memory budget in bytes — triggers flush at 70%.\",\n\t\t},\n\t},\n\trequired: [\"tables\"],\n\tadditionalProperties: false,\n};\n\n/** JSON Schema (draft-07) for API connector ingest configuration. */\nexport const API_INGEST_SCHEMA: Record<string, unknown> = {\n\t$schema: \"http://json-schema.org/draft-07/schema#\",\n\ttype: \"object\",\n\tproperties: {\n\t\tintervalMs: {\n\t\t\ttype: \"number\",\n\t\t\tdescription: \"Poll interval in milliseconds (default 10 000).\",\n\t\t},\n\t\tchunkSize: {\n\t\t\ttype: \"number\",\n\t\t\tdescription: \"Deltas per push chunk (default 500).\",\n\t\t},\n\t\tmemoryBudgetBytes: {\n\t\t\ttype: \"number\",\n\t\t\tdescription: \"Approximate memory budget in bytes — triggers flush at 70%.\",\n\t\t},\n\t},\n\tadditionalProperties: false,\n};\n","/** JSON Schema (draft-07) for Jira Cloud connector configuration. */\nexport const JIRA_CONFIG_SCHEMA: Record<string, unknown> = {\n\t$schema: \"http://json-schema.org/draft-07/schema#\",\n\ttype: \"object\",\n\tproperties: {\n\t\tdomain: {\n\t\t\ttype: \"string\",\n\t\t\tdescription: \"Jira Cloud domain (e.g. mycompany for mycompany.atlassian.net).\",\n\t\t},\n\t\temail: {\n\t\t\ttype: \"string\",\n\t\t\tdescription: \"Email address for Basic auth.\",\n\t\t},\n\t\tapiToken: {\n\t\t\ttype: \"string\",\n\t\t\tdescription: \"API token paired with the email.\",\n\t\t},\n\t\tjql: {\n\t\t\ttype: \"string\",\n\t\t\tdescription: \"Optional JQL filter to scope issue polling.\",\n\t\t},\n\t\tincludeComments: {\n\t\t\ttype: \"boolean\",\n\t\t\tdescription: \"Whether to include comments (default true).\",\n\t\t},\n\t\tincludeProjects: {\n\t\t\ttype: \"boolean\",\n\t\t\tdescription: \"Whether to include projects (default true).\",\n\t\t},\n\t},\n\trequired: [\"domain\", \"email\", \"apiToken\"],\n\tadditionalProperties: false,\n};\n","/** JSON Schema (draft-07) for MySQL connector configuration. */\nexport const MYSQL_CONFIG_SCHEMA: Record<string, unknown> = {\n\t$schema: \"http://json-schema.org/draft-07/schema#\",\n\ttype: \"object\",\n\tproperties: {\n\t\tconnectionString: {\n\t\t\ttype: \"string\",\n\t\t\tdescription: \"MySQL connection string (e.g. mysql://user:pass@host/db).\",\n\t\t},\n\t},\n\trequired: [\"connectionString\"],\n\tadditionalProperties: false,\n};\n","/** JSON Schema (draft-07) for PostgreSQL connector configuration. */\nexport const POSTGRES_CONFIG_SCHEMA: Record<string, unknown> = {\n\t$schema: \"http://json-schema.org/draft-07/schema#\",\n\ttype: \"object\",\n\tproperties: {\n\t\tconnectionString: {\n\t\t\ttype: \"string\",\n\t\t\tdescription: \"PostgreSQL connection string (e.g. postgres://user:pass@host/db).\",\n\t\t},\n\t},\n\trequired: [\"connectionString\"],\n\tadditionalProperties: false,\n};\n","/** JSON Schema (draft-07) for Salesforce CRM connector configuration. */\nexport const SALESFORCE_CONFIG_SCHEMA: Record<string, unknown> = {\n\t$schema: \"http://json-schema.org/draft-07/schema#\",\n\ttype: \"object\",\n\tproperties: {\n\t\tinstanceUrl: {\n\t\t\ttype: \"string\",\n\t\t\tdescription: \"Salesforce instance URL (e.g. https://mycompany.salesforce.com).\",\n\t\t},\n\t\tclientId: {\n\t\t\ttype: \"string\",\n\t\t\tdescription: \"Connected App consumer key.\",\n\t\t},\n\t\tclientSecret: {\n\t\t\ttype: \"string\",\n\t\t\tdescription: \"Connected App consumer secret.\",\n\t\t},\n\t\tusername: {\n\t\t\ttype: \"string\",\n\t\t\tdescription: \"Salesforce username.\",\n\t\t},\n\t\tpassword: {\n\t\t\ttype: \"string\",\n\t\t\tdescription: \"Salesforce password + security token concatenated.\",\n\t\t},\n\t\tapiVersion: {\n\t\t\ttype: \"string\",\n\t\t\tdescription: 'REST API version (default \"v62.0\").',\n\t\t},\n\t\tisSandbox: {\n\t\t\ttype: \"boolean\",\n\t\t\tdescription: \"Use test.salesforce.com for auth (default false).\",\n\t\t},\n\t\tsoqlFilter: {\n\t\t\ttype: \"string\",\n\t\t\tdescription: \"Optional WHERE clause fragment appended to all SOQL queries.\",\n\t\t},\n\t\tincludeAccounts: {\n\t\t\ttype: \"boolean\",\n\t\t\tdescription: \"Whether to include Account objects (default true).\",\n\t\t},\n\t\tincludeContacts: {\n\t\t\ttype: \"boolean\",\n\t\t\tdescription: \"Whether to include Contact objects (default true).\",\n\t\t},\n\t\tincludeOpportunities: {\n\t\t\ttype: \"boolean\",\n\t\t\tdescription: \"Whether to include Opportunity objects (default true).\",\n\t\t},\n\t\tincludeLeads: {\n\t\t\ttype: \"boolean\",\n\t\t\tdescription: \"Whether to include Lead objects (default true).\",\n\t\t},\n\t},\n\trequired: [\"instanceUrl\", \"clientId\", \"clientSecret\", \"username\", \"password\"],\n\tadditionalProperties: false,\n};\n","// ---------------------------------------------------------------------------\n// Built-in connector descriptor registration (side-effect module)\n// ---------------------------------------------------------------------------\n\nimport { registerConnectorDescriptor } from \"./registry\";\nimport {\n\tAPI_INGEST_SCHEMA,\n\tBIGQUERY_CONFIG_SCHEMA,\n\tDATABASE_INGEST_SCHEMA,\n\tJIRA_CONFIG_SCHEMA,\n\tMYSQL_CONFIG_SCHEMA,\n\tPOSTGRES_CONFIG_SCHEMA,\n\tSALESFORCE_CONFIG_SCHEMA,\n} from \"./schemas/index\";\n\nregisterConnectorDescriptor({\n\ttype: \"bigquery\",\n\tdisplayName: \"BigQuery\",\n\tdescription: \"Google BigQuery data warehouse connector.\",\n\tcategory: \"database\",\n\tconfigSchema: BIGQUERY_CONFIG_SCHEMA,\n\tingestSchema: DATABASE_INGEST_SCHEMA,\n\toutputTables: null,\n});\n\nregisterConnectorDescriptor({\n\ttype: \"jira\",\n\tdisplayName: \"Jira\",\n\tdescription: \"Atlassian Jira Cloud issue tracker connector.\",\n\tcategory: \"api\",\n\tconfigSchema: JIRA_CONFIG_SCHEMA,\n\tingestSchema: API_INGEST_SCHEMA,\n\toutputTables: null,\n});\n\nregisterConnectorDescriptor({\n\ttype: \"mysql\",\n\tdisplayName: \"MySQL\",\n\tdescription: \"MySQL relational database connector.\",\n\tcategory: \"database\",\n\tconfigSchema: MYSQL_CONFIG_SCHEMA,\n\tingestSchema: DATABASE_INGEST_SCHEMA,\n\toutputTables: null,\n});\n\nregisterConnectorDescriptor({\n\ttype: \"postgres\",\n\tdisplayName: \"PostgreSQL\",\n\tdescription: \"PostgreSQL relational database connector.\",\n\tcategory: \"database\",\n\tconfigSchema: POSTGRES_CONFIG_SCHEMA,\n\tingestSchema: DATABASE_INGEST_SCHEMA,\n\toutputTables: null,\n});\n\nregisterConnectorDescriptor({\n\ttype: \"salesforce\",\n\tdisplayName: \"Salesforce\",\n\tdescription: \"Salesforce CRM connector for accounts, contacts, opportunities, and leads.\",\n\tcategory: \"api\",\n\tconfigSchema: SALESFORCE_CONFIG_SCHEMA,\n\tingestSchema: API_INGEST_SCHEMA,\n\toutputTables: null,\n});\n","// ---------------------------------------------------------------------------\n// createPoller — registry-based factory for creating pollers from ConnectorConfig\n// ---------------------------------------------------------------------------\n\nimport type { BaseSourcePoller, PushTarget } from \"./base-poller\";\nimport type { ConnectorConfig } from \"./connector/types\";\n\n/** Factory function that creates a poller from a ConnectorConfig. */\nexport type PollerFactory = (config: ConnectorConfig, gateway: PushTarget) => BaseSourcePoller;\n\n// ---------------------------------------------------------------------------\n// PollerRegistry — explicit value holding poller factories\n// ---------------------------------------------------------------------------\n\n/** Immutable registry of poller factories keyed by connector type. */\nexport interface PollerRegistry {\n\t/** Look up a factory by type. */\n\tget(type: string): PollerFactory | undefined;\n\t/** Create a new registry with an additional or replaced factory. */\n\twith(type: string, factory: PollerFactory): PollerRegistry;\n}\n\n/**\n * Create an immutable {@link PollerRegistry} from a Map of factories.\n */\nexport function createPollerRegistry(\n\tfactories: Map<string, PollerFactory> = new Map(),\n): PollerRegistry {\n\treturn buildPollerRegistry(new Map(factories));\n}\n\nfunction buildPollerRegistry(map: Map<string, PollerFactory>): PollerRegistry {\n\treturn {\n\t\tget(type: string): PollerFactory | undefined {\n\t\t\treturn map.get(type);\n\t\t},\n\t\twith(type: string, factory: PollerFactory): PollerRegistry {\n\t\t\tconst next = new Map(map);\n\t\t\tnext.set(type, factory);\n\t\t\treturn buildPollerRegistry(next);\n\t\t},\n\t};\n}\n\n// ---------------------------------------------------------------------------\n// Global mutable registry (backwards compatibility)\n// ---------------------------------------------------------------------------\n\n/** Registry of poller factory functions keyed by connector type. */\nconst pollerFactories = new Map<string, PollerFactory>();\n\n/**\n * Register a poller factory for a connector type.\n * Connector packages call this at module load time so that\n * `createPoller()` can instantiate the correct poller.\n */\nexport function registerPollerFactory(type: string, factory: PollerFactory): void {\n\tpollerFactories.set(type, factory);\n}\n\n/**\n * Create a poller from a {@link ConnectorConfig}.\n *\n * @param config - Connector configuration.\n * @param gateway - Push target for the poller.\n * @param registry - Optional explicit registry. Defaults to the global registry.\n * @throws If no factory has been registered for the config's `type`.\n */\nexport function createPoller(\n\tconfig: ConnectorConfig,\n\tgateway: PushTarget,\n\tregistry?: PollerRegistry,\n): BaseSourcePoller {\n\tconst factory = registry ? registry.get(config.type) : pollerFactories.get(config.type);\n\tif (!factory) {\n\t\tthrow new Error(\n\t\t\t`No poller factory registered for connector type \"${config.type}\". ` +\n\t\t\t\t`Did you import the connector package (e.g. \"@lakesync/connector-${config.type}\")?`,\n\t\t);\n\t}\n\treturn factory(config, gateway);\n}\n","import type { RowDelta } from \"./types\";\n\n/**\n * Apply a delta to an existing row, returning the merged result.\n *\n * - DELETE → returns null\n * - INSERT → creates a new row from delta columns\n * - UPDATE → merges delta columns onto existing row (immutable — returns a new object)\n *\n * @param row - The current row state, or null if no row exists\n * @param delta - The delta to apply\n * @returns The merged row, or null for DELETE operations\n */\nexport function applyDelta(\n\trow: Record<string, unknown> | null,\n\tdelta: RowDelta,\n): Record<string, unknown> | null {\n\tif (delta.op === \"DELETE\") return null;\n\n\tconst base: Record<string, unknown> = row ? { ...row } : {};\n\tfor (const col of delta.columns) {\n\t\tbase[col.column] = col.value;\n\t}\n\treturn base;\n}\n","import equal from \"fast-deep-equal\";\nimport stableStringify from \"fast-json-stable-stringify\";\nimport type { HLCTimestamp } from \"../hlc/types\";\nimport type { ColumnDelta, RowDelta, TableSchema } from \"./types\";\n\n/**\n * Extract a column-level delta between two row states.\n *\n * - `before` null/undefined + `after` present -> INSERT (all columns)\n * - `before` present + `after` null/undefined -> DELETE (empty columns)\n * - Both present -> compare each column, emit only changed columns as UPDATE\n * - No columns changed -> returns null (no-op)\n *\n * If `schema` is provided, only columns listed in the schema are considered.\n *\n * @param before - The previous row state, or null/undefined for a new row\n * @param after - The current row state, or null/undefined for a deleted row\n * @param opts - Table name, row ID, client ID, HLC timestamp, and optional schema\n * @returns The extracted RowDelta, or null if nothing changed\n */\nexport async function extractDelta(\n\tbefore: Record<string, unknown> | null | undefined,\n\tafter: Record<string, unknown> | null | undefined,\n\topts: {\n\t\ttable: string;\n\t\trowId: string;\n\t\tclientId: string;\n\t\thlc: HLCTimestamp;\n\t\tschema?: TableSchema;\n\t},\n): Promise<RowDelta | null> {\n\tconst { table, rowId, clientId, hlc, schema } = opts;\n\n\tconst beforeExists = before != null;\n\tconst afterExists = after != null;\n\n\tif (!beforeExists && !afterExists) {\n\t\treturn null;\n\t}\n\n\t// INSERT: no previous state, new state exists\n\tif (!beforeExists && afterExists) {\n\t\tconst columns = buildColumns(after, schema);\n\t\tconst deltaId = await generateDeltaId({ clientId, hlc, table, rowId, columns });\n\t\treturn { op: \"INSERT\", table, rowId, clientId, columns, hlc, deltaId };\n\t}\n\n\t// DELETE: previous state exists, no new state\n\tif (beforeExists && !afterExists) {\n\t\tconst columns: ColumnDelta[] = [];\n\t\tconst deltaId = await generateDeltaId({ clientId, hlc, table, rowId, columns });\n\t\treturn { op: \"DELETE\", table, rowId, clientId, columns, hlc, deltaId };\n\t}\n\n\t// UPDATE: both states exist — compare columns\n\tconst columns = diffColumns(before!, after!, schema);\n\tif (columns.length === 0) {\n\t\treturn null;\n\t}\n\n\tconst deltaId = await generateDeltaId({ clientId, hlc, table, rowId, columns });\n\treturn { op: \"UPDATE\", table, rowId, clientId, columns, hlc, deltaId };\n}\n\n/** Build an allow-set from a schema, or null if no schema is provided. */\nfunction allowedSet(schema?: TableSchema): Set<string> | null {\n\treturn schema ? new Set(schema.columns.map((c) => c.name)) : null;\n}\n\n/**\n * Build column deltas from a row, optionally filtered by schema.\n * Skips columns whose value is undefined (treated as absent).\n */\nfunction buildColumns(row: Record<string, unknown>, schema?: TableSchema): ColumnDelta[] {\n\tconst allowed = allowedSet(schema);\n\tconst columns: ColumnDelta[] = [];\n\n\tfor (const [key, value] of Object.entries(row)) {\n\t\tif (value === undefined) continue;\n\t\tif (allowed && !allowed.has(key)) continue;\n\t\tcolumns.push({ column: key, value });\n\t}\n\n\treturn columns;\n}\n\n/**\n * Diff two row objects and return only the changed columns.\n * Uses Object.is() for primitives and fast-deep-equal for objects/arrays.\n */\nfunction diffColumns(\n\tbefore: Record<string, unknown>,\n\tafter: Record<string, unknown>,\n\tschema?: TableSchema,\n): ColumnDelta[] {\n\tconst allowed = allowedSet(schema);\n\tconst allKeys = new Set([...Object.keys(before), ...Object.keys(after)]);\n\tconst columns: ColumnDelta[] = [];\n\n\tfor (const key of allKeys) {\n\t\tif (allowed && !allowed.has(key)) continue;\n\n\t\tconst beforeVal = before[key];\n\t\tconst afterVal = after[key];\n\n\t\t// Skip absent or removed columns\n\t\tif (afterVal === undefined) continue;\n\n\t\t// New column — before was undefined\n\t\tif (beforeVal === undefined) {\n\t\t\tcolumns.push({ column: key, value: afterVal });\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Exact primitive equality (handles NaN, +0/-0)\n\t\tif (Object.is(beforeVal, afterVal)) continue;\n\n\t\t// Deep equality for objects/arrays (key-order-agnostic)\n\t\tif (\n\t\t\ttypeof beforeVal === \"object\" &&\n\t\t\tbeforeVal !== null &&\n\t\t\ttypeof afterVal === \"object\" &&\n\t\t\tafterVal !== null &&\n\t\t\tequal(beforeVal, afterVal)\n\t\t) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tcolumns.push({ column: key, value: afterVal });\n\t}\n\n\treturn columns;\n}\n\n/**\n * Generate a deterministic delta ID using SHA-256.\n * Uses the Web Crypto API (works in both Bun and browsers).\n */\nasync function generateDeltaId(params: {\n\tclientId: string;\n\thlc: HLCTimestamp;\n\ttable: string;\n\trowId: string;\n\tcolumns: ColumnDelta[];\n}): Promise<string> {\n\tconst payload = stableStringify({\n\t\tclientId: params.clientId,\n\t\thlc: params.hlc.toString(),\n\t\ttable: params.table,\n\t\trowId: params.rowId,\n\t\tcolumns: params.columns,\n\t});\n\n\tconst data = new TextEncoder().encode(payload);\n\tconst hashBuffer = await crypto.subtle.digest(\"SHA-256\", data);\n\tconst bytes = new Uint8Array(hashBuffer);\n\n\tlet hex = \"\";\n\tfor (const b of bytes) {\n\t\thex += b.toString(16).padStart(2, \"0\");\n\t}\n\treturn hex;\n}\n","import type { HLCTimestamp } from \"../hlc/types\";\n\n/** Delta operation type */\nexport type DeltaOp = \"INSERT\" | \"UPDATE\" | \"DELETE\";\n\n/** A single column-level change */\nexport interface ColumnDelta {\n\t/** Column name */\n\tcolumn: string;\n\t/** Serialisable JSON value — NEVER undefined, use null instead */\n\tvalue: unknown;\n}\n\n/** A row-level delta containing column-level changes */\nexport interface RowDelta {\n\t/** Operation type */\n\top: DeltaOp;\n\t/** Table name */\n\ttable: string;\n\t/** Row identifier */\n\trowId: string;\n\t/** Client identifier — used for LWW tiebreak and audit */\n\tclientId: string;\n\t/** Changed columns — empty for DELETE */\n\tcolumns: ColumnDelta[];\n\t/** HLC timestamp (branded bigint) */\n\thlc: HLCTimestamp;\n\t/** Deterministic identifier: hash(clientId + hlc + table + rowId + columns) */\n\tdeltaId: string;\n}\n\n/** Valid column types as a const tuple — single source of truth for both type and runtime validation. */\nexport const COLUMN_TYPES = [\"string\", \"number\", \"boolean\", \"json\", \"null\"] as const;\n\n/** A valid column type. */\nexport type ColumnType = (typeof COLUMN_TYPES)[number];\n\n/** Foreign key reference from a column to another table. */\nexport interface ColumnReference {\n\t/** Target table name (e.g. 'jira_issues'). */\n\ttable: string;\n\t/** Target column name (e.g. 'key'). */\n\tcolumn: string;\n\t/** Cardinality from this column's perspective. */\n\tcardinality: \"many-to-one\" | \"one-to-many\";\n}\n\n/** Minimal schema for Phase 1. Column allow-list + type hints. */\nexport interface TableSchema {\n\t/** Destination table name (what gets created in the database). */\n\ttable: string;\n\t/** Delta table name to match against. Defaults to `table` when omitted. Use to rename destination tables. */\n\tsourceTable?: string;\n\tcolumns: Array<{\n\t\tname: string;\n\t\ttype: ColumnType;\n\t\t/** FK reference to another table. */\n\t\treferences?: ColumnReference;\n\t}>;\n\t/** Composite primary key columns. Defaults to `[\"row_id\"]`. Each entry must be `\"row_id\"` or exist in `columns`. */\n\tprimaryKey?: string[];\n\t/** When true (default), tombstoned rows are soft-deleted (`deleted_at` set) instead of hard-deleted. */\n\tsoftDelete?: boolean;\n\t/** When set, upsert resolves on this column (UNIQUE constraint) instead of the primary key. Must exist in `columns`. */\n\texternalIdColumn?: string;\n}\n\n/** Composite key utility — avoids string concatenation bugs */\nexport type RowKey = string & { readonly __brand: \"RowKey\" };\n\n/** Create a composite row key from table and row ID */\nexport function rowKey(table: string, rowId: string): RowKey {\n\treturn `${table}:${rowId}` as RowKey;\n}\n\n/** SyncPush input message — sent by clients to push local deltas to the gateway */\nexport interface SyncPush {\n\t/** Client that sent the push */\n\tclientId: string;\n\t/** Deltas to push */\n\tdeltas: RowDelta[];\n\t/** Client's last-seen HLC */\n\tlastSeenHlc: HLCTimestamp;\n}\n\n/** SyncPull input message — sent by clients to pull remote deltas from the gateway */\nexport interface SyncPull {\n\t/** Client that sent the pull */\n\tclientId: string;\n\t/** Return deltas with HLC strictly after this value */\n\tsinceHlc: HLCTimestamp;\n\t/** Maximum number of deltas to return */\n\tmaxDeltas: number;\n\t/** Optional source adapter name — when set, pull from the named adapter instead of the buffer */\n\tsource?: string;\n}\n\n/** SyncResponse output — returned by the gateway after push or pull */\nexport interface SyncResponse {\n\t/** Deltas matching the pull criteria */\n\tdeltas: RowDelta[];\n\t/** Current server HLC */\n\tserverHlc: HLCTimestamp;\n\t/** Whether there are more deltas to fetch */\n\thasMore: boolean;\n}\n","/**\n * BigInt-safe JSON replacer.\n *\n * Converts BigInt values to strings so they survive `JSON.stringify`,\n * which otherwise throws on BigInt.\n */\nexport function bigintReplacer(_key: string, value: unknown): unknown {\n\treturn typeof value === \"bigint\" ? value.toString() : value;\n}\n\n/**\n * BigInt-aware JSON reviver.\n *\n * Restores string-encoded HLC timestamps (fields ending in `Hlc` or `hlc`)\n * back to BigInt so they match the branded `HLCTimestamp` type.\n *\n * Invalid numeric strings are left as-is to prevent runtime crashes.\n */\nexport function bigintReviver(key: string, value: unknown): unknown {\n\tif (typeof value === \"string\" && /hlc$/i.test(key)) {\n\t\ttry {\n\t\t\treturn BigInt(value);\n\t\t} catch {\n\t\t\treturn value;\n\t\t}\n\t}\n\treturn value;\n}\n","import type { SyncRulesConfig } from \"./types\";\n\n/**\n * Create a pass-all sync rules configuration.\n *\n * Every delta reaches every client — equivalent to having no rules at all.\n * Useful for apps without multi-tenancy or per-user data isolation.\n */\nexport function createPassAllRules(): SyncRulesConfig {\n\treturn {\n\t\tversion: 1,\n\t\tbuckets: [\n\t\t\t{\n\t\t\t\tname: \"all\",\n\t\t\t\ttables: [],\n\t\t\t\tfilters: [],\n\t\t\t},\n\t\t],\n\t};\n}\n\n/**\n * Create user-scoped sync rules configuration.\n *\n * Filters rows by matching a configurable column against the JWT `sub` claim,\n * so each client only receives deltas belonging to the authenticated user.\n *\n * @param tables - Which tables to scope. Empty array means all tables.\n * @param userColumn - Column to match against `jwt:sub`. Defaults to `\"user_id\"`.\n */\nexport function createUserScopedRules(tables: string[], userColumn = \"user_id\"): SyncRulesConfig {\n\treturn {\n\t\tversion: 1,\n\t\tbuckets: [\n\t\t\t{\n\t\t\t\tname: \"user\",\n\t\t\t\ttables,\n\t\t\t\tfilters: [\n\t\t\t\t\t{\n\t\t\t\t\t\tcolumn: userColumn,\n\t\t\t\t\t\top: \"eq\",\n\t\t\t\t\t\tvalue: \"jwt:sub\",\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t},\n\t\t],\n\t};\n}\n","import { LakeSyncError } from \"../result/errors\";\n\n/** Sync rule configuration or evaluation error */\nexport class SyncRuleError extends LakeSyncError {\n\tconstructor(message: string, cause?: Error) {\n\t\tsuper(message, \"SYNC_RULE_ERROR\", cause);\n\t}\n}\n","import type { RowDelta } from \"../delta/types\";\nimport { Err, Ok, type Result } from \"../result/result\";\nimport { SyncRuleError } from \"./errors\";\nimport type {\n\tBucketDefinition,\n\tResolvedClaims,\n\tSyncRuleFilter,\n\tSyncRulesConfig,\n\tSyncRulesContext,\n} from \"./types\";\n\n/**\n * Resolve a filter value, substituting JWT claim references.\n *\n * Values prefixed with `jwt:` are looked up in the claims record.\n * Literal values are returned as-is (wrapped in an array for uniform handling).\n *\n * @param value - The filter value string (e.g. \"jwt:sub\" or \"tenant-1\")\n * @param claims - Resolved JWT claims\n * @returns An array of resolved values, or an empty array if the claim is missing\n */\nexport function resolveFilterValue(value: string, claims: ResolvedClaims): string[] {\n\tif (!value.startsWith(\"jwt:\")) {\n\t\treturn [value];\n\t}\n\n\tconst claimKey = value.slice(4);\n\tconst claimValue = claims[claimKey];\n\n\tif (claimValue === undefined) {\n\t\treturn [];\n\t}\n\n\treturn Array.isArray(claimValue) ? claimValue : [claimValue];\n}\n\n/**\n * Check whether a delta matches a single bucket definition.\n *\n * A delta matches if:\n * 1. The bucket's `tables` list is empty (matches all tables) or includes the delta's table\n * 2. All filters match (conjunctive AND):\n * - `eq`: the delta column value equals one of the resolved filter values\n * - `in`: the delta column value is contained in the resolved filter values\n *\n * @param delta - The row delta to evaluate\n * @param bucket - The bucket definition\n * @param claims - Resolved JWT claims\n * @returns true if the delta matches this bucket\n */\nexport function deltaMatchesBucket(\n\tdelta: RowDelta,\n\tbucket: BucketDefinition,\n\tclaims: ResolvedClaims,\n): boolean {\n\t// Table filter: empty tables list = match all\n\tif (bucket.tables.length > 0 && !bucket.tables.includes(delta.table)) {\n\t\treturn false;\n\t}\n\n\t// All filters must match (conjunctive AND)\n\tfor (const filter of bucket.filters) {\n\t\tif (!filterMatchesDelta(delta, filter, claims)) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\treturn true;\n}\n\n/**\n * Compare two values using a comparison operator.\n * Attempts numeric comparison first; falls back to string localeCompare.\n */\nfunction compareValues(\n\tdeltaValue: string,\n\tfilterValue: string,\n\top: \"gt\" | \"lt\" | \"gte\" | \"lte\",\n): boolean {\n\tconst numDelta = parseFloat(deltaValue);\n\tconst numFilter = parseFloat(filterValue);\n\tconst useNumeric = !Number.isNaN(numDelta) && !Number.isNaN(numFilter);\n\n\tif (useNumeric) {\n\t\tswitch (op) {\n\t\t\tcase \"gt\":\n\t\t\t\treturn numDelta > numFilter;\n\t\t\tcase \"lt\":\n\t\t\t\treturn numDelta < numFilter;\n\t\t\tcase \"gte\":\n\t\t\t\treturn numDelta >= numFilter;\n\t\t\tcase \"lte\":\n\t\t\t\treturn numDelta <= numFilter;\n\t\t}\n\t}\n\n\tconst cmp = deltaValue.localeCompare(filterValue);\n\tswitch (op) {\n\t\tcase \"gt\":\n\t\t\treturn cmp > 0;\n\t\tcase \"lt\":\n\t\t\treturn cmp < 0;\n\t\tcase \"gte\":\n\t\t\treturn cmp >= 0;\n\t\tcase \"lte\":\n\t\t\treturn cmp <= 0;\n\t}\n}\n\nconst FILTER_OPS: Record<string, (dv: string, rv: string[]) => boolean> = {\n\teq: (dv, rv) => rv.includes(dv),\n\tin: (dv, rv) => rv.includes(dv),\n\tneq: (dv, rv) => !rv.includes(dv),\n\tgt: (dv, rv) => compareValues(dv, rv[0]!, \"gt\"),\n\tlt: (dv, rv) => compareValues(dv, rv[0]!, \"lt\"),\n\tgte: (dv, rv) => compareValues(dv, rv[0]!, \"gte\"),\n\tlte: (dv, rv) => compareValues(dv, rv[0]!, \"lte\"),\n};\n\n/**\n * Check whether a single filter matches a delta's column values.\n */\nfunction filterMatchesDelta(\n\tdelta: RowDelta,\n\tfilter: SyncRuleFilter,\n\tclaims: ResolvedClaims,\n): boolean {\n\tconst col = delta.columns.find((c) => c.column === filter.column);\n\tif (!col) {\n\t\t// Column not present in delta — filter does not match\n\t\treturn false;\n\t}\n\n\tconst deltaValue = String(col.value);\n\tconst resolvedValues = resolveFilterValue(filter.value, claims);\n\n\tif (resolvedValues.length === 0) {\n\t\t// JWT claim missing — filter cannot match\n\t\treturn false;\n\t}\n\n\treturn FILTER_OPS[filter.op]?.(deltaValue, resolvedValues) ?? false;\n}\n\n/**\n * Filter an array of deltas by sync rules.\n *\n * A delta is included if it matches **any** bucket (union across buckets).\n * If no sync rules are configured (empty buckets), all deltas pass through.\n *\n * @param deltas - The deltas to filter\n * @param context - Sync rules context (rules + resolved claims)\n * @returns Filtered array of deltas\n */\nexport function filterDeltas(deltas: RowDelta[], context: SyncRulesContext): RowDelta[] {\n\tif (context.rules.buckets.length === 0) {\n\t\treturn deltas;\n\t}\n\n\treturn deltas.filter((delta) =>\n\t\tcontext.rules.buckets.some((bucket) => deltaMatchesBucket(delta, bucket, context.claims)),\n\t);\n}\n\n/**\n * Determine which buckets a client matches based on their claims.\n *\n * A client matches a bucket if the bucket has no table-level restrictions\n * or if the client's claims satisfy all filter conditions for at least\n * one possible row. This is used for bucket-level access decisions, not\n * row-level filtering.\n *\n * @param rules - The sync rules configuration\n * @param claims - Resolved JWT claims\n * @returns Array of bucket names the client matches\n */\nexport function resolveClientBuckets(rules: SyncRulesConfig, claims: ResolvedClaims): string[] {\n\treturn rules.buckets\n\t\t.filter((bucket) => {\n\t\t\t// A client matches a bucket if all JWT-referenced filters\n\t\t\t// can be resolved (i.e. the required claims exist)\n\t\t\tfor (const filter of bucket.filters) {\n\t\t\t\tif (filter.value.startsWith(\"jwt:\")) {\n\t\t\t\t\tconst resolved = resolveFilterValue(filter.value, claims);\n\t\t\t\t\tif (resolved.length === 0) {\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t})\n\t\t.map((b) => b.name);\n}\n\n/**\n * Validate a sync rules configuration for structural correctness.\n *\n * Checks:\n * - Version is a positive integer\n * - Buckets is an array\n * - Each bucket has a non-empty name, valid tables array, valid filters\n * - Filter operators are \"eq\" or \"in\"\n * - Filter values and columns are non-empty strings\n * - Bucket names are unique\n *\n * @param config - The sync rules configuration to validate\n * @returns Ok(void) if valid, Err(SyncRuleError) with details if invalid\n */\nexport function validateSyncRules(config: unknown): Result<void, SyncRuleError> {\n\tif (typeof config !== \"object\" || config === null) {\n\t\treturn Err(new SyncRuleError(\"Sync rules config must be an object\"));\n\t}\n\n\tconst obj = config as Record<string, unknown>;\n\n\tif (typeof obj.version !== \"number\" || !Number.isInteger(obj.version) || obj.version < 1) {\n\t\treturn Err(new SyncRuleError(\"Sync rules version must be a positive integer\"));\n\t}\n\n\tif (!Array.isArray(obj.buckets)) {\n\t\treturn Err(new SyncRuleError(\"Sync rules buckets must be an array\"));\n\t}\n\n\tconst seenNames = new Set<string>();\n\n\tfor (let i = 0; i < obj.buckets.length; i++) {\n\t\tconst bucket = obj.buckets[i] as Record<string, unknown>;\n\n\t\tif (typeof bucket !== \"object\" || bucket === null) {\n\t\t\treturn Err(new SyncRuleError(`Bucket at index ${i} must be an object`));\n\t\t}\n\n\t\tif (typeof bucket.name !== \"string\" || bucket.name.length === 0) {\n\t\t\treturn Err(new SyncRuleError(`Bucket at index ${i} must have a non-empty name`));\n\t\t}\n\n\t\tif (seenNames.has(bucket.name as string)) {\n\t\t\treturn Err(new SyncRuleError(`Duplicate bucket name: \"${bucket.name}\"`));\n\t\t}\n\t\tseenNames.add(bucket.name as string);\n\n\t\tif (!Array.isArray(bucket.tables)) {\n\t\t\treturn Err(new SyncRuleError(`Bucket \"${bucket.name}\" tables must be an array`));\n\t\t}\n\n\t\tfor (const table of bucket.tables as unknown[]) {\n\t\t\tif (typeof table !== \"string\" || table.length === 0) {\n\t\t\t\treturn Err(\n\t\t\t\t\tnew SyncRuleError(`Bucket \"${bucket.name}\" tables must contain non-empty strings`),\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tif (!Array.isArray(bucket.filters)) {\n\t\t\treturn Err(new SyncRuleError(`Bucket \"${bucket.name}\" filters must be an array`));\n\t\t}\n\n\t\tfor (let j = 0; j < (bucket.filters as unknown[]).length; j++) {\n\t\t\tconst filter = (bucket.filters as Record<string, unknown>[])[j]!;\n\n\t\t\tif (typeof filter !== \"object\" || filter === null) {\n\t\t\t\treturn Err(\n\t\t\t\t\tnew SyncRuleError(`Bucket \"${bucket.name}\" filter at index ${j} must be an object`),\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif (typeof filter.column !== \"string\" || (filter.column as string).length === 0) {\n\t\t\t\treturn Err(\n\t\t\t\t\tnew SyncRuleError(\n\t\t\t\t\t\t`Bucket \"${bucket.name}\" filter at index ${j} must have a non-empty column`,\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst validOps = [\"eq\", \"in\", \"neq\", \"gt\", \"lt\", \"gte\", \"lte\"];\n\t\t\tif (!validOps.includes(filter.op as string)) {\n\t\t\t\treturn Err(\n\t\t\t\t\tnew SyncRuleError(\n\t\t\t\t\t\t`Bucket \"${bucket.name}\" filter at index ${j} op must be one of: ${validOps.join(\", \")}`,\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif (typeof filter.value !== \"string\" || (filter.value as string).length === 0) {\n\t\t\t\treturn Err(\n\t\t\t\t\tnew SyncRuleError(\n\t\t\t\t\t\t`Bucket \"${bucket.name}\" filter at index ${j} must have a non-empty value`,\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\treturn Ok(undefined);\n}\n","import { SchemaError } from \"../result/errors\";\nimport { Err, Ok, type Result } from \"../result/result\";\n\n/** Valid SQL identifier: starts with letter or underscore, alphanumeric + underscore, max 64 chars. */\nconst IDENTIFIER_RE = /^[a-zA-Z_][a-zA-Z0-9_]{0,63}$/;\n\n/**\n * Check whether a string is a valid SQL identifier.\n *\n * Valid identifiers start with a letter or underscore, contain only\n * alphanumeric characters and underscores, and are at most 64 characters long.\n *\n * @param name - The identifier to validate\n * @returns `true` if valid, `false` otherwise\n */\nexport function isValidIdentifier(name: string): boolean {\n\treturn IDENTIFIER_RE.test(name);\n}\n\n/**\n * Assert that a string is a valid SQL identifier, returning a Result.\n *\n * @param name - The identifier to validate\n * @returns Ok(undefined) if valid, Err(SchemaError) if invalid\n */\nexport function assertValidIdentifier(name: string): Result<void, SchemaError> {\n\tif (isValidIdentifier(name)) {\n\t\treturn Ok(undefined);\n\t}\n\treturn Err(\n\t\tnew SchemaError(\n\t\t\t`Invalid SQL identifier: \"${name}\". Identifiers must start with a letter or underscore, contain only alphanumeric characters and underscores, and be at most 64 characters long.`,\n\t\t),\n\t);\n}\n\n/**\n * Quote a SQL identifier using double quotes as defence-in-depth.\n *\n * Any embedded double-quote characters are escaped by doubling them,\n * following the SQL standard for delimited identifiers.\n *\n * @param name - The identifier to quote\n * @returns The double-quoted identifier string\n */\nexport function quoteIdentifier(name: string): string {\n\treturn `\"${name.replace(/\"/g, '\"\"')}\"`;\n}\n"],"mappings":"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","names":["descriptors","stableStringify","columns","deltaId"]}
|