lakesync 0.1.6 → 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.
Files changed (70) hide show
  1. package/dist/adapter-types-DwsQGQS4.d.ts +94 -0
  2. package/dist/adapter.d.ts +202 -63
  3. package/dist/adapter.js +20 -5
  4. package/dist/analyst.js +2 -2
  5. package/dist/{base-poller-BpUyuG2R.d.ts → base-poller-Y7ORYgUv.d.ts} +78 -19
  6. package/dist/catalogue.d.ts +1 -1
  7. package/dist/catalogue.js +3 -3
  8. package/dist/{chunk-P3FT7QCW.js → chunk-4SG66H5K.js} +395 -252
  9. package/dist/chunk-4SG66H5K.js.map +1 -0
  10. package/dist/{chunk-GUJWMK5P.js → chunk-C4KD6YKP.js} +419 -380
  11. package/dist/chunk-C4KD6YKP.js.map +1 -0
  12. package/dist/chunk-DGUM43GV.js +11 -0
  13. package/dist/{chunk-IRJ4QRWV.js → chunk-FIIHPQMQ.js} +396 -209
  14. package/dist/chunk-FIIHPQMQ.js.map +1 -0
  15. package/dist/{chunk-UAUQGP3B.js → chunk-U2NV4DUX.js} +2 -2
  16. package/dist/{chunk-NCZYFZ3B.js → chunk-XVP5DJJ7.js} +44 -18
  17. package/dist/{chunk-NCZYFZ3B.js.map → chunk-XVP5DJJ7.js.map} +1 -1
  18. package/dist/{chunk-FHVTUKXL.js → chunk-YHYBLU6W.js} +2 -2
  19. package/dist/{chunk-QMS7TGFL.js → chunk-ZNY4DSFU.js} +29 -15
  20. package/dist/{chunk-QMS7TGFL.js.map → chunk-ZNY4DSFU.js.map} +1 -1
  21. package/dist/{chunk-SF7Y6ZUA.js → chunk-ZU7RC7CT.js} +2 -2
  22. package/dist/client.d.ts +186 -17
  23. package/dist/client.js +456 -188
  24. package/dist/client.js.map +1 -1
  25. package/dist/compactor.d.ts +2 -2
  26. package/dist/compactor.js +4 -4
  27. package/dist/connector-jira.d.ts +13 -3
  28. package/dist/connector-jira.js +7 -3
  29. package/dist/connector-salesforce.d.ts +13 -3
  30. package/dist/connector-salesforce.js +7 -3
  31. package/dist/{coordinator-D32a5rNk.d.ts → coordinator-eGmZMnJ_.d.ts} +120 -30
  32. package/dist/create-poller-Cc2MGfhh.d.ts +55 -0
  33. package/dist/factory-DFfR-030.d.ts +33 -0
  34. package/dist/gateway-server.d.ts +516 -119
  35. package/dist/gateway-server.js +1201 -4035
  36. package/dist/gateway-server.js.map +1 -1
  37. package/dist/gateway.d.ts +69 -106
  38. package/dist/gateway.js +13 -6
  39. package/dist/index.d.ts +65 -58
  40. package/dist/index.js +18 -4
  41. package/dist/parquet.d.ts +1 -1
  42. package/dist/parquet.js +3 -3
  43. package/dist/proto.d.ts +1 -1
  44. package/dist/proto.js +3 -3
  45. package/dist/react.d.ts +47 -10
  46. package/dist/react.js +88 -40
  47. package/dist/react.js.map +1 -1
  48. package/dist/{registry-CPTgO9jv.d.ts → registry-Dd8JuW8T.d.ts} +19 -4
  49. package/dist/{gateway-Bpvatd9n.d.ts → request-handler-B1I5xDOx.d.ts} +193 -20
  50. package/dist/{resolver-CbuXm3nB.d.ts → resolver-CXxmC0jR.d.ts} +1 -1
  51. package/dist/{src-RHKJFQKR.js → src-WU7IBVC4.js} +19 -5
  52. package/dist/{types-CLlD4XOy.d.ts → types-BdGBv2ba.d.ts} +17 -2
  53. package/dist/{types-D-E0VrfS.d.ts → types-D2C9jTbL.d.ts} +39 -22
  54. package/package.json +1 -1
  55. package/dist/auth-CAVutXzx.d.ts +0 -30
  56. package/dist/chunk-7D4SUZUM.js +0 -38
  57. package/dist/chunk-GUJWMK5P.js.map +0 -1
  58. package/dist/chunk-IRJ4QRWV.js.map +0 -1
  59. package/dist/chunk-P3FT7QCW.js.map +0 -1
  60. package/dist/db-types-BlN-4KbQ.d.ts +0 -29
  61. package/dist/src-CLCALYDT.js +0 -25
  62. package/dist/src-FPJQYQNA.js +0 -27
  63. package/dist/src-FPJQYQNA.js.map +0 -1
  64. package/dist/src-RHKJFQKR.js.map +0 -1
  65. package/dist/types-DSC_EiwR.d.ts +0 -45
  66. /package/dist/{chunk-7D4SUZUM.js.map → chunk-DGUM43GV.js.map} +0 -0
  67. /package/dist/{chunk-UAUQGP3B.js.map → chunk-U2NV4DUX.js.map} +0 -0
  68. /package/dist/{chunk-FHVTUKXL.js.map → chunk-YHYBLU6W.js.map} +0 -0
  69. /package/dist/{chunk-SF7Y6ZUA.js.map → chunk-ZU7RC7CT.js.map} +0 -0
  70. /package/dist/{src-CLCALYDT.js.map → src-WU7IBVC4.js.map} +0 -0
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../adapter/src/db-types.ts","../../adapter/src/materialise.ts","../../adapter/src/shared.ts","../../adapter/src/bigquery.ts","../../adapter/src/composite.ts","../../adapter/src/mysql.ts","../../adapter/src/postgres.ts","../../adapter/src/factory.ts","../../adapter/src/fan-out.ts","../../adapter/src/lifecycle.ts","../../adapter/src/migrate.ts","../../adapter/src/minio.ts","../../adapter/src/query-fn.ts"],"sourcesContent":["import type { AdapterError, HLCTimestamp, Result, RowDelta, TableSchema } from \"@lakesync/core\";\n\n/** Configuration for a database adapter connection. */\nexport interface DatabaseAdapterConfig {\n\t/** Connection string (e.g. postgres://user:pass@host/db) */\n\tconnectionString: string;\n}\n\n/**\n * Abstract interface for SQL database storage operations.\n * Alternative to LakeAdapter for small-data backends (Postgres, MySQL, etc).\n */\nexport interface DatabaseAdapter {\n\t/** Insert deltas into the database in a single batch. Idempotent via deltaId uniqueness. */\n\tinsertDeltas(deltas: RowDelta[]): Promise<Result<void, AdapterError>>;\n\n\t/** Query deltas with HLC greater than the given timestamp, optionally filtered by table. */\n\tqueryDeltasSince(hlc: HLCTimestamp, tables?: string[]): Promise<Result<RowDelta[], AdapterError>>;\n\n\t/** Get the latest merged state for a specific row. Returns null if the row doesn't exist. */\n\tgetLatestState(\n\t\ttable: string,\n\t\trowId: string,\n\t): Promise<Result<Record<string, unknown> | null, AdapterError>>;\n\n\t/** Ensure the database schema matches the given TableSchema. Creates/alters tables as needed. */\n\tensureSchema(schema: TableSchema): Promise<Result<void, AdapterError>>;\n\n\t/** Close the database connection and release resources. */\n\tclose(): Promise<void>;\n}\n\n/**\n * Map a LakeSync column type to a BigQuery column definition.\n */\nconst BIGQUERY_TYPE_MAP: Record<TableSchema[\"columns\"][number][\"type\"], string> = {\n\tstring: \"STRING\",\n\tnumber: \"FLOAT64\",\n\tboolean: \"BOOL\",\n\tjson: \"JSON\",\n\tnull: \"STRING\",\n};\n\nexport function lakeSyncTypeToBigQuery(type: TableSchema[\"columns\"][number][\"type\"]): string {\n\treturn BIGQUERY_TYPE_MAP[type];\n}\n\n/** Type guard to distinguish DatabaseAdapter from LakeAdapter at runtime. */\nexport function isDatabaseAdapter(adapter: unknown): adapter is DatabaseAdapter {\n\treturn (\n\t\tadapter !== null &&\n\t\ttypeof adapter === \"object\" &&\n\t\t\"insertDeltas\" in adapter &&\n\t\t\"queryDeltasSince\" in adapter &&\n\t\ttypeof (adapter as DatabaseAdapter).insertDeltas === \"function\"\n\t);\n}\n","import type { AdapterError, Result, RowDelta, TableSchema } from \"@lakesync/core\";\n\n/**\n * Opt-in capability for adapters that can materialise deltas into destination tables.\n *\n * Materialisation is a separate concern from delta storage — adapters that store\n * deltas (via `DatabaseAdapter.insertDeltas`) may also materialise them into\n * queryable destination tables by implementing this interface.\n *\n * Destination tables follow the hybrid column model:\n * - Synced columns (written by materialiser, derived from `TableSchema.columns`)\n * - `props JSONB DEFAULT '{}'` — consumer-extensible, never touched by materialiser\n * - `synced_at` — updated on every materialise cycle\n */\nexport interface Materialisable {\n\t/**\n\t * Materialise deltas into destination tables.\n\t *\n\t * For each table with a matching schema, merges delta history into the\n\t * latest row state and upserts into the destination table. Tombstoned\n\t * rows are deleted. The `props` column is never touched.\n\t *\n\t * @param deltas - The deltas that were just flushed.\n\t * @param schemas - Table schemas defining destination tables and column mappings.\n\t */\n\tmaterialise(\n\t\tdeltas: RowDelta[],\n\t\tschemas: ReadonlyArray<TableSchema>,\n\t): Promise<Result<void, AdapterError>>;\n}\n\n/**\n * Type guard to check if an adapter supports materialisation.\n *\n * Uses duck-typing (same pattern as `isDatabaseAdapter`).\n */\nexport function isMaterialisable(adapter: unknown): adapter is Materialisable {\n\treturn (\n\t\tadapter !== null &&\n\t\ttypeof adapter === \"object\" &&\n\t\t\"materialise\" in adapter &&\n\t\ttypeof (adapter as Materialisable).materialise === \"function\"\n\t);\n}\n\n/**\n * Resolve the primary key columns for a table schema.\n * Defaults to `[\"row_id\"]` when not explicitly set.\n */\nexport function resolvePrimaryKey(schema: TableSchema): string[] {\n\treturn schema.primaryKey ?? [\"row_id\"];\n}\n\n/**\n * Resolve the conflict columns used for upsert ON CONFLICT targeting.\n * When `externalIdColumn` is set, upserts resolve on that column instead of the PK.\n */\nexport function resolveConflictColumns(schema: TableSchema): string[] {\n\treturn schema.externalIdColumn ? [schema.externalIdColumn] : resolvePrimaryKey(schema);\n}\n\n/**\n * Whether tombstoned rows should be soft-deleted (default) or hard-deleted.\n */\nexport function isSoftDelete(schema: TableSchema): boolean {\n\treturn schema.softDelete !== false;\n}\n\n/**\n * Group deltas by their table name, collecting the set of affected row IDs per table.\n *\n * @param deltas - The deltas to group.\n * @returns A map from table name to the set of affected row IDs.\n */\nexport function groupDeltasByTable(deltas: ReadonlyArray<RowDelta>): Map<string, Set<string>> {\n\tconst result = new Map<string, Set<string>>();\n\tfor (const delta of deltas) {\n\t\tlet rowIds = result.get(delta.table);\n\t\tif (!rowIds) {\n\t\t\trowIds = new Set<string>();\n\t\t\tresult.set(delta.table, rowIds);\n\t\t}\n\t\trowIds.add(delta.rowId);\n\t}\n\treturn result;\n}\n\n/**\n * Build an index from source table name to schema.\n *\n * Keys are `schema.sourceTable ?? schema.table`, so deltas can be matched\n * by their `table` field to find the correct destination schema.\n *\n * @param schemas - The table schemas to index.\n * @returns A map from source table name to schema.\n */\nexport function buildSchemaIndex(schemas: ReadonlyArray<TableSchema>): Map<string, TableSchema> {\n\tconst index = new Map<string, TableSchema>();\n\tfor (const schema of schemas) {\n\t\tconst key = schema.sourceTable ?? schema.table;\n\t\tindex.set(key, schema);\n\t}\n\treturn index;\n}\n","import { AdapterError, type ColumnDelta, Err, Ok, type Result } from \"@lakesync/core\";\n\n/** Normalise a caught value into an Error or undefined. */\nexport function toCause(error: unknown): Error | undefined {\n\treturn error instanceof Error ? error : undefined;\n}\n\n/** Execute an async operation and wrap errors into an AdapterError Result. */\nexport async function wrapAsync<T>(\n\toperation: () => Promise<T>,\n\terrorMessage: string,\n): Promise<Result<T, AdapterError>> {\n\ttry {\n\t\tconst value = await operation();\n\t\treturn Ok(value);\n\t} catch (error) {\n\t\tif (error instanceof AdapterError) {\n\t\t\treturn Err(error);\n\t\t}\n\t\treturn Err(new AdapterError(errorMessage, toCause(error)));\n\t}\n}\n\n/**\n * Merge delta rows into final state using column-level LWW.\n * Shared by Postgres, MySQL, and BigQuery getLatestState implementations.\n * Rows must be sorted by HLC ascending.\n */\nexport function mergeLatestState(\n\trows: Array<{ columns: string | ColumnDelta[]; op: string }>,\n): Record<string, unknown> | null {\n\tif (rows.length === 0) return null;\n\n\tconst lastRow = rows[rows.length - 1]!;\n\tif (lastRow.op === \"DELETE\") return null;\n\n\tconst state: Record<string, unknown> = {};\n\n\tfor (const row of rows) {\n\t\tif (row.op === \"DELETE\") {\n\t\t\tfor (const key of Object.keys(state)) {\n\t\t\t\tdelete state[key];\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst columns: ColumnDelta[] =\n\t\t\ttypeof row.columns === \"string\" ? JSON.parse(row.columns) : row.columns;\n\n\t\tfor (const col of columns) {\n\t\t\tstate[col.column] = col.value;\n\t\t}\n\t}\n\n\treturn state;\n}\n","import { BigQuery } from \"@google-cloud/bigquery\";\nimport {\n\ttype AdapterError,\n\ttype ColumnDelta,\n\ttype HLCTimestamp,\n\tOk,\n\ttype Result,\n\ttype RowDelta,\n\ttype TableSchema,\n} from \"@lakesync/core\";\nimport type { DatabaseAdapter } from \"./db-types\";\nimport { lakeSyncTypeToBigQuery } from \"./db-types\";\nimport type { Materialisable } from \"./materialise\";\nimport {\n\tbuildSchemaIndex,\n\tgroupDeltasByTable,\n\tisSoftDelete,\n\tresolveConflictColumns,\n\tresolvePrimaryKey,\n} from \"./materialise\";\nimport { mergeLatestState, wrapAsync } from \"./shared\";\n\n/**\n * Configuration for the BigQuery adapter.\n * Unlike SQL adapters, BigQuery is HTTP-based — no connection string needed.\n */\nexport interface BigQueryAdapterConfig {\n\t/** GCP project ID. */\n\tprojectId: string;\n\t/** BigQuery dataset name. */\n\tdataset: string;\n\t/** Path to a service account JSON key file. Falls back to ADC if omitted. */\n\tkeyFilename?: string;\n\t/** Dataset location (default: \"US\"). */\n\tlocation?: string;\n}\n\n/** Shape of a row returned from the lakesync_deltas table. */\ninterface BigQueryDeltaRow {\n\tdelta_id: string;\n\ttable: string;\n\trow_id: string;\n\tcolumns: string;\n\thlc: { value: string } | string | number;\n\tclient_id: string;\n\top: string;\n}\n\n/**\n * Convert a raw BigQuery row into a RowDelta.\n * BigQuery returns INT64 as `{ value: string }` objects to avoid precision loss.\n */\nfunction rowToRowDelta(row: BigQueryDeltaRow): RowDelta {\n\tconst columns: ColumnDelta[] =\n\t\ttypeof row.columns === \"string\" ? JSON.parse(row.columns) : row.columns;\n\n\t// BigQuery INT64 comes back as { value: \"123\" } to preserve precision\n\tconst hlcRaw = row.hlc;\n\tconst hlcString =\n\t\ttypeof hlcRaw === \"object\" && hlcRaw !== null && \"value\" in hlcRaw\n\t\t\t? hlcRaw.value\n\t\t\t: String(hlcRaw);\n\n\treturn {\n\t\tdeltaId: row.delta_id,\n\t\ttable: row.table,\n\t\trowId: row.row_id,\n\t\tcolumns,\n\t\thlc: BigInt(hlcString) as HLCTimestamp,\n\t\tclientId: row.client_id,\n\t\top: row.op as RowDelta[\"op\"],\n\t};\n}\n\n/**\n * BigQuery database adapter for LakeSync.\n *\n * Stores deltas in a `lakesync_deltas` table using standard SQL DML.\n * Idempotent inserts via MERGE statement. All public methods return\n * `Result` and never throw.\n *\n * **Note:** BigQuery DML is limited to 1,500 statements per table per day\n * on standard (non-partitioned) tables. Query latency is seconds, not\n * milliseconds — this adapter is designed for the analytics tier.\n */\nexport class BigQueryAdapter implements DatabaseAdapter, Materialisable {\n\t/** @internal */\n\treadonly client: BigQuery;\n\t/** @internal */\n\treadonly dataset: string;\n\t/** @internal */\n\treadonly location: string;\n\n\tconstructor(config: BigQueryAdapterConfig) {\n\t\tthis.client = new BigQuery({\n\t\t\tprojectId: config.projectId,\n\t\t\tkeyFilename: config.keyFilename,\n\t\t});\n\t\tthis.dataset = config.dataset;\n\t\tthis.location = config.location ?? \"US\";\n\t}\n\n\t/**\n\t * Insert deltas into the database in a single batch.\n\t * Idempotent via MERGE — existing deltaIds are silently skipped.\n\t */\n\tasync insertDeltas(deltas: RowDelta[]): Promise<Result<void, AdapterError>> {\n\t\tif (deltas.length === 0) {\n\t\t\treturn Ok(undefined);\n\t\t}\n\n\t\treturn wrapAsync(async () => {\n\t\t\t// Build MERGE source from UNION ALL of parameterised SELECTs\n\t\t\tconst params: Record<string, string> = {};\n\t\t\tconst selects: string[] = [];\n\n\t\t\tfor (let i = 0; i < deltas.length; i++) {\n\t\t\t\tconst d = deltas[i]!;\n\t\t\t\tparams[`did_${i}`] = d.deltaId;\n\t\t\t\tparams[`tbl_${i}`] = d.table;\n\t\t\t\tparams[`rid_${i}`] = d.rowId;\n\t\t\t\tparams[`col_${i}`] = JSON.stringify(d.columns);\n\t\t\t\tparams[`hlc_${i}`] = d.hlc.toString();\n\t\t\t\tparams[`cid_${i}`] = d.clientId;\n\t\t\t\tparams[`op_${i}`] = d.op;\n\n\t\t\t\tselects.push(\n\t\t\t\t\t`SELECT @did_${i} AS delta_id, @tbl_${i} AS \\`table\\`, @rid_${i} AS row_id, @col_${i} AS columns, CAST(@hlc_${i} AS INT64) AS hlc, @cid_${i} AS client_id, @op_${i} AS op`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst sql = `MERGE \\`${this.dataset}.lakesync_deltas\\` AS target\nUSING (${selects.join(\" UNION ALL \")}) AS source\nON target.delta_id = source.delta_id\nWHEN NOT MATCHED THEN INSERT (delta_id, \\`table\\`, row_id, columns, hlc, client_id, op)\nVALUES (source.delta_id, source.\\`table\\`, source.row_id, source.columns, source.hlc, source.client_id, source.op)`;\n\n\t\t\tawait this.client.query({ query: sql, params, location: this.location });\n\t\t}, \"Failed to insert deltas\");\n\t}\n\n\t/**\n\t * Query deltas with HLC greater than the given timestamp, optionally filtered by table.\n\t */\n\tasync queryDeltasSince(\n\t\thlc: HLCTimestamp,\n\t\ttables?: string[],\n\t): Promise<Result<RowDelta[], AdapterError>> {\n\t\treturn wrapAsync(async () => {\n\t\t\tlet sql: string;\n\t\t\tconst params: Record<string, string | string[]> = {\n\t\t\t\tsinceHlc: hlc.toString(),\n\t\t\t};\n\n\t\t\tif (tables && tables.length > 0) {\n\t\t\t\tsql = `SELECT delta_id, \\`table\\`, row_id, columns, hlc, client_id, op\nFROM \\`${this.dataset}.lakesync_deltas\\`\nWHERE hlc > CAST(@sinceHlc AS INT64) AND \\`table\\` IN UNNEST(@tables)\nORDER BY hlc ASC`;\n\t\t\t\tparams.tables = tables;\n\t\t\t} else {\n\t\t\t\tsql = `SELECT delta_id, \\`table\\`, row_id, columns, hlc, client_id, op\nFROM \\`${this.dataset}.lakesync_deltas\\`\nWHERE hlc > CAST(@sinceHlc AS INT64)\nORDER BY hlc ASC`;\n\t\t\t}\n\n\t\t\tconst [rows] = await this.client.query({\n\t\t\t\tquery: sql,\n\t\t\t\tparams,\n\t\t\t\tlocation: this.location,\n\t\t\t});\n\t\t\treturn (rows as BigQueryDeltaRow[]).map(rowToRowDelta);\n\t\t}, \"Failed to query deltas\");\n\t}\n\n\t/**\n\t * Get the latest merged state for a specific row using column-level LWW.\n\t * Returns null if no deltas exist for this row.\n\t */\n\tasync getLatestState(\n\t\ttable: string,\n\t\trowId: string,\n\t): Promise<Result<Record<string, unknown> | null, AdapterError>> {\n\t\treturn wrapAsync(async () => {\n\t\t\tconst sql = `SELECT columns, hlc, client_id, op\nFROM \\`${this.dataset}.lakesync_deltas\\`\nWHERE \\`table\\` = @tbl AND row_id = @rid\nORDER BY hlc ASC`;\n\n\t\t\tconst [rows] = await this.client.query({\n\t\t\t\tquery: sql,\n\t\t\t\tparams: { tbl: table, rid: rowId },\n\t\t\t\tlocation: this.location,\n\t\t\t});\n\t\t\treturn mergeLatestState(rows as BigQueryDeltaRow[]);\n\t\t}, `Failed to get latest state for ${table}:${rowId}`);\n\t}\n\n\t/**\n\t * Ensure the BigQuery dataset and lakesync_deltas table exist.\n\t * The `schema` parameter is accepted for interface compliance but the\n\t * internal table structure is fixed (deltas store column data as JSON).\n\t */\n\tasync ensureSchema(_schema: TableSchema): Promise<Result<void, AdapterError>> {\n\t\treturn wrapAsync(async () => {\n\t\t\t// Create dataset if it doesn't exist\n\t\t\tconst datasetRef = this.client.dataset(this.dataset);\n\t\t\tconst [datasetExists] = await datasetRef.exists();\n\t\t\tif (!datasetExists) {\n\t\t\t\tawait this.client.createDataset(this.dataset, {\n\t\t\t\t\tlocation: this.location,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\t// Create the deltas table\n\t\t\tawait this.client.query({\n\t\t\t\tquery: `CREATE TABLE IF NOT EXISTS \\`${this.dataset}.lakesync_deltas\\` (\n\tdelta_id STRING NOT NULL,\n\t\\`table\\` STRING NOT NULL,\n\trow_id STRING NOT NULL,\n\tcolumns JSON NOT NULL,\n\thlc INT64 NOT NULL,\n\tclient_id STRING NOT NULL,\n\top STRING NOT NULL\n)\nCLUSTER BY \\`table\\`, hlc`,\n\t\t\t\tlocation: this.location,\n\t\t\t});\n\t\t}, \"Failed to ensure schema\");\n\t}\n\n\t/**\n\t * Materialise deltas into destination tables.\n\t *\n\t * For each affected table, queries the full delta history for touched rows,\n\t * merges to latest state via column-level LWW, then upserts live rows and\n\t * deletes tombstoned rows. The consumer-owned `props` column is never\n\t * touched on UPDATE.\n\t */\n\tasync materialise(\n\t\tdeltas: RowDelta[],\n\t\tschemas: ReadonlyArray<TableSchema>,\n\t): Promise<Result<void, AdapterError>> {\n\t\tif (deltas.length === 0) {\n\t\t\treturn Ok(undefined);\n\t\t}\n\n\t\treturn wrapAsync(async () => {\n\t\t\tconst tableRowIds = groupDeltasByTable(deltas);\n\t\t\tconst schemaIndex = buildSchemaIndex(schemas);\n\n\t\t\tfor (const [sourceTable, rowIds] of tableRowIds) {\n\t\t\t\tconst schema = schemaIndex.get(sourceTable);\n\t\t\t\tif (!schema) continue;\n\n\t\t\t\tconst pk = resolvePrimaryKey(schema);\n\t\t\t\tconst conflictCols = resolveConflictColumns(schema);\n\t\t\t\tconst soft = isSoftDelete(schema);\n\n\t\t\t\t// Ensure destination table exists\n\t\t\t\tconst colDefs = schema.columns\n\t\t\t\t\t.map((c) => `${c.name} ${lakeSyncTypeToBigQuery(c.type)}`)\n\t\t\t\t\t.join(\", \");\n\t\t\t\tconst deletedAtCol = soft ? `,\\n\\tdeleted_at TIMESTAMP` : \"\";\n\t\t\t\tawait this.client.query({\n\t\t\t\t\tquery: `CREATE TABLE IF NOT EXISTS \\`${this.dataset}.${schema.table}\\` (\n\trow_id STRING NOT NULL,\n\t${colDefs},\n\tprops JSON DEFAULT '{}'${deletedAtCol},\n\tsynced_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP()\n)\nCLUSTER BY ${pk.map((c) => (c === \"row_id\" ? \"row_id\" : c)).join(\", \")}`,\n\t\t\t\t\tlocation: this.location,\n\t\t\t\t});\n\n\t\t\t\t// Query delta history for affected rows\n\t\t\t\tconst rowIdArray = [...rowIds];\n\t\t\t\tconst [deltaRows] = await this.client.query({\n\t\t\t\t\tquery: `SELECT row_id, columns, op FROM \\`${this.dataset}.lakesync_deltas\\`\nWHERE \\`table\\` = @sourceTable AND row_id IN UNNEST(@rowIds)\nORDER BY hlc ASC`,\n\t\t\t\t\tparams: { sourceTable, rowIds: rowIdArray },\n\t\t\t\t\tlocation: this.location,\n\t\t\t\t});\n\n\t\t\t\t// Group by row_id and merge to latest state\n\t\t\t\tconst rowGroups = new Map<string, Array<{ columns: string | ColumnDelta[]; op: string }>>();\n\t\t\t\tfor (const row of deltaRows as Array<{\n\t\t\t\t\trow_id: string;\n\t\t\t\t\tcolumns: string | ColumnDelta[];\n\t\t\t\t\top: string;\n\t\t\t\t}>) {\n\t\t\t\t\tlet group = rowGroups.get(row.row_id);\n\t\t\t\t\tif (!group) {\n\t\t\t\t\t\tgroup = [];\n\t\t\t\t\t\trowGroups.set(row.row_id, group);\n\t\t\t\t\t}\n\t\t\t\t\tgroup.push({ columns: row.columns, op: row.op });\n\t\t\t\t}\n\n\t\t\t\tconst upserts: Array<{ rowId: string; state: Record<string, unknown> }> = [];\n\t\t\t\tconst deleteRowIds: string[] = [];\n\n\t\t\t\tfor (const [rowId, group] of rowGroups) {\n\t\t\t\t\tconst state = mergeLatestState(group);\n\t\t\t\t\tif (state === null) {\n\t\t\t\t\t\tdeleteRowIds.push(rowId);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tupserts.push({ rowId, state });\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// MERGE upserts\n\t\t\t\tif (upserts.length > 0) {\n\t\t\t\t\tconst params: Record<string, unknown> = {};\n\t\t\t\t\tconst selects: string[] = [];\n\n\t\t\t\t\tfor (let i = 0; i < upserts.length; i++) {\n\t\t\t\t\t\tconst u = upserts[i]!;\n\t\t\t\t\t\tparams[`rid_${i}`] = u.rowId;\n\t\t\t\t\t\tfor (const col of schema.columns) {\n\t\t\t\t\t\t\tparams[`c${schema.columns.indexOf(col)}_${i}`] = u.state[col.name] ?? null;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst colSelects = schema.columns\n\t\t\t\t\t\t\t.map((col, ci) => `@c${ci}_${i} AS ${col.name}`)\n\t\t\t\t\t\t\t.join(\", \");\n\t\t\t\t\t\tconst deletedAtSelect = soft ? \", CAST(NULL AS TIMESTAMP) AS deleted_at\" : \"\";\n\t\t\t\t\t\tselects.push(\n\t\t\t\t\t\t\t`SELECT @rid_${i} AS row_id, ${colSelects}${deletedAtSelect}, CURRENT_TIMESTAMP() AS synced_at`,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\tconst mergeOn = conflictCols\n\t\t\t\t\t\t.map((c) => `t.${c === \"row_id\" ? \"row_id\" : c} = s.${c === \"row_id\" ? \"row_id\" : c}`)\n\t\t\t\t\t\t.join(\" AND \");\n\n\t\t\t\t\tconst updateSet = schema.columns.map((col) => `${col.name} = s.${col.name}`).join(\", \");\n\t\t\t\t\tconst softUpdateExtra = soft ? \", deleted_at = s.deleted_at\" : \"\";\n\n\t\t\t\t\tconst insertColsList = [\n\t\t\t\t\t\t\"row_id\",\n\t\t\t\t\t\t...schema.columns.map((c) => c.name),\n\t\t\t\t\t\t\"props\",\n\t\t\t\t\t\t...(soft ? [\"deleted_at\"] : []),\n\t\t\t\t\t\t\"synced_at\",\n\t\t\t\t\t].join(\", \");\n\t\t\t\t\tconst insertValsList = [\n\t\t\t\t\t\t\"s.row_id\",\n\t\t\t\t\t\t...schema.columns.map((c) => `s.${c.name}`),\n\t\t\t\t\t\t\"'{}'\",\n\t\t\t\t\t\t...(soft ? [\"s.deleted_at\"] : []),\n\t\t\t\t\t\t\"s.synced_at\",\n\t\t\t\t\t].join(\", \");\n\n\t\t\t\t\tconst mergeSql = `MERGE \\`${this.dataset}.${schema.table}\\` AS t\nUSING (${selects.join(\" UNION ALL \")}) AS s\nON ${mergeOn}\nWHEN MATCHED THEN UPDATE SET ${updateSet}${softUpdateExtra}, synced_at = s.synced_at\nWHEN NOT MATCHED THEN INSERT (${insertColsList})\nVALUES (${insertValsList})`;\n\n\t\t\t\t\tawait this.client.query({\n\t\t\t\t\t\tquery: mergeSql,\n\t\t\t\t\t\tparams,\n\t\t\t\t\t\tlocation: this.location,\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\t// DELETE / soft-delete tombstoned rows\n\t\t\t\tif (deleteRowIds.length > 0) {\n\t\t\t\t\tif (soft) {\n\t\t\t\t\t\tawait this.client.query({\n\t\t\t\t\t\t\tquery: `UPDATE \\`${this.dataset}.${schema.table}\\` SET deleted_at = CURRENT_TIMESTAMP(), synced_at = CURRENT_TIMESTAMP() WHERE row_id IN UNNEST(@rowIds)`,\n\t\t\t\t\t\t\tparams: { rowIds: deleteRowIds },\n\t\t\t\t\t\t\tlocation: this.location,\n\t\t\t\t\t\t});\n\t\t\t\t\t} else {\n\t\t\t\t\t\tawait this.client.query({\n\t\t\t\t\t\t\tquery: `DELETE FROM \\`${this.dataset}.${schema.table}\\` WHERE row_id IN UNNEST(@rowIds)`,\n\t\t\t\t\t\t\tparams: { rowIds: deleteRowIds },\n\t\t\t\t\t\t\tlocation: this.location,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}, \"Failed to materialise deltas\");\n\t}\n\n\t/**\n\t * No-op — BigQuery client is HTTP-based with no persistent connections.\n\t */\n\tasync close(): Promise<void> {\n\t\t// No-op: BigQuery uses HTTP requests, no connection pool to close\n\t}\n}\n","import {\n\ttype AdapterError,\n\ttype HLCTimestamp,\n\tOk,\n\ttype Result,\n\ttype RowDelta,\n\ttype TableSchema,\n} from \"@lakesync/core\";\n\nimport type { DatabaseAdapter } from \"./db-types\";\n\n/** A routing rule that maps specific tables to a database adapter. */\nexport interface CompositeRoute {\n\t/** Tables handled by this adapter */\n\ttables: string[];\n\t/** The adapter for these tables */\n\tadapter: DatabaseAdapter;\n}\n\n/** Configuration for CompositeAdapter routing. */\nexport interface CompositeAdapterConfig {\n\t/** Table-to-adapter routing rules */\n\troutes: CompositeRoute[];\n\t/** Fallback adapter for tables not matching any route */\n\tdefaultAdapter: DatabaseAdapter;\n}\n\n/**\n * Routes database operations to different adapters based on table name.\n * Implements DatabaseAdapter so it can be used as a drop-in replacement.\n */\nexport class CompositeAdapter implements DatabaseAdapter {\n\tprivate readonly routeMap: Map<string, DatabaseAdapter>;\n\tprivate readonly adapters: Set<DatabaseAdapter>;\n\tprivate readonly defaultAdapter: DatabaseAdapter;\n\n\tconstructor(config: CompositeAdapterConfig) {\n\t\tthis.routeMap = new Map();\n\t\tthis.adapters = new Set();\n\t\tthis.defaultAdapter = config.defaultAdapter;\n\t\tthis.adapters.add(config.defaultAdapter);\n\n\t\tfor (const route of config.routes) {\n\t\t\tthis.adapters.add(route.adapter);\n\t\t\tfor (const table of route.tables) {\n\t\t\t\tif (this.routeMap.has(table)) {\n\t\t\t\t\tthrow new Error(`Duplicate table route: \"${table}\" appears in multiple routes`);\n\t\t\t\t}\n\t\t\t\tthis.routeMap.set(table, route.adapter);\n\t\t\t}\n\t\t}\n\t}\n\n\t/** Insert deltas, routing each group to the correct adapter by table. */\n\tasync insertDeltas(deltas: RowDelta[]): Promise<Result<void, AdapterError>> {\n\t\tconst groups = new Map<DatabaseAdapter, RowDelta[]>();\n\n\t\tfor (const delta of deltas) {\n\t\t\tconst adapter = this.routeMap.get(delta.table) ?? this.defaultAdapter;\n\t\t\tlet group = groups.get(adapter);\n\t\t\tif (!group) {\n\t\t\t\tgroup = [];\n\t\t\t\tgroups.set(adapter, group);\n\t\t\t}\n\t\t\tgroup.push(delta);\n\t\t}\n\n\t\tfor (const [adapter, group] of groups) {\n\t\t\tconst result = await adapter.insertDeltas(group);\n\t\t\tif (!result.ok) {\n\t\t\t\treturn result;\n\t\t\t}\n\t\t}\n\n\t\treturn Ok(undefined);\n\t}\n\n\t/** Query deltas since a given HLC, fanning out to relevant adapters and merging results. */\n\tasync queryDeltasSince(\n\t\thlc: HLCTimestamp,\n\t\ttables?: string[],\n\t): Promise<Result<RowDelta[], AdapterError>> {\n\t\tconst adapterSet = new Set<DatabaseAdapter>();\n\t\tconst adapterTables = new Map<DatabaseAdapter, string[]>();\n\n\t\tif (tables && tables.length > 0) {\n\t\t\tfor (const table of tables) {\n\t\t\t\tconst adapter = this.routeMap.get(table) ?? this.defaultAdapter;\n\t\t\t\tadapterSet.add(adapter);\n\t\t\t\tlet existing = adapterTables.get(adapter);\n\t\t\t\tif (!existing) {\n\t\t\t\t\texisting = [];\n\t\t\t\t\tadapterTables.set(adapter, existing);\n\t\t\t\t}\n\t\t\t\texisting.push(table);\n\t\t\t}\n\t\t} else {\n\t\t\tfor (const adapter of this.adapters) {\n\t\t\t\tadapterSet.add(adapter);\n\t\t\t}\n\t\t}\n\n\t\tconst merged: RowDelta[] = [];\n\n\t\tfor (const adapter of adapterSet) {\n\t\t\tconst filterTables = adapterTables.get(adapter);\n\t\t\tconst result = await adapter.queryDeltasSince(hlc, filterTables);\n\t\t\tif (!result.ok) {\n\t\t\t\treturn result;\n\t\t\t}\n\t\t\tmerged.push(...result.value);\n\t\t}\n\n\t\tmerged.sort((a, b) => (a.hlc < b.hlc ? -1 : a.hlc > b.hlc ? 1 : 0));\n\n\t\treturn Ok(merged);\n\t}\n\n\t/** Get the latest state for a row, routing to the correct adapter. */\n\tasync getLatestState(\n\t\ttable: string,\n\t\trowId: string,\n\t): Promise<Result<Record<string, unknown> | null, AdapterError>> {\n\t\tconst adapter = this.routeMap.get(table) ?? this.defaultAdapter;\n\t\treturn adapter.getLatestState(table, rowId);\n\t}\n\n\t/** Ensure schema exists, routing to the correct adapter for the table. */\n\tasync ensureSchema(schema: TableSchema): Promise<Result<void, AdapterError>> {\n\t\tconst adapter = this.routeMap.get(schema.table) ?? this.defaultAdapter;\n\t\treturn adapter.ensureSchema(schema);\n\t}\n\n\t/** Close all unique adapters (routes + default, deduplicated). */\n\tasync close(): Promise<void> {\n\t\tfor (const adapter of this.adapters) {\n\t\t\tawait adapter.close();\n\t\t}\n\t}\n}\n","import {\n\ttype AdapterError,\n\ttype HLCTimestamp,\n\tOk,\n\ttype Result,\n\ttype RowDelta,\n\ttype TableSchema,\n} from \"@lakesync/core\";\nimport mysql from \"mysql2/promise\";\nimport type { DatabaseAdapter, DatabaseAdapterConfig } from \"./db-types\";\nimport type { Materialisable } from \"./materialise\";\nimport {\n\tbuildSchemaIndex,\n\tgroupDeltasByTable,\n\tisSoftDelete,\n\tresolvePrimaryKey,\n} from \"./materialise\";\nimport { mergeLatestState, wrapAsync } from \"./shared\";\n\n/**\n * Map a LakeSync column type to a MySQL column definition.\n */\nconst MYSQL_TYPE_MAP: Record<TableSchema[\"columns\"][number][\"type\"], string> = {\n\tstring: \"TEXT\",\n\tnumber: \"DOUBLE\",\n\tboolean: \"TINYINT(1)\",\n\tjson: \"JSON\",\n\tnull: \"TEXT\",\n};\n\nfunction lakeSyncTypeToMySQL(type: TableSchema[\"columns\"][number][\"type\"]): string {\n\treturn MYSQL_TYPE_MAP[type];\n}\n\n/**\n * MySQL database adapter for LakeSync.\n *\n * Stores deltas in a `lakesync_deltas` table using INSERT IGNORE for\n * idempotent writes. All public methods return `Result` and never throw.\n * Uses mysql2/promise connection pool for async operations.\n */\nexport class MySQLAdapter implements DatabaseAdapter, Materialisable {\n\t/** @internal */\n\treadonly pool: mysql.Pool;\n\n\tconstructor(config: DatabaseAdapterConfig) {\n\t\tthis.pool = mysql.createPool(config.connectionString);\n\t}\n\n\t/**\n\t * Insert deltas into the database in a single batch.\n\t * Uses INSERT IGNORE for idempotent writes — duplicate deltaIds are silently skipped.\n\t */\n\tasync insertDeltas(deltas: RowDelta[]): Promise<Result<void, AdapterError>> {\n\t\tif (deltas.length === 0) {\n\t\t\treturn Ok(undefined);\n\t\t}\n\n\t\treturn wrapAsync(async () => {\n\t\t\tconst sql = `INSERT IGNORE INTO lakesync_deltas (delta_id, \\`table\\`, row_id, columns, hlc, client_id, op) VALUES ${deltas.map(() => \"(?, ?, ?, ?, ?, ?, ?)\").join(\", \")}`;\n\n\t\t\tconst values: unknown[] = [];\n\t\t\tfor (const delta of deltas) {\n\t\t\t\tvalues.push(\n\t\t\t\t\tdelta.deltaId,\n\t\t\t\t\tdelta.table,\n\t\t\t\t\tdelta.rowId,\n\t\t\t\t\tJSON.stringify(delta.columns),\n\t\t\t\t\tdelta.hlc.toString(),\n\t\t\t\t\tdelta.clientId,\n\t\t\t\t\tdelta.op,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tawait this.pool.execute(sql, values);\n\t\t}, \"Failed to insert deltas\");\n\t}\n\n\t/**\n\t * Query deltas with HLC greater than the given timestamp.\n\t * Optionally filtered by table name(s).\n\t */\n\tasync queryDeltasSince(\n\t\thlc: HLCTimestamp,\n\t\ttables?: string[],\n\t): Promise<Result<RowDelta[], AdapterError>> {\n\t\treturn wrapAsync(async () => {\n\t\t\tlet sql =\n\t\t\t\t\"SELECT delta_id, `table`, row_id, columns, hlc, client_id, op FROM lakesync_deltas WHERE hlc > ?\";\n\t\t\tconst params: unknown[] = [hlc.toString()];\n\n\t\t\tif (tables && tables.length > 0) {\n\t\t\t\tsql += ` AND \\`table\\` IN (${tables.map(() => \"?\").join(\", \")})`;\n\t\t\t\tparams.push(...tables);\n\t\t\t}\n\n\t\t\tsql += \" ORDER BY hlc ASC\";\n\n\t\t\tconst [rows] = await this.pool.execute(sql, params);\n\t\t\treturn (rows as MySQLDeltaRow[]).map(rowToDelta);\n\t\t}, \"Failed to query deltas\");\n\t}\n\n\t/**\n\t * Get the latest merged state for a specific row using column-level LWW.\n\t * Returns null if no deltas exist or if the row is tombstoned by DELETE.\n\t */\n\tasync getLatestState(\n\t\ttable: string,\n\t\trowId: string,\n\t): Promise<Result<Record<string, unknown> | null, AdapterError>> {\n\t\treturn wrapAsync(async () => {\n\t\t\tconst sql =\n\t\t\t\t\"SELECT columns, hlc, client_id, op FROM lakesync_deltas WHERE `table` = ? AND row_id = ? ORDER BY hlc ASC\";\n\t\t\tconst [rows] = await this.pool.execute(sql, [table, rowId]);\n\t\t\treturn mergeLatestState(rows as MySQLDeltaRow[]);\n\t\t}, `Failed to get latest state for ${table}:${rowId}`);\n\t}\n\n\t/**\n\t * Ensure the database schema exists. Creates the lakesync_deltas table\n\t * and a user table matching the given TableSchema definition.\n\t */\n\tasync ensureSchema(schema: TableSchema): Promise<Result<void, AdapterError>> {\n\t\treturn wrapAsync(async () => {\n\t\t\t// Create the deltas table\n\t\t\tawait this.pool.execute(`\n\t\t\t\tCREATE TABLE IF NOT EXISTS lakesync_deltas (\n\t\t\t\t\tdelta_id VARCHAR(255) PRIMARY KEY,\n\t\t\t\t\t\\`table\\` VARCHAR(255) NOT NULL,\n\t\t\t\t\trow_id VARCHAR(255) NOT NULL,\n\t\t\t\t\tcolumns JSON NOT NULL,\n\t\t\t\t\thlc BIGINT NOT NULL,\n\t\t\t\t\tclient_id VARCHAR(255) NOT NULL,\n\t\t\t\t\top VARCHAR(50) NOT NULL DEFAULT 'upsert',\n\t\t\t\t\tINDEX idx_hlc (hlc),\n\t\t\t\t\tINDEX idx_table_row (\\`table\\`, row_id)\n\t\t\t\t)\n\t\t\t`);\n\n\t\t\t// Create the user-defined table\n\t\t\tconst columnDefs = schema.columns\n\t\t\t\t.map((col) => `\\`${col.name}\\` ${lakeSyncTypeToMySQL(col.type)}`)\n\t\t\t\t.join(\", \");\n\n\t\t\tawait this.pool.execute(\n\t\t\t\t`CREATE TABLE IF NOT EXISTS \\`${schema.table}\\` (row_id VARCHAR(255) PRIMARY KEY, ${columnDefs}, props JSON NOT NULL DEFAULT ('{}'), synced_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP)`,\n\t\t\t);\n\t\t}, `Failed to ensure schema for table ${schema.table}`);\n\t}\n\n\t/**\n\t * Materialise deltas into destination tables.\n\t *\n\t * For each table with a matching schema, merges delta history into the\n\t * latest row state and upserts into the destination table. Tombstoned\n\t * rows are soft-deleted (default) or hard-deleted. The `props` column\n\t * is never touched.\n\t */\n\tasync materialise(\n\t\tdeltas: RowDelta[],\n\t\tschemas: ReadonlyArray<TableSchema>,\n\t): Promise<Result<void, AdapterError>> {\n\t\tif (deltas.length === 0) {\n\t\t\treturn Ok(undefined);\n\t\t}\n\n\t\treturn wrapAsync(async () => {\n\t\t\tconst grouped = groupDeltasByTable(deltas);\n\t\t\tconst schemaIndex = buildSchemaIndex(schemas);\n\n\t\t\tfor (const [tableName, rowIds] of grouped) {\n\t\t\t\tconst schema = schemaIndex.get(tableName);\n\t\t\t\tif (!schema) continue;\n\n\t\t\t\tconst pk = resolvePrimaryKey(schema);\n\t\t\t\tconst soft = isSoftDelete(schema);\n\n\t\t\t\t// Ensure destination table exists\n\t\t\t\tconst typedCols = schema.columns\n\t\t\t\t\t.map((col) => `\\`${col.name}\\` ${lakeSyncTypeToMySQL(col.type)}`)\n\t\t\t\t\t.join(\", \");\n\n\t\t\t\tconst pkConstraint = `PRIMARY KEY (${pk.map((c) => `\\`${c}\\``).join(\", \")})`;\n\t\t\t\tconst deletedAtCol = soft ? `, deleted_at TIMESTAMP NULL` : \"\";\n\t\t\t\tconst uniqueConstraint = schema.externalIdColumn\n\t\t\t\t\t? `, UNIQUE KEY (\\`${schema.externalIdColumn}\\`)`\n\t\t\t\t\t: \"\";\n\n\t\t\t\tawait this.pool.execute(\n\t\t\t\t\t`CREATE TABLE IF NOT EXISTS \\`${schema.table}\\` (row_id VARCHAR(255) NOT NULL, ${typedCols}, props JSON NOT NULL DEFAULT ('{}')${deletedAtCol}, synced_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, ${pkConstraint}${uniqueConstraint})`,\n\t\t\t\t);\n\n\t\t\t\t// Query delta history for affected rows\n\t\t\t\tconst rowIdArray = [...rowIds];\n\t\t\t\tconst placeholders = rowIdArray.map(() => \"?\").join(\", \");\n\t\t\t\tconst [rows] = await this.pool.execute(\n\t\t\t\t\t`SELECT row_id, columns, op FROM lakesync_deltas WHERE \\`table\\` = ? AND row_id IN (${placeholders}) ORDER BY hlc ASC`,\n\t\t\t\t\t[tableName, ...rowIdArray],\n\t\t\t\t);\n\n\t\t\t\t// Group by row_id and merge\n\t\t\t\tconst byRow = new Map<string, Array<{ columns: string; op: string }>>();\n\t\t\t\tfor (const row of rows as Array<{ row_id: string; columns: string; op: string }>) {\n\t\t\t\t\tlet list = byRow.get(row.row_id);\n\t\t\t\t\tif (!list) {\n\t\t\t\t\t\tlist = [];\n\t\t\t\t\t\tbyRow.set(row.row_id, list);\n\t\t\t\t\t}\n\t\t\t\t\tlist.push(row);\n\t\t\t\t}\n\n\t\t\t\tconst upserts: Array<{ rowId: string; state: Record<string, unknown> }> = [];\n\t\t\t\tconst deleteIds: string[] = [];\n\n\t\t\t\tfor (const [rowId, rowDeltas] of byRow) {\n\t\t\t\t\tconst state = mergeLatestState(rowDeltas);\n\t\t\t\t\tif (state === null) {\n\t\t\t\t\t\tdeleteIds.push(rowId);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tupserts.push({ rowId, state });\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// UPSERT rows\n\t\t\t\tif (upserts.length > 0) {\n\t\t\t\t\tconst cols = schema.columns.map((c) => c.name);\n\t\t\t\t\tconst valuePlaceholders = soft\n\t\t\t\t\t\t? upserts.map(() => `(?, ${cols.map(() => \"?\").join(\", \")}, NULL, NOW())`).join(\", \")\n\t\t\t\t\t\t: upserts.map(() => `(?, ${cols.map(() => \"?\").join(\", \")}, NOW())`).join(\", \");\n\n\t\t\t\t\tconst values: unknown[] = [];\n\t\t\t\t\tfor (const { rowId, state } of upserts) {\n\t\t\t\t\t\tvalues.push(rowId);\n\t\t\t\t\t\tfor (const col of cols) {\n\t\t\t\t\t\t\tvalues.push(state[col] ?? null);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tconst updateCols = cols.map((c) => `\\`${c}\\` = VALUES(\\`${c}\\`)`).join(\", \");\n\t\t\t\t\tconst softUpdateExtra = soft ? \", deleted_at = NULL\" : \"\";\n\t\t\t\t\tconst colList = soft\n\t\t\t\t\t\t? `row_id, ${cols.map((c) => `\\`${c}\\``).join(\", \")}, deleted_at, synced_at`\n\t\t\t\t\t\t: `row_id, ${cols.map((c) => `\\`${c}\\``).join(\", \")}, synced_at`;\n\n\t\t\t\t\tawait this.pool.execute(\n\t\t\t\t\t\t`INSERT INTO \\`${schema.table}\\` (${colList}) VALUES ${valuePlaceholders} ON DUPLICATE KEY UPDATE ${updateCols}${softUpdateExtra}, synced_at = VALUES(synced_at)`,\n\t\t\t\t\t\tvalues,\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\t// DELETE / soft-delete tombstoned rows\n\t\t\t\tif (deleteIds.length > 0) {\n\t\t\t\t\tconst delPlaceholders = deleteIds.map(() => \"?\").join(\", \");\n\t\t\t\t\tif (soft) {\n\t\t\t\t\t\tawait this.pool.execute(\n\t\t\t\t\t\t\t`UPDATE \\`${schema.table}\\` SET deleted_at = NOW(), synced_at = NOW() WHERE row_id IN (${delPlaceholders})`,\n\t\t\t\t\t\t\tdeleteIds,\n\t\t\t\t\t\t);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tawait this.pool.execute(\n\t\t\t\t\t\t\t`DELETE FROM \\`${schema.table}\\` WHERE row_id IN (${delPlaceholders})`,\n\t\t\t\t\t\t\tdeleteIds,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}, \"Failed to materialise deltas\");\n\t}\n\n\t/** Close the database connection pool and release resources. */\n\tasync close(): Promise<void> {\n\t\tawait this.pool.end();\n\t}\n}\n\n/** Shape of a row returned from the lakesync_deltas table. */\ninterface MySQLDeltaRow {\n\tdelta_id: string;\n\ttable: string;\n\trow_id: string;\n\tcolumns: string;\n\thlc: string | bigint;\n\tclient_id: string;\n\top: string;\n}\n\n/**\n * Convert a raw MySQL row into a RowDelta.\n * Handles both string and bigint HLC representations.\n */\nfunction rowToDelta(row: MySQLDeltaRow): RowDelta {\n\treturn {\n\t\tdeltaId: row.delta_id,\n\t\ttable: row.table,\n\t\trowId: row.row_id,\n\t\tcolumns: typeof row.columns === \"string\" ? JSON.parse(row.columns) : row.columns,\n\t\thlc: BigInt(row.hlc) as HLCTimestamp,\n\t\tclientId: row.client_id,\n\t\top: row.op as RowDelta[\"op\"],\n\t};\n}\n","import {\n\ttype AdapterError,\n\ttype ColumnDelta,\n\ttype HLCTimestamp,\n\tOk,\n\ttype Result,\n\ttype RowDelta,\n\ttype TableSchema,\n} from \"@lakesync/core\";\nimport { Pool, type PoolConfig } from \"pg\";\nimport type { DatabaseAdapter, DatabaseAdapterConfig } from \"./db-types\";\nimport type { Materialisable } from \"./materialise\";\nimport {\n\tbuildSchemaIndex,\n\tgroupDeltasByTable,\n\tisSoftDelete,\n\tresolveConflictColumns,\n\tresolvePrimaryKey,\n} from \"./materialise\";\nimport { mergeLatestState, wrapAsync } from \"./shared\";\n\nconst POSTGRES_TYPE_MAP: Record<TableSchema[\"columns\"][number][\"type\"], string> = {\n\tstring: \"TEXT\",\n\tnumber: \"DOUBLE PRECISION\",\n\tboolean: \"BOOLEAN\",\n\tjson: \"JSONB\",\n\tnull: \"TEXT\",\n};\n\n/**\n * PostgreSQL database adapter for LakeSync.\n *\n * Stores deltas in a `lakesync_deltas` table using pg Pool.\n * All public methods return `Result` and never throw.\n */\nexport class PostgresAdapter implements DatabaseAdapter, Materialisable {\n\t/** @internal */\n\treadonly pool: Pool;\n\n\tconstructor(config: DatabaseAdapterConfig) {\n\t\tconst poolConfig: PoolConfig = {\n\t\t\tconnectionString: config.connectionString,\n\t\t};\n\t\tthis.pool = new Pool(poolConfig);\n\t}\n\n\t/**\n\t * Insert deltas into the database in a single batch.\n\t * Idempotent via `ON CONFLICT (delta_id) DO NOTHING`.\n\t */\n\tasync insertDeltas(deltas: RowDelta[]): Promise<Result<void, AdapterError>> {\n\t\tif (deltas.length === 0) {\n\t\t\treturn Ok(undefined);\n\t\t}\n\n\t\treturn wrapAsync(async () => {\n\t\t\t// Build a multi-row INSERT with parameterised values\n\t\t\tconst values: unknown[] = [];\n\t\t\tconst rows: string[] = [];\n\n\t\t\tfor (let i = 0; i < deltas.length; i++) {\n\t\t\t\tconst d = deltas[i]!;\n\t\t\t\tconst offset = i * 7;\n\t\t\t\trows.push(\n\t\t\t\t\t`($${offset + 1}, $${offset + 2}, $${offset + 3}, $${offset + 4}, $${offset + 5}, $${offset + 6}, $${offset + 7})`,\n\t\t\t\t);\n\t\t\t\tvalues.push(\n\t\t\t\t\td.deltaId,\n\t\t\t\t\td.table,\n\t\t\t\t\td.rowId,\n\t\t\t\t\tJSON.stringify(d.columns),\n\t\t\t\t\td.hlc.toString(),\n\t\t\t\t\td.clientId,\n\t\t\t\t\td.op,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst sql = `INSERT INTO lakesync_deltas (delta_id, \"table\", row_id, columns, hlc, client_id, op)\nVALUES ${rows.join(\", \")}\nON CONFLICT (delta_id) DO NOTHING`;\n\n\t\t\tawait this.pool.query(sql, values);\n\t\t}, \"Failed to insert deltas\");\n\t}\n\n\t/**\n\t * Query deltas with HLC greater than the given timestamp, optionally filtered by table.\n\t */\n\tasync queryDeltasSince(\n\t\thlc: HLCTimestamp,\n\t\ttables?: string[],\n\t): Promise<Result<RowDelta[], AdapterError>> {\n\t\treturn wrapAsync(async () => {\n\t\t\tlet sql: string;\n\t\t\tlet params: unknown[];\n\n\t\t\tif (tables && tables.length > 0) {\n\t\t\t\tsql = `SELECT delta_id, \"table\", row_id, columns, hlc, client_id, op\nFROM lakesync_deltas\nWHERE hlc > $1 AND \"table\" = ANY($2)\nORDER BY hlc ASC`;\n\t\t\t\tparams = [hlc.toString(), tables];\n\t\t\t} else {\n\t\t\t\tsql = `SELECT delta_id, \"table\", row_id, columns, hlc, client_id, op\nFROM lakesync_deltas\nWHERE hlc > $1\nORDER BY hlc ASC`;\n\t\t\t\tparams = [hlc.toString()];\n\t\t\t}\n\n\t\t\tconst result = await this.pool.query(sql, params);\n\t\t\treturn result.rows.map(rowToRowDelta);\n\t\t}, \"Failed to query deltas\");\n\t}\n\n\t/**\n\t * Get the latest merged state for a specific row using column-level LWW.\n\t * Returns null if no deltas exist for this row.\n\t */\n\tasync getLatestState(\n\t\ttable: string,\n\t\trowId: string,\n\t): Promise<Result<Record<string, unknown> | null, AdapterError>> {\n\t\treturn wrapAsync(async () => {\n\t\t\tconst sql = `SELECT columns, hlc, client_id, op\nFROM lakesync_deltas\nWHERE \"table\" = $1 AND row_id = $2\nORDER BY hlc ASC`;\n\n\t\t\tconst result = await this.pool.query(sql, [table, rowId]);\n\t\t\treturn mergeLatestState(result.rows);\n\t\t}, `Failed to get latest state for ${table}:${rowId}`);\n\t}\n\n\t/**\n\t * Ensure the lakesync_deltas table and indices exist.\n\t * The `schema` parameter is accepted for interface compliance but the\n\t * internal table structure is fixed (deltas store column data as JSONB).\n\t */\n\tasync ensureSchema(_schema: TableSchema): Promise<Result<void, AdapterError>> {\n\t\treturn wrapAsync(async () => {\n\t\t\tawait this.pool.query(`\nCREATE TABLE IF NOT EXISTS lakesync_deltas (\n\tdelta_id TEXT PRIMARY KEY,\n\t\"table\" TEXT NOT NULL,\n\trow_id TEXT NOT NULL,\n\tcolumns JSONB NOT NULL,\n\thlc BIGINT NOT NULL,\n\tclient_id TEXT NOT NULL,\n\top TEXT NOT NULL DEFAULT 'INSERT'\n);\nCREATE INDEX IF NOT EXISTS idx_lakesync_deltas_hlc ON lakesync_deltas (hlc);\nCREATE INDEX IF NOT EXISTS idx_lakesync_deltas_table_row ON lakesync_deltas (\"table\", row_id);\n`);\n\t\t}, \"Failed to ensure schema\");\n\t}\n\n\t/**\n\t * Materialise deltas into destination tables.\n\t *\n\t * For each table with a matching schema, merges delta history into the\n\t * latest row state and upserts into the destination table. Tombstoned\n\t * rows are deleted. The `props` column is never touched.\n\t */\n\tasync materialise(\n\t\tdeltas: RowDelta[],\n\t\tschemas: ReadonlyArray<TableSchema>,\n\t): Promise<Result<void, AdapterError>> {\n\t\tif (deltas.length === 0) {\n\t\t\treturn Ok(undefined);\n\t\t}\n\n\t\treturn wrapAsync(async () => {\n\t\t\tconst grouped = groupDeltasByTable(deltas);\n\t\t\tconst schemaIndex = buildSchemaIndex(schemas);\n\n\t\t\tfor (const [tableName, rowIds] of grouped) {\n\t\t\t\tconst schema = schemaIndex.get(tableName);\n\t\t\t\tif (!schema) continue;\n\n\t\t\t\tconst dest = schema.table;\n\t\t\t\tconst pk = resolvePrimaryKey(schema);\n\t\t\t\tconst conflictCols = resolveConflictColumns(schema);\n\t\t\t\tconst soft = isSoftDelete(schema);\n\n\t\t\t\tconst columnDefs = schema.columns\n\t\t\t\t\t.map((c) => `\"${c.name}\" ${POSTGRES_TYPE_MAP[c.type]}`)\n\t\t\t\t\t.join(\", \");\n\n\t\t\t\tconst pkConstraint = `PRIMARY KEY (${pk.map((c) => `\"${c}\"`).join(\", \")})`;\n\t\t\t\tconst deletedAtCol = soft ? `,\\n\\tdeleted_at TIMESTAMPTZ` : \"\";\n\t\t\t\tconst uniqueConstraint = schema.externalIdColumn\n\t\t\t\t\t? `,\\n\\tUNIQUE (\"${schema.externalIdColumn}\")`\n\t\t\t\t\t: \"\";\n\n\t\t\t\tawait this.pool.query(\n\t\t\t\t\t`CREATE TABLE IF NOT EXISTS \"${dest}\" (\n\trow_id TEXT NOT NULL,\n\t${columnDefs},\n\tprops JSONB NOT NULL DEFAULT '{}'${deletedAtCol},\n\tsynced_at TIMESTAMPTZ NOT NULL DEFAULT now(),\n\t${pkConstraint}${uniqueConstraint}\n)`,\n\t\t\t\t);\n\n\t\t\t\tconst sourceTable = schema.sourceTable ?? schema.table;\n\t\t\t\tconst rowIdArray = [...rowIds];\n\n\t\t\t\tconst deltaResult = await this.pool.query(\n\t\t\t\t\t`SELECT row_id, columns, op FROM lakesync_deltas WHERE \"table\" = $1 AND row_id = ANY($2) ORDER BY hlc ASC`,\n\t\t\t\t\t[sourceTable, rowIdArray],\n\t\t\t\t);\n\n\t\t\t\t// Group results by row_id\n\t\t\t\tconst byRowId = new Map<string, Array<{ columns: string | ColumnDelta[]; op: string }>>();\n\t\t\t\tfor (const row of deltaResult.rows) {\n\t\t\t\t\tconst rid = row.row_id as string;\n\t\t\t\t\tlet arr = byRowId.get(rid);\n\t\t\t\t\tif (!arr) {\n\t\t\t\t\t\tarr = [];\n\t\t\t\t\t\tbyRowId.set(rid, arr);\n\t\t\t\t\t}\n\t\t\t\t\tarr.push(row as { columns: string | ColumnDelta[]; op: string });\n\t\t\t\t}\n\n\t\t\t\tconst upserts: Array<{ rowId: string; state: Record<string, unknown> }> = [];\n\t\t\t\tconst deleteIds: string[] = [];\n\n\t\t\t\tfor (const [rowId, rows] of byRowId) {\n\t\t\t\t\tconst state = mergeLatestState(rows);\n\t\t\t\t\tif (state !== null) {\n\t\t\t\t\t\tupserts.push({ rowId, state });\n\t\t\t\t\t} else {\n\t\t\t\t\t\tdeleteIds.push(rowId);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (upserts.length > 0) {\n\t\t\t\t\tconst colNames = schema.columns.map((c) => c.name);\n\t\t\t\t\tconst baseCols = [\"row_id\", ...colNames];\n\t\t\t\t\tconst allCols = soft\n\t\t\t\t\t\t? [...baseCols, \"deleted_at\", \"synced_at\"]\n\t\t\t\t\t\t: [...baseCols, \"synced_at\"];\n\t\t\t\t\tconst colList = allCols.map((c) => `\"${c}\"`).join(\", \");\n\n\t\t\t\t\tconst values: unknown[] = [];\n\t\t\t\t\tconst valueRows: string[] = [];\n\t\t\t\t\tconst paramsPerRow = allCols.length;\n\n\t\t\t\t\tfor (let i = 0; i < upserts.length; i++) {\n\t\t\t\t\t\tconst u = upserts[i]!;\n\t\t\t\t\t\tconst offset = i * paramsPerRow;\n\t\t\t\t\t\tconst placeholders = allCols.map((_, j) => `$${offset + j + 1}`);\n\t\t\t\t\t\tvalueRows.push(`(${placeholders.join(\", \")})`);\n\n\t\t\t\t\t\tvalues.push(u.rowId);\n\t\t\t\t\t\tfor (const col of colNames) {\n\t\t\t\t\t\t\tvalues.push(u.state[col] ?? null);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (soft) values.push(null); // deleted_at = NULL (un-delete)\n\t\t\t\t\t\tvalues.push(new Date());\n\t\t\t\t\t}\n\n\t\t\t\t\tconst conflictList = conflictCols.map((c) => `\"${c}\"`).join(\", \");\n\t\t\t\t\tconst updateCols = soft\n\t\t\t\t\t\t? [...colNames, \"deleted_at\", \"synced_at\"]\n\t\t\t\t\t\t: [...colNames, \"synced_at\"];\n\t\t\t\t\tconst updateSet = updateCols.map((c) => `\"${c}\" = EXCLUDED.\"${c}\"`).join(\", \");\n\n\t\t\t\t\tawait this.pool.query(\n\t\t\t\t\t\t`INSERT INTO \"${dest}\" (${colList}) VALUES ${valueRows.join(\", \")} ON CONFLICT (${conflictList}) DO UPDATE SET ${updateSet}`,\n\t\t\t\t\t\tvalues,\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tif (deleteIds.length > 0) {\n\t\t\t\t\tif (soft) {\n\t\t\t\t\t\tawait this.pool.query(\n\t\t\t\t\t\t\t`UPDATE \"${dest}\" SET deleted_at = now(), synced_at = now() WHERE row_id = ANY($1)`,\n\t\t\t\t\t\t\t[deleteIds],\n\t\t\t\t\t\t);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tawait this.pool.query(`DELETE FROM \"${dest}\" WHERE row_id = ANY($1)`, [deleteIds]);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}, \"Failed to materialise deltas\");\n\t}\n\n\t/** Close the database connection pool and release resources. */\n\tasync close(): Promise<void> {\n\t\tawait this.pool.end();\n\t}\n}\n\n/**\n * Convert a raw Postgres row into a RowDelta.\n */\nfunction rowToRowDelta(row: Record<string, unknown>): RowDelta {\n\tconst columns: ColumnDelta[] =\n\t\ttypeof row.columns === \"string\"\n\t\t\t? JSON.parse(row.columns as string)\n\t\t\t: (row.columns as ColumnDelta[]);\n\n\treturn {\n\t\tdeltaId: row.delta_id as string,\n\t\ttable: row.table as string,\n\t\trowId: row.row_id as string,\n\t\tcolumns,\n\t\thlc: BigInt(row.hlc as string) as HLCTimestamp,\n\t\tclientId: row.client_id as string,\n\t\top: row.op as RowDelta[\"op\"],\n\t};\n}\n","import { AdapterError, type ConnectorConfig, Err, Ok, type Result, toError } from \"@lakesync/core\";\nimport { BigQueryAdapter } from \"./bigquery\";\nimport type { DatabaseAdapter } from \"./db-types\";\nimport { MySQLAdapter } from \"./mysql\";\nimport { PostgresAdapter } from \"./postgres\";\n\n/**\n * Instantiate a {@link DatabaseAdapter} from a {@link ConnectorConfig}.\n *\n * Switches on `config.type` and creates the matching adapter using\n * the type-specific connection configuration. Returns an {@link AdapterError}\n * if the type-specific config is missing or the adapter constructor throws.\n *\n * @param config - Validated connector configuration.\n * @returns The instantiated adapter or an error.\n */\nexport function createDatabaseAdapter(\n\tconfig: ConnectorConfig,\n): Result<DatabaseAdapter, AdapterError> {\n\ttry {\n\t\tswitch (config.type) {\n\t\t\tcase \"postgres\": {\n\t\t\t\tif (!config.postgres) {\n\t\t\t\t\treturn Err(new AdapterError(\"Postgres connector config missing postgres field\"));\n\t\t\t\t}\n\t\t\t\treturn Ok(\n\t\t\t\t\tnew PostgresAdapter({\n\t\t\t\t\t\tconnectionString: config.postgres.connectionString,\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t}\n\t\t\tcase \"mysql\": {\n\t\t\t\tif (!config.mysql) {\n\t\t\t\t\treturn Err(new AdapterError(\"MySQL connector config missing mysql field\"));\n\t\t\t\t}\n\t\t\t\treturn Ok(\n\t\t\t\t\tnew MySQLAdapter({\n\t\t\t\t\t\tconnectionString: config.mysql.connectionString,\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t}\n\t\t\tcase \"bigquery\": {\n\t\t\t\tif (!config.bigquery) {\n\t\t\t\t\treturn Err(new AdapterError(\"BigQuery connector config missing bigquery field\"));\n\t\t\t\t}\n\t\t\t\treturn Ok(\n\t\t\t\t\tnew BigQueryAdapter({\n\t\t\t\t\t\tprojectId: config.bigquery.projectId,\n\t\t\t\t\t\tdataset: config.bigquery.dataset,\n\t\t\t\t\t\tkeyFilename: config.bigquery.keyFilename,\n\t\t\t\t\t\tlocation: config.bigquery.location,\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t}\n\t\t\tdefault:\n\t\t\t\treturn Err(new AdapterError(`Unsupported connector type: ${config.type}`));\n\t\t}\n\t} catch (err: unknown) {\n\t\treturn Err(new AdapterError(`Failed to create adapter: ${toError(err).message}`));\n\t}\n}\n","import {\n\ttype AdapterError,\n\ttype HLCTimestamp,\n\tOk,\n\ttype Result,\n\ttype RowDelta,\n\ttype TableSchema,\n} from \"@lakesync/core\";\n\nimport type { DatabaseAdapter } from \"./db-types\";\nimport type { Materialisable } from \"./materialise\";\nimport { isMaterialisable } from \"./materialise\";\n\n/** Configuration for the FanOutAdapter. */\nexport interface FanOutAdapterConfig {\n\t/** The primary adapter that handles all reads and authoritative writes. */\n\tprimary: DatabaseAdapter;\n\t/** Secondary adapters that receive replicated writes on a best-effort basis. */\n\tsecondaries: DatabaseAdapter[];\n}\n\n/**\n * Writes to a primary adapter synchronously and replicates to secondary\n * adapters asynchronously. Reads always go to the primary.\n *\n * Secondary failures are silently caught and never affect the return value.\n * Use case: write to Postgres (fast, operational), replicate to BigQuery (analytics).\n */\nexport class FanOutAdapter implements DatabaseAdapter, Materialisable {\n\tprivate readonly primary: DatabaseAdapter;\n\tprivate readonly secondaries: ReadonlyArray<DatabaseAdapter>;\n\n\tconstructor(config: FanOutAdapterConfig) {\n\t\tthis.primary = config.primary;\n\t\tthis.secondaries = config.secondaries;\n\t}\n\n\t/** Insert deltas into the primary, then replicate to secondaries (fire-and-forget). */\n\tasync insertDeltas(deltas: RowDelta[]): Promise<Result<void, AdapterError>> {\n\t\tconst result = await this.primary.insertDeltas(deltas);\n\t\tif (!result.ok) {\n\t\t\treturn result;\n\t\t}\n\n\t\tfor (const secondary of this.secondaries) {\n\t\t\tsecondary.insertDeltas(deltas).catch(() => {});\n\t\t}\n\n\t\treturn Ok(undefined);\n\t}\n\n\t/** Query deltas from the primary adapter only. */\n\tasync queryDeltasSince(\n\t\thlc: HLCTimestamp,\n\t\ttables?: string[],\n\t): Promise<Result<RowDelta[], AdapterError>> {\n\t\treturn this.primary.queryDeltasSince(hlc, tables);\n\t}\n\n\t/** Get the latest state from the primary adapter only. */\n\tasync getLatestState(\n\t\ttable: string,\n\t\trowId: string,\n\t): Promise<Result<Record<string, unknown> | null, AdapterError>> {\n\t\treturn this.primary.getLatestState(table, rowId);\n\t}\n\n\t/** Ensure schema on the primary first, then best-effort on secondaries. */\n\tasync ensureSchema(schema: TableSchema): Promise<Result<void, AdapterError>> {\n\t\tconst result = await this.primary.ensureSchema(schema);\n\t\tif (!result.ok) {\n\t\t\treturn result;\n\t\t}\n\n\t\tfor (const secondary of this.secondaries) {\n\t\t\tsecondary.ensureSchema(schema).catch(() => {});\n\t\t}\n\n\t\treturn Ok(undefined);\n\t}\n\n\t/** Materialise via primary, then replicate to materialisable secondaries (fire-and-forget). */\n\tasync materialise(\n\t\tdeltas: RowDelta[],\n\t\tschemas: ReadonlyArray<TableSchema>,\n\t): Promise<Result<void, AdapterError>> {\n\t\tif (isMaterialisable(this.primary)) {\n\t\t\tconst result = await this.primary.materialise(deltas, schemas);\n\t\t\tif (!result.ok) {\n\t\t\t\treturn result;\n\t\t\t}\n\t\t}\n\n\t\tfor (const secondary of this.secondaries) {\n\t\t\tif (isMaterialisable(secondary)) {\n\t\t\t\tsecondary.materialise(deltas, schemas).catch(() => {});\n\t\t\t}\n\t\t}\n\n\t\treturn Ok(undefined);\n\t}\n\n\t/** Close primary and all secondary adapters. */\n\tasync close(): Promise<void> {\n\t\tawait this.primary.close();\n\t\tfor (const secondary of this.secondaries) {\n\t\t\tawait secondary.close();\n\t\t}\n\t}\n}\n","import {\n\ttype AdapterError,\n\ttype HLCTimestamp,\n\tOk,\n\ttype Result,\n\ttype RowDelta,\n\ttype TableSchema,\n} from \"@lakesync/core\";\n\nimport type { DatabaseAdapter } from \"./db-types\";\nimport type { Materialisable } from \"./materialise\";\nimport { isMaterialisable } from \"./materialise\";\n\n/** Configuration for age-based tiered storage. */\nexport interface LifecycleAdapterConfig {\n\t/** Hot tier — recent data, fast queries. */\n\thot: {\n\t\t/** The adapter storing recent deltas. */\n\t\tadapter: DatabaseAdapter;\n\t\t/** Maximum age in milliseconds before data is considered cold. */\n\t\tmaxAgeMs: number;\n\t};\n\t/** Cold tier — older data, cheap storage. */\n\tcold: {\n\t\t/** The adapter storing archived deltas. */\n\t\tadapter: DatabaseAdapter;\n\t};\n}\n\n/**\n * Routes database operations across hot and cold tiers based on delta age.\n *\n * Writes always go to the hot adapter. Reads fan out to both tiers when\n * the requested HLC is older than the configured `maxAgeMs` threshold.\n *\n * Use {@link migrateToTier} as a background job to copy aged-out deltas\n * from hot to cold.\n */\nexport class LifecycleAdapter implements DatabaseAdapter, Materialisable {\n\tprivate readonly hot: DatabaseAdapter;\n\tprivate readonly cold: DatabaseAdapter;\n\tprivate readonly maxAgeMs: number;\n\n\tconstructor(config: LifecycleAdapterConfig) {\n\t\tthis.hot = config.hot.adapter;\n\t\tthis.cold = config.cold.adapter;\n\t\tthis.maxAgeMs = config.hot.maxAgeMs;\n\t}\n\n\t/** Insert deltas into the hot adapter — new data is always hot. */\n\tasync insertDeltas(deltas: RowDelta[]): Promise<Result<void, AdapterError>> {\n\t\treturn this.hot.insertDeltas(deltas);\n\t}\n\n\t/**\n\t * Query deltas since the given HLC.\n\t *\n\t * If `sinceHlc` is older than `now - maxAgeMs`, queries both hot and cold\n\t * adapters and merges the results sorted by HLC. Otherwise queries hot only.\n\t */\n\tasync queryDeltasSince(\n\t\thlc: HLCTimestamp,\n\t\ttables?: string[],\n\t): Promise<Result<RowDelta[], AdapterError>> {\n\t\tconst sinceWallMs = Number(hlc >> 16n);\n\t\tconst thresholdMs = Date.now() - this.maxAgeMs;\n\n\t\tif (sinceWallMs < thresholdMs) {\n\t\t\t// Query spans into cold territory — fan out to both tiers\n\t\t\tconst [hotResult, coldResult] = await Promise.all([\n\t\t\t\tthis.hot.queryDeltasSince(hlc, tables),\n\t\t\t\tthis.cold.queryDeltasSince(hlc, tables),\n\t\t\t]);\n\n\t\t\tif (!hotResult.ok) return hotResult;\n\t\t\tif (!coldResult.ok) return coldResult;\n\n\t\t\tconst merged = [...hotResult.value, ...coldResult.value];\n\t\t\tmerged.sort((a, b) => (a.hlc < b.hlc ? -1 : a.hlc > b.hlc ? 1 : 0));\n\n\t\t\treturn Ok(merged);\n\t\t}\n\n\t\t// Recent query — hot tier only\n\t\treturn this.hot.queryDeltasSince(hlc, tables);\n\t}\n\n\t/** Get latest state — try hot first, fall back to cold if hot returns null. */\n\tasync getLatestState(\n\t\ttable: string,\n\t\trowId: string,\n\t): Promise<Result<Record<string, unknown> | null, AdapterError>> {\n\t\tconst hotResult = await this.hot.getLatestState(table, rowId);\n\t\tif (!hotResult.ok) return hotResult;\n\n\t\tif (hotResult.value !== null) {\n\t\t\treturn hotResult;\n\t\t}\n\n\t\treturn this.cold.getLatestState(table, rowId);\n\t}\n\n\t/** Ensure schema exists on both hot and cold adapters. */\n\tasync ensureSchema(schema: TableSchema): Promise<Result<void, AdapterError>> {\n\t\tconst hotResult = await this.hot.ensureSchema(schema);\n\t\tif (!hotResult.ok) return hotResult;\n\n\t\treturn this.cold.ensureSchema(schema);\n\t}\n\n\t/** Materialise via hot tier only — cold tier stores archived deltas, not destination tables. */\n\tasync materialise(\n\t\tdeltas: RowDelta[],\n\t\tschemas: ReadonlyArray<TableSchema>,\n\t): Promise<Result<void, AdapterError>> {\n\t\tif (isMaterialisable(this.hot)) {\n\t\t\treturn this.hot.materialise(deltas, schemas);\n\t\t}\n\t\treturn Ok(undefined);\n\t}\n\n\t/** Close both hot and cold adapters. */\n\tasync close(): Promise<void> {\n\t\tawait this.hot.close();\n\t\tawait this.cold.close();\n\t}\n}\n\n/**\n * Migrate aged-out deltas from the hot adapter to the cold adapter.\n *\n * Queries the hot adapter for all deltas since HLC 0, filters those with\n * wall time older than `Date.now() - maxAgeMs`, and inserts them into the\n * cold adapter. Insertion is idempotent via deltaId uniqueness.\n *\n * Does NOT delete from hot — that is a separate cleanup concern.\n *\n * @param hot - The hot-tier adapter to read old deltas from.\n * @param cold - The cold-tier adapter to write old deltas to.\n * @param maxAgeMs - Age threshold in milliseconds.\n * @returns The count of migrated deltas, or an AdapterError.\n */\nexport async function migrateToTier(\n\thot: DatabaseAdapter,\n\tcold: DatabaseAdapter,\n\tmaxAgeMs: number,\n): Promise<Result<{ migrated: number }, AdapterError>> {\n\tconst thresholdMs = Date.now() - maxAgeMs;\n\tconst thresholdHlc = (BigInt(0) << 16n) as HLCTimestamp;\n\n\tconst result = await hot.queryDeltasSince(thresholdHlc);\n\tif (!result.ok) return result;\n\n\tconst oldDeltas = result.value.filter((delta) => {\n\t\tconst wallMs = Number(delta.hlc >> 16n);\n\t\treturn wallMs < thresholdMs;\n\t});\n\n\tif (oldDeltas.length === 0) {\n\t\treturn Ok({ migrated: 0 });\n\t}\n\n\tconst insertResult = await cold.insertDeltas(oldDeltas);\n\tif (!insertResult.ok) return insertResult;\n\n\treturn Ok({ migrated: oldDeltas.length });\n}\n","import { type AdapterError, type HLCTimestamp, Ok, type Result } from \"@lakesync/core\";\n\nimport type { DatabaseAdapter } from \"./db-types\";\n\n/** Options for migrating deltas between database adapters. */\nexport interface MigrateOptions {\n\t/** Source adapter to read from */\n\tfrom: DatabaseAdapter;\n\t/** Target adapter to write to */\n\tto: DatabaseAdapter;\n\t/** Optional: only migrate specific tables */\n\ttables?: string[];\n\t/** Batch size for writing (default: 1000) */\n\tbatchSize?: number;\n\t/** Progress callback invoked after each batch write */\n\tonProgress?: (info: MigrateProgress) => void;\n}\n\n/** Progress information reported during migration. */\nexport interface MigrateProgress {\n\t/** Current batch number (1-based) */\n\tbatch: number;\n\t/** Total deltas migrated so far */\n\ttotalSoFar: number;\n}\n\n/** Result of a successful migration. */\nexport interface MigrateResult {\n\t/** Total number of deltas migrated */\n\ttotalDeltas: number;\n\t/** Number of batches processed */\n\tbatches: number;\n}\n\n/**\n * Migrate deltas from one database adapter to another.\n * Reads all matching deltas from the source, then writes them in batches to the target.\n * Idempotent via deltaId uniqueness in the target adapter.\n */\nexport async function migrateAdapter(\n\topts: MigrateOptions,\n): Promise<Result<MigrateResult, AdapterError>> {\n\tconst batchSize = opts.batchSize ?? 1000;\n\n\tconst readResult = await opts.from.queryDeltasSince(BigInt(0) as HLCTimestamp, opts.tables);\n\tif (!readResult.ok) {\n\t\treturn readResult;\n\t}\n\n\tconst deltas = readResult.value;\n\n\tif (deltas.length === 0) {\n\t\treturn Ok({ totalDeltas: 0, batches: 0 });\n\t}\n\n\tlet batchCount = 0;\n\tlet totalSoFar = 0;\n\n\tfor (let i = 0; i < deltas.length; i += batchSize) {\n\t\tconst batch = deltas.slice(i, i + batchSize);\n\t\tconst writeResult = await opts.to.insertDeltas(batch);\n\t\tif (!writeResult.ok) {\n\t\t\treturn writeResult;\n\t\t}\n\n\t\tbatchCount++;\n\t\ttotalSoFar += batch.length;\n\n\t\topts.onProgress?.({ batch: batchCount, totalSoFar });\n\t}\n\n\treturn Ok({ totalDeltas: totalSoFar, batches: batchCount });\n}\n","import {\n\tDeleteObjectCommand,\n\tDeleteObjectsCommand,\n\tGetObjectCommand,\n\tHeadObjectCommand,\n\tListObjectsV2Command,\n\tPutObjectCommand,\n\tS3Client,\n} from \"@aws-sdk/client-s3\";\nimport { AdapterError, Ok, type Result } from \"@lakesync/core\";\nimport { wrapAsync } from \"./shared\";\nimport type { AdapterConfig, LakeAdapter, ObjectInfo } from \"./types\";\n\n/**\n * MinIO/S3-compatible lake adapter.\n *\n * Wraps the AWS S3 SDK to provide a Result-based interface for\n * interacting with MinIO or any S3-compatible object store.\n * All public methods return `Result` and never throw.\n */\nexport class MinIOAdapter implements LakeAdapter {\n\tprivate readonly client: S3Client;\n\tprivate readonly bucket: string;\n\n\tconstructor(config: AdapterConfig) {\n\t\tthis.bucket = config.bucket;\n\t\tthis.client = new S3Client({\n\t\t\tendpoint: config.endpoint,\n\t\t\tregion: config.region ?? \"us-east-1\",\n\t\t\tcredentials: config.credentials,\n\t\t\tforcePathStyle: true, // Required for MinIO\n\t\t});\n\t}\n\n\t/** Store an object in the lake */\n\tasync putObject(\n\t\tpath: string,\n\t\tdata: Uint8Array,\n\t\tcontentType?: string,\n\t): Promise<Result<void, AdapterError>> {\n\t\treturn wrapAsync(async () => {\n\t\t\tawait this.client.send(\n\t\t\t\tnew PutObjectCommand({\n\t\t\t\t\tBucket: this.bucket,\n\t\t\t\t\tKey: path,\n\t\t\t\t\tBody: data,\n\t\t\t\t\tContentType: contentType,\n\t\t\t\t}),\n\t\t\t);\n\t\t}, `Failed to put object: ${path}`);\n\t}\n\n\t/** Retrieve an object from the lake */\n\tasync getObject(path: string): Promise<Result<Uint8Array, AdapterError>> {\n\t\treturn wrapAsync(async () => {\n\t\t\tconst response = await this.client.send(\n\t\t\t\tnew GetObjectCommand({\n\t\t\t\t\tBucket: this.bucket,\n\t\t\t\t\tKey: path,\n\t\t\t\t}),\n\t\t\t);\n\t\t\tconst bytes = await response.Body?.transformToByteArray();\n\t\t\tif (!bytes) {\n\t\t\t\tthrow new AdapterError(`Empty response for object: ${path}`);\n\t\t\t}\n\t\t\treturn bytes;\n\t\t}, `Failed to get object: ${path}`);\n\t}\n\n\t/** Get object metadata without retrieving the body */\n\tasync headObject(\n\t\tpath: string,\n\t): Promise<Result<{ size: number; lastModified: Date }, AdapterError>> {\n\t\treturn wrapAsync(async () => {\n\t\t\tconst response = await this.client.send(\n\t\t\t\tnew HeadObjectCommand({\n\t\t\t\t\tBucket: this.bucket,\n\t\t\t\t\tKey: path,\n\t\t\t\t}),\n\t\t\t);\n\t\t\treturn {\n\t\t\t\tsize: response.ContentLength ?? 0,\n\t\t\t\tlastModified: response.LastModified ?? new Date(0),\n\t\t\t};\n\t\t}, `Failed to head object: ${path}`);\n\t}\n\n\t/** List objects matching a given prefix */\n\tasync listObjects(prefix: string): Promise<Result<ObjectInfo[], AdapterError>> {\n\t\treturn wrapAsync(async () => {\n\t\t\tconst response = await this.client.send(\n\t\t\t\tnew ListObjectsV2Command({\n\t\t\t\t\tBucket: this.bucket,\n\t\t\t\t\tPrefix: prefix,\n\t\t\t\t}),\n\t\t\t);\n\t\t\treturn (response.Contents ?? []).map((item) => ({\n\t\t\t\tkey: item.Key ?? \"\",\n\t\t\t\tsize: item.Size ?? 0,\n\t\t\t\tlastModified: item.LastModified ?? new Date(0),\n\t\t\t}));\n\t\t}, `Failed to list objects with prefix: ${prefix}`);\n\t}\n\n\t/** Delete a single object from the lake */\n\tasync deleteObject(path: string): Promise<Result<void, AdapterError>> {\n\t\treturn wrapAsync(async () => {\n\t\t\tawait this.client.send(\n\t\t\t\tnew DeleteObjectCommand({\n\t\t\t\t\tBucket: this.bucket,\n\t\t\t\t\tKey: path,\n\t\t\t\t}),\n\t\t\t);\n\t\t}, `Failed to delete object: ${path}`);\n\t}\n\n\t/** Delete multiple objects from the lake in a single batch operation */\n\tasync deleteObjects(paths: string[]): Promise<Result<void, AdapterError>> {\n\t\tif (paths.length === 0) {\n\t\t\treturn Ok(undefined);\n\t\t}\n\n\t\treturn wrapAsync(async () => {\n\t\t\tawait this.client.send(\n\t\t\t\tnew DeleteObjectsCommand({\n\t\t\t\t\tBucket: this.bucket,\n\t\t\t\t\tDelete: {\n\t\t\t\t\t\tObjects: paths.map((key) => ({ Key: key })),\n\t\t\t\t\t\tQuiet: true,\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t);\n\t\t}, `Failed to batch delete ${paths.length} objects`);\n\t}\n}\n","import type { ConnectorConfig } from \"@lakesync/core\";\n\n/** Generic query function — abstracts any SQL database connection. */\nexport type QueryFn = (sql: string, params?: unknown[]) => Promise<Record<string, unknown>[]>;\n\n/**\n * Create a raw SQL query function from a {@link ConnectorConfig}.\n *\n * Uses dynamic imports so the database drivers (pg, mysql2) are only\n * loaded when actually needed. Returns `null` for connector types that\n * do not support the standard SQL polling model (e.g. BigQuery).\n *\n * @param config - Validated connector configuration.\n * @returns A query function or `null` if the connector type is unsupported.\n */\nexport async function createQueryFn(config: ConnectorConfig): Promise<QueryFn | null> {\n\tswitch (config.type) {\n\t\tcase \"postgres\": {\n\t\t\tif (!config.postgres) return null;\n\t\t\tconst { Pool } = await import(\"pg\");\n\t\t\tconst pool = new Pool({ connectionString: config.postgres.connectionString });\n\t\t\treturn async (sql: string, params?: unknown[]) => {\n\t\t\t\tconst result = await pool.query(sql, params);\n\t\t\t\treturn result.rows as Record<string, unknown>[];\n\t\t\t};\n\t\t}\n\t\tcase \"mysql\": {\n\t\t\tif (!config.mysql) return null;\n\t\t\tconst mysql = await import(\"mysql2/promise\");\n\t\t\tconst pool = mysql.createPool(config.mysql.connectionString);\n\t\t\treturn async (sql: string, params?: unknown[]) => {\n\t\t\t\tconst [rows] = await pool.query(sql, params);\n\t\t\t\treturn rows as Record<string, unknown>[];\n\t\t\t};\n\t\t}\n\t\tdefault:\n\t\t\treturn null;\n\t}\n}\n"],"mappings":"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","names":["rowToRowDelta","Pool","mysql"]}
@@ -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/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/**\n * Dispatches imperative actions to registered handlers.\n *\n * Manages idempotency via actionId deduplication and idempotencyKey mapping.\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<\n\t\tstring,\n\t\tActionResult | { actionId: string; code: string; message: string; retryable: boolean }\n\t> = new Map();\n\n\tconstructor(handlers?: Record<string, ActionHandler>) {\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}\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\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.idempotencyMap.get(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.idempotencyMap.get(`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\tthis.executedActions.add(action.actionId);\n\t\tthis.idempotencyMap.set(action.actionId, result);\n\t\tif (action.idempotencyKey) {\n\t\t\tthis.idempotencyMap.set(`idem:${action.idempotencyKey}`, result);\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/** Drain the log for flush. Returns log entries and clears both structures. */\n\tdrain(): RowDelta[] {\n\t\tconst entries = [...this.log];\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\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","/** 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. */\nexport const VALID_COLUMN_TYPES = new Set([\"string\", \"number\", \"boolean\", \"json\", \"null\"]);\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, isDatabaseAdapter, type 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\tFlushError,\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 { flushEntries } from \"./flush\";\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 ActionDispatcher, DeltaBuffer, and flushEntries.\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 flushing = false;\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}\n\n\t/** Restore drained entries back to the buffer for retry. */\n\tprivate restoreEntries(entries: RowDelta[]): void {\n\t\tfor (const entry of entries) {\n\t\t\tthis.buffer.append(entry);\n\t\t}\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// Backpressure — reject when buffer exceeds threshold to prevent OOM\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\n\t\tlet accepted = 0;\n\t\tconst ingested: RowDelta[] = [];\n\n\t\tfor (const delta of msg.deltas) {\n\t\t\t// Check for idempotent re-push\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// Validate delta against the schema if a schema manager is configured\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// Validate HLC drift against server's physical clock\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// Check for conflict with existing state\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\t// If resolution fails (should not happen with LWW on same row), skip\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/**\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\t// No more data in buffer\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\t// Trim to exactly 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\t// Exhausted the buffer\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\t// Advance cursor past the last examined delta\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.config.sourceAdapters?.[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\t// Apply sync rules filtering if context is provided\n\t\tif (context) {\n\t\t\tdeltas = filterDeltas(deltas, context);\n\t\t}\n\n\t\t// Paginate\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 flush module\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\tif (this.flushing) {\n\t\t\treturn Err(new FlushError(\"Flush already in progress\"));\n\t\t}\n\t\tif (this.buffer.logSize === 0) {\n\t\t\treturn Ok(undefined);\n\t\t}\n\t\tif (!this.adapter) {\n\t\t\treturn Err(new FlushError(\"No adapter configured\"));\n\t\t}\n\n\t\tthis.flushing = true;\n\n\t\t// Database adapter path — drain after flushing flag is set\n\t\tif (isDatabaseAdapter(this.adapter)) {\n\t\t\tconst entries = this.buffer.drain();\n\t\t\tif (entries.length === 0) {\n\t\t\t\tthis.flushing = false;\n\t\t\t\treturn Ok(undefined);\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\treturn await flushEntries(entries, 0, {\n\t\t\t\t\tadapter: this.adapter,\n\t\t\t\t\tconfig: {\n\t\t\t\t\t\tgatewayId: this.config.gatewayId,\n\t\t\t\t\t\tflushFormat: this.config.flushFormat,\n\t\t\t\t\t\ttableSchema: this.config.tableSchema,\n\t\t\t\t\t\tcatalogue: this.config.catalogue,\n\t\t\t\t\t},\n\t\t\t\t\trestoreEntries: (e) => this.restoreEntries(e),\n\t\t\t\t\tschemas: this.config.schemas,\n\t\t\t\t});\n\t\t\t} finally {\n\t\t\t\tthis.flushing = false;\n\t\t\t}\n\t\t}\n\n\t\t// Lake adapter path\n\t\tconst byteSize = this.buffer.byteSize;\n\t\tconst entries = this.buffer.drain();\n\n\t\ttry {\n\t\t\treturn await flushEntries(entries, byteSize, {\n\t\t\t\tadapter: this.adapter,\n\t\t\t\tconfig: {\n\t\t\t\t\tgatewayId: this.config.gatewayId,\n\t\t\t\t\tflushFormat: this.config.flushFormat,\n\t\t\t\t\ttableSchema: this.config.tableSchema,\n\t\t\t\t\tcatalogue: this.config.catalogue,\n\t\t\t\t},\n\t\t\t\trestoreEntries: (e) => this.restoreEntries(e),\n\t\t\t\tschemas: this.config.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(table: string): 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 (!this.adapter) {\n\t\t\treturn Err(new FlushError(\"No adapter configured\"));\n\t\t}\n\n\t\tconst entries = this.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: this.adapter,\n\t\t\t\t\tconfig: {\n\t\t\t\t\t\tgatewayId: this.config.gatewayId,\n\t\t\t\t\t\tflushFormat: this.config.flushFormat,\n\t\t\t\t\t\ttableSchema: this.config.tableSchema,\n\t\t\t\t\t\tcatalogue: this.config.catalogue,\n\t\t\t\t\t},\n\t\t\t\t\trestoreEntries: (e) => this.restoreEntries(e),\n\t\t\t\t\tschemas: this.config.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// -----------------------------------------------------------------------\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\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.config.sourceAdapters![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\tdelete this.config.sourceAdapters![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 Object.keys(this.config.sourceAdapters!);\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/**\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\tlet body: SyncPush;\n\ttry {\n\t\tbody = JSON.parse(raw, bigintReviver) as SyncPush;\n\t} catch {\n\t\treturn Err({ status: 400, message: \"Invalid JSON body\" });\n\t}\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\tlet body: ActionPush;\n\ttry {\n\t\tbody = JSON.parse(raw, bigintReviver) as ActionPush;\n\t} catch {\n\t\treturn Err({ status: 400, message: \"Invalid JSON body\" });\n\t}\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\tlet schema: TableSchema;\n\ttry {\n\t\tschema = JSON.parse(raw) as TableSchema;\n\t} catch {\n\t\treturn Err({ status: 400, message: \"Invalid JSON body\" });\n\t}\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\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\tlet config: unknown;\n\ttry {\n\t\tconfig = JSON.parse(raw);\n\t} catch {\n\t\treturn { status: 400, body: { error: \"Invalid JSON body\" } };\n\t}\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\tlet body: unknown;\n\ttry {\n\t\tbody = JSON.parse(raw);\n\t} catch {\n\t\treturn { status: 400, body: { error: \"Invalid JSON body\" } };\n\t}\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":"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","names":["hasMore","serverHlc","trimmed","entries"]}