@useairfoil/connector-kit 0.6.1 → 0.7.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/LICENSE.txt +201 -0
- package/METRICS.md +27 -30
- package/README.md +33 -51
- package/dist/{annotations-BE74YmAO.d.mts → annotations-vzSzXtr-.d.mts} +5 -10
- package/dist/{wings-I56hGtNv.mjs → arrow-flight-DDQ0ktx9.mjs} +25 -99
- package/dist/arrow-flight-DDQ0ktx9.mjs.map +1 -0
- package/dist/connector-app/index.d.mts +2 -2
- package/dist/connector-app/index.mjs +2 -2
- package/dist/connector-app-C6_dZnhE.mjs +256 -0
- package/dist/connector-app-C6_dZnhE.mjs.map +1 -0
- package/dist/{constants-D-GQzpHZ.mjs → constants-v3UX-hf6.mjs} +3 -2
- package/dist/constants-v3UX-hf6.mjs.map +1 -0
- package/dist/demo/index.d.mts +1 -1
- package/dist/demo/index.mjs +1 -1
- package/dist/{demo-B30Vlkk2.mjs → demo-DqTJ7TWI.mjs} +32 -19
- package/dist/demo-DqTJ7TWI.mjs.map +1 -0
- package/dist/iceberg/index.d.mts +3 -3
- package/dist/iceberg/index.mjs +3 -3
- package/dist/iceberg-Cj2PwlNm.mjs +30 -0
- package/dist/iceberg-Cj2PwlNm.mjs.map +1 -0
- package/dist/{index-DJhDp4Xc.d.mts → index-BTAbexBp.d.mts} +13 -16
- package/dist/{index-BUHSGm9Q.d.mts → index-Byr8NTdG.d.mts} +2 -2
- package/dist/{index-Dk7urvpF.d.mts → index-CV6V6fyx.d.mts} +9 -6
- package/dist/{index-NnCutIqM.d.mts → index-CZKx2Yce.d.mts} +29 -19
- package/dist/{index-BfXpgxk9.d.mts → index-DeTwIUKl.d.mts} +3 -3
- package/dist/{index-CRVAwJ5-.d.mts → index-dHS59EZl.d.mts} +4 -4
- package/dist/{index-ygpml2kC.d.mts → index-fHIJJoRe.d.mts} +17 -10
- package/dist/index-uFa2wwYo.d.mts +27 -0
- package/dist/index.d.mts +11 -11
- package/dist/index.mjs +10 -10
- package/dist/ingestion/index.d.mts +1 -1
- package/dist/ingestion/index.mjs +1 -1
- package/dist/{ingestion-q0WwqUSt.mjs → ingestion-DoCUwm5N.mjs} +6 -6
- package/dist/{ingestion-q0WwqUSt.mjs.map → ingestion-DoCUwm5N.mjs.map} +1 -1
- package/dist/ingestor/index.d.mts +3 -3
- package/dist/ingestor/index.mjs +3 -3
- package/dist/{ingestor-D4L-HPkg.mjs → ingestor-DjCEzBzZ.mjs} +6 -6
- package/dist/ingestor-DjCEzBzZ.mjs.map +1 -0
- package/dist/{instrumented-Bhp7fyvh.mjs → instrumented-Bq1WX2L5.mjs} +2 -2
- package/dist/{instrumented-Bhp7fyvh.mjs.map → instrumented-Bq1WX2L5.mjs.map} +1 -1
- package/dist/manifest/index.mjs +1 -1
- package/dist/{manifest-BGKxmKLy.mjs → manifest-CABeIhAG.mjs} +2 -2
- package/dist/{manifest-BGKxmKLy.mjs.map → manifest-CABeIhAG.mjs.map} +1 -1
- package/dist/{metrics-BaEX__MN.mjs → metrics-C901IIYZ.mjs} +6 -11
- package/dist/metrics-C901IIYZ.mjs.map +1 -0
- package/dist/{metrics-CVXFL7YT.d.mts → metrics-DoJ0WeKu.d.mts} +2 -2
- package/dist/metrics.d.mts +1 -1
- package/dist/metrics.mjs +1 -1
- package/dist/runtime-config/index.d.mts +2 -2
- package/dist/runtime-config/index.mjs +3 -3
- package/dist/{runtime-config-Oa55gAew.mjs → runtime-config-Bn8Fivt1.mjs} +11 -8
- package/dist/runtime-config-Bn8Fivt1.mjs.map +1 -0
- package/dist/{server-CMnxz3h0.mjs → server-D1TTN0_D.mjs} +3 -3
- package/dist/{server-CMnxz3h0.mjs.map → server-D1TTN0_D.mjs.map} +1 -1
- package/dist/{service-DLkhuxYl.d.mts → service-BRoy_EId.d.mts} +2 -2
- package/dist/state-store/index.mjs +1 -1
- package/dist/{state-store-uFvHY7Ax.mjs → state-store-DhSrKVEH.mjs} +2 -2
- package/dist/{state-store-uFvHY7Ax.mjs.map → state-store-DhSrKVEH.mjs.map} +1 -1
- package/dist/status/index.d.mts +1 -1
- package/dist/status/index.mjs +1 -1
- package/dist/{status-CKb9IhQ9.mjs → status-4h6Oxh-O.mjs} +2 -2
- package/dist/{status-CKb9IhQ9.mjs.map → status-4h6Oxh-O.mjs.map} +1 -1
- package/dist/{table-V0tgUC5i.mjs → table-CxM09xf7.mjs} +22 -85
- package/dist/table-CxM09xf7.mjs.map +1 -0
- package/dist/{types-xZtSmrGA.d.mts → types-NtSv6gwl.d.mts} +3 -3
- package/dist/webhook/index.d.mts +2 -2
- package/dist/webhook/index.mjs +1 -1
- package/package.json +19 -18
- package/src/catalog/retry.ts +25 -0
- package/src/catalog/table.ts +73 -37
- package/src/connector-app/create-table.ts +8 -8
- package/src/connector-app/demo.ts +24 -19
- package/src/connector-app/index.ts +1 -0
- package/src/connector-app/setup.ts +69 -0
- package/src/core/types.ts +1 -1
- package/src/demo/definition.ts +1 -1
- package/src/demo/generate.ts +1 -1
- package/src/demo/run.ts +60 -30
- package/src/iceberg/annotations.ts +3 -16
- package/src/iceberg/index.ts +2 -2
- package/src/iceberg/table.ts +28 -78
- package/src/ingestion/engine.ts +1 -1
- package/src/ingestor/{wings.ts → arrow-flight.ts} +25 -27
- package/src/ingestor/console.ts +1 -1
- package/src/ingestor/index.ts +5 -1
- package/src/runtime-config/config.ts +8 -3
- package/src/runtime-config/constants.ts +2 -1
- package/src/runtime-config/index.ts +1 -1
- package/src/runtime-config/table-bindings.ts +6 -4
- package/src/telemetry.ts +11 -19
- package/dist/connector-app-C-L4QqG6.mjs +0 -123
- package/dist/connector-app-C-L4QqG6.mjs.map +0 -1
- package/dist/constants-D-GQzpHZ.mjs.map +0 -1
- package/dist/demo-B30Vlkk2.mjs.map +0 -1
- package/dist/iceberg-D6L8I6vA.mjs +0 -39
- package/dist/iceberg-D6L8I6vA.mjs.map +0 -1
- package/dist/index-CUPP2A_m.d.mts +0 -27
- package/dist/ingestor-D4L-HPkg.mjs.map +0 -1
- package/dist/metrics-BaEX__MN.mjs.map +0 -1
- package/dist/runtime-config-Oa55gAew.mjs.map +0 -1
- package/dist/table-V0tgUC5i.mjs.map +0 -1
- package/dist/wings-I56hGtNv.mjs.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"state-store-uFvHY7Ax.mjs","names":[],"sources":["../src/state-store/service.ts","../src/state-store/keys.ts","../src/state-store/schema.ts","../src/state-store/layer-key-value-store.ts","../src/state-store/layer-memory.ts","../src/state-store/layer-sql.ts","../src/state-store/index.ts"],"sourcesContent":["import { Context, Effect } from \"effect\";\n\nimport type {\n PersistedBackfillState,\n PersistedChangesState,\n PersistedResourceState,\n StateOperation,\n StateSource,\n} from \"./schema\";\n\nimport { ConnectorError } from \"../errors\";\n\n/** Connector-facing durable state operations, independent of the storage backend. */\nexport interface StateStoreService {\n readonly getResourceState: (\n resource: string,\n ) => Effect.Effect<PersistedResourceState | undefined, ConnectorError>;\n readonly setBackfillState: (\n resource: string,\n state: PersistedBackfillState,\n ) => Effect.Effect<void, ConnectorError>;\n readonly setChangesState: (\n resource: string,\n state: PersistedChangesState,\n ) => Effect.Effect<void, ConnectorError>;\n readonly setResourceError: (\n resource: string,\n source: StateSource,\n operation: StateOperation,\n ) => Effect.Effect<void, ConnectorError>;\n readonly clearResourceError: (\n resource: string,\n source: StateSource,\n ) => Effect.Effect<void, ConnectorError>;\n}\n\n/**\n * Effect service used by ingestion and status logic for connector checkpoints.\n * Production provides `layerSql`; sandboxes and tests may provide `layerMemory`.\n *\n * @example\n * ```ts\n * const program = Effect.gen(function* () {\n * const state = yield* StateStore;\n * yield* state.setChangesState(\"orders\", { cursor: \"next-page\" });\n * });\n * ```\n */\nexport class StateStore extends Context.Service<StateStore, StateStoreService>()(\n \"@useairfoil/connector-kit/StateStore\",\n) {}\n","import type { StateSource } from \"./schema\";\n\ntype StateComponent = StateSource | `error:${StateSource}`;\n\nexport const resourceComponentKey = (resource: string, component: StateComponent): string =>\n `resource:${resource}:${component}`;\n\nexport const resourceErrorKey = (resource: string, source: StateSource): string =>\n resourceComponentKey(resource, `error:${source}`);\n\n/**\n * Prefix for all state owned by one connector instance. The platform-owned ID\n * stays visible so operators can inspect and clean up shared-table rows directly.\n *\n * @example\n * ```ts\n * connectorInstanceKeyPrefix(\"team-a/orders\");\n * // \"connector-instance:team-a/orders:\"\n * ```\n */\nexport const connectorInstanceKeyPrefix = (connectorInstanceId: string): string =>\n `connector-instance:${connectorInstanceId}:`;\n","import { Schema } from \"effect\";\n\nconst CursorValueSchema = Schema.Union([Schema.String, Schema.Number]);\n\n/** Durable progress for a finite historical backfill. */\nexport const BackfillStateSchema = Schema.Struct({\n cutoff: CursorValueSchema,\n pageCursor: Schema.optional(CursorValueSchema),\n completed: Schema.Boolean,\n lastSuccessAt: Schema.optional(Schema.String),\n});\n\n/** Durable cursor for an ongoing incremental changes stream. */\nexport const ChangesStateSchema = Schema.Struct({\n cursor: CursorValueSchema,\n lastSuccessAt: Schema.optional(Schema.String),\n});\n\nexport const StateSourceSchema = Schema.Literals([\"backfill\", \"changes\"]);\n\nexport const StateOperationSchema = Schema.Literals([\"fetch\", \"ingest\", \"checkpoint\"]);\n\nexport const StateErrorCodeSchema = Schema.Literals([\n \"fetch_failed\",\n \"ingest_failed\",\n \"checkpoint_failed\",\n]);\n\n/** SDK-owned error context safe to persist and expose through status. */\nexport const ResourceErrorContextSchema = Schema.Struct({\n source: StateSourceSchema,\n operation: StateOperationSchema,\n code: StateErrorCodeSchema,\n message: Schema.String,\n});\n\n/** Stable public error summary persisted for status reporting; never a raw cause. */\nexport const ResourceErrorSchema = Schema.Struct({\n ...ResourceErrorContextSchema.fields,\n at: Schema.String,\n});\n\n/** Complete persisted state assembled from independently stored components. */\nexport const ResourceStateSchema = Schema.Struct({\n backfill: Schema.optional(BackfillStateSchema),\n changes: Schema.optional(ChangesStateSchema),\n lastError: Schema.optional(ResourceErrorSchema),\n});\n\nexport type PersistedBackfillState = Schema.Schema.Type<typeof BackfillStateSchema>;\nexport type PersistedChangesState = Schema.Schema.Type<typeof ChangesStateSchema>;\nexport type StateSource = Schema.Schema.Type<typeof StateSourceSchema>;\nexport type StateOperation = Schema.Schema.Type<typeof StateOperationSchema>;\nexport type StateErrorCode = Schema.Schema.Type<typeof StateErrorCodeSchema>;\nexport type ResourceErrorContext = Schema.Schema.Type<typeof ResourceErrorContextSchema>;\nexport type PersistedResourceError = Schema.Schema.Type<typeof ResourceErrorSchema>;\nexport type PersistedResourceState = Schema.Schema.Type<typeof ResourceStateSchema>;\n","import { DateTime, Effect, Layer, Option, Schema } from \"effect\";\nimport { KeyValueStore } from \"effect/persistence\";\n\nimport { ConnectorError } from \"../errors\";\nimport { resourceComponentKey, resourceErrorKey } from \"./keys\";\nimport {\n BackfillStateSchema,\n ChangesStateSchema,\n ResourceErrorSchema,\n type PersistedBackfillState,\n type PersistedChangesState,\n type PersistedResourceError,\n type ResourceErrorContext,\n type StateOperation,\n type StateSource,\n} from \"./schema\";\nimport { StateStore } from \"./service\";\n\nconst mapStoreError = (operation: \"read\" | \"write\" | \"clear\", resource: string) =>\n Effect.mapError(\n (cause: KeyValueStore.KeyValueStoreError | Schema.SchemaError) =>\n new ConnectorError({\n message: `Failed to ${operation} state for resource ${resource}`,\n cause,\n }),\n );\n\nconst resourceErrorContext = (\n source: StateSource,\n operation: StateOperation,\n): ResourceErrorContext => {\n const sourceName = source === \"backfill\" ? \"Backfill\" : \"Changes\";\n switch (operation) {\n case \"fetch\":\n return { source, operation, code: \"fetch_failed\", message: `${sourceName} fetch failed` };\n case \"ingest\":\n return {\n source,\n operation,\n code: \"ingest_failed\",\n message: `${sourceName} ingestion failed`,\n };\n case \"checkpoint\":\n return {\n source,\n operation,\n code: \"checkpoint_failed\",\n message: `${sourceName} checkpoint failed`,\n };\n }\n};\n\nconst latestError = (\n backfill: Option.Option<PersistedResourceError>,\n changes: Option.Option<PersistedResourceError>,\n): Option.Option<PersistedResourceError> => {\n if (Option.isNone(backfill)) return changes;\n if (Option.isNone(changes)) return backfill;\n return backfill.value.at >= changes.value.at ? backfill : changes;\n};\n\n/**\n * Implements StateStore over any Effect KeyValueStore. `toSchemaStore` owns\n * serialization and validates persisted values when they are read and written.\n * The caller owns instance scoping; `layerSql` supplies the production prefix.\n */\nexport const layerKeyValueStore: Layer.Layer<StateStore, never, KeyValueStore.KeyValueStore> =\n Layer.effect(StateStore)(\n Effect.gen(function* () {\n const keyValueStore = yield* KeyValueStore.KeyValueStore;\n const backfillStore = KeyValueStore.toSchemaStore(keyValueStore, BackfillStateSchema);\n const changesStore = KeyValueStore.toSchemaStore(keyValueStore, ChangesStateSchema);\n const errorStore = KeyValueStore.toSchemaStore(keyValueStore, ResourceErrorSchema);\n\n const getResourceState = (resource: string) =>\n // Components use separate keys so a cursor update cannot overwrite the\n // independently managed error or backfill state.\n Effect.all(\n {\n backfill: backfillStore.get(resourceComponentKey(resource, \"backfill\")),\n changes: changesStore.get(resourceComponentKey(resource, \"changes\")),\n backfillError: errorStore.get(resourceErrorKey(resource, \"backfill\")),\n changesError: errorStore.get(resourceErrorKey(resource, \"changes\")),\n },\n { concurrency: \"unbounded\" },\n ).pipe(\n Effect.map(({ backfill, changes, backfillError, changesError }) => {\n const lastError = latestError(backfillError, changesError);\n if (Option.isNone(backfill) && Option.isNone(changes) && Option.isNone(lastError)) {\n return undefined;\n }\n return {\n ...(Option.isSome(backfill) ? { backfill: backfill.value } : {}),\n ...(Option.isSome(changes) ? { changes: changes.value } : {}),\n ...(Option.isSome(lastError) ? { lastError: lastError.value } : {}),\n };\n }),\n mapStoreError(\"read\", resource),\n );\n\n const setBackfillState = (resource: string, state: PersistedBackfillState) =>\n backfillStore\n .set(resourceComponentKey(resource, \"backfill\"), state)\n .pipe(mapStoreError(\"write\", resource));\n\n const setChangesState = (resource: string, state: PersistedChangesState) =>\n changesStore\n .set(resourceComponentKey(resource, \"changes\"), state)\n .pipe(mapStoreError(\"write\", resource));\n\n const setResourceError = (resource: string, source: StateSource, operation: StateOperation) =>\n DateTime.now.pipe(\n Effect.map(DateTime.formatIso),\n Effect.flatMap((at) => {\n const error = resourceErrorContext(source, operation);\n return errorStore.set(resourceErrorKey(resource, source), {\n ...error,\n at,\n });\n }),\n mapStoreError(\"write\", resource),\n );\n\n const clearResourceError = (resource: string, source: StateSource) =>\n errorStore\n .remove(resourceErrorKey(resource, source))\n .pipe(mapStoreError(\"clear\", resource));\n\n return StateStore.of({\n getResourceState,\n setBackfillState,\n setChangesState,\n setResourceError,\n clearResourceError,\n });\n }),\n );\n","import { Layer } from \"effect\";\nimport { KeyValueStore } from \"effect/persistence\";\n\nimport type { StateStore } from \"./service\";\n\nimport { layerKeyValueStore } from \"./layer-key-value-store\";\n\n/** Process-local state for tests and explicit local sandbox commands. */\nexport const layerMemory: Layer.Layer<StateStore> = layerKeyValueStore.pipe(\n Layer.provide(KeyValueStore.layerMemory),\n);\n","import { Config, Effect, Layer } from \"effect\";\nimport { KeyValueStore } from \"effect/persistence\";\nimport { SqlClient } from \"effect/sql\";\n\nimport type { StateStore } from \"./service\";\n\nimport { PlatformRuntimeDefault, PlatformRuntimeKey } from \"../runtime-config/constants\";\nimport { connectorInstanceKeyPrefix } from \"./keys\";\nimport { layerKeyValueStore } from \"./layer-key-value-store\";\n\nconst scopedKeyValueStore = (connectorInstanceId: string) =>\n Layer.effect(KeyValueStore.KeyValueStore)(\n KeyValueStore.KeyValueStore.pipe(\n Effect.map(KeyValueStore.prefix(connectorInstanceKeyPrefix(connectorInstanceId))),\n ),\n );\n\n/**\n * Shared SQL state using the immutable connector instance ID supplied by\n * platform-owned Effect configuration. The table defaults to\n * `_airfoil_connectors_state` and can be overridden with `AIRFOIL_STATE_TABLE`.\n * Effect's SQL KeyValueStore owns the table, while `KeyValueStore.prefix`\n * provides application-level isolation between connector instances in that\n * table. The resulting layer exposes only StateStore, never the unscoped\n * KeyValueStore.\n *\n * @example\n * ```ts\n * const StateStoreLive = layerSql().pipe(Layer.provide(PostgresLive));\n * ```\n */\nexport const layerSql = (): Layer.Layer<StateStore, Config.ConfigError, SqlClient.SqlClient> =>\n Layer.unwrap(\n Config.all({\n connectorInstanceId: Config.NonEmptyString(PlatformRuntimeKey.connectorInstanceId),\n table: Config.NonEmptyString(PlatformRuntimeKey.stateTable).pipe(\n Config.withDefault(PlatformRuntimeDefault.stateTable),\n ),\n }).pipe(\n Effect.map(({ connectorInstanceId, table }) =>\n layerKeyValueStore.pipe(\n Layer.provide(\n scopedKeyValueStore(connectorInstanceId).pipe(\n Layer.provide(KeyValueStore.layerSql({ table })),\n ),\n ),\n ),\n ),\n ),\n );\n","export { StateStore, type StateStoreService } from \"./service\";\nexport { layerMemory } from \"./layer-memory\";\nexport { layerSql } from \"./layer-sql\";\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"state-store-DhSrKVEH.mjs","names":[],"sources":["../src/state-store/service.ts","../src/state-store/keys.ts","../src/state-store/schema.ts","../src/state-store/layer-key-value-store.ts","../src/state-store/layer-memory.ts","../src/state-store/layer-sql.ts","../src/state-store/index.ts"],"sourcesContent":["import { Context, Effect } from \"effect\";\n\nimport type {\n PersistedBackfillState,\n PersistedChangesState,\n PersistedResourceState,\n StateOperation,\n StateSource,\n} from \"./schema\";\n\nimport { ConnectorError } from \"../errors\";\n\n/** Connector-facing durable state operations, independent of the storage backend. */\nexport interface StateStoreService {\n readonly getResourceState: (\n resource: string,\n ) => Effect.Effect<PersistedResourceState | undefined, ConnectorError>;\n readonly setBackfillState: (\n resource: string,\n state: PersistedBackfillState,\n ) => Effect.Effect<void, ConnectorError>;\n readonly setChangesState: (\n resource: string,\n state: PersistedChangesState,\n ) => Effect.Effect<void, ConnectorError>;\n readonly setResourceError: (\n resource: string,\n source: StateSource,\n operation: StateOperation,\n ) => Effect.Effect<void, ConnectorError>;\n readonly clearResourceError: (\n resource: string,\n source: StateSource,\n ) => Effect.Effect<void, ConnectorError>;\n}\n\n/**\n * Effect service used by ingestion and status logic for connector checkpoints.\n * Production provides `layerSql`; sandboxes and tests may provide `layerMemory`.\n *\n * @example\n * ```ts\n * const program = Effect.gen(function* () {\n * const state = yield* StateStore;\n * yield* state.setChangesState(\"orders\", { cursor: \"next-page\" });\n * });\n * ```\n */\nexport class StateStore extends Context.Service<StateStore, StateStoreService>()(\n \"@useairfoil/connector-kit/StateStore\",\n) {}\n","import type { StateSource } from \"./schema\";\n\ntype StateComponent = StateSource | `error:${StateSource}`;\n\nexport const resourceComponentKey = (resource: string, component: StateComponent): string =>\n `resource:${resource}:${component}`;\n\nexport const resourceErrorKey = (resource: string, source: StateSource): string =>\n resourceComponentKey(resource, `error:${source}`);\n\n/**\n * Prefix for all state owned by one connector instance. The platform-owned ID\n * stays visible so operators can inspect and clean up shared-table rows directly.\n *\n * @example\n * ```ts\n * connectorInstanceKeyPrefix(\"team-a/orders\");\n * // \"connector-instance:team-a/orders:\"\n * ```\n */\nexport const connectorInstanceKeyPrefix = (connectorInstanceId: string): string =>\n `connector-instance:${connectorInstanceId}:`;\n","import { Schema } from \"effect\";\n\nconst CursorValueSchema = Schema.Union([Schema.String, Schema.Number]);\n\n/** Durable progress for a finite historical backfill. */\nexport const BackfillStateSchema = Schema.Struct({\n cutoff: CursorValueSchema,\n pageCursor: Schema.optional(CursorValueSchema),\n completed: Schema.Boolean,\n lastSuccessAt: Schema.optional(Schema.String),\n});\n\n/** Durable cursor for an ongoing incremental changes stream. */\nexport const ChangesStateSchema = Schema.Struct({\n cursor: CursorValueSchema,\n lastSuccessAt: Schema.optional(Schema.String),\n});\n\nexport const StateSourceSchema = Schema.Literals([\"backfill\", \"changes\"]);\n\nexport const StateOperationSchema = Schema.Literals([\"fetch\", \"ingest\", \"checkpoint\"]);\n\nexport const StateErrorCodeSchema = Schema.Literals([\n \"fetch_failed\",\n \"ingest_failed\",\n \"checkpoint_failed\",\n]);\n\n/** SDK-owned error context safe to persist and expose through status. */\nexport const ResourceErrorContextSchema = Schema.Struct({\n source: StateSourceSchema,\n operation: StateOperationSchema,\n code: StateErrorCodeSchema,\n message: Schema.String,\n});\n\n/** Stable public error summary persisted for status reporting; never a raw cause. */\nexport const ResourceErrorSchema = Schema.Struct({\n ...ResourceErrorContextSchema.fields,\n at: Schema.String,\n});\n\n/** Complete persisted state assembled from independently stored components. */\nexport const ResourceStateSchema = Schema.Struct({\n backfill: Schema.optional(BackfillStateSchema),\n changes: Schema.optional(ChangesStateSchema),\n lastError: Schema.optional(ResourceErrorSchema),\n});\n\nexport type PersistedBackfillState = Schema.Schema.Type<typeof BackfillStateSchema>;\nexport type PersistedChangesState = Schema.Schema.Type<typeof ChangesStateSchema>;\nexport type StateSource = Schema.Schema.Type<typeof StateSourceSchema>;\nexport type StateOperation = Schema.Schema.Type<typeof StateOperationSchema>;\nexport type StateErrorCode = Schema.Schema.Type<typeof StateErrorCodeSchema>;\nexport type ResourceErrorContext = Schema.Schema.Type<typeof ResourceErrorContextSchema>;\nexport type PersistedResourceError = Schema.Schema.Type<typeof ResourceErrorSchema>;\nexport type PersistedResourceState = Schema.Schema.Type<typeof ResourceStateSchema>;\n","import { DateTime, Effect, Layer, Option, Schema } from \"effect\";\nimport { KeyValueStore } from \"effect/persistence\";\n\nimport { ConnectorError } from \"../errors\";\nimport { resourceComponentKey, resourceErrorKey } from \"./keys\";\nimport {\n BackfillStateSchema,\n ChangesStateSchema,\n ResourceErrorSchema,\n type PersistedBackfillState,\n type PersistedChangesState,\n type PersistedResourceError,\n type ResourceErrorContext,\n type StateOperation,\n type StateSource,\n} from \"./schema\";\nimport { StateStore } from \"./service\";\n\nconst mapStoreError = (operation: \"read\" | \"write\" | \"clear\", resource: string) =>\n Effect.mapError(\n (cause: KeyValueStore.KeyValueStoreError | Schema.SchemaError) =>\n new ConnectorError({\n message: `Failed to ${operation} state for resource ${resource}`,\n cause,\n }),\n );\n\nconst resourceErrorContext = (\n source: StateSource,\n operation: StateOperation,\n): ResourceErrorContext => {\n const sourceName = source === \"backfill\" ? \"Backfill\" : \"Changes\";\n switch (operation) {\n case \"fetch\":\n return { source, operation, code: \"fetch_failed\", message: `${sourceName} fetch failed` };\n case \"ingest\":\n return {\n source,\n operation,\n code: \"ingest_failed\",\n message: `${sourceName} ingestion failed`,\n };\n case \"checkpoint\":\n return {\n source,\n operation,\n code: \"checkpoint_failed\",\n message: `${sourceName} checkpoint failed`,\n };\n }\n};\n\nconst latestError = (\n backfill: Option.Option<PersistedResourceError>,\n changes: Option.Option<PersistedResourceError>,\n): Option.Option<PersistedResourceError> => {\n if (Option.isNone(backfill)) return changes;\n if (Option.isNone(changes)) return backfill;\n return backfill.value.at >= changes.value.at ? backfill : changes;\n};\n\n/**\n * Implements StateStore over any Effect KeyValueStore. `toSchemaStore` owns\n * serialization and validates persisted values when they are read and written.\n * The caller owns instance scoping; `layerSql` supplies the production prefix.\n */\nexport const layerKeyValueStore: Layer.Layer<StateStore, never, KeyValueStore.KeyValueStore> =\n Layer.effect(StateStore)(\n Effect.gen(function* () {\n const keyValueStore = yield* KeyValueStore.KeyValueStore;\n const backfillStore = KeyValueStore.toSchemaStore(keyValueStore, BackfillStateSchema);\n const changesStore = KeyValueStore.toSchemaStore(keyValueStore, ChangesStateSchema);\n const errorStore = KeyValueStore.toSchemaStore(keyValueStore, ResourceErrorSchema);\n\n const getResourceState = (resource: string) =>\n // Components use separate keys so a cursor update cannot overwrite the\n // independently managed error or backfill state.\n Effect.all(\n {\n backfill: backfillStore.get(resourceComponentKey(resource, \"backfill\")),\n changes: changesStore.get(resourceComponentKey(resource, \"changes\")),\n backfillError: errorStore.get(resourceErrorKey(resource, \"backfill\")),\n changesError: errorStore.get(resourceErrorKey(resource, \"changes\")),\n },\n { concurrency: \"unbounded\" },\n ).pipe(\n Effect.map(({ backfill, changes, backfillError, changesError }) => {\n const lastError = latestError(backfillError, changesError);\n if (Option.isNone(backfill) && Option.isNone(changes) && Option.isNone(lastError)) {\n return undefined;\n }\n return {\n ...(Option.isSome(backfill) ? { backfill: backfill.value } : {}),\n ...(Option.isSome(changes) ? { changes: changes.value } : {}),\n ...(Option.isSome(lastError) ? { lastError: lastError.value } : {}),\n };\n }),\n mapStoreError(\"read\", resource),\n );\n\n const setBackfillState = (resource: string, state: PersistedBackfillState) =>\n backfillStore\n .set(resourceComponentKey(resource, \"backfill\"), state)\n .pipe(mapStoreError(\"write\", resource));\n\n const setChangesState = (resource: string, state: PersistedChangesState) =>\n changesStore\n .set(resourceComponentKey(resource, \"changes\"), state)\n .pipe(mapStoreError(\"write\", resource));\n\n const setResourceError = (resource: string, source: StateSource, operation: StateOperation) =>\n DateTime.now.pipe(\n Effect.map(DateTime.formatIso),\n Effect.flatMap((at) => {\n const error = resourceErrorContext(source, operation);\n return errorStore.set(resourceErrorKey(resource, source), {\n ...error,\n at,\n });\n }),\n mapStoreError(\"write\", resource),\n );\n\n const clearResourceError = (resource: string, source: StateSource) =>\n errorStore\n .remove(resourceErrorKey(resource, source))\n .pipe(mapStoreError(\"clear\", resource));\n\n return StateStore.of({\n getResourceState,\n setBackfillState,\n setChangesState,\n setResourceError,\n clearResourceError,\n });\n }),\n );\n","import { Layer } from \"effect\";\nimport { KeyValueStore } from \"effect/persistence\";\n\nimport type { StateStore } from \"./service\";\n\nimport { layerKeyValueStore } from \"./layer-key-value-store\";\n\n/** Process-local state for tests and explicit local sandbox commands. */\nexport const layerMemory: Layer.Layer<StateStore> = layerKeyValueStore.pipe(\n Layer.provide(KeyValueStore.layerMemory),\n);\n","import { Config, Effect, Layer } from \"effect\";\nimport { KeyValueStore } from \"effect/persistence\";\nimport { SqlClient } from \"effect/sql\";\n\nimport type { StateStore } from \"./service\";\n\nimport { PlatformRuntimeDefault, PlatformRuntimeKey } from \"../runtime-config/constants\";\nimport { connectorInstanceKeyPrefix } from \"./keys\";\nimport { layerKeyValueStore } from \"./layer-key-value-store\";\n\nconst scopedKeyValueStore = (connectorInstanceId: string) =>\n Layer.effect(KeyValueStore.KeyValueStore)(\n KeyValueStore.KeyValueStore.pipe(\n Effect.map(KeyValueStore.prefix(connectorInstanceKeyPrefix(connectorInstanceId))),\n ),\n );\n\n/**\n * Shared SQL state using the immutable connector instance ID supplied by\n * platform-owned Effect configuration. The table defaults to\n * `_airfoil_connectors_state` and can be overridden with `AIRFOIL_STATE_TABLE`.\n * Effect's SQL KeyValueStore owns the table, while `KeyValueStore.prefix`\n * provides application-level isolation between connector instances in that\n * table. The resulting layer exposes only StateStore, never the unscoped\n * KeyValueStore.\n *\n * @example\n * ```ts\n * const StateStoreLive = layerSql().pipe(Layer.provide(PostgresLive));\n * ```\n */\nexport const layerSql = (): Layer.Layer<StateStore, Config.ConfigError, SqlClient.SqlClient> =>\n Layer.unwrap(\n Config.all({\n connectorInstanceId: Config.NonEmptyString(PlatformRuntimeKey.connectorInstanceId),\n table: Config.NonEmptyString(PlatformRuntimeKey.stateTable).pipe(\n Config.withDefault(PlatformRuntimeDefault.stateTable),\n ),\n }).pipe(\n Effect.map(({ connectorInstanceId, table }) =>\n layerKeyValueStore.pipe(\n Layer.provide(\n scopedKeyValueStore(connectorInstanceId).pipe(\n Layer.provide(KeyValueStore.layerSql({ table })),\n ),\n ),\n ),\n ),\n ),\n );\n","export { StateStore, type StateStoreService } from \"./service\";\nexport { layerMemory } from \"./layer-memory\";\nexport { layerSql } from \"./layer-sql\";\n"],"mappings":"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"}
|
package/dist/status/index.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as ResourceStatusSchema, c as StatusUnavailableResponse, d as SyncStateSchema, f as statusRoute, i as ResourceStatus, l as StatusUnavailableResponseSchema, n as ResourceError, o as StatusResponse, r as ResourceErrorSchema, s as StatusResponseSchema, u as SyncState } from "../index-
|
|
1
|
+
import { a as ResourceStatusSchema, c as StatusUnavailableResponse, d as SyncStateSchema, f as statusRoute, i as ResourceStatus, l as StatusUnavailableResponseSchema, n as ResourceError, o as StatusResponse, r as ResourceErrorSchema, s as StatusResponseSchema, u as SyncState } from "../index-Byr8NTdG.mjs";
|
|
2
2
|
export { ResourceError, ResourceErrorSchema, ResourceStatus, ResourceStatusSchema, StatusResponse, StatusResponseSchema, StatusUnavailableResponse, StatusUnavailableResponseSchema, SyncState, SyncStateSchema, statusRoute };
|
package/dist/status/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as StatusUnavailableResponseSchema, i as StatusResponseSchema, n as ResourceErrorSchema, o as SyncStateSchema, r as ResourceStatusSchema, s as statusRoute } from "../status-
|
|
1
|
+
import { a as StatusUnavailableResponseSchema, i as StatusResponseSchema, n as ResourceErrorSchema, o as SyncStateSchema, r as ResourceStatusSchema, s as statusRoute } from "../status-4h6Oxh-O.mjs";
|
|
2
2
|
export { ResourceErrorSchema, ResourceStatusSchema, StatusResponseSchema, StatusUnavailableResponseSchema, SyncStateSchema, statusRoute };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
|
|
2
|
-
import { a as ResourceStateSchema, i as ResourceErrorSchema$1, o as StateStore } from "./state-store-
|
|
2
|
+
import { a as ResourceStateSchema, i as ResourceErrorSchema$1, o as StateStore } from "./state-store-DhSrKVEH.mjs";
|
|
3
3
|
import { Cause, Effect, Schema } from "effect";
|
|
4
4
|
import { HttpRouter, HttpServerResponse } from "effect/http";
|
|
5
5
|
//#region src/state-store/state.ts
|
|
@@ -79,4 +79,4 @@ var status_exports = /* @__PURE__ */ __exportAll({
|
|
|
79
79
|
//#endregion
|
|
80
80
|
export { StatusUnavailableResponseSchema as a, deriveSyncState as c, StatusResponseSchema as i, hasChanges as l, ResourceErrorSchema as n, SyncStateSchema as o, ResourceStatusSchema as r, statusRoute as s, status_exports as t, normalizeCursor as u };
|
|
81
81
|
|
|
82
|
-
//# sourceMappingURL=status-
|
|
82
|
+
//# sourceMappingURL=status-4h6Oxh-O.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"status-
|
|
1
|
+
{"version":3,"file":"status-4h6Oxh-O.mjs","names":["StateResourceErrorSchema"],"sources":["../src/state-store/state.ts","../src/status/route.ts","../src/status/types.ts","../src/status/index.ts"],"sourcesContent":["import type {\n ConnectorDefinition,\n Cursor,\n ResourceDefinition,\n ResourceState,\n SyncState,\n} from \"../core/types\";\n\n/** Normalizes a cursor value to its persisted/wire representation (never a Date). */\nexport const normalizeCursor = (value: Cursor.Value): string | number =>\n value instanceof Date ? value.toISOString() : value;\n\n/** Whether a resource gets changes, from its own `changes` or the connector's feed. */\nexport const hasChanges = (connector: ConnectorDefinition, resource: ResourceDefinition) =>\n resource.changes !== undefined ||\n (connector.changes?.resources.some((member) => member.name === resource.name) ?? false);\n\n/** Derives connector-facing sync state from durable state and resource capabilities. */\nexport const deriveSyncState = (\n connector: ConnectorDefinition,\n resource: ResourceDefinition,\n state: ResourceState | undefined,\n): SyncState => {\n if (state?.lastError) return \"error\";\n if (!resource.backfill && !hasChanges(connector, resource)) return \"live\";\n if (!state) return \"pending\";\n if (resource.backfill && (!state.backfill || !state.backfill.completed)) return \"backfilling\";\n return \"live\";\n};\n","import { Cause, Effect } from \"effect\";\nimport { HttpRouter, HttpServerResponse } from \"effect/http\";\n\nimport type { ConnectorDefinition } from \"../core/types\";\nimport type { ResourceStatus, StatusUnavailableResponse } from \"./types\";\n\nimport { StateStore } from \"../state-store\";\nimport { deriveSyncState, normalizeCursor } from \"../state-store/state\";\n\nexport const statusRoute = (\n connector: ConnectorDefinition,\n path: HttpRouter.PathInput = \"/status\",\n) =>\n HttpRouter.add(\n \"GET\",\n path,\n Effect.gen(function* () {\n const store = yield* StateStore;\n\n const resources = yield* Effect.forEach(\n connector.resources,\n (resource) =>\n store.getResourceState(resource.name).pipe(\n Effect.map(\n (state): ResourceStatus => ({\n name: resource.name,\n state: deriveSyncState(connector, resource, state),\n ...(state?.backfill\n ? {\n backfill: {\n completed: state.backfill.completed,\n cutoff: normalizeCursor(state.backfill.cutoff),\n ...(state.backfill.pageCursor !== undefined\n ? { pageCursor: normalizeCursor(state.backfill.pageCursor) }\n : {}),\n ...(state.backfill.lastSuccessAt !== undefined\n ? { lastSuccessAt: state.backfill.lastSuccessAt }\n : {}),\n },\n }\n : {}),\n ...(state?.changes\n ? {\n changes: {\n cursor: normalizeCursor(state.changes.cursor),\n ...(state.changes.lastSuccessAt !== undefined\n ? { lastSuccessAt: state.changes.lastSuccessAt }\n : {}),\n },\n }\n : {}),\n ...(state?.lastError ? { lastError: state.lastError } : {}),\n }),\n ),\n ),\n { concurrency: \"unbounded\" },\n );\n\n return HttpServerResponse.jsonUnsafe({ connector: connector.name, resources });\n }).pipe(\n Effect.catchCause((cause) =>\n Effect.logWarning(`Status route failed: ${Cause.pretty(cause)}`).pipe(\n Effect.andThen(\n Effect.succeed(\n HttpServerResponse.jsonUnsafe(\n {\n ok: false,\n error: \"Failed to compute status\",\n } satisfies StatusUnavailableResponse,\n { status: 500 },\n ),\n ),\n ),\n ),\n ),\n ),\n );\n","import { Schema } from \"effect\";\n\nimport {\n ResourceErrorSchema as StateResourceErrorSchema,\n ResourceStateSchema,\n} from \"../state-store/schema\";\n\nexport const SyncStateSchema = Schema.Literals([\"pending\", \"backfilling\", \"live\", \"error\"]);\nexport type SyncState = Schema.Schema.Type<typeof SyncStateSchema>;\n\n/** Safe source failure returned by the status endpoint. */\nexport const ResourceErrorSchema = StateResourceErrorSchema;\nexport type ResourceError = Schema.Schema.Type<typeof ResourceErrorSchema>;\n\nexport const ResourceStatusSchema = Schema.Struct({\n name: Schema.String,\n state: SyncStateSchema,\n ...ResourceStateSchema.fields,\n});\nexport type ResourceStatus = Schema.Schema.Type<typeof ResourceStatusSchema>;\n\nexport const StatusResponseSchema = Schema.Struct({\n connector: Schema.String,\n resources: Schema.Array(ResourceStatusSchema),\n});\nexport type StatusResponse = Schema.Schema.Type<typeof StatusResponseSchema>;\n\n/** Returned when durable resource status cannot be read. */\nexport const StatusUnavailableResponseSchema = Schema.Struct({\n ok: Schema.Literal(false),\n error: Schema.String,\n});\nexport type StatusUnavailableResponse = Schema.Schema.Type<typeof StatusUnavailableResponseSchema>;\n","export * from \"./route\";\nexport * from \"./types\";\n"],"mappings":";;;;;;AASA,MAAa,mBAAmB,UAC9B,iBAAiB,OAAO,MAAM,YAAY,IAAI;;AAGhD,MAAa,cAAc,WAAgC,aACzD,SAAS,YAAY,KAAA,MACpB,UAAU,SAAS,UAAU,MAAM,WAAW,OAAO,SAAS,SAAS,IAAI,KAAK;;AAGnF,MAAa,mBACX,WACA,UACA,UACc;CACd,IAAI,OAAO,WAAW,OAAO;CAC7B,IAAI,CAAC,SAAS,YAAY,CAAC,WAAW,WAAW,QAAQ,GAAG,OAAO;CACnE,IAAI,CAAC,OAAO,OAAO;CACnB,IAAI,SAAS,aAAa,CAAC,MAAM,YAAY,CAAC,MAAM,SAAS,YAAY,OAAO;CAChF,OAAO;AACT;;;ACnBA,MAAa,eACX,WACA,OAA6B,cAE7B,WAAW,IACT,OACA,MACA,OAAO,IAAI,aAAa;CACtB,MAAM,QAAQ,OAAO;CAErB,MAAM,YAAY,OAAO,OAAO,QAC9B,UAAU,YACT,aACC,MAAM,iBAAiB,SAAS,IAAI,CAAC,CAAC,KACpC,OAAO,KACJ,WAA2B;EAC1B,MAAM,SAAS;EACf,OAAO,gBAAgB,WAAW,UAAU,KAAK;EACjD,GAAI,OAAO,WACP,EACE,UAAU;GACR,WAAW,MAAM,SAAS;GAC1B,QAAQ,gBAAgB,MAAM,SAAS,MAAM;GAC7C,GAAI,MAAM,SAAS,eAAe,KAAA,IAC9B,EAAE,YAAY,gBAAgB,MAAM,SAAS,UAAU,EAAE,IACzD,CAAC;GACL,GAAI,MAAM,SAAS,kBAAkB,KAAA,IACjC,EAAE,eAAe,MAAM,SAAS,cAAc,IAC9C,CAAC;EACP,EACF,IACA,CAAC;EACL,GAAI,OAAO,UACP,EACE,SAAS;GACP,QAAQ,gBAAgB,MAAM,QAAQ,MAAM;GAC5C,GAAI,MAAM,QAAQ,kBAAkB,KAAA,IAChC,EAAE,eAAe,MAAM,QAAQ,cAAc,IAC7C,CAAC;EACP,EACF,IACA,CAAC;EACL,GAAI,OAAO,YAAY,EAAE,WAAW,MAAM,UAAU,IAAI,CAAC;CAC3D,EACF,CACF,GACF,EAAE,aAAa,YAAY,CAC7B;CAEA,OAAO,mBAAmB,WAAW;EAAE,WAAW,UAAU;EAAM;CAAU,CAAC;AAC/E,CAAC,CAAC,CAAC,KACD,OAAO,YAAY,UACjB,OAAO,WAAW,wBAAwB,MAAM,OAAO,KAAK,GAAG,CAAC,CAAC,KAC/D,OAAO,QACL,OAAO,QACL,mBAAmB,WACjB;CACE,IAAI;CACJ,OAAO;AACT,GACA,EAAE,QAAQ,IAAI,CAChB,CACF,CACF,CACF,CACF,CACF,CACF;;;ACrEF,MAAa,kBAAkB,OAAO,SAAS;CAAC;CAAW;CAAe;CAAQ;AAAO,CAAC;;AAI1F,MAAa,sBAAsBA;AAGnC,MAAa,uBAAuB,OAAO,OAAO;CAChD,MAAM,OAAO;CACb,OAAO;CACP,GAAG,oBAAoB;AACzB,CAAC;AAGD,MAAa,uBAAuB,OAAO,OAAO;CAChD,WAAW,OAAO;CAClB,WAAW,OAAO,MAAM,oBAAoB;AAC9C,CAAC;;AAID,MAAa,kCAAkC,OAAO,OAAO;CAC3D,IAAI,OAAO,QAAQ,KAAK;CACxB,OAAO,OAAO;AAChB,CAAC"}
|
|
@@ -4,7 +4,6 @@ import { Data, Effect, Schema } from "effect";
|
|
|
4
4
|
var IcebergSchemaError = class extends Data.TaggedError("IcebergSchemaError") {};
|
|
5
5
|
//#endregion
|
|
6
6
|
//#region src/iceberg/table.ts
|
|
7
|
-
const maxFieldId = 2147483447;
|
|
8
7
|
const anonymousDeclaration = "Schemas without a name, such as Schema.Class, do not work here; use Schema.Struct";
|
|
9
8
|
var CompilationFailure = class extends Error {
|
|
10
9
|
path;
|
|
@@ -52,7 +51,7 @@ var Compiler = class {
|
|
|
52
51
|
#activeObjects = /* @__PURE__ */ new Set();
|
|
53
52
|
#activeReferences = /* @__PURE__ */ new Set();
|
|
54
53
|
#activeSuspends = /* @__PURE__ */ new Set();
|
|
55
|
-
#
|
|
54
|
+
#nextId = 0;
|
|
56
55
|
constructor(references) {
|
|
57
56
|
this.references = references;
|
|
58
57
|
}
|
|
@@ -79,19 +78,6 @@ var Compiler = class {
|
|
|
79
78
|
};
|
|
80
79
|
});
|
|
81
80
|
}
|
|
82
|
-
#readId(annotations, path, source) {
|
|
83
|
-
const id = annotations?.fieldId;
|
|
84
|
-
if (typeof id !== "number") return fail(path, `Missing fieldId; add it with ${source}`);
|
|
85
|
-
if (!Number.isInteger(id)) return fail(path, "fieldId must be a whole number");
|
|
86
|
-
if (id < 1 || id > maxFieldId) return fail(path, `fieldId must be between 1 and ${maxFieldId}`);
|
|
87
|
-
const previousPath = this.#fieldIds.get(id);
|
|
88
|
-
if (previousPath !== void 0) return fail(path, `fieldId ${id} is already used at ${previousPath}`);
|
|
89
|
-
this.#fieldIds.set(id, path);
|
|
90
|
-
return id;
|
|
91
|
-
}
|
|
92
|
-
#readNodeId(representation, path) {
|
|
93
|
-
return this.#withReference(representation, path, (resolved) => this.#readId(resolveAnnotations(resolved), path, ".annotate({ fieldId }) on the schema itself"));
|
|
94
|
-
}
|
|
95
81
|
#withReference(representation, path, compile) {
|
|
96
82
|
if (representation._tag !== "Reference") return compile(representation);
|
|
97
83
|
const reference = representation.$ref;
|
|
@@ -114,7 +100,7 @@ var Compiler = class {
|
|
|
114
100
|
if (typeof property.name !== "string") return fail(propertyPath(path, String(property.name)), "Iceberg field names must be strings");
|
|
115
101
|
const fieldPath = propertyPath(path, property.name);
|
|
116
102
|
this.#checkRecursion(property.type, fieldPath);
|
|
117
|
-
const id = this.#
|
|
103
|
+
const id = ++this.#nextId;
|
|
118
104
|
const compiled = this.#compileType(property.type, fieldPath);
|
|
119
105
|
const fieldDescription = description(property.annotations);
|
|
120
106
|
return {
|
|
@@ -192,7 +178,7 @@ var Compiler = class {
|
|
|
192
178
|
if (representation.elements.length > 0 || representation.rest.length !== 1) return fail(path, "A tuple does not work here; use a Schema.Array where every item has the same type");
|
|
193
179
|
const elementPath = `${path}.element`;
|
|
194
180
|
const elementRepresentation = representation.rest[0];
|
|
195
|
-
const elementId = this.#
|
|
181
|
+
const elementId = ++this.#nextId;
|
|
196
182
|
const compiled = this.#compileType(elementRepresentation, elementPath);
|
|
197
183
|
return {
|
|
198
184
|
type: {
|
|
@@ -226,10 +212,10 @@ var Compiler = class {
|
|
|
226
212
|
const valuePath = `${path}.value`;
|
|
227
213
|
const keyRepresentation = representation.typeParameters[0];
|
|
228
214
|
const valueRepresentation = representation.typeParameters[1];
|
|
229
|
-
const keyId = this.#
|
|
215
|
+
const keyId = ++this.#nextId;
|
|
230
216
|
const compiledKey = this.#compileType(keyRepresentation, keyPath);
|
|
231
217
|
if (compiledKey.nullable) return fail(keyPath, "Map keys cannot be null");
|
|
232
|
-
const valueId = this.#
|
|
218
|
+
const valueId = ++this.#nextId;
|
|
233
219
|
const compiledValue = this.#compileType(valueRepresentation, valuePath);
|
|
234
220
|
return {
|
|
235
221
|
type: {
|
|
@@ -280,69 +266,19 @@ const compileTable = (schema) => Effect.try({
|
|
|
280
266
|
cause
|
|
281
267
|
})
|
|
282
268
|
});
|
|
283
|
-
const
|
|
284
|
-
|
|
269
|
+
const makeCreateRequest = (table, options) => ({
|
|
270
|
+
name: options.name,
|
|
271
|
+
schema: table.schema,
|
|
272
|
+
...options.location === void 0 ? {} : { location: options.location },
|
|
273
|
+
properties: {
|
|
285
274
|
...table.description === void 0 ? {} : { comment: table.description },
|
|
286
|
-
...options.properties
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
updates: [
|
|
291
|
-
{
|
|
292
|
-
action: "assign-uuid",
|
|
293
|
-
uuid: options.uuid ?? crypto.randomUUID()
|
|
294
|
-
},
|
|
295
|
-
{
|
|
296
|
-
action: "upgrade-format-version",
|
|
297
|
-
"format-version": 2
|
|
298
|
-
},
|
|
299
|
-
{
|
|
300
|
-
action: "add-schema",
|
|
301
|
-
schema: table.schema
|
|
302
|
-
},
|
|
303
|
-
{
|
|
304
|
-
action: "set-current-schema",
|
|
305
|
-
"schema-id": -1
|
|
306
|
-
},
|
|
307
|
-
{
|
|
308
|
-
action: "add-spec",
|
|
309
|
-
spec: {
|
|
310
|
-
"spec-id": 0,
|
|
311
|
-
fields: []
|
|
312
|
-
}
|
|
313
|
-
},
|
|
314
|
-
{
|
|
315
|
-
action: "set-default-spec",
|
|
316
|
-
"spec-id": -1
|
|
317
|
-
},
|
|
318
|
-
{
|
|
319
|
-
action: "add-sort-order",
|
|
320
|
-
"sort-order": {
|
|
321
|
-
"order-id": 0,
|
|
322
|
-
fields: []
|
|
323
|
-
}
|
|
324
|
-
},
|
|
325
|
-
{
|
|
326
|
-
action: "set-default-sort-order",
|
|
327
|
-
"sort-order-id": -1
|
|
328
|
-
},
|
|
329
|
-
...options.location === void 0 ? [] : [{
|
|
330
|
-
action: "set-location",
|
|
331
|
-
location: options.location
|
|
332
|
-
}],
|
|
333
|
-
...Object.keys(properties).length === 0 ? [] : [{
|
|
334
|
-
action: "set-properties",
|
|
335
|
-
updates: properties
|
|
336
|
-
}]
|
|
337
|
-
]
|
|
338
|
-
};
|
|
339
|
-
};
|
|
275
|
+
...options.properties,
|
|
276
|
+
"format-version": "3"
|
|
277
|
+
}
|
|
278
|
+
});
|
|
340
279
|
/**
|
|
341
|
-
* Builds
|
|
342
|
-
*
|
|
343
|
-
* The field IDs come from the schema, so the table has to keep them. Send the
|
|
344
|
-
* commit with `commitTable`. Then load the table and check the IDs before you
|
|
345
|
-
* write any rows. Don't use `createTable` here, because it can change the IDs.
|
|
280
|
+
* Builds a REST create-table request from an Effect schema.
|
|
281
|
+
* The catalog assigns the stored field IDs.
|
|
346
282
|
*
|
|
347
283
|
* A root `description` becomes the table `comment`, and a field `description`
|
|
348
284
|
* becomes its `doc`. `title` and `examples` are dropped.
|
|
@@ -353,18 +289,19 @@ const makeCommitRequest = (table, options) => {
|
|
|
353
289
|
* @example
|
|
354
290
|
* ```ts
|
|
355
291
|
* const Row = Schema.Struct({
|
|
356
|
-
* id: Schema.String.pipe(
|
|
292
|
+
* id: Schema.String.pipe(Schema.annotateKey({ description: "Row identifier" })),
|
|
357
293
|
* })
|
|
358
294
|
* .annotate({ description: "Connector rows" })
|
|
359
295
|
* .pipe(Iceberg.identifier("id"))
|
|
360
296
|
*
|
|
361
|
-
* const request = yield* Iceberg.
|
|
297
|
+
* const request = yield* Iceberg.makeCreateTableRequest(Row, {
|
|
298
|
+
* name: "rows",
|
|
362
299
|
* location: "s3://warehouse/rows"
|
|
363
300
|
* })
|
|
364
301
|
* ```
|
|
365
302
|
*/
|
|
366
|
-
const
|
|
303
|
+
const makeCreateTableRequest = (schema, options) => Effect.map(compileTable(schema), (table) => makeCreateRequest(table, options));
|
|
367
304
|
//#endregion
|
|
368
|
-
export { IcebergSchemaError as a,
|
|
305
|
+
export { IcebergSchemaError as a, makeCreateTableRequest as i, compileTable as n, makeCreateRequest as r, checkHasRepresentation as t };
|
|
369
306
|
|
|
370
|
-
//# sourceMappingURL=table-
|
|
307
|
+
//# sourceMappingURL=table-CxM09xf7.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"table-CxM09xf7.mjs","names":[],"sources":["../src/iceberg/error.ts","../src/iceberg/table.ts"],"sourcesContent":["import { Data } from \"effect\";\n\n/** A schema could not be turned into an Iceberg table. */\nexport class IcebergSchemaError extends Data.TaggedError(\"IcebergSchemaError\")<{\n /** Schema path, such as `$.orders.element`. */\n readonly path: string;\n readonly message: string;\n readonly cause?: unknown;\n}> {}\n","import type {\n CreateTableRequest,\n IcebergType,\n MapType,\n StructField,\n StructType,\n TableSchema,\n} from \"iceberg-js\";\n\nimport { Effect, Schema, type SchemaRepresentation } from \"effect\";\n\nimport { IcebergSchemaError } from \"./error\";\n\n/** Options for creating a table. */\nexport type CreateTableOptions = {\n readonly name: string;\n /** Where the table's files go. The catalog may choose this when omitted. */\n readonly location?: string | undefined;\n /** Extra table properties. These win over the ones from the schema. */\n readonly properties?: Readonly<Record<string, string>> | undefined;\n};\n\ntype Representation = SchemaRepresentation.Representation;\ntype Resolved = Exclude<Representation, SchemaRepresentation.Reference>;\ntype Annotations = Schema.Annotations.Annotations;\n\ntype CompiledType = {\n readonly type: IcebergType;\n readonly nullable: boolean;\n};\n\nexport type CompiledTable = {\n readonly schema: TableSchema;\n readonly description: string | undefined;\n};\n\nconst anonymousDeclaration =\n \"Schemas without a name, such as Schema.Class, do not work here; use Schema.Struct\";\n\nclass CompilationFailure extends Error {\n readonly path: string;\n\n constructor(path: string, message: string) {\n super(message);\n this.path = path;\n }\n}\n\nconst fail = (path: string, message: string): never => {\n throw new CompilationFailure(path, message);\n};\n\nconst propertyPath = (path: string, name: string): string =>\n /^[A-Za-z_$][\\w$]*$/.test(name) ? `${path}.${name}` : `${path}[${JSON.stringify(name)}]`;\n\n/** Reads annotations the way Effect does: if there are checks, the last one wins. */\nconst resolveAnnotations = (representation: Resolved): Annotations | undefined => {\n const lastCheck = representation.checks.at(-1);\n return lastCheck === undefined ? representation.annotations : lastCheck.annotations;\n};\n\nconst description = (annotations: Annotations | undefined): string | undefined => {\n const value = annotations?.description;\n return typeof value === \"string\" ? value : undefined;\n};\n\n/** @internal */\nexport const checkHasRepresentation = (\n checks: ReadonlyArray<SchemaRepresentation.Check>,\n id: string,\n): boolean =>\n checks.some(\n (check) =>\n check.representation?.id === id ||\n (check._tag === \"FilterGroup\" && checkHasRepresentation(check.checks, id)),\n );\n\nconst isAnonymousDeclaration = (representation: Resolved): boolean =>\n representation._tag === \"Declaration\" && representation.representation?.id === undefined;\n\nconst literalType = (\n literal: SchemaRepresentation.Literal[\"literal\"],\n path: string,\n): IcebergType => {\n switch (typeof literal) {\n case \"string\":\n return \"string\";\n case \"boolean\":\n return \"boolean\";\n case \"number\":\n return Number.isFinite(literal)\n ? \"double\"\n : fail(path, \"A number literal must be a real number, not Infinity or NaN\");\n case \"bigint\":\n return \"long\";\n default:\n return fail(path, `A ${typeof literal} literal does not work here`);\n }\n};\n\nconst identifierId = (fields: ReadonlyArray<StructField>, name: string): number => {\n const path = propertyPath(\"$\", name);\n const field = fields.find((candidate) => candidate.name === name);\n\n if (!field) return fail(path, \"Iceberg.identifier names a field that does not exist\");\n if (!field.required) return fail(path, \"An identifier field cannot be optional or null\");\n if (typeof field.type !== \"string\" || field.type === \"float\" || field.type === \"double\") {\n return fail(path, \"An identifier field must be a primitive type other than float or double\");\n }\n return field.id;\n};\n\nconst assertNever = (_representation: never, path: string): never =>\n fail(path, \"This kind of schema does not work here\");\n\nclass Compiler {\n readonly #activeObjects = new Set<SchemaRepresentation.Objects>();\n readonly #activeReferences = new Set<string>();\n readonly #activeSuspends = new Set<SchemaRepresentation.Suspend>();\n // The REST request needs IDs. Only the catalog's returned IDs are authoritative.\n #nextId = 0;\n\n constructor(private readonly references: SchemaRepresentation.References) {}\n\n compile(root: Representation): CompiledTable {\n return this.#withReference(root, \"$\", (representation) => {\n if (isAnonymousDeclaration(representation)) return fail(\"$\", anonymousDeclaration);\n if (representation._tag !== \"Objects\") {\n return fail(\"$\", \"The top level of a table must be a Schema.Struct\");\n }\n\n const annotations = resolveAnnotations(representation);\n const fields = this.#compileFields(representation, \"$\");\n const identifierIds = (annotations?.icebergIdentifierFields ?? []).map((name) =>\n identifierId(fields, name),\n );\n\n return {\n schema:\n identifierIds.length === 0\n ? { type: \"struct\", fields }\n : {\n type: \"struct\",\n // Deletes only send the key and version, so other columns must be nullable.\n fields: fields.map((field) => ({\n ...field,\n required: identifierIds.includes(field.id),\n })),\n \"identifier-field-ids\": identifierIds,\n },\n description: description(annotations),\n };\n });\n }\n\n #withReference<A>(\n representation: Representation,\n path: string,\n compile: (resolved: Resolved) => A,\n ): A {\n if (representation._tag !== \"Reference\") return compile(representation);\n\n const reference = representation.$ref;\n const resolved = this.references[reference];\n if (resolved === undefined) return fail(path, `Cannot find the schema named ${reference}`);\n if (this.#activeReferences.has(reference)) {\n return fail(path, \"Iceberg cannot store a schema that contains itself\");\n }\n\n this.#activeReferences.add(reference);\n try {\n return this.#withReference(resolved, path, compile);\n } finally {\n this.#activeReferences.delete(reference);\n }\n }\n\n #checkRecursion(representation: Representation, path: string): void {\n if (representation._tag === \"Reference\" && this.#activeReferences.has(representation.$ref)) {\n fail(path, \"Iceberg cannot store a schema that contains itself\");\n }\n }\n\n #compileFields(representation: SchemaRepresentation.Objects, path: string): Array<StructField> {\n if (representation.indexSignatures.length > 0) {\n return fail(\n path,\n \"Schema.Record does not work here; name the keys with Schema.Struct, or store it as a JSON string\",\n );\n }\n\n return representation.propertySignatures.map((property) => {\n if (typeof property.name !== \"string\") {\n return fail(\n propertyPath(path, String(property.name)),\n \"Iceberg field names must be strings\",\n );\n }\n\n const fieldPath = propertyPath(path, property.name);\n this.#checkRecursion(property.type, fieldPath);\n const id = ++this.#nextId;\n const compiled = this.#compileType(property.type, fieldPath);\n const fieldDescription = description(property.annotations);\n\n return {\n id,\n name: property.name,\n type: compiled.type,\n required: !property.isOptional && !compiled.nullable,\n ...(fieldDescription === undefined ? {} : { doc: fieldDescription }),\n };\n });\n }\n\n #compileType(representation: Representation, path: string): CompiledType {\n if (representation._tag === \"Reference\") {\n return this.#withReference(representation, path, (resolved) =>\n this.#compileType(resolved, path),\n );\n }\n\n switch (representation._tag) {\n case \"String\":\n return { type: \"string\", nullable: false };\n case \"Boolean\":\n return { type: \"boolean\", nullable: false };\n case \"BigInt\":\n return { type: \"long\", nullable: false };\n case \"Number\":\n // Schema.Int can exceed Iceberg int. A double holds every safe integer\n // exactly; a long would need bigint rows.\n return checkHasRepresentation(representation.checks, \"effect/schema/isFinite\") ||\n checkHasRepresentation(representation.checks, \"effect/schema/isInt\")\n ? { type: \"double\", nullable: false }\n : fail(path, \"Plain Schema.Number does not work here; use Schema.Finite or Schema.Int\");\n case \"Literal\":\n return { type: literalType(representation.literal, path), nullable: false };\n case \"Objects\": {\n if (this.#activeObjects.has(representation)) {\n return fail(path, \"Iceberg cannot store a schema that contains itself\");\n }\n\n this.#activeObjects.add(representation);\n try {\n return {\n type: {\n type: \"struct\",\n fields: this.#compileFields(representation, path),\n } satisfies StructType,\n nullable: false,\n };\n } finally {\n this.#activeObjects.delete(representation);\n }\n }\n case \"Arrays\":\n return this.#compileArray(representation, path);\n case \"Declaration\":\n return this.#compileDeclaration(representation, path);\n case \"Union\":\n return this.#compileUnion(representation, path);\n case \"Suspend\": {\n if (this.#activeSuspends.has(representation)) {\n return fail(path, \"Iceberg cannot store a schema that contains itself\");\n }\n\n this.#activeSuspends.add(representation);\n try {\n return this.#compileType(representation.thunk, path);\n } finally {\n this.#activeSuspends.delete(representation);\n }\n }\n case \"Null\":\n case \"Undefined\":\n return fail(path, \"A field cannot contain only null or undefined\");\n case \"Any\":\n case \"Unknown\":\n case \"ObjectKeyword\":\n case \"Symbol\":\n case \"UniqueSymbol\":\n case \"Void\":\n case \"Never\":\n case \"Enum\":\n case \"TemplateLiteral\":\n return fail(path, `A ${representation._tag} schema does not work here`);\n default:\n return assertNever(representation, path);\n }\n }\n\n #compileArray(representation: SchemaRepresentation.Arrays, path: string): CompiledType {\n if (representation.elements.length > 0 || representation.rest.length !== 1) {\n return fail(\n path,\n \"A tuple does not work here; use a Schema.Array where every item has the same type\",\n );\n }\n\n const elementPath = `${path}.element`;\n const elementRepresentation = representation.rest[0]!;\n const elementId = ++this.#nextId;\n const compiled = this.#compileType(elementRepresentation, elementPath);\n\n return {\n type: {\n type: \"list\",\n \"element-id\": elementId,\n element: compiled.type,\n \"element-required\": !compiled.nullable,\n },\n nullable: false,\n };\n }\n\n #compileDeclaration(\n representation: SchemaRepresentation.Declaration,\n path: string,\n ): CompiledType {\n const id = representation.representation?.id;\n\n switch (id) {\n case \"effect/schema/Date\":\n return { type: \"timestamptz\", nullable: false };\n case \"effect/schema/Uint8Array\":\n return { type: \"binary\", nullable: false };\n case \"effect/schema/ReadonlyMap\":\n return this.#compileMap(representation, path);\n case undefined:\n return fail(path, anonymousDeclaration);\n default:\n return fail(path, `The ${id} schema does not work here`);\n }\n }\n\n #compileMap(representation: SchemaRepresentation.Declaration, path: string): CompiledType {\n if (representation.typeParameters.length !== 2) {\n return fail(path, \"ReadonlyMap needs one key schema and one value schema\");\n }\n\n const keyPath = `${path}.key`;\n const valuePath = `${path}.value`;\n const keyRepresentation = representation.typeParameters[0]!;\n const valueRepresentation = representation.typeParameters[1]!;\n const keyId = ++this.#nextId;\n const compiledKey = this.#compileType(keyRepresentation, keyPath);\n\n if (compiledKey.nullable) return fail(keyPath, \"Map keys cannot be null\");\n\n const valueId = ++this.#nextId;\n const compiledValue = this.#compileType(valueRepresentation, valuePath);\n\n return {\n type: {\n type: \"map\",\n \"key-id\": keyId,\n key: compiledKey.type,\n \"value-id\": valueId,\n value: compiledValue.type,\n \"value-required\": !compiledValue.nullable,\n } satisfies MapType,\n nullable: false,\n };\n }\n\n #compileUnion(representation: SchemaRepresentation.Union, path: string): CompiledType {\n let nullable = false;\n const concrete: Array<Representation> = [];\n\n for (const member of representation.types) {\n if (member._tag === \"Null\" || member._tag === \"Undefined\") {\n nullable = true;\n } else {\n concrete.push(member);\n }\n }\n\n if (concrete.length === 0) return fail(path, \"A field cannot contain only null or undefined\");\n\n if (concrete.length === 1) {\n const compiled = this.#compileType(concrete[0]!, path);\n return { type: compiled.type, nullable: nullable || compiled.nullable };\n }\n\n if (!concrete.every((member) => member._tag === \"Literal\")) {\n return fail(path, \"A union only works when every member is a literal\");\n }\n\n const first = literalType(concrete[0]!.literal, path);\n for (const member of concrete.slice(1)) {\n if (literalType(member.literal, path) !== first) {\n return fail(path, \"Every literal in a union must be the same type\");\n }\n }\n\n return { type: first, nullable };\n }\n}\n\nexport const compileTable = (\n schema: Schema.Top,\n): Effect.Effect<CompiledTable, IcebergSchemaError> =>\n Effect.try({\n try: () => {\n const document = Schema.toRepresentation(Schema.toType(schema));\n return new Compiler(document.references).compile(document.representation);\n },\n catch: (cause) =>\n cause instanceof CompilationFailure\n ? new IcebergSchemaError({ path: cause.path, message: cause.message, cause })\n : new IcebergSchemaError({\n path: \"$\",\n message: cause instanceof Error ? cause.message : String(cause),\n cause,\n }),\n });\n\nexport const makeCreateRequest = (\n table: CompiledTable,\n options: CreateTableOptions,\n): CreateTableRequest => ({\n name: options.name,\n schema: table.schema,\n ...(options.location === undefined ? {} : { location: options.location }),\n properties: {\n ...(table.description === undefined ? {} : { comment: table.description }),\n ...options.properties,\n \"format-version\": \"3\",\n },\n});\n\n/**\n * Builds a REST create-table request from an Effect schema.\n * The catalog assigns the stored field IDs.\n *\n * A root `description` becomes the table `comment`, and a field `description`\n * becomes its `doc`. `title` and `examples` are dropped.\n *\n * `Iceberg.identifier` sets the `identifier-field-ids`, and makes every other\n * top-level column nullable.\n *\n * @example\n * ```ts\n * const Row = Schema.Struct({\n * id: Schema.String.pipe(Schema.annotateKey({ description: \"Row identifier\" })),\n * })\n * .annotate({ description: \"Connector rows\" })\n * .pipe(Iceberg.identifier(\"id\"))\n *\n * const request = yield* Iceberg.makeCreateTableRequest(Row, {\n * name: \"rows\",\n * location: \"s3://warehouse/rows\"\n * })\n * ```\n */\nexport const makeCreateTableRequest = (\n schema: Schema.Top,\n options: CreateTableOptions,\n): Effect.Effect<CreateTableRequest, IcebergSchemaError> =>\n Effect.map(compileTable(schema), (table) => makeCreateRequest(table, options));\n"],"mappings":";;;AAGA,IAAa,qBAAb,cAAwC,KAAK,YAAY,oBAAoB,CAAC,CAK3E,CAAC;;;AC4BJ,MAAM,uBACJ;AAEF,IAAM,qBAAN,cAAiC,MAAM;CACrC;CAEA,YAAY,MAAc,SAAiB;EACzC,MAAM,OAAO;EACb,KAAK,OAAO;CACd;AACF;AAEA,MAAM,QAAQ,MAAc,YAA2B;CACrD,MAAM,IAAI,mBAAmB,MAAM,OAAO;AAC5C;AAEA,MAAM,gBAAgB,MAAc,SAClC,qBAAqB,KAAK,IAAI,IAAI,GAAG,KAAK,GAAG,SAAS,GAAG,KAAK,GAAG,KAAK,UAAU,IAAI,EAAE;;AAGxF,MAAM,sBAAsB,mBAAsD;CAChF,MAAM,YAAY,eAAe,OAAO,GAAG,EAAE;CAC7C,OAAO,cAAc,KAAA,IAAY,eAAe,cAAc,UAAU;AAC1E;AAEA,MAAM,eAAe,gBAA6D;CAChF,MAAM,QAAQ,aAAa;CAC3B,OAAO,OAAO,UAAU,WAAW,QAAQ,KAAA;AAC7C;;AAGA,MAAa,0BACX,QACA,OAEA,OAAO,MACJ,UACC,MAAM,gBAAgB,OAAO,MAC5B,MAAM,SAAS,iBAAiB,uBAAuB,MAAM,QAAQ,EAAE,CAC5E;AAEF,MAAM,0BAA0B,mBAC9B,eAAe,SAAS,iBAAiB,eAAe,gBAAgB,OAAO,KAAA;AAEjF,MAAM,eACJ,SACA,SACgB;CAChB,QAAQ,OAAO,SAAf;EACE,KAAK,UACH,OAAO;EACT,KAAK,WACH,OAAO;EACT,KAAK,UACH,OAAO,OAAO,SAAS,OAAO,IAC1B,WACA,KAAK,MAAM,6DAA6D;EAC9E,KAAK,UACH,OAAO;EACT,SACE,OAAO,KAAK,MAAM,KAAK,OAAO,QAAQ,4BAA4B;CACtE;AACF;AAEA,MAAM,gBAAgB,QAAoC,SAAyB;CACjF,MAAM,OAAO,aAAa,KAAK,IAAI;CACnC,MAAM,QAAQ,OAAO,MAAM,cAAc,UAAU,SAAS,IAAI;CAEhE,IAAI,CAAC,OAAO,OAAO,KAAK,MAAM,sDAAsD;CACpF,IAAI,CAAC,MAAM,UAAU,OAAO,KAAK,MAAM,gDAAgD;CACvF,IAAI,OAAO,MAAM,SAAS,YAAY,MAAM,SAAS,WAAW,MAAM,SAAS,UAC7E,OAAO,KAAK,MAAM,yEAAyE;CAE7F,OAAO,MAAM;AACf;AAEA,MAAM,eAAe,iBAAwB,SAC3C,KAAK,MAAM,wCAAwC;AAErD,IAAM,WAAN,MAAe;CAOgB;CAN7B,iCAA0B,IAAI,IAAkC;CAChE,oCAA6B,IAAI,IAAY;CAC7C,kCAA2B,IAAI,IAAkC;CAEjE,UAAU;CAEV,YAAY,YAA8D;EAA7C,KAAA,aAAA;CAA8C;CAE3E,QAAQ,MAAqC;EAC3C,OAAO,KAAK,eAAe,MAAM,MAAM,mBAAmB;GACxD,IAAI,uBAAuB,cAAc,GAAG,OAAO,KAAK,KAAK,oBAAoB;GACjF,IAAI,eAAe,SAAS,WAC1B,OAAO,KAAK,KAAK,kDAAkD;GAGrE,MAAM,cAAc,mBAAmB,cAAc;GACrD,MAAM,SAAS,KAAK,eAAe,gBAAgB,GAAG;GACtD,MAAM,iBAAiB,aAAa,2BAA2B,CAAC,EAAA,CAAG,KAAK,SACtE,aAAa,QAAQ,IAAI,CAC3B;GAEA,OAAO;IACL,QACE,cAAc,WAAW,IACrB;KAAE,MAAM;KAAU;IAAO,IACzB;KACE,MAAM;KAEN,QAAQ,OAAO,KAAK,WAAW;MAC7B,GAAG;MACH,UAAU,cAAc,SAAS,MAAM,EAAE;KAC3C,EAAE;KACF,wBAAwB;IAC1B;IACN,aAAa,YAAY,WAAW;GACtC;EACF,CAAC;CACH;CAEA,eACE,gBACA,MACA,SACG;EACH,IAAI,eAAe,SAAS,aAAa,OAAO,QAAQ,cAAc;EAEtE,MAAM,YAAY,eAAe;EACjC,MAAM,WAAW,KAAK,WAAW;EACjC,IAAI,aAAa,KAAA,GAAW,OAAO,KAAK,MAAM,gCAAgC,WAAW;EACzF,IAAI,KAAK,kBAAkB,IAAI,SAAS,GACtC,OAAO,KAAK,MAAM,oDAAoD;EAGxE,KAAK,kBAAkB,IAAI,SAAS;EACpC,IAAI;GACF,OAAO,KAAK,eAAe,UAAU,MAAM,OAAO;EACpD,UAAU;GACR,KAAK,kBAAkB,OAAO,SAAS;EACzC;CACF;CAEA,gBAAgB,gBAAgC,MAAoB;EAClE,IAAI,eAAe,SAAS,eAAe,KAAK,kBAAkB,IAAI,eAAe,IAAI,GACvF,KAAK,MAAM,oDAAoD;CAEnE;CAEA,eAAe,gBAA8C,MAAkC;EAC7F,IAAI,eAAe,gBAAgB,SAAS,GAC1C,OAAO,KACL,MACA,kGACF;EAGF,OAAO,eAAe,mBAAmB,KAAK,aAAa;GACzD,IAAI,OAAO,SAAS,SAAS,UAC3B,OAAO,KACL,aAAa,MAAM,OAAO,SAAS,IAAI,CAAC,GACxC,qCACF;GAGF,MAAM,YAAY,aAAa,MAAM,SAAS,IAAI;GAClD,KAAK,gBAAgB,SAAS,MAAM,SAAS;GAC7C,MAAM,KAAK,EAAE,KAAK;GAClB,MAAM,WAAW,KAAK,aAAa,SAAS,MAAM,SAAS;GAC3D,MAAM,mBAAmB,YAAY,SAAS,WAAW;GAEzD,OAAO;IACL;IACA,MAAM,SAAS;IACf,MAAM,SAAS;IACf,UAAU,CAAC,SAAS,cAAc,CAAC,SAAS;IAC5C,GAAI,qBAAqB,KAAA,IAAY,CAAC,IAAI,EAAE,KAAK,iBAAiB;GACpE;EACF,CAAC;CACH;CAEA,aAAa,gBAAgC,MAA4B;EACvE,IAAI,eAAe,SAAS,aAC1B,OAAO,KAAK,eAAe,gBAAgB,OAAO,aAChD,KAAK,aAAa,UAAU,IAAI,CAClC;EAGF,QAAQ,eAAe,MAAvB;GACE,KAAK,UACH,OAAO;IAAE,MAAM;IAAU,UAAU;GAAM;GAC3C,KAAK,WACH,OAAO;IAAE,MAAM;IAAW,UAAU;GAAM;GAC5C,KAAK,UACH,OAAO;IAAE,MAAM;IAAQ,UAAU;GAAM;GACzC,KAAK,UAGH,OAAO,uBAAuB,eAAe,QAAQ,wBAAwB,KAC3E,uBAAuB,eAAe,QAAQ,qBAAqB,IACjE;IAAE,MAAM;IAAU,UAAU;GAAM,IAClC,KAAK,MAAM,yEAAyE;GAC1F,KAAK,WACH,OAAO;IAAE,MAAM,YAAY,eAAe,SAAS,IAAI;IAAG,UAAU;GAAM;GAC5E,KAAK;IACH,IAAI,KAAK,eAAe,IAAI,cAAc,GACxC,OAAO,KAAK,MAAM,oDAAoD;IAGxE,KAAK,eAAe,IAAI,cAAc;IACtC,IAAI;KACF,OAAO;MACL,MAAM;OACJ,MAAM;OACN,QAAQ,KAAK,eAAe,gBAAgB,IAAI;MAClD;MACA,UAAU;KACZ;IACF,UAAU;KACR,KAAK,eAAe,OAAO,cAAc;IAC3C;GAEF,KAAK,UACH,OAAO,KAAK,cAAc,gBAAgB,IAAI;GAChD,KAAK,eACH,OAAO,KAAK,oBAAoB,gBAAgB,IAAI;GACtD,KAAK,SACH,OAAO,KAAK,cAAc,gBAAgB,IAAI;GAChD,KAAK;IACH,IAAI,KAAK,gBAAgB,IAAI,cAAc,GACzC,OAAO,KAAK,MAAM,oDAAoD;IAGxE,KAAK,gBAAgB,IAAI,cAAc;IACvC,IAAI;KACF,OAAO,KAAK,aAAa,eAAe,OAAO,IAAI;IACrD,UAAU;KACR,KAAK,gBAAgB,OAAO,cAAc;IAC5C;GAEF,KAAK;GACL,KAAK,aACH,OAAO,KAAK,MAAM,+CAA+C;GACnE,KAAK;GACL,KAAK;GACL,KAAK;GACL,KAAK;GACL,KAAK;GACL,KAAK;GACL,KAAK;GACL,KAAK;GACL,KAAK,mBACH,OAAO,KAAK,MAAM,KAAK,eAAe,KAAK,2BAA2B;GACxE,SACE,OAAO,YAAY,gBAAgB,IAAI;EAC3C;CACF;CAEA,cAAc,gBAA6C,MAA4B;EACrF,IAAI,eAAe,SAAS,SAAS,KAAK,eAAe,KAAK,WAAW,GACvE,OAAO,KACL,MACA,mFACF;EAGF,MAAM,cAAc,GAAG,KAAK;EAC5B,MAAM,wBAAwB,eAAe,KAAK;EAClD,MAAM,YAAY,EAAE,KAAK;EACzB,MAAM,WAAW,KAAK,aAAa,uBAAuB,WAAW;EAErE,OAAO;GACL,MAAM;IACJ,MAAM;IACN,cAAc;IACd,SAAS,SAAS;IAClB,oBAAoB,CAAC,SAAS;GAChC;GACA,UAAU;EACZ;CACF;CAEA,oBACE,gBACA,MACc;EACd,MAAM,KAAK,eAAe,gBAAgB;EAE1C,QAAQ,IAAR;GACE,KAAK,sBACH,OAAO;IAAE,MAAM;IAAe,UAAU;GAAM;GAChD,KAAK,4BACH,OAAO;IAAE,MAAM;IAAU,UAAU;GAAM;GAC3C,KAAK,6BACH,OAAO,KAAK,YAAY,gBAAgB,IAAI;GAC9C,KAAK,KAAA,GACH,OAAO,KAAK,MAAM,oBAAoB;GACxC,SACE,OAAO,KAAK,MAAM,OAAO,GAAG,2BAA2B;EAC3D;CACF;CAEA,YAAY,gBAAkD,MAA4B;EACxF,IAAI,eAAe,eAAe,WAAW,GAC3C,OAAO,KAAK,MAAM,uDAAuD;EAG3E,MAAM,UAAU,GAAG,KAAK;EACxB,MAAM,YAAY,GAAG,KAAK;EAC1B,MAAM,oBAAoB,eAAe,eAAe;EACxD,MAAM,sBAAsB,eAAe,eAAe;EAC1D,MAAM,QAAQ,EAAE,KAAK;EACrB,MAAM,cAAc,KAAK,aAAa,mBAAmB,OAAO;EAEhE,IAAI,YAAY,UAAU,OAAO,KAAK,SAAS,yBAAyB;EAExE,MAAM,UAAU,EAAE,KAAK;EACvB,MAAM,gBAAgB,KAAK,aAAa,qBAAqB,SAAS;EAEtE,OAAO;GACL,MAAM;IACJ,MAAM;IACN,UAAU;IACV,KAAK,YAAY;IACjB,YAAY;IACZ,OAAO,cAAc;IACrB,kBAAkB,CAAC,cAAc;GACnC;GACA,UAAU;EACZ;CACF;CAEA,cAAc,gBAA4C,MAA4B;EACpF,IAAI,WAAW;EACf,MAAM,WAAkC,CAAC;EAEzC,KAAK,MAAM,UAAU,eAAe,OAClC,IAAI,OAAO,SAAS,UAAU,OAAO,SAAS,aAC5C,WAAW;OAEX,SAAS,KAAK,MAAM;EAIxB,IAAI,SAAS,WAAW,GAAG,OAAO,KAAK,MAAM,+CAA+C;EAE5F,IAAI,SAAS,WAAW,GAAG;GACzB,MAAM,WAAW,KAAK,aAAa,SAAS,IAAK,IAAI;GACrD,OAAO;IAAE,MAAM,SAAS;IAAM,UAAU,YAAY,SAAS;GAAS;EACxE;EAEA,IAAI,CAAC,SAAS,OAAO,WAAW,OAAO,SAAS,SAAS,GACvD,OAAO,KAAK,MAAM,mDAAmD;EAGvE,MAAM,QAAQ,YAAY,SAAS,EAAE,CAAE,SAAS,IAAI;EACpD,KAAK,MAAM,UAAU,SAAS,MAAM,CAAC,GACnC,IAAI,YAAY,OAAO,SAAS,IAAI,MAAM,OACxC,OAAO,KAAK,MAAM,gDAAgD;EAItE,OAAO;GAAE,MAAM;GAAO;EAAS;CACjC;AACF;AAEA,MAAa,gBACX,WAEA,OAAO,IAAI;CACT,WAAW;EACT,MAAM,WAAW,OAAO,iBAAiB,OAAO,OAAO,MAAM,CAAC;EAC9D,OAAO,IAAI,SAAS,SAAS,UAAU,CAAC,CAAC,QAAQ,SAAS,cAAc;CAC1E;CACA,QAAQ,UACN,iBAAiB,qBACb,IAAI,mBAAmB;EAAE,MAAM,MAAM;EAAM,SAAS,MAAM;EAAS;CAAM,CAAC,IAC1E,IAAI,mBAAmB;EACrB,MAAM;EACN,SAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;EAC9D;CACF,CAAC;AACT,CAAC;AAEH,MAAa,qBACX,OACA,aACwB;CACxB,MAAM,QAAQ;CACd,QAAQ,MAAM;CACd,GAAI,QAAQ,aAAa,KAAA,IAAY,CAAC,IAAI,EAAE,UAAU,QAAQ,SAAS;CACvE,YAAY;EACV,GAAI,MAAM,gBAAgB,KAAA,IAAY,CAAC,IAAI,EAAE,SAAS,MAAM,YAAY;EACxE,GAAG,QAAQ;EACX,kBAAkB;CACpB;AACF;;;;;;;;;;;;;;;;;;;;;;;;;AA0BA,MAAa,0BACX,QACA,YAEA,OAAO,IAAI,aAAa,MAAM,IAAI,UAAU,kBAAkB,OAAO,OAAO,CAAC"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as ConnectorError } from "./index-DkVNO6ks.mjs";
|
|
2
|
-
import { n as RequiredField, t as Identified } from "./annotations-
|
|
2
|
+
import { n as RequiredField, t as Identified } from "./annotations-vzSzXtr-.mjs";
|
|
3
3
|
import { Duration, Effect, Schema } from "effect";
|
|
4
4
|
import { HttpRouter, HttpServerRequest, HttpServerResponse } from "effect/http";
|
|
5
5
|
//#region src/core/types.d.ts
|
|
@@ -77,7 +77,7 @@ type ResourceKey<S extends ResourceSchema> = S extends Identified<infer Key> ? K
|
|
|
77
77
|
type ResourceDelete<S extends ResourceSchema, Version extends ResourceField<S>> = Pick<ResourceRow<S>, Extract<ResourceKey<S> | Version, keyof ResourceRow<S>>> & {
|
|
78
78
|
readonly _deleted: true;
|
|
79
79
|
};
|
|
80
|
-
/** A full row, or a delete.
|
|
80
|
+
/** A full row, or a delete. The engine replaces the whole row. */
|
|
81
81
|
type ResourceUpdate<S extends ResourceSchema, Version extends ResourceField<S>> = (ResourceRow<S> & {
|
|
82
82
|
readonly _deleted?: boolean;
|
|
83
83
|
}) | ResourceDelete<S, Version>;
|
|
@@ -217,4 +217,4 @@ type ConnectorDefinition<Resources extends ReadonlyArray<ResourceDefinition> = R
|
|
|
217
217
|
};
|
|
218
218
|
//#endregion
|
|
219
219
|
export { WebhookRouteContext as A, ResourceUpdateOf as C, WebhookAckMode as D, TableSource as E, WebhookHandler as O, ResourceUpdate as S, TableResource as T, ResourceRequiredField as _, FeedRows as a, ResourceSchema as b, FetchPageResult as c, ResourceDefinition as d, ResourceDelete as f, ResourcePayload as g, ResourceName as h, Cursor as i, WebhookRouteInput as j, WebhookRoute as k, PageFetch as l, ResourceKey as m, ChangesFetch as n, FetchChangesResult as o, ResourceField as p, ConnectorDefinition as r, FetchFeedResult as s, ChangesFeed as t, ResourceBatch as u, ResourceRow as v, SyncState as w, ResourceState as x, ResourceRows as y };
|
|
220
|
-
//# sourceMappingURL=types-
|
|
220
|
+
//# sourceMappingURL=types-NtSv6gwl.d.mts.map
|
package/dist/webhook/index.d.mts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { A as WebhookRouteContext, D as WebhookAckMode, j as WebhookRouteInput, k as WebhookRoute } from "../types-
|
|
2
|
-
import { n as route, r as router } from "../index-
|
|
1
|
+
import { A as WebhookRouteContext, D as WebhookAckMode, j as WebhookRouteInput, k as WebhookRoute } from "../types-NtSv6gwl.mjs";
|
|
2
|
+
import { n as route, r as router } from "../index-dHS59EZl.mjs";
|
|
3
3
|
export { type WebhookAckMode, type WebhookRoute, type WebhookRouteContext, type WebhookRouteInput, route, router };
|
package/dist/webhook/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as __exportAll } from "../rolldown-runtime-D7D4PA-g.mjs";
|
|
2
|
-
import { n as router } from "../server-
|
|
2
|
+
import { n as router } from "../server-D1TTN0_D.mjs";
|
|
3
3
|
//#region src/webhook/index.ts
|
|
4
4
|
var webhook_exports = /* @__PURE__ */ __exportAll({
|
|
5
5
|
route: () => route,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@useairfoil/connector-kit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"repository": "useairfoil/connector-kit",
|
|
5
5
|
"files": [
|
|
6
6
|
"dist",
|
|
@@ -83,35 +83,36 @@
|
|
|
83
83
|
"default": "./dist/errors/index.mjs"
|
|
84
84
|
}
|
|
85
85
|
},
|
|
86
|
-
"scripts": {
|
|
87
|
-
"build": "tsdown",
|
|
88
|
-
"test": "vitest",
|
|
89
|
-
"test:ci": "vitest run",
|
|
90
|
-
"typecheck": "tsc --noEmit"
|
|
91
|
-
},
|
|
92
86
|
"dependencies": {
|
|
93
|
-
"@effect/platform-node": "^4.0
|
|
87
|
+
"@effect/platform-node": "^4.1.0",
|
|
94
88
|
"@faker-js/faker": "10.6.0",
|
|
95
|
-
"
|
|
96
|
-
"
|
|
97
|
-
"iceberg-js": "^1.0.0"
|
|
89
|
+
"apache-arrow": "^21.2.0",
|
|
90
|
+
"human-format": "^1.4.0",
|
|
91
|
+
"iceberg-js": "^1.0.0",
|
|
92
|
+
"@useairfoil/api": "0.5.0"
|
|
98
93
|
},
|
|
99
94
|
"devDependencies": {
|
|
100
|
-
"@effect/sql-pg": "^4.0
|
|
101
|
-
"@effect/vitest": "^4.0
|
|
95
|
+
"@effect/sql-pg": "^4.1.0",
|
|
96
|
+
"@effect/vitest": "^4.1.0",
|
|
102
97
|
"@types/node": "^24.2.0",
|
|
103
|
-
"
|
|
104
|
-
"effect": "^4.0.7",
|
|
98
|
+
"effect": "^4.1.0",
|
|
105
99
|
"testcontainers": "^11.14.0",
|
|
106
100
|
"tsdown": "^0.23.0",
|
|
107
|
-
"vitest": "^5.0.3"
|
|
101
|
+
"vitest": "^5.0.3",
|
|
102
|
+
"@useairfoil/testing": "0.2.0"
|
|
108
103
|
},
|
|
109
104
|
"peerDependencies": {
|
|
110
|
-
"effect": "^4.0
|
|
105
|
+
"effect": "^4.1.0"
|
|
111
106
|
},
|
|
112
107
|
"peerDependenciesMeta": {
|
|
113
108
|
"effect": {
|
|
114
109
|
"optional": false
|
|
115
110
|
}
|
|
111
|
+
},
|
|
112
|
+
"scripts": {
|
|
113
|
+
"build": "tsdown",
|
|
114
|
+
"test": "vitest",
|
|
115
|
+
"test:ci": "vitest run",
|
|
116
|
+
"typecheck": "tsc --noEmit"
|
|
116
117
|
}
|
|
117
|
-
}
|
|
118
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { Effect, Schedule, type Duration } from "effect";
|
|
2
|
+
|
|
3
|
+
export type TableRetryOptions = {
|
|
4
|
+
readonly interval: Duration.Input;
|
|
5
|
+
/** Retries after the initial attempt. */
|
|
6
|
+
readonly times: number;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
/** Retries transient catalog responses at the request boundary. */
|
|
10
|
+
export const retryCatalogRequest = <A, E extends { readonly status?: number }, R>(
|
|
11
|
+
request: Effect.Effect<A, E, R>,
|
|
12
|
+
options?: TableRetryOptions,
|
|
13
|
+
) =>
|
|
14
|
+
options === undefined
|
|
15
|
+
? request
|
|
16
|
+
: request.pipe(
|
|
17
|
+
Effect.retry({
|
|
18
|
+
schedule: Schedule.spaced(options.interval),
|
|
19
|
+
times: options.times,
|
|
20
|
+
while: (error) =>
|
|
21
|
+
error.status === 408 ||
|
|
22
|
+
error.status === 429 ||
|
|
23
|
+
(error.status !== undefined && error.status >= 500 && error.status <= 599),
|
|
24
|
+
}),
|
|
25
|
+
);
|