lakesync 0.1.8 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapter-types-DwsQGQS4.d.ts +94 -0
- package/dist/adapter.d.ts +23 -49
- package/dist/adapter.js +9 -4
- package/dist/analyst.js +1 -1
- package/dist/{base-poller-Bj9kX9dv.d.ts → base-poller-Y7ORYgUv.d.ts} +2 -0
- package/dist/catalogue.js +2 -2
- package/dist/{chunk-LDFFCG2K.js → chunk-4SG66H5K.js} +44 -31
- package/dist/chunk-4SG66H5K.js.map +1 -0
- package/dist/{chunk-LPWXOYNS.js → chunk-C4KD6YKP.js} +59 -43
- package/dist/chunk-C4KD6YKP.js.map +1 -0
- package/dist/{chunk-JI4C4R5H.js → chunk-FIIHPQMQ.js} +196 -118
- package/dist/chunk-FIIHPQMQ.js.map +1 -0
- package/dist/{chunk-TMLG32QV.js → chunk-U2NV4DUX.js} +2 -2
- package/dist/{chunk-QNITY4F6.js → chunk-XVP5DJJ7.js} +16 -13
- package/dist/{chunk-QNITY4F6.js.map → chunk-XVP5DJJ7.js.map} +1 -1
- package/dist/{chunk-KVSWLIJR.js → chunk-YHYBLU6W.js} +2 -2
- package/dist/{chunk-PYRS74YP.js → chunk-ZNY4DSFU.js} +16 -13
- package/dist/{chunk-PYRS74YP.js.map → chunk-ZNY4DSFU.js.map} +1 -1
- package/dist/{chunk-SSICS5KI.js → chunk-ZU7RC7CT.js} +2 -2
- package/dist/client.d.ts +28 -10
- package/dist/client.js +150 -29
- package/dist/client.js.map +1 -1
- package/dist/compactor.d.ts +1 -1
- package/dist/compactor.js +3 -3
- package/dist/connector-jira.d.ts +13 -3
- package/dist/connector-jira.js +6 -2
- package/dist/connector-salesforce.d.ts +13 -3
- package/dist/connector-salesforce.js +6 -2
- package/dist/{coordinator-NXy6tA0h.d.ts → coordinator-eGmZMnJ_.d.ts} +99 -16
- package/dist/create-poller-Cc2MGfhh.d.ts +55 -0
- package/dist/factory-DFfR-030.d.ts +33 -0
- package/dist/gateway-server.d.ts +398 -95
- package/dist/gateway-server.js +743 -56
- package/dist/gateway-server.js.map +1 -1
- package/dist/gateway.d.ts +14 -8
- package/dist/gateway.js +6 -5
- package/dist/index.d.ts +45 -73
- package/dist/index.js +5 -3
- package/dist/parquet.js +2 -2
- package/dist/proto.js +2 -2
- package/dist/react.d.ts +3 -3
- package/dist/{registry-BcspAtZI.d.ts → registry-Dd8JuW8T.d.ts} +1 -1
- package/dist/{request-handler-pUvL7ozF.d.ts → request-handler-B1I5xDOx.d.ts} +71 -27
- package/dist/{src-ROW4XLO7.js → src-WU7IBVC4.js} +6 -4
- package/dist/{types-BrcD1oJg.d.ts → types-D2C9jTbL.d.ts} +33 -23
- package/package.json +1 -1
- package/dist/auth-CAVutXzx.d.ts +0 -30
- package/dist/chunk-JI4C4R5H.js.map +0 -1
- package/dist/chunk-LDFFCG2K.js.map +0 -1
- package/dist/chunk-LPWXOYNS.js.map +0 -1
- package/dist/db-types-CfLMUBfW.d.ts +0 -29
- package/dist/src-B6NLV3FP.js +0 -27
- package/dist/src-ROW4XLO7.js.map +0 -1
- package/dist/src-ZRHKG42A.js +0 -25
- package/dist/src-ZRHKG42A.js.map +0 -1
- package/dist/types-DSC_EiwR.d.ts +0 -45
- /package/dist/{chunk-TMLG32QV.js.map → chunk-U2NV4DUX.js.map} +0 -0
- /package/dist/{chunk-KVSWLIJR.js.map → chunk-YHYBLU6W.js.map} +0 -0
- /package/dist/{chunk-SSICS5KI.js.map → chunk-ZU7RC7CT.js.map} +0 -0
- /package/dist/{src-B6NLV3FP.js.map → src-WU7IBVC4.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../gateway/src/idempotency-cache.ts","../../gateway/src/action-dispatcher.ts","../../gateway/src/buffer.ts","../../gateway/src/config-store.ts","../../gateway/src/constants.ts","../../gateway/src/flush.ts","../../gateway/src/flush-coordinator.ts","../../gateway/src/source-registry.ts","../../gateway/src/gateway.ts","../../gateway/src/validation.ts","../../gateway/src/request-handler.ts","../../gateway/src/schema-manager.ts"],"sourcesContent":["import type { ActionResult } from \"@lakesync/core\";\n\n/** Cached action result — either a successful result or an error descriptor. */\nexport type CachedActionResult =\n\t| ActionResult\n\t| { actionId: string; code: string; message: string; retryable: boolean };\n\n/**\n * Interface for idempotency caching of action results.\n *\n * Implementations store action results keyed by actionId and optional\n * idempotencyKey, enabling deduplication of repeated action dispatches.\n */\nexport interface IdempotencyCache {\n\t/** Check whether an action ID has been executed. */\n\thas(actionId: string): boolean;\n\t/** Get a cached result by action ID or idempotency key. Returns `undefined` if not found or expired. */\n\tget(key: string): CachedActionResult | undefined;\n\t/** Cache an action result. Also stores by idempotencyKey if provided. */\n\tset(actionId: string, result: CachedActionResult, idempotencyKey?: string): void;\n}\n\n/** Default maximum number of cached action results. */\nconst DEFAULT_MAX_CACHE_SIZE = 10_000;\n\n/** Default TTL for idempotency cache entries (5 minutes). */\nconst DEFAULT_CACHE_TTL_MS = 5 * 60 * 1000;\n\n/** Configuration for {@link MemoryIdempotencyCache}. */\nexport interface IdempotencyCacheConfig {\n\t/** Maximum number of entries in the cache. */\n\tmaxSize?: number;\n\t/** Time-to-live for cache entries in milliseconds. */\n\tttlMs?: number;\n}\n\n/** Cached action result with a timestamp for TTL eviction. */\ninterface CachedEntry {\n\tvalue: CachedActionResult;\n\tcachedAt: number;\n}\n\n/**\n * In-memory idempotency cache with TTL expiration and bounded size.\n *\n * All state lives in a single Map keyed by actionId or `idem:{idempotencyKey}`.\n * Stale entries are evicted on every `set()` call and the cache is\n * trimmed to the configured max size (counting only non-idem entries).\n */\nexport class MemoryIdempotencyCache implements IdempotencyCache {\n\tprivate readonly entries: Map<string, CachedEntry> = new Map();\n\tprivate readonly maxSize: number;\n\tprivate readonly ttlMs: number;\n\n\tconstructor(config?: IdempotencyCacheConfig) {\n\t\tthis.maxSize = config?.maxSize ?? DEFAULT_MAX_CACHE_SIZE;\n\t\tthis.ttlMs = config?.ttlMs ?? DEFAULT_CACHE_TTL_MS;\n\t}\n\n\t/** {@inheritDoc IdempotencyCache.has} */\n\thas(actionId: string): boolean {\n\t\tconst entry = this.entries.get(actionId);\n\t\tif (!entry) return false;\n\t\tif (Date.now() - entry.cachedAt > this.ttlMs) {\n\t\t\tthis.entries.delete(actionId);\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t}\n\n\t/** {@inheritDoc IdempotencyCache.get} */\n\tget(key: string): CachedActionResult | undefined {\n\t\tconst entry = this.entries.get(key);\n\t\tif (!entry) return undefined;\n\t\tif (Date.now() - entry.cachedAt > this.ttlMs) {\n\t\t\tthis.entries.delete(key);\n\t\t\treturn undefined;\n\t\t}\n\t\treturn entry.value;\n\t}\n\n\t/** {@inheritDoc IdempotencyCache.set} */\n\tset(actionId: string, result: CachedActionResult, idempotencyKey?: string): void {\n\t\tthis.evictStaleEntries();\n\n\t\tconst entry: CachedEntry = { value: result, cachedAt: Date.now() };\n\t\tthis.entries.set(actionId, entry);\n\t\tif (idempotencyKey) {\n\t\t\tthis.entries.set(`idem:${idempotencyKey}`, entry);\n\t\t}\n\t}\n\n\t/** Evict expired entries and trim to max size (counting only non-idem entries). */\n\tprivate evictStaleEntries(): void {\n\t\tconst now = Date.now();\n\n\t\t// Evict expired entries\n\t\tfor (const [key, entry] of this.entries) {\n\t\t\tif (now - entry.cachedAt > this.ttlMs) {\n\t\t\t\tthis.entries.delete(key);\n\t\t\t}\n\t\t}\n\n\t\t// Trim to max size — count only non-idem entries\n\t\tconst actionKeys = [...this.entries.keys()].filter((k) => !k.startsWith(\"idem:\"));\n\t\tif (actionKeys.length > this.maxSize) {\n\t\t\tconst excess = actionKeys.length - this.maxSize;\n\t\t\tfor (let i = 0; i < excess; i++) {\n\t\t\t\tthis.entries.delete(actionKeys[i]!);\n\t\t\t}\n\t\t}\n\t}\n}\n","import type {\n\tActionDescriptor,\n\tActionDiscovery,\n\tActionExecutionError,\n\tActionHandler,\n\tActionPush,\n\tActionResponse,\n\tActionValidationError,\n\tAuthContext,\n\tHLCTimestamp,\n\tResult,\n} from \"@lakesync/core\";\nimport { Err, Ok, validateAction } from \"@lakesync/core\";\nimport {\n\ttype CachedActionResult,\n\ttype IdempotencyCache,\n\ttype IdempotencyCacheConfig,\n\tMemoryIdempotencyCache,\n} from \"./idempotency-cache\";\n\n/** @deprecated Use {@link IdempotencyCacheConfig} instead. */\nexport type ActionCacheConfig = IdempotencyCacheConfig;\n\n/**\n * Dispatches imperative actions to registered handlers.\n *\n * Routing and handler management are separated from idempotency caching,\n * which is delegated to an {@link IdempotencyCache} instance.\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 readonly cache: IdempotencyCache;\n\n\t/**\n\t * Create an ActionDispatcher.\n\t *\n\t * @param handlers - Optional map of connector name to action handler.\n\t * @param cacheConfig - Optional cache configuration (used when no `cache` is provided).\n\t * @param cache - Optional pre-built idempotency cache; defaults to a {@link MemoryIdempotencyCache}.\n\t */\n\tconstructor(\n\t\thandlers?: Record<string, ActionHandler>,\n\t\tcacheConfig?: ActionCacheConfig,\n\t\tcache?: IdempotencyCache,\n\t) {\n\t\tif (handlers) {\n\t\t\tfor (const [name, handler] of Object.entries(handlers)) {\n\t\t\t\tthis.actionHandlers.set(name, handler);\n\t\t\t}\n\t\t}\n\t\tthis.cache = cache ?? new MemoryIdempotencyCache(cacheConfig);\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<CachedActionResult> = [];\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.cache.has(action.actionId)) {\n\t\t\t\tconst cached = this.cache.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.cache.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.cache.set(action.actionId, errorResult, action.idempotencyKey);\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.cache.set(action.actionId, errorResult, action.idempotencyKey);\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.cache.set(action.actionId, execResult.value, action.idempotencyKey);\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.cache.set(action.actionId, errorResult, action.idempotencyKey);\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","import type { HLCTimestamp, RowDelta, RowKey } from \"@lakesync/core\";\nimport { HLC, rowKey } from \"@lakesync/core\";\n\n/** Estimated base overhead per delta entry (metadata fields: deltaId, table, rowId, clientId, op + HLC bigint). */\nconst BASE_DELTA_OVERHEAD = 8 + 8 + 8 + 8 + 1;\n\n/**\n * Estimate the byte size of a single column value.\n * Uses type-aware heuristics as a proxy for in-memory size.\n */\nfunction estimateValueBytes(value: unknown): number {\n\tif (value === null || value === undefined) return 4;\n\tswitch (typeof value) {\n\t\tcase \"boolean\":\n\t\t\treturn 4;\n\t\tcase \"number\":\n\t\t\treturn 8;\n\t\tcase \"bigint\":\n\t\t\treturn 8;\n\t\tcase \"string\":\n\t\t\treturn (value as string).length * 2; // UTF-16\n\t\tdefault:\n\t\t\t// Objects, arrays — use JSON.stringify as proxy\n\t\t\ttry {\n\t\t\t\treturn JSON.stringify(value).length;\n\t\t\t} catch {\n\t\t\t\treturn 100; // fallback for circular refs etc.\n\t\t\t}\n\t}\n}\n\n/** Estimate the byte size of a RowDelta. */\nfunction estimateDeltaBytes(delta: RowDelta): number {\n\tlet bytes = BASE_DELTA_OVERHEAD;\n\tbytes += delta.deltaId.length;\n\tbytes += delta.table.length * 2;\n\tbytes += delta.rowId.length * 2;\n\tbytes += delta.clientId.length * 2;\n\tfor (const col of delta.columns) {\n\t\tbytes += col.column.length * 2; // column name\n\t\tbytes += estimateValueBytes(col.value); // column value\n\t}\n\treturn bytes;\n}\n\n/**\n * Dual-structure delta buffer.\n *\n * Maintains an append-only log for event streaming (pull) and flush,\n * plus a row-level index for O(1) conflict resolution lookups.\n */\nexport class DeltaBuffer {\n\tprivate log: RowDelta[] = [];\n\tprivate index: Map<RowKey, RowDelta> = new Map();\n\tprivate deltaIds = new Set<string>();\n\tprivate estimatedBytes = 0;\n\tprivate createdAt: number = Date.now();\n\tprivate tableBytes = new Map<string, number>();\n\tprivate tableLog = new Map<string, RowDelta[]>();\n\n\t/** Append a delta to the log and upsert the index (post-conflict-resolution). */\n\tappend(delta: RowDelta): void {\n\t\tthis.log.push(delta);\n\t\tconst key = rowKey(delta.table, delta.rowId);\n\t\tthis.index.set(key, delta);\n\t\tthis.deltaIds.add(delta.deltaId);\n\t\tconst bytes = estimateDeltaBytes(delta);\n\t\tthis.estimatedBytes += bytes;\n\t\t// Per-table tracking\n\t\tthis.tableBytes.set(delta.table, (this.tableBytes.get(delta.table) ?? 0) + bytes);\n\t\tconst tableEntries = this.tableLog.get(delta.table);\n\t\tif (tableEntries) {\n\t\t\ttableEntries.push(delta);\n\t\t} else {\n\t\t\tthis.tableLog.set(delta.table, [delta]);\n\t\t}\n\t}\n\n\t/** Get the current merged state for a row (for conflict resolution). */\n\tgetRow(key: RowKey): RowDelta | undefined {\n\t\treturn this.index.get(key);\n\t}\n\n\t/** Check if a delta with this ID already exists in the log (for idempotency). */\n\thasDelta(deltaId: string): boolean {\n\t\treturn this.deltaIds.has(deltaId);\n\t}\n\n\t/** Return change events from the log since a given HLC. */\n\tgetEventsSince(hlc: HLCTimestamp, limit: number): { deltas: RowDelta[]; hasMore: boolean } {\n\t\tlet lo = 0;\n\t\tlet hi = this.log.length;\n\t\twhile (lo < hi) {\n\t\t\tconst mid = (lo + hi) >>> 1;\n\t\t\tif (HLC.compare(this.log[mid]!.hlc, hlc) <= 0) {\n\t\t\t\tlo = mid + 1;\n\t\t\t} else {\n\t\t\t\thi = mid;\n\t\t\t}\n\t\t}\n\t\tconst hasMore = this.log.length - lo > limit;\n\t\treturn { deltas: this.log.slice(lo, lo + limit), hasMore };\n\t}\n\n\t/** Check if the buffer should be flushed based on size or age thresholds. */\n\tshouldFlush(config: { maxBytes: number; maxAgeMs: number }): boolean {\n\t\tif (this.log.length === 0) return false;\n\t\treturn this.estimatedBytes >= config.maxBytes || Date.now() - this.createdAt >= config.maxAgeMs;\n\t}\n\n\t/** Per-table buffer statistics. */\n\ttableStats(): Array<{ table: string; byteSize: number; deltaCount: number }> {\n\t\tconst stats: Array<{ table: string; byteSize: number; deltaCount: number }> = [];\n\t\tfor (const [table, bytes] of this.tableBytes) {\n\t\t\tstats.push({\n\t\t\t\ttable,\n\t\t\t\tbyteSize: bytes,\n\t\t\t\tdeltaCount: this.tableLog.get(table)?.length ?? 0,\n\t\t\t});\n\t\t}\n\t\treturn stats;\n\t}\n\n\t/** Drain only the specified table's deltas, leaving other tables intact. */\n\tdrainTable(table: string): RowDelta[] {\n\t\tconst tableDeltas = this.tableLog.get(table) ?? [];\n\t\tif (tableDeltas.length === 0) return [];\n\n\t\t// Remove from main log\n\t\tthis.log = this.log.filter((d) => d.table !== table);\n\n\t\t// Remove from index and deltaIds\n\t\tfor (const delta of tableDeltas) {\n\t\t\tthis.index.delete(rowKey(delta.table, delta.rowId));\n\t\t\tthis.deltaIds.delete(delta.deltaId);\n\t\t}\n\n\t\t// Adjust byte tracking\n\t\tconst tableByteSize = this.tableBytes.get(table) ?? 0;\n\t\tthis.estimatedBytes -= tableByteSize;\n\t\tthis.tableBytes.delete(table);\n\t\tthis.tableLog.delete(table);\n\n\t\treturn tableDeltas;\n\t}\n\n\t/**\n\t * Snapshot the current buffer state without clearing it.\n\t *\n\t * Useful for inspecting the buffer contents without draining.\n\t * Use {@link clear} separately after a successful flush for\n\t * transactional semantics.\n\t */\n\tsnapshot(): { entries: RowDelta[]; byteSize: number } {\n\t\treturn { entries: [...this.log], byteSize: this.estimatedBytes };\n\t}\n\n\t/** Clear all buffer state. */\n\tclear(): void {\n\t\tthis.log = [];\n\t\tthis.index.clear();\n\t\tthis.deltaIds.clear();\n\t\tthis.estimatedBytes = 0;\n\t\tthis.createdAt = Date.now();\n\t\tthis.tableBytes.clear();\n\t\tthis.tableLog.clear();\n\t}\n\n\t/** Drain the log for flush. Returns log entries and clears both structures. */\n\tdrain(): RowDelta[] {\n\t\tconst { entries } = this.snapshot();\n\t\tthis.clear();\n\t\treturn entries;\n\t}\n\n\t/** Number of log entries */\n\tget logSize(): number {\n\t\treturn this.log.length;\n\t}\n\n\t/** Number of unique rows in the index */\n\tget indexSize(): number {\n\t\treturn this.index.size;\n\t}\n\n\t/** Estimated byte size of the buffer */\n\tget byteSize(): number {\n\t\treturn this.estimatedBytes;\n\t}\n\n\t/** Average byte size per delta in the buffer (0 if empty). */\n\tget averageDeltaBytes(): number {\n\t\treturn this.log.length === 0 ? 0 : this.estimatedBytes / this.log.length;\n\t}\n}\n","import type { ConnectorConfig, SyncRulesConfig, TableSchema } from \"@lakesync/core\";\n\n/**\n * Platform-agnostic configuration storage interface.\n *\n * Implemented by MemoryConfigStore (tests, gateway-server) and\n * DurableStorageConfigStore (gateway-worker).\n */\nexport interface ConfigStore {\n\tgetSchema(gatewayId: string): Promise<TableSchema | undefined>;\n\tsetSchema(gatewayId: string, schema: TableSchema): Promise<void>;\n\tgetSyncRules(gatewayId: string): Promise<SyncRulesConfig | undefined>;\n\tsetSyncRules(gatewayId: string, rules: SyncRulesConfig): Promise<void>;\n\tgetConnectors(): Promise<Record<string, ConnectorConfig>>;\n\tsetConnectors(connectors: Record<string, ConnectorConfig>): Promise<void>;\n}\n\n/**\n * In-memory implementation of ConfigStore.\n * Used by tests and gateway-server.\n */\nexport class MemoryConfigStore implements ConfigStore {\n\tprivate schemas = new Map<string, TableSchema>();\n\tprivate syncRules = new Map<string, SyncRulesConfig>();\n\tprivate connectors: Record<string, ConnectorConfig> = {};\n\n\tasync getSchema(gatewayId: string): Promise<TableSchema | undefined> {\n\t\treturn this.schemas.get(gatewayId);\n\t}\n\n\tasync setSchema(gatewayId: string, schema: TableSchema): Promise<void> {\n\t\tthis.schemas.set(gatewayId, schema);\n\t}\n\n\tasync getSyncRules(gatewayId: string): Promise<SyncRulesConfig | undefined> {\n\t\treturn this.syncRules.get(gatewayId);\n\t}\n\n\tasync setSyncRules(gatewayId: string, rules: SyncRulesConfig): Promise<void> {\n\t\tthis.syncRules.set(gatewayId, rules);\n\t}\n\n\tasync getConnectors(): Promise<Record<string, ConnectorConfig>> {\n\t\treturn { ...this.connectors };\n\t}\n\n\tasync setConnectors(connectors: Record<string, ConnectorConfig>): Promise<void> {\n\t\tthis.connectors = { ...connectors };\n\t}\n}\n","import { COLUMN_TYPES } from \"@lakesync/core\";\n\n/** Maximum push payload size (1 MiB). */\nexport const MAX_PUSH_PAYLOAD_BYTES = 1_048_576;\n\n/** Maximum number of deltas allowed in a single push. */\nexport const MAX_DELTAS_PER_PUSH = 10_000;\n\n/** Maximum number of deltas returned in a single pull. */\nexport const MAX_PULL_LIMIT = 10_000;\n\n/** Default number of deltas returned in a pull when no limit is specified. */\nexport const DEFAULT_PULL_LIMIT = 100;\n\n/** Allowed column types for schema validation. Derived from core COLUMN_TYPES. */\nexport const VALID_COLUMN_TYPES: ReadonlySet<string> = new Set(COLUMN_TYPES);\n\n/** Default maximum buffer size before triggering flush (4 MiB). */\nexport const DEFAULT_MAX_BUFFER_BYTES = 4 * 1024 * 1024;\n\n/** Default maximum buffer age before triggering flush (30 seconds). */\nexport const DEFAULT_MAX_BUFFER_AGE_MS = 30_000;\n","import {\n\tbuildPartitionSpec,\n\ttype DataFile,\n\tlakeSyncTableName,\n\ttype NessieCatalogueClient,\n\ttableSchemaToIceberg,\n} from \"@lakesync/catalogue\";\nimport {\n\ttype DatabaseAdapter,\n\tErr,\n\tFlushError,\n\tHLC,\n\ttype HLCTimestamp,\n\tisDatabaseAdapter,\n\tisMaterialisable,\n\ttype LakeAdapter,\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\t/** Optional callback invoked when materialisation fails. Useful for metrics/alerting. */\n\tonMaterialisationFailure?: (table: string, deltaCount: number, error: Error) => void;\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/** Strategy for flushing deltas to a specific adapter type. */\nexport interface FlushStrategy {\n\t/** Flush entries to the target adapter. */\n\tflush(\n\t\tentries: RowDelta[],\n\t\tbyteSize: number,\n\t\tdeps: FlushDeps,\n\t\tkeyPrefix?: string,\n\t): Promise<Result<void, FlushError>>;\n}\n\n/**\n * Notify the onMaterialisationFailure callback if configured.\n * Extracts unique table names from deltas for per-table reporting.\n */\nfunction notifyMaterialisationFailure(\n\tentries: RowDelta[],\n\terror: Error,\n\tconfig: FlushConfig,\n): void {\n\tif (!config.onMaterialisationFailure) return;\n\tconst tables = new Set(entries.map((e) => e.table));\n\tfor (const table of tables) {\n\t\tconst count = entries.filter((e) => e.table === table).length;\n\t\tconfig.onMaterialisationFailure(table, count, error);\n\t}\n}\n\n/** Strategy for flushing deltas to a DatabaseAdapter (batch INSERT). */\nclass DatabaseFlushStrategy implements FlushStrategy {\n\tasync flush(\n\t\tentries: RowDelta[],\n\t\t_byteSize: number,\n\t\tdeps: FlushDeps,\n\t): Promise<Result<void, FlushError>> {\n\t\tconst adapter = deps.adapter as DatabaseAdapter;\n\t\ttry {\n\t\t\tconst result = await 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(adapter)) {\n\t\t\t\ttry {\n\t\t\t\t\tconst matResult = await adapter.materialise(entries, deps.schemas);\n\t\t\t\t\tif (!matResult.ok) {\n\t\t\t\t\t\tconst error = new Error(matResult.error.message);\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\tnotifyMaterialisationFailure(entries, error, deps.config);\n\t\t\t\t\t}\n\t\t\t\t} catch (error: unknown) {\n\t\t\t\t\tconst err = error instanceof Error ? error : new Error(String(error));\n\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t`[lakesync] Materialisation error (${entries.length} deltas): ${err.message}`,\n\t\t\t\t\t);\n\t\t\t\t\tnotifyMaterialisationFailure(entries, err, deps.config);\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\n/** Strategy for flushing deltas to a LakeAdapter as JSON. */\nclass LakeJsonFlushStrategy implements FlushStrategy {\n\tasync flush(\n\t\tentries: RowDelta[],\n\t\tbyteSize: number,\n\t\tdeps: FlushDeps,\n\t\tkeyPrefix?: string,\n\t): Promise<Result<void, FlushError>> {\n\t\tconst adapter = deps.adapter as LakeAdapter;\n\t\ttry {\n\t\t\tconst { min, max } = hlcRange(entries);\n\t\t\tconst date = new Date().toISOString().split(\"T\")[0];\n\t\t\tconst prefix = keyPrefix ? `${keyPrefix}-` : \"\";\n\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\tconst objectKey = `deltas/${date}/${deps.config.gatewayId}/${prefix}${min.toString()}-${max.toString()}.json`;\n\t\t\tconst data = new TextEncoder().encode(JSON.stringify(envelope, bigintReplacer));\n\n\t\t\tconst result = await adapter.putObject(objectKey, data, \"application/json\");\n\t\t\tif (!result.ok) {\n\t\t\t\tdeps.restoreEntries(entries);\n\t\t\t\treturn Err(new FlushError(`Failed to write flush envelope: ${result.error.message}`));\n\t\t\t}\n\n\t\t\tif (deps.config.catalogue && deps.config.tableSchema) {\n\t\t\t\tawait commitToCatalogue(\n\t\t\t\t\tobjectKey,\n\t\t\t\t\tdata.byteLength,\n\t\t\t\t\tentries.length,\n\t\t\t\t\tdeps.config.catalogue,\n\t\t\t\t\tdeps.config.tableSchema,\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 flush failure: ${toError(error).message}`));\n\t\t}\n\t}\n}\n\n/** Strategy for flushing deltas to a LakeAdapter as Parquet. */\nclass LakeParquetFlushStrategy implements FlushStrategy {\n\tasync flush(\n\t\tentries: RowDelta[],\n\t\t_byteSize: number,\n\t\tdeps: FlushDeps,\n\t\tkeyPrefix?: string,\n\t): Promise<Result<void, FlushError>> {\n\t\tconst adapter = deps.adapter as LakeAdapter;\n\t\ttry {\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\tconst { min, max } = hlcRange(entries);\n\t\t\tconst date = new Date().toISOString().split(\"T\")[0];\n\t\t\tconst prefix = keyPrefix ? `${keyPrefix}-` : \"\";\n\t\t\tconst objectKey = `deltas/${date}/${deps.config.gatewayId}/${prefix}${min.toString()}-${max.toString()}.parquet`;\n\t\t\tconst data = parquetResult.value;\n\n\t\t\tconst result = await adapter.putObject(objectKey, data, \"application/vnd.apache.parquet\");\n\t\t\tif (!result.ok) {\n\t\t\t\tdeps.restoreEntries(entries);\n\t\t\t\treturn Err(new FlushError(`Failed to write flush envelope: ${result.error.message}`));\n\t\t\t}\n\n\t\t\tif (deps.config.catalogue && deps.config.tableSchema) {\n\t\t\t\tawait commitToCatalogue(\n\t\t\t\t\tobjectKey,\n\t\t\t\t\tdata.byteLength,\n\t\t\t\t\tentries.length,\n\t\t\t\t\tdeps.config.catalogue,\n\t\t\t\t\tdeps.config.tableSchema,\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 flush failure: ${toError(error).message}`));\n\t\t}\n\t}\n}\n\n// Module-level singleton instances (strategies are stateless).\nconst databaseStrategy: FlushStrategy = new DatabaseFlushStrategy();\nconst lakeJsonStrategy: FlushStrategy = new LakeJsonFlushStrategy();\nconst lakeParquetStrategy: FlushStrategy = new LakeParquetFlushStrategy();\n\n/** Select the appropriate flush strategy based on adapter type and format. */\nfunction selectFlushStrategy(\n\tadapter: LakeAdapter | DatabaseAdapter,\n\tformat?: string,\n): FlushStrategy {\n\tif (isDatabaseAdapter(adapter)) return databaseStrategy;\n\tif (format === \"json\") return lakeJsonStrategy;\n\treturn lakeParquetStrategy;\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\tconst strategy = selectFlushStrategy(deps.adapter, deps.config.flushFormat);\n\treturn strategy.flush(entries, byteSize, deps, keyPrefix);\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 {\n\ttype DatabaseAdapter,\n\tErr,\n\tFlushError,\n\tisDatabaseAdapter,\n\ttype LakeAdapter,\n\tOk,\n\ttype Result,\n\ttype RowDelta,\n\ttype TableSchema,\n} from \"@lakesync/core\";\nimport type { DeltaBuffer } from \"./buffer\";\nimport type { FlushConfig } from \"./flush\";\nimport { flushEntries } from \"./flush\";\n\n/** Dependencies for flush operations. */\nexport interface FlushCoordinatorDeps {\n\t/** Gateway configuration for flush. */\n\tconfig: FlushConfig;\n\t/** Table schemas for materialisation after flush. */\n\tschemas?: ReadonlyArray<TableSchema>;\n}\n\n/**\n * Coordinates flush operations from the buffer to the adapter.\n *\n * Owns the flushing state to prevent concurrent flushes and handles\n * entry restoration on failure.\n */\nexport class FlushCoordinator {\n\tprivate flushing = false;\n\n\t/** Whether a flush is currently in progress. */\n\tget isFlushing(): boolean {\n\t\treturn this.flushing;\n\t}\n\n\t/**\n\t * Flush all entries from the buffer to the adapter.\n\t *\n\t * Drains the buffer first, then writes to the adapter. On failure,\n\t * entries are restored to the buffer.\n\t */\n\tasync flush(\n\t\tbuffer: DeltaBuffer,\n\t\tadapter: LakeAdapter | DatabaseAdapter | null,\n\t\tdeps: FlushCoordinatorDeps,\n\t): Promise<Result<void, FlushError>> {\n\t\tif (this.flushing) {\n\t\t\treturn Err(new FlushError(\"Flush already in progress\"));\n\t\t}\n\t\tif (buffer.logSize === 0) {\n\t\t\treturn Ok(undefined);\n\t\t}\n\t\tif (!adapter) {\n\t\t\treturn Err(new FlushError(\"No adapter configured\"));\n\t\t}\n\n\t\tthis.flushing = true;\n\n\t\tconst byteSize = isDatabaseAdapter(adapter) ? 0 : buffer.byteSize;\n\t\tconst entries = buffer.drain();\n\t\tif (entries.length === 0) {\n\t\t\tthis.flushing = false;\n\t\t\treturn Ok(undefined);\n\t\t}\n\n\t\ttry {\n\t\t\treturn await flushEntries(entries, byteSize, {\n\t\t\t\tadapter,\n\t\t\t\tconfig: deps.config,\n\t\t\t\trestoreEntries: (e) => this.restoreEntries(buffer, e),\n\t\t\t\tschemas: deps.schemas,\n\t\t\t});\n\t\t} finally {\n\t\t\tthis.flushing = false;\n\t\t}\n\t}\n\n\t/**\n\t * Flush a single table's deltas from the buffer.\n\t *\n\t * Drains only the specified table's deltas and flushes them,\n\t * leaving other tables in the buffer.\n\t */\n\tasync flushTable(\n\t\ttable: string,\n\t\tbuffer: DeltaBuffer,\n\t\tadapter: LakeAdapter | DatabaseAdapter | null,\n\t\tdeps: FlushCoordinatorDeps,\n\t): Promise<Result<void, FlushError>> {\n\t\tif (this.flushing) {\n\t\t\treturn Err(new FlushError(\"Flush already in progress\"));\n\t\t}\n\t\tif (!adapter) {\n\t\t\treturn Err(new FlushError(\"No adapter configured\"));\n\t\t}\n\n\t\tconst entries = buffer.drainTable(table);\n\t\tif (entries.length === 0) {\n\t\t\treturn Ok(undefined);\n\t\t}\n\n\t\tthis.flushing = true;\n\n\t\ttry {\n\t\t\treturn await flushEntries(\n\t\t\t\tentries,\n\t\t\t\t0,\n\t\t\t\t{\n\t\t\t\t\tadapter,\n\t\t\t\t\tconfig: deps.config,\n\t\t\t\t\trestoreEntries: (e) => this.restoreEntries(buffer, e),\n\t\t\t\t\tschemas: deps.schemas,\n\t\t\t\t},\n\t\t\t\ttable,\n\t\t\t);\n\t\t} finally {\n\t\t\tthis.flushing = false;\n\t\t}\n\t}\n\n\t/** Restore drained entries back to the buffer for retry. */\n\tprivate restoreEntries(buffer: DeltaBuffer, entries: RowDelta[]): void {\n\t\tfor (const entry of entries) {\n\t\t\tbuffer.append(entry);\n\t\t}\n\t}\n}\n","import type { DatabaseAdapter } from \"@lakesync/core\";\n\n/**\n * Registry for named source adapters used in adapter-sourced pulls.\n *\n * Manages the mapping of source names to DatabaseAdapter instances,\n * decoupling source adapter management from the gateway.\n */\nexport class SourceRegistry {\n\tprivate sources: Map<string, DatabaseAdapter> = new Map();\n\n\tconstructor(initial?: Record<string, DatabaseAdapter>) {\n\t\tif (initial) {\n\t\t\tfor (const [name, adapter] of Object.entries(initial)) {\n\t\t\t\tthis.sources.set(name, adapter);\n\t\t\t}\n\t\t}\n\t}\n\n\t/** Register a named source adapter. */\n\tregister(name: string, adapter: DatabaseAdapter): void {\n\t\tthis.sources.set(name, adapter);\n\t}\n\n\t/** Unregister a named source adapter. */\n\tunregister(name: string): void {\n\t\tthis.sources.delete(name);\n\t}\n\n\t/** Get a source adapter by name, or undefined if not registered. */\n\tget(name: string): DatabaseAdapter | undefined {\n\t\treturn this.sources.get(name);\n\t}\n\n\t/** List all registered source adapter names. */\n\tlist(): string[] {\n\t\treturn [...this.sources.keys()];\n\t}\n}\n","import {\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\ttype DatabaseAdapter,\n\tErr,\n\ttype FlushError,\n\tfilterDeltas,\n\tHLC,\n\ttype IngestTarget,\n\ttype LakeAdapter,\n\tOk,\n\ttype Result,\n\ttype RowDelta,\n\tresolveLWW,\n\trowKey,\n\ttype SchemaError,\n\ttype SyncPull,\n\ttype SyncPush,\n\ttype SyncResponse,\n\ttype SyncRulesContext,\n} from \"@lakesync/core\";\nimport { ActionDispatcher } from \"./action-dispatcher\";\nimport { DeltaBuffer } from \"./buffer\";\nimport { FlushCoordinator } from \"./flush-coordinator\";\nimport { SourceRegistry } from \"./source-registry\";\nimport type { GatewayConfig, HandlePushResult } from \"./types\";\n\nexport type { SyncPush, SyncPull, SyncResponse };\n\n/**\n * Sync gateway -- coordinates delta ingestion, conflict resolution, and flush.\n *\n * Thin facade composing DeltaBuffer, ActionDispatcher, SourceRegistry,\n * and FlushCoordinator. Public methods delegate to composed modules.\n */\nexport class SyncGateway implements IngestTarget {\n\tprivate hlc: HLC;\n\treadonly buffer: DeltaBuffer;\n\treadonly actions: ActionDispatcher;\n\tprivate config: GatewayConfig;\n\tprivate adapter: LakeAdapter | DatabaseAdapter | null;\n\tprivate readonly sources: SourceRegistry;\n\tprivate readonly flushCoordinator: FlushCoordinator;\n\n\tconstructor(config: GatewayConfig, adapter?: LakeAdapter | DatabaseAdapter) {\n\t\tthis.config = { sourceAdapters: {}, ...config };\n\t\tthis.hlc = new HLC();\n\t\tthis.buffer = new DeltaBuffer();\n\t\tthis.adapter = this.config.adapter ?? adapter ?? null;\n\t\tthis.actions = new ActionDispatcher(config.actionHandlers);\n\t\tthis.sources = new SourceRegistry(this.config.sourceAdapters);\n\t\tthis.flushCoordinator = new FlushCoordinator();\n\t}\n\n\t// -----------------------------------------------------------------------\n\t// Push — pipeline of validation steps then buffer append\n\t// -----------------------------------------------------------------------\n\n\t/**\n\t * Handle an incoming push from a client.\n\t *\n\t * Validates HLC drift, resolves conflicts via LWW, and appends to the buffer.\n\t *\n\t * @param msg - The push message containing client deltas.\n\t * @returns A `Result` with the new server HLC and accepted count,\n\t * or a `ClockDriftError` if the client clock is too far ahead.\n\t */\n\thandlePush(\n\t\tmsg: SyncPush,\n\t): Result<HandlePushResult, ClockDriftError | SchemaError | BackpressureError> {\n\t\t// Step 1: Check backpressure\n\t\tconst bpResult = this.checkBackpressure();\n\t\tif (!bpResult.ok) return bpResult;\n\n\t\tlet accepted = 0;\n\t\tconst ingested: RowDelta[] = [];\n\n\t\tfor (const delta of msg.deltas) {\n\t\t\t// Step 2: Filter duplicates\n\t\t\tif (this.buffer.hasDelta(delta.deltaId)) {\n\t\t\t\taccepted++;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// Step 3: Validate schema\n\t\t\tif (this.config.schemaManager) {\n\t\t\t\tconst schemaResult = this.config.schemaManager.validateDelta(delta);\n\t\t\t\tif (!schemaResult.ok) {\n\t\t\t\t\treturn Err(schemaResult.error);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Step 4: Validate HLC\n\t\t\tconst recvResult = this.hlc.recv(delta.hlc);\n\t\t\tif (!recvResult.ok) {\n\t\t\t\treturn Err(recvResult.error);\n\t\t\t}\n\n\t\t\t// Step 5: Resolve conflicts + append\n\t\t\tconst key = rowKey(delta.table, delta.rowId);\n\t\t\tconst existing = this.buffer.getRow(key);\n\n\t\t\tif (existing) {\n\t\t\t\tconst resolved = resolveLWW(existing, delta);\n\t\t\t\tif (resolved.ok) {\n\t\t\t\t\tthis.buffer.append(resolved.value);\n\t\t\t\t\tingested.push(resolved.value);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tthis.buffer.append(delta);\n\t\t\t\tingested.push(delta);\n\t\t\t}\n\n\t\t\taccepted++;\n\t\t}\n\n\t\tconst serverHlc = this.hlc.now();\n\t\treturn Ok({ serverHlc, accepted, deltas: ingested });\n\t}\n\n\t/** Check buffer backpressure. */\n\tprivate checkBackpressure(): Result<void, BackpressureError> {\n\t\tconst backpressureLimit = this.config.maxBackpressureBytes ?? this.config.maxBufferBytes * 2;\n\t\tif (this.buffer.byteSize >= backpressureLimit) {\n\t\t\treturn Err(\n\t\t\t\tnew BackpressureError(\n\t\t\t\t\t`Buffer backpressure exceeded (${this.buffer.byteSize} >= ${backpressureLimit} bytes)`,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\t\treturn Ok(undefined);\n\t}\n\n\t// -----------------------------------------------------------------------\n\t// Pull — delegates to buffer or source registry\n\t// -----------------------------------------------------------------------\n\n\t/**\n\t * Handle a pull request from a client.\n\t *\n\t * When `msg.source` is set, pulls deltas from the named source adapter\n\t * instead of the in-memory buffer. Otherwise, returns change events\n\t * from the log since the given HLC. When a {@link SyncRulesContext} is\n\t * provided, deltas are post-filtered by the client's bucket definitions\n\t * and JWT claims. The buffer path over-fetches (3x the requested limit)\n\t * and retries up to 5 times to fill the page.\n\t *\n\t * @param msg - The pull message specifying the cursor and limit.\n\t * @param context - Optional sync rules context for row-level filtering.\n\t * @returns A `Result` containing the matching deltas, server HLC, and pagination flag.\n\t */\n\thandlePull(\n\t\tmsg: SyncPull & { source: string },\n\t\tcontext?: SyncRulesContext,\n\t): Promise<Result<SyncResponse, AdapterNotFoundError | AdapterError>>;\n\thandlePull(msg: SyncPull, context?: SyncRulesContext): Result<SyncResponse, never>;\n\thandlePull(\n\t\tmsg: SyncPull,\n\t\tcontext?: SyncRulesContext,\n\t):\n\t\t| Promise<Result<SyncResponse, AdapterNotFoundError | AdapterError>>\n\t\t| Result<SyncResponse, never> {\n\t\tif (msg.source) {\n\t\t\treturn this.handleAdapterPull(msg, context);\n\t\t}\n\n\t\treturn this.handleBufferPull(msg, context);\n\t}\n\n\t/** Pull from the in-memory buffer (original path). */\n\tprivate handleBufferPull(msg: SyncPull, context?: SyncRulesContext): Result<SyncResponse, never> {\n\t\tif (!context) {\n\t\t\tconst { deltas, hasMore } = this.buffer.getEventsSince(msg.sinceHlc, msg.maxDeltas);\n\t\t\tconst serverHlc = this.hlc.now();\n\t\t\treturn Ok({ deltas, serverHlc, hasMore });\n\t\t}\n\n\t\t// Over-fetch and filter with bounded retry\n\t\tconst maxRetries = 5;\n\t\tconst overFetchMultiplier = 3;\n\t\tlet cursor = msg.sinceHlc;\n\t\tconst collected: RowDelta[] = [];\n\n\t\tfor (let attempt = 0; attempt < maxRetries; attempt++) {\n\t\t\tconst fetchLimit = msg.maxDeltas * overFetchMultiplier;\n\t\t\tconst { deltas: raw, hasMore: rawHasMore } = this.buffer.getEventsSince(cursor, fetchLimit);\n\n\t\t\tif (raw.length === 0) {\n\t\t\t\tconst serverHlc = this.hlc.now();\n\t\t\t\treturn Ok({ deltas: collected, serverHlc, hasMore: false });\n\t\t\t}\n\n\t\t\tconst filtered = filterDeltas(raw, context);\n\t\t\tcollected.push(...filtered);\n\n\t\t\tif (collected.length >= msg.maxDeltas) {\n\t\t\t\tconst trimmed = collected.slice(0, msg.maxDeltas);\n\t\t\t\tconst serverHlc = this.hlc.now();\n\t\t\t\treturn Ok({ deltas: trimmed, serverHlc, hasMore: true });\n\t\t\t}\n\n\t\t\tif (!rawHasMore) {\n\t\t\t\tconst serverHlc = this.hlc.now();\n\t\t\t\treturn Ok({ deltas: collected, serverHlc, hasMore: false });\n\t\t\t}\n\n\t\t\tcursor = raw[raw.length - 1]!.hlc;\n\t\t}\n\n\t\t// Exhausted retries — return what we have\n\t\tconst serverHlc = this.hlc.now();\n\t\tconst hasMore = collected.length >= msg.maxDeltas;\n\t\tconst trimmed = collected.slice(0, msg.maxDeltas);\n\t\treturn Ok({ deltas: trimmed, serverHlc, hasMore });\n\t}\n\n\t/** Pull from a named source adapter. */\n\tprivate async handleAdapterPull(\n\t\tmsg: SyncPull,\n\t\tcontext?: SyncRulesContext,\n\t): Promise<Result<SyncResponse, AdapterNotFoundError | AdapterError>> {\n\t\tconst adapter = this.sources.get(msg.source!);\n\t\tif (!adapter) {\n\t\t\treturn Err(new AdapterNotFoundError(`Source adapter \"${msg.source}\" not found`));\n\t\t}\n\n\t\tconst queryResult = await adapter.queryDeltasSince(msg.sinceHlc);\n\t\tif (!queryResult.ok) {\n\t\t\treturn Err(queryResult.error);\n\t\t}\n\n\t\tlet deltas = queryResult.value;\n\n\t\tif (context) {\n\t\t\tdeltas = filterDeltas(deltas, context);\n\t\t}\n\n\t\tconst hasMore = deltas.length > msg.maxDeltas;\n\t\tconst sliced = deltas.slice(0, msg.maxDeltas);\n\n\t\tconst serverHlc = this.hlc.now();\n\t\treturn Ok({ deltas: sliced, serverHlc, hasMore });\n\t}\n\n\t// -----------------------------------------------------------------------\n\t// Flush — delegates to FlushCoordinator\n\t// -----------------------------------------------------------------------\n\n\t/**\n\t * Flush the buffer to the configured adapter.\n\t *\n\t * Writes deltas as either a Parquet file (default) or a JSON\n\t * {@link FlushEnvelope} to the adapter, depending on\n\t * `config.flushFormat`. If the write fails, the buffer entries\n\t * are restored so they can be retried.\n\t *\n\t * @returns A `Result` indicating success or a `FlushError`.\n\t */\n\tasync flush(): Promise<Result<void, FlushError>> {\n\t\treturn this.flushCoordinator.flush(this.buffer, this.adapter, {\n\t\t\tconfig: {\n\t\t\t\tgatewayId: this.config.gatewayId,\n\t\t\t\tflushFormat: this.config.flushFormat,\n\t\t\t\ttableSchema: this.config.tableSchema,\n\t\t\t\tcatalogue: this.config.catalogue,\n\t\t\t},\n\t\t\tschemas: this.config.schemas,\n\t\t});\n\t}\n\n\t/**\n\t * Flush a single table's deltas from the buffer.\n\t *\n\t * Drains only the specified table's deltas and flushes them,\n\t * leaving other tables in the buffer.\n\t */\n\tasync flushTable(table: string): Promise<Result<void, FlushError>> {\n\t\treturn this.flushCoordinator.flushTable(table, this.buffer, this.adapter, {\n\t\t\tconfig: {\n\t\t\t\tgatewayId: this.config.gatewayId,\n\t\t\t\tflushFormat: this.config.flushFormat,\n\t\t\t\ttableSchema: this.config.tableSchema,\n\t\t\t\tcatalogue: this.config.catalogue,\n\t\t\t},\n\t\t\tschemas: this.config.schemas,\n\t\t});\n\t}\n\n\t// -----------------------------------------------------------------------\n\t// Actions — delegates to ActionDispatcher\n\t// -----------------------------------------------------------------------\n\n\t/** Handle an incoming action push from a client. */\n\tasync handleAction(\n\t\tmsg: ActionPush,\n\t\tcontext?: AuthContext,\n\t): Promise<Result<ActionResponse, ActionValidationError>> {\n\t\treturn this.actions.dispatch(msg, () => this.hlc.now(), context);\n\t}\n\n\t/** Register a named action handler. */\n\tregisterActionHandler(name: string, handler: ActionHandler): void {\n\t\tthis.actions.registerHandler(name, handler);\n\t}\n\n\t/** Unregister a named action handler. */\n\tunregisterActionHandler(name: string): void {\n\t\tthis.actions.unregisterHandler(name);\n\t}\n\n\t/** List all registered action handler names. */\n\tlistActionHandlers(): string[] {\n\t\treturn this.actions.listHandlers();\n\t}\n\n\t/** Describe all registered action handlers and their supported actions. */\n\tdescribeActions(): ActionDiscovery {\n\t\treturn this.actions.describe();\n\t}\n\n\t// -----------------------------------------------------------------------\n\t// Source adapters — delegates to SourceRegistry\n\t// -----------------------------------------------------------------------\n\n\t/**\n\t * Register a named source adapter for adapter-sourced pulls.\n\t *\n\t * @param name - Unique source name (used as the `source` parameter in pull requests).\n\t * @param adapter - The database adapter to register.\n\t */\n\tregisterSource(name: string, adapter: DatabaseAdapter): void {\n\t\tthis.sources.register(name, adapter);\n\t}\n\n\t/**\n\t * Unregister a named source adapter.\n\t *\n\t * @param name - The source name to remove.\n\t */\n\tunregisterSource(name: string): void {\n\t\tthis.sources.unregister(name);\n\t}\n\n\t/**\n\t * List all registered source adapter names.\n\t *\n\t * @returns Array of registered source adapter names.\n\t */\n\tlistSources(): string[] {\n\t\treturn this.sources.list();\n\t}\n\n\t// -----------------------------------------------------------------------\n\t// Rehydration — restore persisted deltas without push validation\n\t// -----------------------------------------------------------------------\n\n\t/** Rehydrate the buffer with persisted deltas (bypasses push validation). */\n\trehydrate(deltas: ReadonlyArray<RowDelta>): void {\n\t\tfor (const delta of deltas) {\n\t\t\tthis.buffer.append(delta);\n\t\t}\n\t}\n\n\t// -----------------------------------------------------------------------\n\t// Buffer queries\n\t// -----------------------------------------------------------------------\n\n\t/** Get per-table buffer statistics. */\n\tget tableStats(): Array<{ table: string; byteSize: number; deltaCount: number }> {\n\t\treturn this.buffer.tableStats();\n\t}\n\n\t/**\n\t * Get tables that exceed the per-table budget.\n\t */\n\tgetTablesExceedingBudget(): string[] {\n\t\tconst budget = this.config.perTableBudgetBytes;\n\t\tif (!budget) return [];\n\t\treturn this.buffer\n\t\t\t.tableStats()\n\t\t\t.filter((s) => s.byteSize >= budget)\n\t\t\t.map((s) => s.table);\n\t}\n\n\t/** Check if the buffer should be flushed based on config thresholds. */\n\tshouldFlush(): boolean {\n\t\tlet effectiveMaxBytes = this.config.maxBufferBytes;\n\n\t\t// Reduce threshold for wide-column deltas\n\t\tconst adaptive = this.config.adaptiveBufferConfig;\n\t\tif (adaptive && this.buffer.averageDeltaBytes > adaptive.wideColumnThreshold) {\n\t\t\teffectiveMaxBytes = Math.floor(effectiveMaxBytes * adaptive.reductionFactor);\n\t\t}\n\n\t\treturn this.buffer.shouldFlush({\n\t\t\tmaxBytes: effectiveMaxBytes,\n\t\t\tmaxAgeMs: this.config.maxBufferAgeMs,\n\t\t});\n\t}\n\n\t/** Get buffer statistics for monitoring. */\n\tget bufferStats(): {\n\t\tlogSize: number;\n\t\tindexSize: number;\n\t\tbyteSize: number;\n\t} {\n\t\treturn {\n\t\t\tlogSize: this.buffer.logSize,\n\t\t\tindexSize: this.buffer.indexSize,\n\t\t\tbyteSize: this.buffer.byteSize,\n\t\t};\n\t}\n}\n","import type {\n\tActionPush,\n\tHLCTimestamp,\n\tResolvedClaims,\n\tSyncPull,\n\tSyncPush,\n\tSyncRulesConfig,\n\tSyncRulesContext,\n\tTableSchema,\n} from \"@lakesync/core\";\nimport { bigintReviver, Err, Ok, type Result } from \"@lakesync/core\";\nimport {\n\tDEFAULT_PULL_LIMIT,\n\tMAX_DELTAS_PER_PUSH,\n\tMAX_PULL_LIMIT,\n\tVALID_COLUMN_TYPES,\n} from \"./constants\";\n\n/** Validation error with HTTP status code. */\nexport interface RequestError {\n\tstatus: number;\n\tmessage: string;\n}\n\n/** Parse a JSON string, returning Err on invalid JSON. */\nexport function parseJson<T>(\n\traw: string,\n\treviver?: (key: string, value: unknown) => unknown,\n): Result<T, RequestError> {\n\ttry {\n\t\treturn Ok(JSON.parse(raw, reviver) as T);\n\t} catch {\n\t\treturn Err({ status: 400, message: \"Invalid JSON body\" });\n\t}\n}\n\n/**\n * Validate and parse a push request body.\n * Handles JSON parsing with bigint revival.\n */\nexport function validatePushBody(\n\traw: string,\n\theaderClientId?: string | null,\n): Result<SyncPush, RequestError> {\n\tconst parsed = parseJson<SyncPush>(raw, bigintReviver);\n\tif (!parsed.ok) return parsed;\n\tconst body = parsed.value;\n\n\tif (!body.clientId || !Array.isArray(body.deltas)) {\n\t\treturn Err({ status: 400, message: \"Missing required fields: clientId, deltas\" });\n\t}\n\n\tif (headerClientId && body.clientId !== headerClientId) {\n\t\treturn Err({\n\t\t\tstatus: 403,\n\t\t\tmessage: \"Client ID mismatch: push clientId does not match authenticated identity\",\n\t\t});\n\t}\n\n\tif (body.deltas.length > MAX_DELTAS_PER_PUSH) {\n\t\treturn Err({ status: 400, message: \"Too many deltas in a single push (max 10,000)\" });\n\t}\n\n\treturn Ok(body);\n}\n\n/**\n * Parse and validate pull query parameters.\n */\nexport function parsePullParams(params: {\n\tsince: string | null;\n\tclientId: string | null;\n\tlimit: string | null;\n\tsource: string | null;\n}): Result<SyncPull, RequestError> {\n\tif (!params.since || !params.clientId) {\n\t\treturn Err({ status: 400, message: \"Missing required query params: since, clientId\" });\n\t}\n\n\tlet sinceHlc: HLCTimestamp;\n\ttry {\n\t\tsinceHlc = BigInt(params.since) as HLCTimestamp;\n\t} catch {\n\t\treturn Err({\n\t\t\tstatus: 400,\n\t\t\tmessage: \"Invalid 'since' parameter \\u2014 must be a decimal integer\",\n\t\t});\n\t}\n\n\tconst rawLimit = params.limit ? Number.parseInt(params.limit, 10) : DEFAULT_PULL_LIMIT;\n\tif (Number.isNaN(rawLimit) || rawLimit < 1) {\n\t\treturn Err({\n\t\t\tstatus: 400,\n\t\t\tmessage: \"Invalid 'limit' parameter \\u2014 must be a positive integer\",\n\t\t});\n\t}\n\tconst maxDeltas = Math.min(rawLimit, MAX_PULL_LIMIT);\n\n\tconst msg: SyncPull = {\n\t\tclientId: params.clientId,\n\t\tsinceHlc,\n\t\tmaxDeltas,\n\t\t...(params.source ? { source: params.source } : {}),\n\t};\n\n\treturn Ok(msg);\n}\n\n/**\n * Validate and parse an action request body.\n */\nexport function validateActionBody(\n\traw: string,\n\theaderClientId?: string | null,\n): Result<ActionPush, RequestError> {\n\tconst parsed = parseJson<ActionPush>(raw, bigintReviver);\n\tif (!parsed.ok) return parsed;\n\tconst body = parsed.value;\n\n\tif (!body.clientId || !Array.isArray(body.actions)) {\n\t\treturn Err({ status: 400, message: \"Missing required fields: clientId, actions\" });\n\t}\n\n\tif (headerClientId && body.clientId !== headerClientId) {\n\t\treturn Err({\n\t\t\tstatus: 403,\n\t\t\tmessage: \"Client ID mismatch: action clientId does not match authenticated identity\",\n\t\t});\n\t}\n\n\treturn Ok(body);\n}\n\n/**\n * Validate a table schema body.\n */\nexport function validateSchemaBody(raw: string): Result<TableSchema, RequestError> {\n\tconst parsed = parseJson<TableSchema>(raw);\n\tif (!parsed.ok) return parsed;\n\tconst schema = parsed.value;\n\n\tif (!schema.table || !Array.isArray(schema.columns)) {\n\t\treturn Err({ status: 400, message: \"Missing required fields: table, columns\" });\n\t}\n\n\tfor (const col of schema.columns) {\n\t\tif (typeof col.name !== \"string\" || col.name.length === 0) {\n\t\t\treturn Err({ status: 400, message: \"Each column must have a non-empty 'name' string\" });\n\t\t}\n\t\tif (!VALID_COLUMN_TYPES.has(col.type)) {\n\t\t\treturn Err({\n\t\t\t\tstatus: 400,\n\t\t\t\tmessage: `Invalid column type \"${col.type}\" for column \"${col.name}\". Allowed: string, number, boolean, json, null`,\n\t\t\t});\n\t\t}\n\t}\n\n\tconst columnNames = new Set(schema.columns.map((c) => c.name));\n\n\t// Validate primaryKey\n\tif (schema.primaryKey !== undefined) {\n\t\tif (!Array.isArray(schema.primaryKey) || schema.primaryKey.length === 0) {\n\t\t\treturn Err({ status: 400, message: \"primaryKey must be a non-empty array of strings\" });\n\t\t}\n\t\tfor (const pk of schema.primaryKey) {\n\t\t\tif (typeof pk !== \"string\") {\n\t\t\t\treturn Err({ status: 400, message: \"primaryKey must be a non-empty array of strings\" });\n\t\t\t}\n\t\t\tif (pk !== \"row_id\" && !columnNames.has(pk)) {\n\t\t\t\treturn Err({\n\t\t\t\t\tstatus: 400,\n\t\t\t\t\tmessage: `primaryKey column \"${pk}\" must be \"row_id\" or exist in columns`,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\t// Validate softDelete\n\tif (schema.softDelete !== undefined && typeof schema.softDelete !== \"boolean\") {\n\t\treturn Err({ status: 400, message: \"softDelete must be a boolean\" });\n\t}\n\n\t// Validate externalIdColumn\n\tif (schema.externalIdColumn !== undefined) {\n\t\tif (typeof schema.externalIdColumn !== \"string\" || schema.externalIdColumn.length === 0) {\n\t\t\treturn Err({ status: 400, message: \"externalIdColumn must be a non-empty string\" });\n\t\t}\n\t\tif (!columnNames.has(schema.externalIdColumn)) {\n\t\t\treturn Err({\n\t\t\t\tstatus: 400,\n\t\t\t\tmessage: `externalIdColumn \"${schema.externalIdColumn}\" must exist in columns`,\n\t\t\t});\n\t\t}\n\t}\n\n\treturn Ok(schema);\n}\n\n/**\n * Map a gateway push error code to an HTTP status code.\n */\nexport function pushErrorToStatus(code: string): number {\n\tswitch (code) {\n\t\tcase \"CLOCK_DRIFT\":\n\t\t\treturn 409;\n\t\tcase \"SCHEMA_MISMATCH\":\n\t\t\treturn 422;\n\t\tcase \"BACKPRESSURE\":\n\t\t\treturn 503;\n\t\tdefault:\n\t\t\treturn 500;\n\t}\n}\n\n/**\n * Build a SyncRulesContext from rules and claims.\n * Returns undefined when no rules or empty buckets.\n */\nexport function buildSyncRulesContext(\n\trules: SyncRulesConfig | undefined,\n\tclaims: ResolvedClaims,\n): SyncRulesContext | undefined {\n\tif (!rules || rules.buckets.length === 0) {\n\t\treturn undefined;\n\t}\n\treturn { claims, rules };\n}\n","import type { HLCTimestamp, ResolvedClaims, RowDelta, SyncRulesConfig } from \"@lakesync/core\";\nimport {\n\tlistConnectorDescriptors,\n\tvalidateConnectorConfig,\n\tvalidateSyncRules,\n} from \"@lakesync/core\";\nimport type { ConfigStore } from \"./config-store\";\nimport type { SyncGateway } from \"./gateway\";\nimport {\n\tbuildSyncRulesContext,\n\tparseJson,\n\tparsePullParams,\n\tpushErrorToStatus,\n\tvalidateActionBody,\n\tvalidatePushBody,\n\tvalidateSchemaBody,\n} from \"./validation\";\n\n/** Result from a request handler, ready for platform-specific serialisation. */\nexport interface HandlerResult {\n\tstatus: number;\n\tbody: unknown;\n}\n\n/**\n * Handle a push request.\n *\n * @param gateway - The SyncGateway instance.\n * @param raw - The raw request body string.\n * @param headerClientId - Client ID from auth header (for mismatch check).\n * @param opts - Optional callbacks for persistence and broadcast.\n */\nexport function handlePushRequest(\n\tgateway: SyncGateway,\n\traw: string,\n\theaderClientId?: string | null,\n\topts?: {\n\t\t/** Persist deltas before processing (WAL-style). */\n\t\tpersistBatch?: (deltas: RowDelta[]) => void;\n\t\t/** Clear persisted deltas after successful push. */\n\t\tclearPersistence?: () => void;\n\t\t/** Broadcast deltas to connected clients. */\n\t\tbroadcastFn?: (\n\t\t\tdeltas: RowDelta[],\n\t\t\tserverHlc: HLCTimestamp,\n\t\t\texcludeClientId: string,\n\t\t) => void | Promise<void>;\n\t},\n): HandlerResult {\n\tconst validation = validatePushBody(raw, headerClientId);\n\tif (!validation.ok) {\n\t\treturn { status: validation.error.status, body: { error: validation.error.message } };\n\t}\n\n\tconst body = validation.value;\n\n\t// Persist before processing (WAL-style)\n\topts?.persistBatch?.(body.deltas);\n\n\tconst result = gateway.handlePush(body);\n\tif (!result.ok) {\n\t\treturn {\n\t\t\tstatus: pushErrorToStatus(result.error.code),\n\t\t\tbody: { error: result.error.message },\n\t\t};\n\t}\n\n\t// Clear persisted deltas on success\n\topts?.clearPersistence?.();\n\n\t// Broadcast to connected clients (fire and forget)\n\tif (opts?.broadcastFn && result.value.deltas.length > 0) {\n\t\topts.broadcastFn(result.value.deltas, result.value.serverHlc, body.clientId);\n\t}\n\n\treturn { status: 200, body: result.value };\n}\n\n/**\n * Handle a pull request.\n */\nexport async function handlePullRequest(\n\tgateway: SyncGateway,\n\tparams: {\n\t\tsince: string | null;\n\t\tclientId: string | null;\n\t\tlimit: string | null;\n\t\tsource: string | null;\n\t},\n\tclaims?: ResolvedClaims,\n\tsyncRules?: SyncRulesConfig,\n): Promise<HandlerResult> {\n\tconst validation = parsePullParams(params);\n\tif (!validation.ok) {\n\t\treturn { status: validation.error.status, body: { error: validation.error.message } };\n\t}\n\n\tconst msg = validation.value;\n\tconst context = buildSyncRulesContext(syncRules, claims ?? {});\n\n\tconst result = msg.source\n\t\t? await gateway.handlePull(\n\t\t\t\tmsg as import(\"@lakesync/core\").SyncPull & { source: string },\n\t\t\t\tcontext,\n\t\t\t)\n\t\t: gateway.handlePull(msg, context);\n\n\tif (!result.ok) {\n\t\tconst err = result.error;\n\t\tif (err.code === \"ADAPTER_NOT_FOUND\") {\n\t\t\treturn { status: 404, body: { error: err.message } };\n\t\t}\n\t\treturn { status: 500, body: { error: err.message } };\n\t}\n\n\treturn { status: 200, body: result.value };\n}\n\n/**\n * Handle an action request.\n */\nexport async function handleActionRequest(\n\tgateway: SyncGateway,\n\traw: string,\n\theaderClientId?: string | null,\n\tclaims?: ResolvedClaims,\n): Promise<HandlerResult> {\n\tconst validation = validateActionBody(raw, headerClientId);\n\tif (!validation.ok) {\n\t\treturn { status: validation.error.status, body: { error: validation.error.message } };\n\t}\n\n\tconst context = claims ? { claims } : undefined;\n\tconst result = await gateway.handleAction(validation.value, context);\n\n\tif (!result.ok) {\n\t\treturn { status: 400, body: { error: result.error.message } };\n\t}\n\n\treturn { status: 200, body: result.value };\n}\n\n/**\n * Handle a flush request.\n */\nexport async function handleFlushRequest(\n\tgateway: SyncGateway,\n\topts?: { clearPersistence?: () => void },\n): Promise<HandlerResult> {\n\tconst result = await gateway.flush();\n\tif (!result.ok) {\n\t\treturn { status: 500, body: { error: result.error.message } };\n\t}\n\n\topts?.clearPersistence?.();\n\treturn { status: 200, body: { flushed: true } };\n}\n\n/**\n * Handle saving a table schema.\n */\nexport async function handleSaveSchema(\n\traw: string,\n\tstore: ConfigStore,\n\tgatewayId: string,\n): Promise<HandlerResult> {\n\tconst validation = validateSchemaBody(raw);\n\tif (!validation.ok) {\n\t\treturn { status: validation.error.status, body: { error: validation.error.message } };\n\t}\n\n\tawait store.setSchema(gatewayId, validation.value);\n\treturn { status: 200, body: { saved: true } };\n}\n\n/**\n * Handle saving sync rules.\n */\nexport async function handleSaveSyncRules(\n\traw: string,\n\tstore: ConfigStore,\n\tgatewayId: string,\n): Promise<HandlerResult> {\n\tconst parsed = parseJson<unknown>(raw);\n\tif (!parsed.ok) {\n\t\treturn { status: parsed.error.status, body: { error: parsed.error.message } };\n\t}\n\tconst config = parsed.value;\n\n\tconst validation = validateSyncRules(config);\n\tif (!validation.ok) {\n\t\treturn { status: 400, body: { error: validation.error.message } };\n\t}\n\n\tawait store.setSyncRules(gatewayId, config as SyncRulesConfig);\n\treturn { status: 200, body: { saved: true } };\n}\n\n/**\n * Handle registering a connector.\n */\nexport async function handleRegisterConnector(\n\traw: string,\n\tstore: ConfigStore,\n): Promise<HandlerResult> {\n\tconst parsed = parseJson<unknown>(raw);\n\tif (!parsed.ok) {\n\t\treturn { status: parsed.error.status, body: { error: parsed.error.message } };\n\t}\n\tconst body = parsed.value;\n\n\tconst validation = validateConnectorConfig(body);\n\tif (!validation.ok) {\n\t\treturn { status: 400, body: { error: validation.error.message } };\n\t}\n\n\tconst config = validation.value;\n\tconst connectors = await store.getConnectors();\n\n\tif (connectors[config.name]) {\n\t\treturn { status: 409, body: { error: `Connector \"${config.name}\" already exists` } };\n\t}\n\n\tconnectors[config.name] = config;\n\tawait store.setConnectors(connectors);\n\n\treturn { status: 200, body: { registered: true, name: config.name } };\n}\n\n/**\n * Handle unregistering a connector.\n */\nexport async function handleUnregisterConnector(\n\tname: string,\n\tstore: ConfigStore,\n): Promise<HandlerResult> {\n\tconst connectors = await store.getConnectors();\n\n\tif (!connectors[name]) {\n\t\treturn { status: 404, body: { error: `Connector \"${name}\" not found` } };\n\t}\n\n\tdelete connectors[name];\n\tawait store.setConnectors(connectors);\n\n\treturn { status: 200, body: { unregistered: true, name } };\n}\n\n/**\n * Handle listing connectors.\n */\nexport async function handleListConnectors(store: ConfigStore): Promise<HandlerResult> {\n\tconst connectors = await store.getConnectors();\n\tconst list = Object.values(connectors).map((c) => ({\n\t\tname: c.name,\n\t\ttype: c.type,\n\t\thasIngest: c.ingest !== undefined,\n\t}));\n\n\treturn { status: 200, body: list };\n}\n\n/**\n * Handle listing available connector types (static metadata).\n */\nexport function handleListConnectorTypes(): HandlerResult {\n\treturn { status: 200, body: listConnectorDescriptors() };\n}\n\n/**\n * Handle metrics request.\n */\nexport function handleMetrics(\n\tgateway: SyncGateway,\n\textra?: Record<string, unknown>,\n): HandlerResult {\n\tconst stats = gateway.bufferStats;\n\treturn { status: 200, body: { ...stats, ...extra } };\n}\n","import { Err, Ok, type Result, type RowDelta, SchemaError, type TableSchema } from \"@lakesync/core\";\n\n/** Immutable snapshot of schema state — swapped atomically on evolution. */\ninterface SchemaSnapshot {\n\tschema: TableSchema;\n\tversion: number;\n\tallowedColumns: Set<string>;\n}\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). Schema, version,\n * and allowed columns are held in a single {@link SchemaSnapshot} that\n * is swapped atomically — no intermediate inconsistent state is possible.\n */\nexport class SchemaManager {\n\tprivate state: SchemaSnapshot;\n\n\tconstructor(schema: TableSchema, version?: number) {\n\t\tthis.state = {\n\t\t\tschema,\n\t\t\tversion: version ?? 1,\n\t\t\tallowedColumns: new Set(schema.columns.map((c) => c.name)),\n\t\t};\n\t}\n\n\t/** Get the current schema and version. */\n\tgetSchema(): { schema: TableSchema; version: number } {\n\t\treturn { schema: this.state.schema, version: this.state.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.state.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.state.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.state.schema.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.state.schema.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// Atomic swap — no intermediate inconsistent state\n\t\tconst newVersion = this.state.version + 1;\n\t\tthis.state = {\n\t\t\tschema: newSchema,\n\t\t\tversion: newVersion,\n\t\t\tallowedColumns: new Set(newSchema.columns.map((c) => c.name)),\n\t\t};\n\n\t\treturn Ok({ version: newVersion });\n\t}\n}\n"],"mappings":"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","names":["hasMore","serverHlc","trimmed"]}
|
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
Err,
|
|
3
3
|
LakeSyncError,
|
|
4
4
|
Ok
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-4SG66H5K.js";
|
|
6
6
|
|
|
7
7
|
// ../catalogue/src/types.ts
|
|
8
8
|
var CatalogueError = class extends LakeSyncError {
|
|
@@ -410,4 +410,4 @@ export {
|
|
|
410
410
|
buildPartitionSpec,
|
|
411
411
|
lakeSyncTableName
|
|
412
412
|
};
|
|
413
|
-
//# sourceMappingURL=chunk-
|
|
413
|
+
//# sourceMappingURL=chunk-U2NV4DUX.js.map
|
|
@@ -4,9 +4,8 @@ import {
|
|
|
4
4
|
LakeSyncError,
|
|
5
5
|
Ok,
|
|
6
6
|
extractDelta,
|
|
7
|
-
registerOutputSchemas
|
|
8
|
-
|
|
9
|
-
} from "./chunk-LDFFCG2K.js";
|
|
7
|
+
registerOutputSchemas
|
|
8
|
+
} from "./chunk-4SG66H5K.js";
|
|
10
9
|
|
|
11
10
|
// ../connector-salesforce/src/errors.ts
|
|
12
11
|
var SalesforceApiError = class extends LakeSyncError {
|
|
@@ -542,18 +541,20 @@ async function testConnection(config) {
|
|
|
542
541
|
}
|
|
543
542
|
|
|
544
543
|
// ../connector-salesforce/src/index.ts
|
|
545
|
-
|
|
546
|
-
registerPollerFactory("salesforce", (config, gateway) => {
|
|
544
|
+
function salesforcePollerFactory(config, gateway) {
|
|
547
545
|
if (config.type !== "salesforce") {
|
|
548
546
|
throw new Error(`Expected connector type "salesforce", got "${config.type}"`);
|
|
549
547
|
}
|
|
550
|
-
const
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
548
|
+
const sfConfig = config;
|
|
549
|
+
const ingest = sfConfig.ingest ? {
|
|
550
|
+
intervalMs: sfConfig.ingest.intervalMs,
|
|
551
|
+
chunkSize: sfConfig.ingest.chunkSize,
|
|
552
|
+
memoryBudgetBytes: sfConfig.ingest.memoryBudgetBytes
|
|
554
553
|
} : void 0;
|
|
555
|
-
return new SalesforceSourcePoller(
|
|
556
|
-
}
|
|
554
|
+
return new SalesforceSourcePoller(sfConfig.salesforce, ingest, sfConfig.name, gateway);
|
|
555
|
+
}
|
|
556
|
+
var createSalesforcePoller = salesforcePollerFactory;
|
|
557
|
+
registerOutputSchemas("salesforce", SALESFORCE_TABLE_SCHEMAS);
|
|
557
558
|
|
|
558
559
|
export {
|
|
559
560
|
SalesforceApiError,
|
|
@@ -565,6 +566,8 @@ export {
|
|
|
565
566
|
mapLead,
|
|
566
567
|
SalesforceSourcePoller,
|
|
567
568
|
SALESFORCE_TABLE_SCHEMAS,
|
|
568
|
-
testConnection
|
|
569
|
+
testConnection,
|
|
570
|
+
salesforcePollerFactory,
|
|
571
|
+
createSalesforcePoller
|
|
569
572
|
};
|
|
570
|
-
//# sourceMappingURL=chunk-
|
|
573
|
+
//# sourceMappingURL=chunk-XVP5DJJ7.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../connector-salesforce/src/errors.ts","../../connector-salesforce/src/client.ts","../../connector-salesforce/src/mapping.ts","../../connector-salesforce/src/poller.ts","../../connector-salesforce/src/schemas.ts","../../connector-salesforce/src/test-connection.ts","../../connector-salesforce/src/index.ts"],"sourcesContent":["import { LakeSyncError } from \"@lakesync/core\";\n\n/** HTTP error from the Salesforce REST API. */\nexport class SalesforceApiError extends LakeSyncError {\n\t/** HTTP status code returned by Salesforce. */\n\treadonly statusCode: number;\n\t/** Raw response body from Salesforce. */\n\treadonly responseBody: string;\n\n\tconstructor(statusCode: number, responseBody: string, cause?: Error) {\n\t\tsuper(`Salesforce API error (${statusCode}): ${responseBody}`, \"SALESFORCE_API_ERROR\", cause);\n\t\tthis.statusCode = statusCode;\n\t\tthis.responseBody = responseBody;\n\t}\n}\n\n/** Authentication failure from the Salesforce OAuth token endpoint. */\nexport class SalesforceAuthError extends LakeSyncError {\n\tconstructor(message: string, cause?: Error) {\n\t\tsuper(message, \"SALESFORCE_AUTH_ERROR\", cause);\n\t}\n}\n","// ---------------------------------------------------------------------------\n// SalesforceClient — HTTP wrapper for Salesforce REST API\n// ---------------------------------------------------------------------------\n\nimport { Err, Ok, type Result } from \"@lakesync/core\";\nimport { SalesforceApiError, SalesforceAuthError } from \"./errors\";\nimport type {\n\tSalesforceAuthResponse,\n\tSalesforceConnectorConfig,\n\tSalesforceQueryResponse,\n} from \"./types\";\n\nconst DEFAULT_API_VERSION = \"v62.0\";\nconst MAX_RETRY_ATTEMPTS = 3;\nconst DEFAULT_RETRY_AFTER_MS = 10_000;\n\n/**\n * HTTP client for the Salesforce REST API.\n *\n * Uses OAuth 2.0 Username-Password flow for authentication and global `fetch`.\n * All public methods return `Result<T, SalesforceApiError | SalesforceAuthError>`.\n */\nexport class SalesforceClient {\n\tprivate readonly config: SalesforceConnectorConfig;\n\tprivate readonly apiVersion: string;\n\tprivate readonly loginUrl: string;\n\n\tprivate accessToken: string | null = null;\n\tprivate instanceUrl: string;\n\n\tconstructor(config: SalesforceConnectorConfig) {\n\t\tthis.config = config;\n\t\tthis.apiVersion = config.apiVersion ?? DEFAULT_API_VERSION;\n\t\tthis.loginUrl = config.isSandbox\n\t\t\t? \"https://test.salesforce.com\"\n\t\t\t: \"https://login.salesforce.com\";\n\t\tthis.instanceUrl = config.instanceUrl;\n\t}\n\n\t/**\n\t * Authenticate via OAuth 2.0 Username-Password flow.\n\t *\n\t * Stores access token and updates instance URL from the response.\n\t */\n\tasync authenticate(): Promise<Result<void, SalesforceAuthError>> {\n\t\tconst body = new URLSearchParams({\n\t\t\tgrant_type: \"password\",\n\t\t\tclient_id: this.config.clientId,\n\t\t\tclient_secret: this.config.clientSecret,\n\t\t\tusername: this.config.username,\n\t\t\tpassword: this.config.password,\n\t\t});\n\n\t\tlet response: Response;\n\t\ttry {\n\t\t\tresponse = await fetch(`${this.loginUrl}/services/oauth2/token`, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n\t\t\t\tbody: body.toString(),\n\t\t\t});\n\t\t} catch (err) {\n\t\t\treturn Err(\n\t\t\t\tnew SalesforceAuthError(\n\t\t\t\t\t`Failed to connect to Salesforce auth endpoint: ${err instanceof Error ? err.message : String(err)}`,\n\t\t\t\t\terr instanceof Error ? err : undefined,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\n\t\tif (!response.ok) {\n\t\t\tconst text = await response.text();\n\t\t\treturn Err(\n\t\t\t\tnew SalesforceAuthError(`Salesforce authentication failed (${response.status}): ${text}`),\n\t\t\t);\n\t\t}\n\n\t\tconst data = (await response.json()) as SalesforceAuthResponse;\n\t\tthis.accessToken = data.access_token;\n\t\tthis.instanceUrl = data.instance_url;\n\n\t\treturn Ok(undefined);\n\t}\n\n\t/**\n\t * Execute a SOQL query with auto-pagination.\n\t *\n\t * Automatically authenticates on first call and re-authenticates on 401.\n\t */\n\tasync query<T>(soql: string): Promise<Result<T[], SalesforceApiError | SalesforceAuthError>> {\n\t\t// Ensure we have a token\n\t\tif (!this.accessToken) {\n\t\t\tconst authResult = await this.authenticate();\n\t\t\tif (!authResult.ok) return authResult;\n\t\t}\n\n\t\tconst allRecords: T[] = [];\n\t\tlet url = `${this.instanceUrl}/services/data/${this.apiVersion}/query?q=${encodeURIComponent(soql)}`;\n\n\t\twhile (true) {\n\t\t\tconst result = await this.request<SalesforceQueryResponse<T>>(url);\n\n\t\t\t// Re-auth on 401 and retry once\n\t\t\tif (\n\t\t\t\t!result.ok &&\n\t\t\t\tresult.error instanceof SalesforceApiError &&\n\t\t\t\tresult.error.statusCode === 401\n\t\t\t) {\n\t\t\t\tconst authResult = await this.authenticate();\n\t\t\t\tif (!authResult.ok) return authResult;\n\n\t\t\t\tconst retryResult = await this.request<SalesforceQueryResponse<T>>(url);\n\t\t\t\tif (!retryResult.ok) return retryResult;\n\n\t\t\t\tfor (const record of retryResult.value.records) {\n\t\t\t\t\tallRecords.push(record);\n\t\t\t\t}\n\n\t\t\t\tif (retryResult.value.done || !retryResult.value.nextRecordsUrl) break;\n\t\t\t\turl = `${this.instanceUrl}${retryResult.value.nextRecordsUrl}`;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (!result.ok) return result;\n\n\t\t\tfor (const record of result.value.records) {\n\t\t\t\tallRecords.push(record);\n\t\t\t}\n\n\t\t\tif (result.value.done || !result.value.nextRecordsUrl) break;\n\t\t\turl = `${this.instanceUrl}${result.value.nextRecordsUrl}`;\n\t\t}\n\n\t\treturn Ok(allRecords);\n\t}\n\n\t// -----------------------------------------------------------------------\n\t// Internal HTTP helpers\n\t// -----------------------------------------------------------------------\n\n\t/** Make an HTTP request with rate-limit retry logic. */\n\tprivate async request<T>(\n\t\turl: string,\n\t): Promise<Result<T, SalesforceApiError | SalesforceAuthError>> {\n\t\tfor (let attempt = 0; attempt <= MAX_RETRY_ATTEMPTS; attempt++) {\n\t\t\tconst headers: Record<string, string> = {\n\t\t\t\tAuthorization: `Bearer ${this.accessToken}`,\n\t\t\t\tAccept: \"application/json\",\n\t\t\t};\n\n\t\t\tconst response = await fetch(url, { method: \"GET\", headers });\n\n\t\t\tif (response.ok) {\n\t\t\t\tconst data = (await response.json()) as T;\n\t\t\t\treturn Ok(data);\n\t\t\t}\n\n\t\t\t// Rate limit: 503 with Retry-After\n\t\t\tif (response.status === 503) {\n\t\t\t\tconst retryAfter = response.headers.get(\"Retry-After\");\n\t\t\t\tconst waitMs = retryAfter ? Number.parseInt(retryAfter, 10) * 1000 : DEFAULT_RETRY_AFTER_MS;\n\n\t\t\t\tif (attempt < MAX_RETRY_ATTEMPTS) {\n\t\t\t\t\tawait sleep(waitMs);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst responseBody = await response.text();\n\t\t\t\treturn Err(new SalesforceApiError(503, responseBody));\n\t\t\t}\n\n\t\t\tconst responseBody = await response.text();\n\t\t\treturn Err(new SalesforceApiError(response.status, responseBody));\n\t\t}\n\n\t\treturn Err(new SalesforceApiError(0, \"Unknown error after retries\"));\n\t}\n}\n\n/** Sleep for the given number of milliseconds. */\nfunction sleep(ms: number): Promise<void> {\n\treturn new Promise((resolve) => setTimeout(resolve, ms));\n}\n","// ---------------------------------------------------------------------------\n// Salesforce Entity → Flat LakeSync Row Mapping\n// ---------------------------------------------------------------------------\n\nimport type { SfAccount, SfContact, SfLead, SfOpportunity } from \"./types\";\n\n/**\n * Map a Salesforce Account to a flat row for the `sf_accounts` table.\n *\n * The row ID is the Salesforce record Id.\n */\nexport function mapAccount(account: SfAccount): { rowId: string; row: Record<string, unknown> } {\n\treturn {\n\t\trowId: account.Id,\n\t\trow: {\n\t\t\tsf_id: account.Id,\n\t\t\tname: account.Name ?? null,\n\t\t\ttype: account.Type ?? null,\n\t\t\tindustry: account.Industry ?? null,\n\t\t\twebsite: account.Website ?? null,\n\t\t\tphone: account.Phone ?? null,\n\t\t\tbilling_city: account.BillingCity ?? null,\n\t\t\tbilling_state: account.BillingState ?? null,\n\t\t\tbilling_country: account.BillingCountry ?? null,\n\t\t\tannual_revenue: account.AnnualRevenue ?? null,\n\t\t\tnumber_of_employees: account.NumberOfEmployees ?? null,\n\t\t\towner_name: account.Owner?.Name ?? null,\n\t\t\tcreated_date: account.CreatedDate ?? null,\n\t\t\tlast_modified_date: account.LastModifiedDate ?? null,\n\t\t},\n\t};\n}\n\n/**\n * Map a Salesforce Contact to a flat row for the `sf_contacts` table.\n *\n * The row ID is the Salesforce record Id.\n */\nexport function mapContact(contact: SfContact): { rowId: string; row: Record<string, unknown> } {\n\treturn {\n\t\trowId: contact.Id,\n\t\trow: {\n\t\t\tsf_id: contact.Id,\n\t\t\tfirst_name: contact.FirstName ?? null,\n\t\t\tlast_name: contact.LastName ?? null,\n\t\t\temail: contact.Email ?? null,\n\t\t\tphone: contact.Phone ?? null,\n\t\t\ttitle: contact.Title ?? null,\n\t\t\taccount_id: contact.AccountId ?? null,\n\t\t\taccount_name: contact.Account?.Name ?? null,\n\t\t\tmailing_city: contact.MailingCity ?? null,\n\t\t\tmailing_state: contact.MailingState ?? null,\n\t\t\tmailing_country: contact.MailingCountry ?? null,\n\t\t\towner_name: contact.Owner?.Name ?? null,\n\t\t\tcreated_date: contact.CreatedDate ?? null,\n\t\t\tlast_modified_date: contact.LastModifiedDate ?? null,\n\t\t},\n\t};\n}\n\n/**\n * Map a Salesforce Opportunity to a flat row for the `sf_opportunities` table.\n *\n * The row ID is the Salesforce record Id.\n */\nexport function mapOpportunity(opportunity: SfOpportunity): {\n\trowId: string;\n\trow: Record<string, unknown>;\n} {\n\treturn {\n\t\trowId: opportunity.Id,\n\t\trow: {\n\t\t\tsf_id: opportunity.Id,\n\t\t\tname: opportunity.Name ?? null,\n\t\t\tstage_name: opportunity.StageName ?? null,\n\t\t\tamount: opportunity.Amount ?? null,\n\t\t\tclose_date: opportunity.CloseDate ?? null,\n\t\t\tprobability: opportunity.Probability ?? null,\n\t\t\taccount_id: opportunity.AccountId ?? null,\n\t\t\taccount_name: opportunity.Account?.Name ?? null,\n\t\t\ttype: opportunity.Type ?? null,\n\t\t\tlead_source: opportunity.LeadSource ?? null,\n\t\t\tis_closed: opportunity.IsClosed ?? null,\n\t\t\tis_won: opportunity.IsWon ?? null,\n\t\t\towner_name: opportunity.Owner?.Name ?? null,\n\t\t\tcreated_date: opportunity.CreatedDate ?? null,\n\t\t\tlast_modified_date: opportunity.LastModifiedDate ?? null,\n\t\t},\n\t};\n}\n\n/**\n * Map a Salesforce Lead to a flat row for the `sf_leads` table.\n *\n * The row ID is the Salesforce record Id.\n */\nexport function mapLead(lead: SfLead): { rowId: string; row: Record<string, unknown> } {\n\treturn {\n\t\trowId: lead.Id,\n\t\trow: {\n\t\t\tsf_id: lead.Id,\n\t\t\tfirst_name: lead.FirstName ?? null,\n\t\t\tlast_name: lead.LastName ?? null,\n\t\t\tcompany: lead.Company ?? null,\n\t\t\temail: lead.Email ?? null,\n\t\t\tphone: lead.Phone ?? null,\n\t\t\ttitle: lead.Title ?? null,\n\t\t\tstatus: lead.Status ?? null,\n\t\t\tlead_source: lead.LeadSource ?? null,\n\t\t\tis_converted: lead.IsConverted ?? null,\n\t\t\tconverted_account_id: lead.ConvertedAccountId ?? null,\n\t\t\tconverted_contact_id: lead.ConvertedContactId ?? null,\n\t\t\tconverted_opportunity_id: lead.ConvertedOpportunityId ?? null,\n\t\t\towner_name: lead.Owner?.Name ?? null,\n\t\t\tcreated_date: lead.CreatedDate ?? null,\n\t\t\tlast_modified_date: lead.LastModifiedDate ?? null,\n\t\t},\n\t};\n}\n","// ---------------------------------------------------------------------------\n// SalesforceSourcePoller — polls Salesforce CRM and pushes deltas to SyncGateway\n// ---------------------------------------------------------------------------\n\nimport { BaseSourcePoller, extractDelta, type PushTarget } from \"@lakesync/core\";\nimport { SalesforceClient } from \"./client\";\nimport { mapAccount, mapContact, mapLead, mapOpportunity } from \"./mapping\";\nimport type {\n\tSalesforceConnectorConfig,\n\tSalesforceIngestConfig,\n\tSfAccount,\n\tSfContact,\n\tSfLead,\n\tSfOpportunity,\n} from \"./types\";\n\nconst DEFAULT_INTERVAL_MS = 30_000;\n\n// ---------------------------------------------------------------------------\n// SOQL field lists\n// ---------------------------------------------------------------------------\n\nconst ACCOUNT_FIELDS = [\n\t\"Id\",\n\t\"Name\",\n\t\"Type\",\n\t\"Industry\",\n\t\"Website\",\n\t\"Phone\",\n\t\"BillingCity\",\n\t\"BillingState\",\n\t\"BillingCountry\",\n\t\"AnnualRevenue\",\n\t\"NumberOfEmployees\",\n\t\"Owner.Name\",\n\t\"CreatedDate\",\n\t\"LastModifiedDate\",\n].join(\", \");\n\nconst CONTACT_FIELDS = [\n\t\"Id\",\n\t\"FirstName\",\n\t\"LastName\",\n\t\"Email\",\n\t\"Phone\",\n\t\"Title\",\n\t\"AccountId\",\n\t\"Account.Name\",\n\t\"MailingCity\",\n\t\"MailingState\",\n\t\"MailingCountry\",\n\t\"Owner.Name\",\n\t\"CreatedDate\",\n\t\"LastModifiedDate\",\n].join(\", \");\n\nconst OPPORTUNITY_FIELDS = [\n\t\"Id\",\n\t\"Name\",\n\t\"StageName\",\n\t\"Amount\",\n\t\"CloseDate\",\n\t\"Probability\",\n\t\"AccountId\",\n\t\"Account.Name\",\n\t\"Type\",\n\t\"LeadSource\",\n\t\"IsClosed\",\n\t\"IsWon\",\n\t\"Owner.Name\",\n\t\"CreatedDate\",\n\t\"LastModifiedDate\",\n].join(\", \");\n\nconst LEAD_FIELDS = [\n\t\"Id\",\n\t\"FirstName\",\n\t\"LastName\",\n\t\"Company\",\n\t\"Email\",\n\t\"Phone\",\n\t\"Title\",\n\t\"Status\",\n\t\"LeadSource\",\n\t\"IsConverted\",\n\t\"ConvertedAccountId\",\n\t\"ConvertedContactId\",\n\t\"ConvertedOpportunityId\",\n\t\"Owner.Name\",\n\t\"CreatedDate\",\n\t\"LastModifiedDate\",\n].join(\", \");\n\n/**\n * Polls Salesforce CRM for accounts, contacts, opportunities, and leads\n * and pushes detected changes into a gateway via streaming accumulation.\n *\n * Uses {@link BaseSourcePoller.accumulateDelta} to push deltas in\n * memory-bounded chunks instead of collecting all deltas in a single array.\n */\nexport class SalesforceSourcePoller extends BaseSourcePoller {\n\tprivate readonly connectionConfig: SalesforceConnectorConfig;\n\tprivate readonly client: SalesforceClient;\n\n\t/** Per-entity cursors: max LastModifiedDate from the last poll. */\n\tprivate cursors: Record<string, string | undefined> = {\n\t\taccounts: undefined,\n\t\tcontacts: undefined,\n\t\topportunities: undefined,\n\t\tleads: undefined,\n\t};\n\n\t/** Export cursor state as a JSON-serialisable object for external persistence. */\n\toverride getCursorState(): Record<string, unknown> {\n\t\treturn { ...this.cursors };\n\t}\n\n\t/** Restore cursor state from a previously exported snapshot. */\n\toverride setCursorState(state: Record<string, unknown>): void {\n\t\tconst incoming = state as Record<string, string | undefined>;\n\t\tthis.cursors = {\n\t\t\taccounts: incoming.accounts,\n\t\t\tcontacts: incoming.contacts,\n\t\t\topportunities: incoming.opportunities,\n\t\t\tleads: incoming.leads,\n\t\t};\n\t}\n\n\tconstructor(\n\t\tconnectionConfig: SalesforceConnectorConfig,\n\t\tingestConfig: SalesforceIngestConfig | undefined,\n\t\tname: string,\n\t\tgateway: PushTarget,\n\t\tclient?: SalesforceClient,\n\t) {\n\t\tsuper({\n\t\t\tname,\n\t\t\tintervalMs: ingestConfig?.intervalMs ?? DEFAULT_INTERVAL_MS,\n\t\t\tgateway,\n\t\t\tmemory: {\n\t\t\t\tchunkSize: ingestConfig?.chunkSize,\n\t\t\t\tmemoryBudgetBytes: ingestConfig?.memoryBudgetBytes,\n\t\t\t},\n\t\t});\n\t\tthis.connectionConfig = connectionConfig;\n\t\tthis.client = client ?? new SalesforceClient(connectionConfig);\n\t}\n\n\t/** Execute a single poll cycle across all enabled entity types. */\n\tasync poll(): Promise<void> {\n\t\tconst includeAccounts = this.connectionConfig.includeAccounts ?? true;\n\t\tif (includeAccounts) {\n\t\t\tawait this.pollEntity<SfAccount>(\n\t\t\t\t\"Account\",\n\t\t\t\tACCOUNT_FIELDS,\n\t\t\t\t\"accounts\",\n\t\t\t\t\"sf_accounts\",\n\t\t\t\tmapAccount,\n\t\t\t);\n\t\t}\n\n\t\tconst includeContacts = this.connectionConfig.includeContacts ?? true;\n\t\tif (includeContacts) {\n\t\t\tawait this.pollEntity<SfContact>(\n\t\t\t\t\"Contact\",\n\t\t\t\tCONTACT_FIELDS,\n\t\t\t\t\"contacts\",\n\t\t\t\t\"sf_contacts\",\n\t\t\t\tmapContact,\n\t\t\t);\n\t\t}\n\n\t\tconst includeOpportunities = this.connectionConfig.includeOpportunities ?? true;\n\t\tif (includeOpportunities) {\n\t\t\tawait this.pollEntity<SfOpportunity>(\n\t\t\t\t\"Opportunity\",\n\t\t\t\tOPPORTUNITY_FIELDS,\n\t\t\t\t\"opportunities\",\n\t\t\t\t\"sf_opportunities\",\n\t\t\t\tmapOpportunity,\n\t\t\t);\n\t\t}\n\n\t\tconst includeLeads = this.connectionConfig.includeLeads ?? true;\n\t\tif (includeLeads) {\n\t\t\tawait this.pollEntity<SfLead>(\"Lead\", LEAD_FIELDS, \"leads\", \"sf_leads\", mapLead);\n\t\t}\n\n\t\tawait this.flushAccumulator();\n\t}\n\n\t// -----------------------------------------------------------------------\n\t// Generic entity polling via LastModifiedDate cursor\n\t// -----------------------------------------------------------------------\n\n\tprivate async pollEntity<T extends { Id: string; LastModifiedDate: string | null }>(\n\t\tsObjectType: string,\n\t\tfields: string,\n\t\tcursorKey: string,\n\t\ttable: string,\n\t\tmapFn: (record: T) => { rowId: string; row: Record<string, unknown> },\n\t): Promise<void> {\n\t\tconst cursor = this.cursors[cursorKey];\n\t\tconst soql = this.buildSoql(sObjectType, fields, cursor);\n\n\t\tconst result = await this.client.query<T>(soql);\n\t\tif (!result.ok) return;\n\n\t\tconst records = result.value;\n\t\tif (records.length === 0) return;\n\n\t\tlet maxLastModified = cursor;\n\n\t\tfor (const record of records) {\n\t\t\tconst { rowId, row } = mapFn(record);\n\n\t\t\tconst delta = await extractDelta(null, row, {\n\t\t\t\ttable,\n\t\t\t\trowId,\n\t\t\t\tclientId: this.clientId,\n\t\t\t\thlc: this.hlc.now(),\n\t\t\t});\n\n\t\t\tif (delta) {\n\t\t\t\tawait this.accumulateDelta(delta);\n\t\t\t}\n\n\t\t\tconst lastModified = record.LastModifiedDate;\n\t\t\tif (lastModified && (!maxLastModified || lastModified > maxLastModified)) {\n\t\t\t\tmaxLastModified = lastModified;\n\t\t\t}\n\t\t}\n\n\t\tthis.cursors[cursorKey] = maxLastModified;\n\t}\n\n\t// -----------------------------------------------------------------------\n\t// SOQL query builder\n\t// -----------------------------------------------------------------------\n\n\tprivate buildSoql(sObjectType: string, fields: string, cursor: string | undefined): string {\n\t\tconst clauses: string[] = [];\n\n\t\tif (cursor) {\n\t\t\tclauses.push(`LastModifiedDate > ${cursor}`);\n\t\t}\n\n\t\tif (this.connectionConfig.soqlFilter) {\n\t\t\tclauses.push(this.connectionConfig.soqlFilter);\n\t\t}\n\n\t\tconst where = clauses.length > 0 ? ` WHERE ${clauses.join(\" AND \")}` : \"\";\n\t\treturn `SELECT ${fields} FROM ${sObjectType}${where} ORDER BY LastModifiedDate ASC`;\n\t}\n}\n","// ---------------------------------------------------------------------------\n// Salesforce Table Schemas — column definitions for each synced entity\n// ---------------------------------------------------------------------------\n\nimport type { TableSchema } from \"@lakesync/core\";\n\n/** Column helper — all Salesforce columns are mapped to string. */\nfunction textCol(name: string): { name: string; type: \"string\" } {\n\treturn { name, type: \"string\" };\n}\n\n/** Table schemas for all Salesforce entity types synced by the connector. */\nexport const SALESFORCE_TABLE_SCHEMAS: ReadonlyArray<TableSchema> = [\n\t{\n\t\ttable: \"sf_accounts\",\n\t\tcolumns: [\n\t\t\ttextCol(\"sf_id\"),\n\t\t\ttextCol(\"name\"),\n\t\t\ttextCol(\"type\"),\n\t\t\ttextCol(\"industry\"),\n\t\t\ttextCol(\"website\"),\n\t\t\ttextCol(\"phone\"),\n\t\t\ttextCol(\"billing_city\"),\n\t\t\ttextCol(\"billing_state\"),\n\t\t\ttextCol(\"billing_country\"),\n\t\t\ttextCol(\"annual_revenue\"),\n\t\t\ttextCol(\"number_of_employees\"),\n\t\t\ttextCol(\"owner_name\"),\n\t\t\ttextCol(\"created_date\"),\n\t\t\ttextCol(\"last_modified_date\"),\n\t\t],\n\t},\n\t{\n\t\ttable: \"sf_contacts\",\n\t\tcolumns: [\n\t\t\ttextCol(\"sf_id\"),\n\t\t\ttextCol(\"first_name\"),\n\t\t\ttextCol(\"last_name\"),\n\t\t\ttextCol(\"email\"),\n\t\t\ttextCol(\"phone\"),\n\t\t\ttextCol(\"title\"),\n\t\t\t{\n\t\t\t\tname: \"account_id\",\n\t\t\t\ttype: \"string\",\n\t\t\t\treferences: { table: \"sf_accounts\", column: \"sf_id\", cardinality: \"many-to-one\" },\n\t\t\t},\n\t\t\ttextCol(\"account_name\"),\n\t\t\ttextCol(\"mailing_city\"),\n\t\t\ttextCol(\"mailing_state\"),\n\t\t\ttextCol(\"mailing_country\"),\n\t\t\ttextCol(\"owner_name\"),\n\t\t\ttextCol(\"created_date\"),\n\t\t\ttextCol(\"last_modified_date\"),\n\t\t],\n\t},\n\t{\n\t\ttable: \"sf_opportunities\",\n\t\tcolumns: [\n\t\t\ttextCol(\"sf_id\"),\n\t\t\ttextCol(\"name\"),\n\t\t\ttextCol(\"stage_name\"),\n\t\t\ttextCol(\"amount\"),\n\t\t\ttextCol(\"close_date\"),\n\t\t\ttextCol(\"probability\"),\n\t\t\t{\n\t\t\t\tname: \"account_id\",\n\t\t\t\ttype: \"string\",\n\t\t\t\treferences: { table: \"sf_accounts\", column: \"sf_id\", cardinality: \"many-to-one\" },\n\t\t\t},\n\t\t\ttextCol(\"account_name\"),\n\t\t\ttextCol(\"type\"),\n\t\t\ttextCol(\"lead_source\"),\n\t\t\ttextCol(\"is_closed\"),\n\t\t\ttextCol(\"is_won\"),\n\t\t\ttextCol(\"owner_name\"),\n\t\t\ttextCol(\"created_date\"),\n\t\t\ttextCol(\"last_modified_date\"),\n\t\t],\n\t},\n\t{\n\t\ttable: \"sf_leads\",\n\t\tcolumns: [\n\t\t\ttextCol(\"sf_id\"),\n\t\t\ttextCol(\"first_name\"),\n\t\t\ttextCol(\"last_name\"),\n\t\t\ttextCol(\"company\"),\n\t\t\ttextCol(\"email\"),\n\t\t\ttextCol(\"phone\"),\n\t\t\ttextCol(\"title\"),\n\t\t\ttextCol(\"status\"),\n\t\t\ttextCol(\"lead_source\"),\n\t\t\ttextCol(\"is_converted\"),\n\t\t\t{\n\t\t\t\tname: \"converted_account_id\",\n\t\t\t\ttype: \"string\",\n\t\t\t\treferences: { table: \"sf_accounts\", column: \"sf_id\", cardinality: \"many-to-one\" },\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"converted_contact_id\",\n\t\t\t\ttype: \"string\",\n\t\t\t\treferences: { table: \"sf_contacts\", column: \"sf_id\", cardinality: \"many-to-one\" },\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"converted_opportunity_id\",\n\t\t\t\ttype: \"string\",\n\t\t\t\treferences: { table: \"sf_opportunities\", column: \"sf_id\", cardinality: \"many-to-one\" },\n\t\t\t},\n\t\t\ttextCol(\"owner_name\"),\n\t\t\ttextCol(\"created_date\"),\n\t\t\ttextCol(\"last_modified_date\"),\n\t\t],\n\t},\n];\n","import type { Result } from \"@lakesync/core\";\nimport { SalesforceClient } from \"./client\";\nimport type { SalesforceAuthError } from \"./errors\";\nimport type { SalesforceConnectorConfig } from \"./types\";\n\n/**\n * Test a Salesforce connection by attempting OAuth authentication.\n *\n * Creates a `SalesforceClient` internally and calls `authenticate()` —\n * if the OAuth flow succeeds, the connection is valid.\n */\nexport async function testConnection(\n\tconfig: SalesforceConnectorConfig,\n): Promise<Result<void, SalesforceAuthError>> {\n\tconst client = new SalesforceClient(config);\n\treturn client.authenticate();\n}\n","import { registerOutputSchemas, registerPollerFactory } from \"@lakesync/core\";\nimport { SalesforceSourcePoller } from \"./poller\";\nimport { SALESFORCE_TABLE_SCHEMAS } from \"./schemas\";\nimport type { SalesforceIngestConfig } from \"./types\";\n\nexport { SalesforceClient } from \"./client\";\nexport { SalesforceApiError, SalesforceAuthError } from \"./errors\";\nexport { mapAccount, mapContact, mapLead, mapOpportunity } from \"./mapping\";\nexport { SalesforceSourcePoller } from \"./poller\";\nexport { SALESFORCE_TABLE_SCHEMAS } from \"./schemas\";\nexport { testConnection } from \"./test-connection\";\nexport type {\n\tSalesforceAuthResponse,\n\tSalesforceConnectorConfig,\n\tSalesforceIngestConfig,\n\tSalesforceQueryResponse,\n\tSfAccount,\n\tSfContact,\n\tSfLead,\n\tSfOpportunity,\n} from \"./types\";\n\n// Auto-register output schemas so listConnectorDescriptors() includes table info.\nregisterOutputSchemas(\"salesforce\", SALESFORCE_TABLE_SCHEMAS);\n\n// Auto-register poller factory so createPoller(\"salesforce\", ...) works.\nregisterPollerFactory(\"salesforce\", (config, gateway) => {\n\tif (config.type !== \"salesforce\") {\n\t\tthrow new Error(`Expected connector type \"salesforce\", got \"${config.type}\"`);\n\t}\n\tconst ingest: SalesforceIngestConfig | undefined = config.ingest\n\t\t? {\n\t\t\t\tintervalMs: config.ingest.intervalMs,\n\t\t\t\tchunkSize: config.ingest.chunkSize,\n\t\t\t\tmemoryBudgetBytes: config.ingest.memoryBudgetBytes,\n\t\t\t}\n\t\t: undefined;\n\treturn new SalesforceSourcePoller(config.salesforce, ingest, config.name, gateway);\n});\n"],"mappings":"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","names":["responseBody"]}
|
|
1
|
+
{"version":3,"sources":["../../connector-salesforce/src/errors.ts","../../connector-salesforce/src/client.ts","../../connector-salesforce/src/mapping.ts","../../connector-salesforce/src/poller.ts","../../connector-salesforce/src/schemas.ts","../../connector-salesforce/src/test-connection.ts","../../connector-salesforce/src/index.ts"],"sourcesContent":["import { LakeSyncError } from \"@lakesync/core\";\n\n/** HTTP error from the Salesforce REST API. */\nexport class SalesforceApiError extends LakeSyncError {\n\t/** HTTP status code returned by Salesforce. */\n\treadonly statusCode: number;\n\t/** Raw response body from Salesforce. */\n\treadonly responseBody: string;\n\n\tconstructor(statusCode: number, responseBody: string, cause?: Error) {\n\t\tsuper(`Salesforce API error (${statusCode}): ${responseBody}`, \"SALESFORCE_API_ERROR\", cause);\n\t\tthis.statusCode = statusCode;\n\t\tthis.responseBody = responseBody;\n\t}\n}\n\n/** Authentication failure from the Salesforce OAuth token endpoint. */\nexport class SalesforceAuthError extends LakeSyncError {\n\tconstructor(message: string, cause?: Error) {\n\t\tsuper(message, \"SALESFORCE_AUTH_ERROR\", cause);\n\t}\n}\n","// ---------------------------------------------------------------------------\n// SalesforceClient — HTTP wrapper for Salesforce REST API\n// ---------------------------------------------------------------------------\n\nimport { Err, Ok, type Result } from \"@lakesync/core\";\nimport { SalesforceApiError, SalesforceAuthError } from \"./errors\";\nimport type {\n\tSalesforceAuthResponse,\n\tSalesforceConnectorConfig,\n\tSalesforceQueryResponse,\n} from \"./types\";\n\nconst DEFAULT_API_VERSION = \"v62.0\";\nconst MAX_RETRY_ATTEMPTS = 3;\nconst DEFAULT_RETRY_AFTER_MS = 10_000;\n\n/**\n * HTTP client for the Salesforce REST API.\n *\n * Uses OAuth 2.0 Username-Password flow for authentication and global `fetch`.\n * All public methods return `Result<T, SalesforceApiError | SalesforceAuthError>`.\n */\nexport class SalesforceClient {\n\tprivate readonly config: SalesforceConnectorConfig;\n\tprivate readonly apiVersion: string;\n\tprivate readonly loginUrl: string;\n\n\tprivate accessToken: string | null = null;\n\tprivate instanceUrl: string;\n\n\tconstructor(config: SalesforceConnectorConfig) {\n\t\tthis.config = config;\n\t\tthis.apiVersion = config.apiVersion ?? DEFAULT_API_VERSION;\n\t\tthis.loginUrl = config.isSandbox\n\t\t\t? \"https://test.salesforce.com\"\n\t\t\t: \"https://login.salesforce.com\";\n\t\tthis.instanceUrl = config.instanceUrl;\n\t}\n\n\t/**\n\t * Authenticate via OAuth 2.0 Username-Password flow.\n\t *\n\t * Stores access token and updates instance URL from the response.\n\t */\n\tasync authenticate(): Promise<Result<void, SalesforceAuthError>> {\n\t\tconst body = new URLSearchParams({\n\t\t\tgrant_type: \"password\",\n\t\t\tclient_id: this.config.clientId,\n\t\t\tclient_secret: this.config.clientSecret,\n\t\t\tusername: this.config.username,\n\t\t\tpassword: this.config.password,\n\t\t});\n\n\t\tlet response: Response;\n\t\ttry {\n\t\t\tresponse = await fetch(`${this.loginUrl}/services/oauth2/token`, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n\t\t\t\tbody: body.toString(),\n\t\t\t});\n\t\t} catch (err) {\n\t\t\treturn Err(\n\t\t\t\tnew SalesforceAuthError(\n\t\t\t\t\t`Failed to connect to Salesforce auth endpoint: ${err instanceof Error ? err.message : String(err)}`,\n\t\t\t\t\terr instanceof Error ? err : undefined,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\n\t\tif (!response.ok) {\n\t\t\tconst text = await response.text();\n\t\t\treturn Err(\n\t\t\t\tnew SalesforceAuthError(`Salesforce authentication failed (${response.status}): ${text}`),\n\t\t\t);\n\t\t}\n\n\t\tconst data = (await response.json()) as SalesforceAuthResponse;\n\t\tthis.accessToken = data.access_token;\n\t\tthis.instanceUrl = data.instance_url;\n\n\t\treturn Ok(undefined);\n\t}\n\n\t/**\n\t * Execute a SOQL query with auto-pagination.\n\t *\n\t * Automatically authenticates on first call and re-authenticates on 401.\n\t */\n\tasync query<T>(soql: string): Promise<Result<T[], SalesforceApiError | SalesforceAuthError>> {\n\t\t// Ensure we have a token\n\t\tif (!this.accessToken) {\n\t\t\tconst authResult = await this.authenticate();\n\t\t\tif (!authResult.ok) return authResult;\n\t\t}\n\n\t\tconst allRecords: T[] = [];\n\t\tlet url = `${this.instanceUrl}/services/data/${this.apiVersion}/query?q=${encodeURIComponent(soql)}`;\n\n\t\twhile (true) {\n\t\t\tconst result = await this.request<SalesforceQueryResponse<T>>(url);\n\n\t\t\t// Re-auth on 401 and retry once\n\t\t\tif (\n\t\t\t\t!result.ok &&\n\t\t\t\tresult.error instanceof SalesforceApiError &&\n\t\t\t\tresult.error.statusCode === 401\n\t\t\t) {\n\t\t\t\tconst authResult = await this.authenticate();\n\t\t\t\tif (!authResult.ok) return authResult;\n\n\t\t\t\tconst retryResult = await this.request<SalesforceQueryResponse<T>>(url);\n\t\t\t\tif (!retryResult.ok) return retryResult;\n\n\t\t\t\tfor (const record of retryResult.value.records) {\n\t\t\t\t\tallRecords.push(record);\n\t\t\t\t}\n\n\t\t\t\tif (retryResult.value.done || !retryResult.value.nextRecordsUrl) break;\n\t\t\t\turl = `${this.instanceUrl}${retryResult.value.nextRecordsUrl}`;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (!result.ok) return result;\n\n\t\t\tfor (const record of result.value.records) {\n\t\t\t\tallRecords.push(record);\n\t\t\t}\n\n\t\t\tif (result.value.done || !result.value.nextRecordsUrl) break;\n\t\t\turl = `${this.instanceUrl}${result.value.nextRecordsUrl}`;\n\t\t}\n\n\t\treturn Ok(allRecords);\n\t}\n\n\t// -----------------------------------------------------------------------\n\t// Internal HTTP helpers\n\t// -----------------------------------------------------------------------\n\n\t/** Make an HTTP request with rate-limit retry logic. */\n\tprivate async request<T>(\n\t\turl: string,\n\t): Promise<Result<T, SalesforceApiError | SalesforceAuthError>> {\n\t\tfor (let attempt = 0; attempt <= MAX_RETRY_ATTEMPTS; attempt++) {\n\t\t\tconst headers: Record<string, string> = {\n\t\t\t\tAuthorization: `Bearer ${this.accessToken}`,\n\t\t\t\tAccept: \"application/json\",\n\t\t\t};\n\n\t\t\tconst response = await fetch(url, { method: \"GET\", headers });\n\n\t\t\tif (response.ok) {\n\t\t\t\tconst data = (await response.json()) as T;\n\t\t\t\treturn Ok(data);\n\t\t\t}\n\n\t\t\t// Rate limit: 503 with Retry-After\n\t\t\tif (response.status === 503) {\n\t\t\t\tconst retryAfter = response.headers.get(\"Retry-After\");\n\t\t\t\tconst waitMs = retryAfter ? Number.parseInt(retryAfter, 10) * 1000 : DEFAULT_RETRY_AFTER_MS;\n\n\t\t\t\tif (attempt < MAX_RETRY_ATTEMPTS) {\n\t\t\t\t\tawait sleep(waitMs);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst responseBody = await response.text();\n\t\t\t\treturn Err(new SalesforceApiError(503, responseBody));\n\t\t\t}\n\n\t\t\tconst responseBody = await response.text();\n\t\t\treturn Err(new SalesforceApiError(response.status, responseBody));\n\t\t}\n\n\t\treturn Err(new SalesforceApiError(0, \"Unknown error after retries\"));\n\t}\n}\n\n/** Sleep for the given number of milliseconds. */\nfunction sleep(ms: number): Promise<void> {\n\treturn new Promise((resolve) => setTimeout(resolve, ms));\n}\n","// ---------------------------------------------------------------------------\n// Salesforce Entity → Flat LakeSync Row Mapping\n// ---------------------------------------------------------------------------\n\nimport type { SfAccount, SfContact, SfLead, SfOpportunity } from \"./types\";\n\n/**\n * Map a Salesforce Account to a flat row for the `sf_accounts` table.\n *\n * The row ID is the Salesforce record Id.\n */\nexport function mapAccount(account: SfAccount): { rowId: string; row: Record<string, unknown> } {\n\treturn {\n\t\trowId: account.Id,\n\t\trow: {\n\t\t\tsf_id: account.Id,\n\t\t\tname: account.Name ?? null,\n\t\t\ttype: account.Type ?? null,\n\t\t\tindustry: account.Industry ?? null,\n\t\t\twebsite: account.Website ?? null,\n\t\t\tphone: account.Phone ?? null,\n\t\t\tbilling_city: account.BillingCity ?? null,\n\t\t\tbilling_state: account.BillingState ?? null,\n\t\t\tbilling_country: account.BillingCountry ?? null,\n\t\t\tannual_revenue: account.AnnualRevenue ?? null,\n\t\t\tnumber_of_employees: account.NumberOfEmployees ?? null,\n\t\t\towner_name: account.Owner?.Name ?? null,\n\t\t\tcreated_date: account.CreatedDate ?? null,\n\t\t\tlast_modified_date: account.LastModifiedDate ?? null,\n\t\t},\n\t};\n}\n\n/**\n * Map a Salesforce Contact to a flat row for the `sf_contacts` table.\n *\n * The row ID is the Salesforce record Id.\n */\nexport function mapContact(contact: SfContact): { rowId: string; row: Record<string, unknown> } {\n\treturn {\n\t\trowId: contact.Id,\n\t\trow: {\n\t\t\tsf_id: contact.Id,\n\t\t\tfirst_name: contact.FirstName ?? null,\n\t\t\tlast_name: contact.LastName ?? null,\n\t\t\temail: contact.Email ?? null,\n\t\t\tphone: contact.Phone ?? null,\n\t\t\ttitle: contact.Title ?? null,\n\t\t\taccount_id: contact.AccountId ?? null,\n\t\t\taccount_name: contact.Account?.Name ?? null,\n\t\t\tmailing_city: contact.MailingCity ?? null,\n\t\t\tmailing_state: contact.MailingState ?? null,\n\t\t\tmailing_country: contact.MailingCountry ?? null,\n\t\t\towner_name: contact.Owner?.Name ?? null,\n\t\t\tcreated_date: contact.CreatedDate ?? null,\n\t\t\tlast_modified_date: contact.LastModifiedDate ?? null,\n\t\t},\n\t};\n}\n\n/**\n * Map a Salesforce Opportunity to a flat row for the `sf_opportunities` table.\n *\n * The row ID is the Salesforce record Id.\n */\nexport function mapOpportunity(opportunity: SfOpportunity): {\n\trowId: string;\n\trow: Record<string, unknown>;\n} {\n\treturn {\n\t\trowId: opportunity.Id,\n\t\trow: {\n\t\t\tsf_id: opportunity.Id,\n\t\t\tname: opportunity.Name ?? null,\n\t\t\tstage_name: opportunity.StageName ?? null,\n\t\t\tamount: opportunity.Amount ?? null,\n\t\t\tclose_date: opportunity.CloseDate ?? null,\n\t\t\tprobability: opportunity.Probability ?? null,\n\t\t\taccount_id: opportunity.AccountId ?? null,\n\t\t\taccount_name: opportunity.Account?.Name ?? null,\n\t\t\ttype: opportunity.Type ?? null,\n\t\t\tlead_source: opportunity.LeadSource ?? null,\n\t\t\tis_closed: opportunity.IsClosed ?? null,\n\t\t\tis_won: opportunity.IsWon ?? null,\n\t\t\towner_name: opportunity.Owner?.Name ?? null,\n\t\t\tcreated_date: opportunity.CreatedDate ?? null,\n\t\t\tlast_modified_date: opportunity.LastModifiedDate ?? null,\n\t\t},\n\t};\n}\n\n/**\n * Map a Salesforce Lead to a flat row for the `sf_leads` table.\n *\n * The row ID is the Salesforce record Id.\n */\nexport function mapLead(lead: SfLead): { rowId: string; row: Record<string, unknown> } {\n\treturn {\n\t\trowId: lead.Id,\n\t\trow: {\n\t\t\tsf_id: lead.Id,\n\t\t\tfirst_name: lead.FirstName ?? null,\n\t\t\tlast_name: lead.LastName ?? null,\n\t\t\tcompany: lead.Company ?? null,\n\t\t\temail: lead.Email ?? null,\n\t\t\tphone: lead.Phone ?? null,\n\t\t\ttitle: lead.Title ?? null,\n\t\t\tstatus: lead.Status ?? null,\n\t\t\tlead_source: lead.LeadSource ?? null,\n\t\t\tis_converted: lead.IsConverted ?? null,\n\t\t\tconverted_account_id: lead.ConvertedAccountId ?? null,\n\t\t\tconverted_contact_id: lead.ConvertedContactId ?? null,\n\t\t\tconverted_opportunity_id: lead.ConvertedOpportunityId ?? null,\n\t\t\towner_name: lead.Owner?.Name ?? null,\n\t\t\tcreated_date: lead.CreatedDate ?? null,\n\t\t\tlast_modified_date: lead.LastModifiedDate ?? null,\n\t\t},\n\t};\n}\n","// ---------------------------------------------------------------------------\n// SalesforceSourcePoller — polls Salesforce CRM and pushes deltas to SyncGateway\n// ---------------------------------------------------------------------------\n\nimport { BaseSourcePoller, extractDelta, type PushTarget } from \"@lakesync/core\";\nimport { SalesforceClient } from \"./client\";\nimport { mapAccount, mapContact, mapLead, mapOpportunity } from \"./mapping\";\nimport type {\n\tSalesforceConnectorConfig,\n\tSalesforceIngestConfig,\n\tSfAccount,\n\tSfContact,\n\tSfLead,\n\tSfOpportunity,\n} from \"./types\";\n\nconst DEFAULT_INTERVAL_MS = 30_000;\n\n// ---------------------------------------------------------------------------\n// SOQL field lists\n// ---------------------------------------------------------------------------\n\nconst ACCOUNT_FIELDS = [\n\t\"Id\",\n\t\"Name\",\n\t\"Type\",\n\t\"Industry\",\n\t\"Website\",\n\t\"Phone\",\n\t\"BillingCity\",\n\t\"BillingState\",\n\t\"BillingCountry\",\n\t\"AnnualRevenue\",\n\t\"NumberOfEmployees\",\n\t\"Owner.Name\",\n\t\"CreatedDate\",\n\t\"LastModifiedDate\",\n].join(\", \");\n\nconst CONTACT_FIELDS = [\n\t\"Id\",\n\t\"FirstName\",\n\t\"LastName\",\n\t\"Email\",\n\t\"Phone\",\n\t\"Title\",\n\t\"AccountId\",\n\t\"Account.Name\",\n\t\"MailingCity\",\n\t\"MailingState\",\n\t\"MailingCountry\",\n\t\"Owner.Name\",\n\t\"CreatedDate\",\n\t\"LastModifiedDate\",\n].join(\", \");\n\nconst OPPORTUNITY_FIELDS = [\n\t\"Id\",\n\t\"Name\",\n\t\"StageName\",\n\t\"Amount\",\n\t\"CloseDate\",\n\t\"Probability\",\n\t\"AccountId\",\n\t\"Account.Name\",\n\t\"Type\",\n\t\"LeadSource\",\n\t\"IsClosed\",\n\t\"IsWon\",\n\t\"Owner.Name\",\n\t\"CreatedDate\",\n\t\"LastModifiedDate\",\n].join(\", \");\n\nconst LEAD_FIELDS = [\n\t\"Id\",\n\t\"FirstName\",\n\t\"LastName\",\n\t\"Company\",\n\t\"Email\",\n\t\"Phone\",\n\t\"Title\",\n\t\"Status\",\n\t\"LeadSource\",\n\t\"IsConverted\",\n\t\"ConvertedAccountId\",\n\t\"ConvertedContactId\",\n\t\"ConvertedOpportunityId\",\n\t\"Owner.Name\",\n\t\"CreatedDate\",\n\t\"LastModifiedDate\",\n].join(\", \");\n\n/**\n * Polls Salesforce CRM for accounts, contacts, opportunities, and leads\n * and pushes detected changes into a gateway via streaming accumulation.\n *\n * Uses {@link BaseSourcePoller.accumulateDelta} to push deltas in\n * memory-bounded chunks instead of collecting all deltas in a single array.\n */\nexport class SalesforceSourcePoller extends BaseSourcePoller {\n\tprivate readonly connectionConfig: SalesforceConnectorConfig;\n\tprivate readonly client: SalesforceClient;\n\n\t/** Per-entity cursors: max LastModifiedDate from the last poll. */\n\tprivate cursors: Record<string, string | undefined> = {\n\t\taccounts: undefined,\n\t\tcontacts: undefined,\n\t\topportunities: undefined,\n\t\tleads: undefined,\n\t};\n\n\t/** Export cursor state as a JSON-serialisable object for external persistence. */\n\toverride getCursorState(): Record<string, unknown> {\n\t\treturn { ...this.cursors };\n\t}\n\n\t/** Restore cursor state from a previously exported snapshot. */\n\toverride setCursorState(state: Record<string, unknown>): void {\n\t\tconst incoming = state as Record<string, string | undefined>;\n\t\tthis.cursors = {\n\t\t\taccounts: incoming.accounts,\n\t\t\tcontacts: incoming.contacts,\n\t\t\topportunities: incoming.opportunities,\n\t\t\tleads: incoming.leads,\n\t\t};\n\t}\n\n\tconstructor(\n\t\tconnectionConfig: SalesforceConnectorConfig,\n\t\tingestConfig: SalesforceIngestConfig | undefined,\n\t\tname: string,\n\t\tgateway: PushTarget,\n\t\tclient?: SalesforceClient,\n\t) {\n\t\tsuper({\n\t\t\tname,\n\t\t\tintervalMs: ingestConfig?.intervalMs ?? DEFAULT_INTERVAL_MS,\n\t\t\tgateway,\n\t\t\tmemory: {\n\t\t\t\tchunkSize: ingestConfig?.chunkSize,\n\t\t\t\tmemoryBudgetBytes: ingestConfig?.memoryBudgetBytes,\n\t\t\t},\n\t\t});\n\t\tthis.connectionConfig = connectionConfig;\n\t\tthis.client = client ?? new SalesforceClient(connectionConfig);\n\t}\n\n\t/** Execute a single poll cycle across all enabled entity types. */\n\tasync poll(): Promise<void> {\n\t\tconst includeAccounts = this.connectionConfig.includeAccounts ?? true;\n\t\tif (includeAccounts) {\n\t\t\tawait this.pollEntity<SfAccount>(\n\t\t\t\t\"Account\",\n\t\t\t\tACCOUNT_FIELDS,\n\t\t\t\t\"accounts\",\n\t\t\t\t\"sf_accounts\",\n\t\t\t\tmapAccount,\n\t\t\t);\n\t\t}\n\n\t\tconst includeContacts = this.connectionConfig.includeContacts ?? true;\n\t\tif (includeContacts) {\n\t\t\tawait this.pollEntity<SfContact>(\n\t\t\t\t\"Contact\",\n\t\t\t\tCONTACT_FIELDS,\n\t\t\t\t\"contacts\",\n\t\t\t\t\"sf_contacts\",\n\t\t\t\tmapContact,\n\t\t\t);\n\t\t}\n\n\t\tconst includeOpportunities = this.connectionConfig.includeOpportunities ?? true;\n\t\tif (includeOpportunities) {\n\t\t\tawait this.pollEntity<SfOpportunity>(\n\t\t\t\t\"Opportunity\",\n\t\t\t\tOPPORTUNITY_FIELDS,\n\t\t\t\t\"opportunities\",\n\t\t\t\t\"sf_opportunities\",\n\t\t\t\tmapOpportunity,\n\t\t\t);\n\t\t}\n\n\t\tconst includeLeads = this.connectionConfig.includeLeads ?? true;\n\t\tif (includeLeads) {\n\t\t\tawait this.pollEntity<SfLead>(\"Lead\", LEAD_FIELDS, \"leads\", \"sf_leads\", mapLead);\n\t\t}\n\n\t\tawait this.flushAccumulator();\n\t}\n\n\t// -----------------------------------------------------------------------\n\t// Generic entity polling via LastModifiedDate cursor\n\t// -----------------------------------------------------------------------\n\n\tprivate async pollEntity<T extends { Id: string; LastModifiedDate: string | null }>(\n\t\tsObjectType: string,\n\t\tfields: string,\n\t\tcursorKey: string,\n\t\ttable: string,\n\t\tmapFn: (record: T) => { rowId: string; row: Record<string, unknown> },\n\t): Promise<void> {\n\t\tconst cursor = this.cursors[cursorKey];\n\t\tconst soql = this.buildSoql(sObjectType, fields, cursor);\n\n\t\tconst result = await this.client.query<T>(soql);\n\t\tif (!result.ok) return;\n\n\t\tconst records = result.value;\n\t\tif (records.length === 0) return;\n\n\t\tlet maxLastModified = cursor;\n\n\t\tfor (const record of records) {\n\t\t\tconst { rowId, row } = mapFn(record);\n\n\t\t\tconst delta = await extractDelta(null, row, {\n\t\t\t\ttable,\n\t\t\t\trowId,\n\t\t\t\tclientId: this.clientId,\n\t\t\t\thlc: this.hlc.now(),\n\t\t\t});\n\n\t\t\tif (delta) {\n\t\t\t\tawait this.accumulateDelta(delta);\n\t\t\t}\n\n\t\t\tconst lastModified = record.LastModifiedDate;\n\t\t\tif (lastModified && (!maxLastModified || lastModified > maxLastModified)) {\n\t\t\t\tmaxLastModified = lastModified;\n\t\t\t}\n\t\t}\n\n\t\tthis.cursors[cursorKey] = maxLastModified;\n\t}\n\n\t// -----------------------------------------------------------------------\n\t// SOQL query builder\n\t// -----------------------------------------------------------------------\n\n\tprivate buildSoql(sObjectType: string, fields: string, cursor: string | undefined): string {\n\t\tconst clauses: string[] = [];\n\n\t\tif (cursor) {\n\t\t\tclauses.push(`LastModifiedDate > ${cursor}`);\n\t\t}\n\n\t\tif (this.connectionConfig.soqlFilter) {\n\t\t\tclauses.push(this.connectionConfig.soqlFilter);\n\t\t}\n\n\t\tconst where = clauses.length > 0 ? ` WHERE ${clauses.join(\" AND \")}` : \"\";\n\t\treturn `SELECT ${fields} FROM ${sObjectType}${where} ORDER BY LastModifiedDate ASC`;\n\t}\n}\n","// ---------------------------------------------------------------------------\n// Salesforce Table Schemas — column definitions for each synced entity\n// ---------------------------------------------------------------------------\n\nimport type { TableSchema } from \"@lakesync/core\";\n\n/** Column helper — all Salesforce columns are mapped to string. */\nfunction textCol(name: string): { name: string; type: \"string\" } {\n\treturn { name, type: \"string\" };\n}\n\n/** Table schemas for all Salesforce entity types synced by the connector. */\nexport const SALESFORCE_TABLE_SCHEMAS: ReadonlyArray<TableSchema> = [\n\t{\n\t\ttable: \"sf_accounts\",\n\t\tcolumns: [\n\t\t\ttextCol(\"sf_id\"),\n\t\t\ttextCol(\"name\"),\n\t\t\ttextCol(\"type\"),\n\t\t\ttextCol(\"industry\"),\n\t\t\ttextCol(\"website\"),\n\t\t\ttextCol(\"phone\"),\n\t\t\ttextCol(\"billing_city\"),\n\t\t\ttextCol(\"billing_state\"),\n\t\t\ttextCol(\"billing_country\"),\n\t\t\ttextCol(\"annual_revenue\"),\n\t\t\ttextCol(\"number_of_employees\"),\n\t\t\ttextCol(\"owner_name\"),\n\t\t\ttextCol(\"created_date\"),\n\t\t\ttextCol(\"last_modified_date\"),\n\t\t],\n\t},\n\t{\n\t\ttable: \"sf_contacts\",\n\t\tcolumns: [\n\t\t\ttextCol(\"sf_id\"),\n\t\t\ttextCol(\"first_name\"),\n\t\t\ttextCol(\"last_name\"),\n\t\t\ttextCol(\"email\"),\n\t\t\ttextCol(\"phone\"),\n\t\t\ttextCol(\"title\"),\n\t\t\t{\n\t\t\t\tname: \"account_id\",\n\t\t\t\ttype: \"string\",\n\t\t\t\treferences: { table: \"sf_accounts\", column: \"sf_id\", cardinality: \"many-to-one\" },\n\t\t\t},\n\t\t\ttextCol(\"account_name\"),\n\t\t\ttextCol(\"mailing_city\"),\n\t\t\ttextCol(\"mailing_state\"),\n\t\t\ttextCol(\"mailing_country\"),\n\t\t\ttextCol(\"owner_name\"),\n\t\t\ttextCol(\"created_date\"),\n\t\t\ttextCol(\"last_modified_date\"),\n\t\t],\n\t},\n\t{\n\t\ttable: \"sf_opportunities\",\n\t\tcolumns: [\n\t\t\ttextCol(\"sf_id\"),\n\t\t\ttextCol(\"name\"),\n\t\t\ttextCol(\"stage_name\"),\n\t\t\ttextCol(\"amount\"),\n\t\t\ttextCol(\"close_date\"),\n\t\t\ttextCol(\"probability\"),\n\t\t\t{\n\t\t\t\tname: \"account_id\",\n\t\t\t\ttype: \"string\",\n\t\t\t\treferences: { table: \"sf_accounts\", column: \"sf_id\", cardinality: \"many-to-one\" },\n\t\t\t},\n\t\t\ttextCol(\"account_name\"),\n\t\t\ttextCol(\"type\"),\n\t\t\ttextCol(\"lead_source\"),\n\t\t\ttextCol(\"is_closed\"),\n\t\t\ttextCol(\"is_won\"),\n\t\t\ttextCol(\"owner_name\"),\n\t\t\ttextCol(\"created_date\"),\n\t\t\ttextCol(\"last_modified_date\"),\n\t\t],\n\t},\n\t{\n\t\ttable: \"sf_leads\",\n\t\tcolumns: [\n\t\t\ttextCol(\"sf_id\"),\n\t\t\ttextCol(\"first_name\"),\n\t\t\ttextCol(\"last_name\"),\n\t\t\ttextCol(\"company\"),\n\t\t\ttextCol(\"email\"),\n\t\t\ttextCol(\"phone\"),\n\t\t\ttextCol(\"title\"),\n\t\t\ttextCol(\"status\"),\n\t\t\ttextCol(\"lead_source\"),\n\t\t\ttextCol(\"is_converted\"),\n\t\t\t{\n\t\t\t\tname: \"converted_account_id\",\n\t\t\t\ttype: \"string\",\n\t\t\t\treferences: { table: \"sf_accounts\", column: \"sf_id\", cardinality: \"many-to-one\" },\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"converted_contact_id\",\n\t\t\t\ttype: \"string\",\n\t\t\t\treferences: { table: \"sf_contacts\", column: \"sf_id\", cardinality: \"many-to-one\" },\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"converted_opportunity_id\",\n\t\t\t\ttype: \"string\",\n\t\t\t\treferences: { table: \"sf_opportunities\", column: \"sf_id\", cardinality: \"many-to-one\" },\n\t\t\t},\n\t\t\ttextCol(\"owner_name\"),\n\t\t\ttextCol(\"created_date\"),\n\t\t\ttextCol(\"last_modified_date\"),\n\t\t],\n\t},\n];\n","import type { Result } from \"@lakesync/core\";\nimport { SalesforceClient } from \"./client\";\nimport type { SalesforceAuthError } from \"./errors\";\nimport type { SalesforceConnectorConfig } from \"./types\";\n\n/**\n * Test a Salesforce connection by attempting OAuth authentication.\n *\n * Creates a `SalesforceClient` internally and calls `authenticate()` —\n * if the OAuth flow succeeds, the connection is valid.\n */\nexport async function testConnection(\n\tconfig: SalesforceConnectorConfig,\n): Promise<Result<void, SalesforceAuthError>> {\n\tconst client = new SalesforceClient(config);\n\treturn client.authenticate();\n}\n","import {\n\ttype BaseSourcePoller,\n\ttype ConnectorConfig,\n\ttype PushTarget,\n\tregisterOutputSchemas,\n\ttype SalesforceConnectorConfigFull,\n} from \"@lakesync/core\";\nimport { SalesforceSourcePoller } from \"./poller\";\nimport { SALESFORCE_TABLE_SCHEMAS } from \"./schemas\";\nimport type { SalesforceIngestConfig } from \"./types\";\n\nexport { SalesforceClient } from \"./client\";\nexport { SalesforceApiError, SalesforceAuthError } from \"./errors\";\nexport { mapAccount, mapContact, mapLead, mapOpportunity } from \"./mapping\";\nexport { SalesforceSourcePoller } from \"./poller\";\nexport { SALESFORCE_TABLE_SCHEMAS } from \"./schemas\";\nexport { testConnection } from \"./test-connection\";\nexport type {\n\tSalesforceAuthResponse,\n\tSalesforceConnectorConfig,\n\tSalesforceIngestConfig,\n\tSalesforceQueryResponse,\n\tSfAccount,\n\tSfContact,\n\tSfLead,\n\tSfOpportunity,\n} from \"./types\";\n\n/**\n * Poller factory for Salesforce connectors.\n *\n * Register with a {@link import(\"@lakesync/core\").PollerRegistry} via `.with(\"salesforce\", salesforcePollerFactory)`.\n */\nexport function salesforcePollerFactory(\n\tconfig: ConnectorConfig,\n\tgateway: PushTarget,\n): BaseSourcePoller {\n\tif (config.type !== \"salesforce\") {\n\t\tthrow new Error(`Expected connector type \"salesforce\", got \"${config.type}\"`);\n\t}\n\tconst sfConfig = config as SalesforceConnectorConfigFull;\n\tconst ingest: SalesforceIngestConfig | undefined = sfConfig.ingest\n\t\t? {\n\t\t\t\tintervalMs: sfConfig.ingest.intervalMs,\n\t\t\t\tchunkSize: sfConfig.ingest.chunkSize,\n\t\t\t\tmemoryBudgetBytes: sfConfig.ingest.memoryBudgetBytes,\n\t\t\t}\n\t\t: undefined;\n\treturn new SalesforceSourcePoller(sfConfig.salesforce, ingest, sfConfig.name, gateway);\n}\n\n/** @deprecated Use {@link salesforcePollerFactory} instead. */\nexport const createSalesforcePoller = salesforcePollerFactory;\n\n// Auto-register output schemas so listConnectorDescriptors() includes table info.\nregisterOutputSchemas(\"salesforce\", SALESFORCE_TABLE_SCHEMAS);\n"],"mappings":";;;;;;;;;;AAGO,IAAM,qBAAN,cAAiC,cAAc;AAAA;AAAA,EAE5C;AAAA;AAAA,EAEA;AAAA,EAET,YAAY,YAAoB,cAAsB,OAAe;AACpE,UAAM,yBAAyB,UAAU,MAAM,YAAY,IAAI,wBAAwB,KAAK;AAC5F,SAAK,aAAa;AAClB,SAAK,eAAe;AAAA,EACrB;AACD;AAGO,IAAM,sBAAN,cAAkC,cAAc;AAAA,EACtD,YAAY,SAAiB,OAAe;AAC3C,UAAM,SAAS,yBAAyB,KAAK;AAAA,EAC9C;AACD;;;ACTA,IAAM,sBAAsB;AAC5B,IAAM,qBAAqB;AAC3B,IAAM,yBAAyB;AAQxB,IAAM,mBAAN,MAAuB;AAAA,EACZ;AAAA,EACA;AAAA,EACA;AAAA,EAET,cAA6B;AAAA,EAC7B;AAAA,EAER,YAAY,QAAmC;AAC9C,SAAK,SAAS;AACd,SAAK,aAAa,OAAO,cAAc;AACvC,SAAK,WAAW,OAAO,YACpB,gCACA;AACH,SAAK,cAAc,OAAO;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,eAA2D;AAChE,UAAM,OAAO,IAAI,gBAAgB;AAAA,MAChC,YAAY;AAAA,MACZ,WAAW,KAAK,OAAO;AAAA,MACvB,eAAe,KAAK,OAAO;AAAA,MAC3B,UAAU,KAAK,OAAO;AAAA,MACtB,UAAU,KAAK,OAAO;AAAA,IACvB,CAAC;AAED,QAAI;AACJ,QAAI;AACH,iBAAW,MAAM,MAAM,GAAG,KAAK,QAAQ,0BAA0B;AAAA,QAChE,QAAQ;AAAA,QACR,SAAS,EAAE,gBAAgB,oCAAoC;AAAA,QAC/D,MAAM,KAAK,SAAS;AAAA,MACrB,CAAC;AAAA,IACF,SAAS,KAAK;AACb,aAAO;AAAA,QACN,IAAI;AAAA,UACH,kDAAkD,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,UAClG,eAAe,QAAQ,MAAM;AAAA,QAC9B;AAAA,MACD;AAAA,IACD;AAEA,QAAI,CAAC,SAAS,IAAI;AACjB,YAAM,OAAO,MAAM,SAAS,KAAK;AACjC,aAAO;AAAA,QACN,IAAI,oBAAoB,qCAAqC,SAAS,MAAM,MAAM,IAAI,EAAE;AAAA,MACzF;AAAA,IACD;AAEA,UAAM,OAAQ,MAAM,SAAS,KAAK;AAClC,SAAK,cAAc,KAAK;AACxB,SAAK,cAAc,KAAK;AAExB,WAAO,GAAG,MAAS;AAAA,EACpB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,MAAS,MAA8E;AAE5F,QAAI,CAAC,KAAK,aAAa;AACtB,YAAM,aAAa,MAAM,KAAK,aAAa;AAC3C,UAAI,CAAC,WAAW,GAAI,QAAO;AAAA,IAC5B;AAEA,UAAM,aAAkB,CAAC;AACzB,QAAI,MAAM,GAAG,KAAK,WAAW,kBAAkB,KAAK,UAAU,YAAY,mBAAmB,IAAI,CAAC;AAElG,WAAO,MAAM;AACZ,YAAM,SAAS,MAAM,KAAK,QAAoC,GAAG;AAGjE,UACC,CAAC,OAAO,MACR,OAAO,iBAAiB,sBACxB,OAAO,MAAM,eAAe,KAC3B;AACD,cAAM,aAAa,MAAM,KAAK,aAAa;AAC3C,YAAI,CAAC,WAAW,GAAI,QAAO;AAE3B,cAAM,cAAc,MAAM,KAAK,QAAoC,GAAG;AACtE,YAAI,CAAC,YAAY,GAAI,QAAO;AAE5B,mBAAW,UAAU,YAAY,MAAM,SAAS;AAC/C,qBAAW,KAAK,MAAM;AAAA,QACvB;AAEA,YAAI,YAAY,MAAM,QAAQ,CAAC,YAAY,MAAM,eAAgB;AACjE,cAAM,GAAG,KAAK,WAAW,GAAG,YAAY,MAAM,cAAc;AAC5D;AAAA,MACD;AAEA,UAAI,CAAC,OAAO,GAAI,QAAO;AAEvB,iBAAW,UAAU,OAAO,MAAM,SAAS;AAC1C,mBAAW,KAAK,MAAM;AAAA,MACvB;AAEA,UAAI,OAAO,MAAM,QAAQ,CAAC,OAAO,MAAM,eAAgB;AACvD,YAAM,GAAG,KAAK,WAAW,GAAG,OAAO,MAAM,cAAc;AAAA,IACxD;AAEA,WAAO,GAAG,UAAU;AAAA,EACrB;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAc,QACb,KAC+D;AAC/D,aAAS,UAAU,GAAG,WAAW,oBAAoB,WAAW;AAC/D,YAAM,UAAkC;AAAA,QACvC,eAAe,UAAU,KAAK,WAAW;AAAA,QACzC,QAAQ;AAAA,MACT;AAEA,YAAM,WAAW,MAAM,MAAM,KAAK,EAAE,QAAQ,OAAO,QAAQ,CAAC;AAE5D,UAAI,SAAS,IAAI;AAChB,cAAM,OAAQ,MAAM,SAAS,KAAK;AAClC,eAAO,GAAG,IAAI;AAAA,MACf;AAGA,UAAI,SAAS,WAAW,KAAK;AAC5B,cAAM,aAAa,SAAS,QAAQ,IAAI,aAAa;AACrD,cAAM,SAAS,aAAa,OAAO,SAAS,YAAY,EAAE,IAAI,MAAO;AAErE,YAAI,UAAU,oBAAoB;AACjC,gBAAM,MAAM,MAAM;AAClB;AAAA,QACD;AAEA,cAAMA,gBAAe,MAAM,SAAS,KAAK;AACzC,eAAO,IAAI,IAAI,mBAAmB,KAAKA,aAAY,CAAC;AAAA,MACrD;AAEA,YAAM,eAAe,MAAM,SAAS,KAAK;AACzC,aAAO,IAAI,IAAI,mBAAmB,SAAS,QAAQ,YAAY,CAAC;AAAA,IACjE;AAEA,WAAO,IAAI,IAAI,mBAAmB,GAAG,6BAA6B,CAAC;AAAA,EACpE;AACD;AAGA,SAAS,MAAM,IAA2B;AACzC,SAAO,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,EAAE,CAAC;AACxD;;;AC1KO,SAAS,WAAW,SAAqE;AAC/F,SAAO;AAAA,IACN,OAAO,QAAQ;AAAA,IACf,KAAK;AAAA,MACJ,OAAO,QAAQ;AAAA,MACf,MAAM,QAAQ,QAAQ;AAAA,MACtB,MAAM,QAAQ,QAAQ;AAAA,MACtB,UAAU,QAAQ,YAAY;AAAA,MAC9B,SAAS,QAAQ,WAAW;AAAA,MAC5B,OAAO,QAAQ,SAAS;AAAA,MACxB,cAAc,QAAQ,eAAe;AAAA,MACrC,eAAe,QAAQ,gBAAgB;AAAA,MACvC,iBAAiB,QAAQ,kBAAkB;AAAA,MAC3C,gBAAgB,QAAQ,iBAAiB;AAAA,MACzC,qBAAqB,QAAQ,qBAAqB;AAAA,MAClD,YAAY,QAAQ,OAAO,QAAQ;AAAA,MACnC,cAAc,QAAQ,eAAe;AAAA,MACrC,oBAAoB,QAAQ,oBAAoB;AAAA,IACjD;AAAA,EACD;AACD;AAOO,SAAS,WAAW,SAAqE;AAC/F,SAAO;AAAA,IACN,OAAO,QAAQ;AAAA,IACf,KAAK;AAAA,MACJ,OAAO,QAAQ;AAAA,MACf,YAAY,QAAQ,aAAa;AAAA,MACjC,WAAW,QAAQ,YAAY;AAAA,MAC/B,OAAO,QAAQ,SAAS;AAAA,MACxB,OAAO,QAAQ,SAAS;AAAA,MACxB,OAAO,QAAQ,SAAS;AAAA,MACxB,YAAY,QAAQ,aAAa;AAAA,MACjC,cAAc,QAAQ,SAAS,QAAQ;AAAA,MACvC,cAAc,QAAQ,eAAe;AAAA,MACrC,eAAe,QAAQ,gBAAgB;AAAA,MACvC,iBAAiB,QAAQ,kBAAkB;AAAA,MAC3C,YAAY,QAAQ,OAAO,QAAQ;AAAA,MACnC,cAAc,QAAQ,eAAe;AAAA,MACrC,oBAAoB,QAAQ,oBAAoB;AAAA,IACjD;AAAA,EACD;AACD;AAOO,SAAS,eAAe,aAG7B;AACD,SAAO;AAAA,IACN,OAAO,YAAY;AAAA,IACnB,KAAK;AAAA,MACJ,OAAO,YAAY;AAAA,MACnB,MAAM,YAAY,QAAQ;AAAA,MAC1B,YAAY,YAAY,aAAa;AAAA,MACrC,QAAQ,YAAY,UAAU;AAAA,MAC9B,YAAY,YAAY,aAAa;AAAA,MACrC,aAAa,YAAY,eAAe;AAAA,MACxC,YAAY,YAAY,aAAa;AAAA,MACrC,cAAc,YAAY,SAAS,QAAQ;AAAA,MAC3C,MAAM,YAAY,QAAQ;AAAA,MAC1B,aAAa,YAAY,cAAc;AAAA,MACvC,WAAW,YAAY,YAAY;AAAA,MACnC,QAAQ,YAAY,SAAS;AAAA,MAC7B,YAAY,YAAY,OAAO,QAAQ;AAAA,MACvC,cAAc,YAAY,eAAe;AAAA,MACzC,oBAAoB,YAAY,oBAAoB;AAAA,IACrD;AAAA,EACD;AACD;AAOO,SAAS,QAAQ,MAA+D;AACtF,SAAO;AAAA,IACN,OAAO,KAAK;AAAA,IACZ,KAAK;AAAA,MACJ,OAAO,KAAK;AAAA,MACZ,YAAY,KAAK,aAAa;AAAA,MAC9B,WAAW,KAAK,YAAY;AAAA,MAC5B,SAAS,KAAK,WAAW;AAAA,MACzB,OAAO,KAAK,SAAS;AAAA,MACrB,OAAO,KAAK,SAAS;AAAA,MACrB,OAAO,KAAK,SAAS;AAAA,MACrB,QAAQ,KAAK,UAAU;AAAA,MACvB,aAAa,KAAK,cAAc;AAAA,MAChC,cAAc,KAAK,eAAe;AAAA,MAClC,sBAAsB,KAAK,sBAAsB;AAAA,MACjD,sBAAsB,KAAK,sBAAsB;AAAA,MACjD,0BAA0B,KAAK,0BAA0B;AAAA,MACzD,YAAY,KAAK,OAAO,QAAQ;AAAA,MAChC,cAAc,KAAK,eAAe;AAAA,MAClC,oBAAoB,KAAK,oBAAoB;AAAA,IAC9C;AAAA,EACD;AACD;;;ACtGA,IAAM,sBAAsB;AAM5B,IAAM,iBAAiB;AAAA,EACtB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD,EAAE,KAAK,IAAI;AAEX,IAAM,iBAAiB;AAAA,EACtB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD,EAAE,KAAK,IAAI;AAEX,IAAM,qBAAqB;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD,EAAE,KAAK,IAAI;AAEX,IAAM,cAAc;AAAA,EACnB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD,EAAE,KAAK,IAAI;AASJ,IAAM,yBAAN,cAAqC,iBAAiB;AAAA,EAC3C;AAAA,EACA;AAAA;AAAA,EAGT,UAA8C;AAAA,IACrD,UAAU;AAAA,IACV,UAAU;AAAA,IACV,eAAe;AAAA,IACf,OAAO;AAAA,EACR;AAAA;AAAA,EAGS,iBAA0C;AAClD,WAAO,EAAE,GAAG,KAAK,QAAQ;AAAA,EAC1B;AAAA;AAAA,EAGS,eAAe,OAAsC;AAC7D,UAAM,WAAW;AACjB,SAAK,UAAU;AAAA,MACd,UAAU,SAAS;AAAA,MACnB,UAAU,SAAS;AAAA,MACnB,eAAe,SAAS;AAAA,MACxB,OAAO,SAAS;AAAA,IACjB;AAAA,EACD;AAAA,EAEA,YACC,kBACA,cACA,MACA,SACA,QACC;AACD,UAAM;AAAA,MACL;AAAA,MACA,YAAY,cAAc,cAAc;AAAA,MACxC;AAAA,MACA,QAAQ;AAAA,QACP,WAAW,cAAc;AAAA,QACzB,mBAAmB,cAAc;AAAA,MAClC;AAAA,IACD,CAAC;AACD,SAAK,mBAAmB;AACxB,SAAK,SAAS,UAAU,IAAI,iBAAiB,gBAAgB;AAAA,EAC9D;AAAA;AAAA,EAGA,MAAM,OAAsB;AAC3B,UAAM,kBAAkB,KAAK,iBAAiB,mBAAmB;AACjE,QAAI,iBAAiB;AACpB,YAAM,KAAK;AAAA,QACV;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACD;AAAA,IACD;AAEA,UAAM,kBAAkB,KAAK,iBAAiB,mBAAmB;AACjE,QAAI,iBAAiB;AACpB,YAAM,KAAK;AAAA,QACV;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACD;AAAA,IACD;AAEA,UAAM,uBAAuB,KAAK,iBAAiB,wBAAwB;AAC3E,QAAI,sBAAsB;AACzB,YAAM,KAAK;AAAA,QACV;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACD;AAAA,IACD;AAEA,UAAM,eAAe,KAAK,iBAAiB,gBAAgB;AAC3D,QAAI,cAAc;AACjB,YAAM,KAAK,WAAmB,QAAQ,aAAa,SAAS,YAAY,OAAO;AAAA,IAChF;AAEA,UAAM,KAAK,iBAAiB;AAAA,EAC7B;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,WACb,aACA,QACA,WACA,OACA,OACgB;AAChB,UAAM,SAAS,KAAK,QAAQ,SAAS;AACrC,UAAM,OAAO,KAAK,UAAU,aAAa,QAAQ,MAAM;AAEvD,UAAM,SAAS,MAAM,KAAK,OAAO,MAAS,IAAI;AAC9C,QAAI,CAAC,OAAO,GAAI;AAEhB,UAAM,UAAU,OAAO;AACvB,QAAI,QAAQ,WAAW,EAAG;AAE1B,QAAI,kBAAkB;AAEtB,eAAW,UAAU,SAAS;AAC7B,YAAM,EAAE,OAAO,IAAI,IAAI,MAAM,MAAM;AAEnC,YAAM,QAAQ,MAAM,aAAa,MAAM,KAAK;AAAA,QAC3C;AAAA,QACA;AAAA,QACA,UAAU,KAAK;AAAA,QACf,KAAK,KAAK,IAAI,IAAI;AAAA,MACnB,CAAC;AAED,UAAI,OAAO;AACV,cAAM,KAAK,gBAAgB,KAAK;AAAA,MACjC;AAEA,YAAM,eAAe,OAAO;AAC5B,UAAI,iBAAiB,CAAC,mBAAmB,eAAe,kBAAkB;AACzE,0BAAkB;AAAA,MACnB;AAAA,IACD;AAEA,SAAK,QAAQ,SAAS,IAAI;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA,EAMQ,UAAU,aAAqB,QAAgB,QAAoC;AAC1F,UAAM,UAAoB,CAAC;AAE3B,QAAI,QAAQ;AACX,cAAQ,KAAK,sBAAsB,MAAM,EAAE;AAAA,IAC5C;AAEA,QAAI,KAAK,iBAAiB,YAAY;AACrC,cAAQ,KAAK,KAAK,iBAAiB,UAAU;AAAA,IAC9C;AAEA,UAAM,QAAQ,QAAQ,SAAS,IAAI,UAAU,QAAQ,KAAK,OAAO,CAAC,KAAK;AACvE,WAAO,UAAU,MAAM,SAAS,WAAW,GAAG,KAAK;AAAA,EACpD;AACD;;;ACvPA,SAAS,QAAQ,MAAgD;AAChE,SAAO,EAAE,MAAM,MAAM,SAAS;AAC/B;AAGO,IAAM,2BAAuD;AAAA,EACnE;AAAA,IACC,OAAO;AAAA,IACP,SAAS;AAAA,MACR,QAAQ,OAAO;AAAA,MACf,QAAQ,MAAM;AAAA,MACd,QAAQ,MAAM;AAAA,MACd,QAAQ,UAAU;AAAA,MAClB,QAAQ,SAAS;AAAA,MACjB,QAAQ,OAAO;AAAA,MACf,QAAQ,cAAc;AAAA,MACtB,QAAQ,eAAe;AAAA,MACvB,QAAQ,iBAAiB;AAAA,MACzB,QAAQ,gBAAgB;AAAA,MACxB,QAAQ,qBAAqB;AAAA,MAC7B,QAAQ,YAAY;AAAA,MACpB,QAAQ,cAAc;AAAA,MACtB,QAAQ,oBAAoB;AAAA,IAC7B;AAAA,EACD;AAAA,EACA;AAAA,IACC,OAAO;AAAA,IACP,SAAS;AAAA,MACR,QAAQ,OAAO;AAAA,MACf,QAAQ,YAAY;AAAA,MACpB,QAAQ,WAAW;AAAA,MACnB,QAAQ,OAAO;AAAA,MACf,QAAQ,OAAO;AAAA,MACf,QAAQ,OAAO;AAAA,MACf;AAAA,QACC,MAAM;AAAA,QACN,MAAM;AAAA,QACN,YAAY,EAAE,OAAO,eAAe,QAAQ,SAAS,aAAa,cAAc;AAAA,MACjF;AAAA,MACA,QAAQ,cAAc;AAAA,MACtB,QAAQ,cAAc;AAAA,MACtB,QAAQ,eAAe;AAAA,MACvB,QAAQ,iBAAiB;AAAA,MACzB,QAAQ,YAAY;AAAA,MACpB,QAAQ,cAAc;AAAA,MACtB,QAAQ,oBAAoB;AAAA,IAC7B;AAAA,EACD;AAAA,EACA;AAAA,IACC,OAAO;AAAA,IACP,SAAS;AAAA,MACR,QAAQ,OAAO;AAAA,MACf,QAAQ,MAAM;AAAA,MACd,QAAQ,YAAY;AAAA,MACpB,QAAQ,QAAQ;AAAA,MAChB,QAAQ,YAAY;AAAA,MACpB,QAAQ,aAAa;AAAA,MACrB;AAAA,QACC,MAAM;AAAA,QACN,MAAM;AAAA,QACN,YAAY,EAAE,OAAO,eAAe,QAAQ,SAAS,aAAa,cAAc;AAAA,MACjF;AAAA,MACA,QAAQ,cAAc;AAAA,MACtB,QAAQ,MAAM;AAAA,MACd,QAAQ,aAAa;AAAA,MACrB,QAAQ,WAAW;AAAA,MACnB,QAAQ,QAAQ;AAAA,MAChB,QAAQ,YAAY;AAAA,MACpB,QAAQ,cAAc;AAAA,MACtB,QAAQ,oBAAoB;AAAA,IAC7B;AAAA,EACD;AAAA,EACA;AAAA,IACC,OAAO;AAAA,IACP,SAAS;AAAA,MACR,QAAQ,OAAO;AAAA,MACf,QAAQ,YAAY;AAAA,MACpB,QAAQ,WAAW;AAAA,MACnB,QAAQ,SAAS;AAAA,MACjB,QAAQ,OAAO;AAAA,MACf,QAAQ,OAAO;AAAA,MACf,QAAQ,OAAO;AAAA,MACf,QAAQ,QAAQ;AAAA,MAChB,QAAQ,aAAa;AAAA,MACrB,QAAQ,cAAc;AAAA,MACtB;AAAA,QACC,MAAM;AAAA,QACN,MAAM;AAAA,QACN,YAAY,EAAE,OAAO,eAAe,QAAQ,SAAS,aAAa,cAAc;AAAA,MACjF;AAAA,MACA;AAAA,QACC,MAAM;AAAA,QACN,MAAM;AAAA,QACN,YAAY,EAAE,OAAO,eAAe,QAAQ,SAAS,aAAa,cAAc;AAAA,MACjF;AAAA,MACA;AAAA,QACC,MAAM;AAAA,QACN,MAAM;AAAA,QACN,YAAY,EAAE,OAAO,oBAAoB,QAAQ,SAAS,aAAa,cAAc;AAAA,MACtF;AAAA,MACA,QAAQ,YAAY;AAAA,MACpB,QAAQ,cAAc;AAAA,MACtB,QAAQ,oBAAoB;AAAA,IAC7B;AAAA,EACD;AACD;;;ACrGA,eAAsB,eACrB,QAC6C;AAC7C,QAAM,SAAS,IAAI,iBAAiB,MAAM;AAC1C,SAAO,OAAO,aAAa;AAC5B;;;ACiBO,SAAS,wBACf,QACA,SACmB;AACnB,MAAI,OAAO,SAAS,cAAc;AACjC,UAAM,IAAI,MAAM,8CAA8C,OAAO,IAAI,GAAG;AAAA,EAC7E;AACA,QAAM,WAAW;AACjB,QAAM,SAA6C,SAAS,SACzD;AAAA,IACA,YAAY,SAAS,OAAO;AAAA,IAC5B,WAAW,SAAS,OAAO;AAAA,IAC3B,mBAAmB,SAAS,OAAO;AAAA,EACpC,IACC;AACH,SAAO,IAAI,uBAAuB,SAAS,YAAY,QAAQ,SAAS,MAAM,OAAO;AACtF;AAGO,IAAM,yBAAyB;AAGtC,sBAAsB,cAAc,wBAAwB;","names":["responseBody"]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
Err,
|
|
3
3
|
Ok
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-4SG66H5K.js";
|
|
5
5
|
|
|
6
6
|
// ../proto/src/gen/lakesync_pb.ts
|
|
7
7
|
import { enumDesc, fileDesc, messageDesc } from "@bufbuild/protobuf/codegenv2";
|
|
@@ -332,4 +332,4 @@ export {
|
|
|
332
332
|
encodeActionResponse,
|
|
333
333
|
decodeActionResponse
|
|
334
334
|
};
|
|
335
|
-
//# sourceMappingURL=chunk-
|
|
335
|
+
//# sourceMappingURL=chunk-YHYBLU6W.js.map
|
|
@@ -4,9 +4,8 @@ import {
|
|
|
4
4
|
LakeSyncError,
|
|
5
5
|
Ok,
|
|
6
6
|
extractDelta,
|
|
7
|
-
registerOutputSchemas
|
|
8
|
-
|
|
9
|
-
} from "./chunk-LDFFCG2K.js";
|
|
7
|
+
registerOutputSchemas
|
|
8
|
+
} from "./chunk-4SG66H5K.js";
|
|
10
9
|
|
|
11
10
|
// ../connector-jira/src/errors.ts
|
|
12
11
|
var JiraApiError = class extends LakeSyncError {
|
|
@@ -466,18 +465,20 @@ async function testConnection(config) {
|
|
|
466
465
|
}
|
|
467
466
|
|
|
468
467
|
// ../connector-jira/src/index.ts
|
|
469
|
-
|
|
470
|
-
registerPollerFactory("jira", (config, gateway) => {
|
|
468
|
+
function jiraPollerFactory(config, gateway) {
|
|
471
469
|
if (config.type !== "jira") {
|
|
472
470
|
throw new Error(`Expected connector type "jira", got "${config.type}"`);
|
|
473
471
|
}
|
|
474
|
-
const
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
472
|
+
const typed = config;
|
|
473
|
+
const ingest = typed.ingest ? {
|
|
474
|
+
intervalMs: typed.ingest.intervalMs,
|
|
475
|
+
chunkSize: typed.ingest.chunkSize,
|
|
476
|
+
memoryBudgetBytes: typed.ingest.memoryBudgetBytes
|
|
478
477
|
} : void 0;
|
|
479
|
-
return new JiraSourcePoller(
|
|
480
|
-
}
|
|
478
|
+
return new JiraSourcePoller(typed.jira, ingest, typed.name, gateway);
|
|
479
|
+
}
|
|
480
|
+
var createJiraPoller = jiraPollerFactory;
|
|
481
|
+
registerOutputSchemas("jira", JIRA_TABLE_SCHEMAS);
|
|
481
482
|
|
|
482
483
|
export {
|
|
483
484
|
JiraApiError,
|
|
@@ -488,6 +489,8 @@ export {
|
|
|
488
489
|
mapProject,
|
|
489
490
|
JiraSourcePoller,
|
|
490
491
|
JIRA_TABLE_SCHEMAS,
|
|
491
|
-
testConnection
|
|
492
|
+
testConnection,
|
|
493
|
+
jiraPollerFactory,
|
|
494
|
+
createJiraPoller
|
|
492
495
|
};
|
|
493
|
-
//# sourceMappingURL=chunk-
|
|
496
|
+
//# sourceMappingURL=chunk-ZNY4DSFU.js.map
|