@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.
Files changed (102) hide show
  1. package/LICENSE.txt +201 -0
  2. package/METRICS.md +27 -30
  3. package/README.md +33 -51
  4. package/dist/{annotations-BE74YmAO.d.mts → annotations-vzSzXtr-.d.mts} +5 -10
  5. package/dist/{wings-I56hGtNv.mjs → arrow-flight-DDQ0ktx9.mjs} +25 -99
  6. package/dist/arrow-flight-DDQ0ktx9.mjs.map +1 -0
  7. package/dist/connector-app/index.d.mts +2 -2
  8. package/dist/connector-app/index.mjs +2 -2
  9. package/dist/connector-app-C6_dZnhE.mjs +256 -0
  10. package/dist/connector-app-C6_dZnhE.mjs.map +1 -0
  11. package/dist/{constants-D-GQzpHZ.mjs → constants-v3UX-hf6.mjs} +3 -2
  12. package/dist/constants-v3UX-hf6.mjs.map +1 -0
  13. package/dist/demo/index.d.mts +1 -1
  14. package/dist/demo/index.mjs +1 -1
  15. package/dist/{demo-B30Vlkk2.mjs → demo-DqTJ7TWI.mjs} +32 -19
  16. package/dist/demo-DqTJ7TWI.mjs.map +1 -0
  17. package/dist/iceberg/index.d.mts +3 -3
  18. package/dist/iceberg/index.mjs +3 -3
  19. package/dist/iceberg-Cj2PwlNm.mjs +30 -0
  20. package/dist/iceberg-Cj2PwlNm.mjs.map +1 -0
  21. package/dist/{index-DJhDp4Xc.d.mts → index-BTAbexBp.d.mts} +13 -16
  22. package/dist/{index-BUHSGm9Q.d.mts → index-Byr8NTdG.d.mts} +2 -2
  23. package/dist/{index-Dk7urvpF.d.mts → index-CV6V6fyx.d.mts} +9 -6
  24. package/dist/{index-NnCutIqM.d.mts → index-CZKx2Yce.d.mts} +29 -19
  25. package/dist/{index-BfXpgxk9.d.mts → index-DeTwIUKl.d.mts} +3 -3
  26. package/dist/{index-CRVAwJ5-.d.mts → index-dHS59EZl.d.mts} +4 -4
  27. package/dist/{index-ygpml2kC.d.mts → index-fHIJJoRe.d.mts} +17 -10
  28. package/dist/index-uFa2wwYo.d.mts +27 -0
  29. package/dist/index.d.mts +11 -11
  30. package/dist/index.mjs +10 -10
  31. package/dist/ingestion/index.d.mts +1 -1
  32. package/dist/ingestion/index.mjs +1 -1
  33. package/dist/{ingestion-q0WwqUSt.mjs → ingestion-DoCUwm5N.mjs} +6 -6
  34. package/dist/{ingestion-q0WwqUSt.mjs.map → ingestion-DoCUwm5N.mjs.map} +1 -1
  35. package/dist/ingestor/index.d.mts +3 -3
  36. package/dist/ingestor/index.mjs +3 -3
  37. package/dist/{ingestor-D4L-HPkg.mjs → ingestor-DjCEzBzZ.mjs} +6 -6
  38. package/dist/ingestor-DjCEzBzZ.mjs.map +1 -0
  39. package/dist/{instrumented-Bhp7fyvh.mjs → instrumented-Bq1WX2L5.mjs} +2 -2
  40. package/dist/{instrumented-Bhp7fyvh.mjs.map → instrumented-Bq1WX2L5.mjs.map} +1 -1
  41. package/dist/manifest/index.mjs +1 -1
  42. package/dist/{manifest-BGKxmKLy.mjs → manifest-CABeIhAG.mjs} +2 -2
  43. package/dist/{manifest-BGKxmKLy.mjs.map → manifest-CABeIhAG.mjs.map} +1 -1
  44. package/dist/{metrics-BaEX__MN.mjs → metrics-C901IIYZ.mjs} +6 -11
  45. package/dist/metrics-C901IIYZ.mjs.map +1 -0
  46. package/dist/{metrics-CVXFL7YT.d.mts → metrics-DoJ0WeKu.d.mts} +2 -2
  47. package/dist/metrics.d.mts +1 -1
  48. package/dist/metrics.mjs +1 -1
  49. package/dist/runtime-config/index.d.mts +2 -2
  50. package/dist/runtime-config/index.mjs +3 -3
  51. package/dist/{runtime-config-Oa55gAew.mjs → runtime-config-Bn8Fivt1.mjs} +11 -8
  52. package/dist/runtime-config-Bn8Fivt1.mjs.map +1 -0
  53. package/dist/{server-CMnxz3h0.mjs → server-D1TTN0_D.mjs} +3 -3
  54. package/dist/{server-CMnxz3h0.mjs.map → server-D1TTN0_D.mjs.map} +1 -1
  55. package/dist/{service-DLkhuxYl.d.mts → service-BRoy_EId.d.mts} +2 -2
  56. package/dist/state-store/index.mjs +1 -1
  57. package/dist/{state-store-uFvHY7Ax.mjs → state-store-DhSrKVEH.mjs} +2 -2
  58. package/dist/{state-store-uFvHY7Ax.mjs.map → state-store-DhSrKVEH.mjs.map} +1 -1
  59. package/dist/status/index.d.mts +1 -1
  60. package/dist/status/index.mjs +1 -1
  61. package/dist/{status-CKb9IhQ9.mjs → status-4h6Oxh-O.mjs} +2 -2
  62. package/dist/{status-CKb9IhQ9.mjs.map → status-4h6Oxh-O.mjs.map} +1 -1
  63. package/dist/{table-V0tgUC5i.mjs → table-CxM09xf7.mjs} +22 -85
  64. package/dist/table-CxM09xf7.mjs.map +1 -0
  65. package/dist/{types-xZtSmrGA.d.mts → types-NtSv6gwl.d.mts} +3 -3
  66. package/dist/webhook/index.d.mts +2 -2
  67. package/dist/webhook/index.mjs +1 -1
  68. package/package.json +19 -18
  69. package/src/catalog/retry.ts +25 -0
  70. package/src/catalog/table.ts +73 -37
  71. package/src/connector-app/create-table.ts +8 -8
  72. package/src/connector-app/demo.ts +24 -19
  73. package/src/connector-app/index.ts +1 -0
  74. package/src/connector-app/setup.ts +69 -0
  75. package/src/core/types.ts +1 -1
  76. package/src/demo/definition.ts +1 -1
  77. package/src/demo/generate.ts +1 -1
  78. package/src/demo/run.ts +60 -30
  79. package/src/iceberg/annotations.ts +3 -16
  80. package/src/iceberg/index.ts +2 -2
  81. package/src/iceberg/table.ts +28 -78
  82. package/src/ingestion/engine.ts +1 -1
  83. package/src/ingestor/{wings.ts → arrow-flight.ts} +25 -27
  84. package/src/ingestor/console.ts +1 -1
  85. package/src/ingestor/index.ts +5 -1
  86. package/src/runtime-config/config.ts +8 -3
  87. package/src/runtime-config/constants.ts +2 -1
  88. package/src/runtime-config/index.ts +1 -1
  89. package/src/runtime-config/table-bindings.ts +6 -4
  90. package/src/telemetry.ts +11 -19
  91. package/dist/connector-app-C-L4QqG6.mjs +0 -123
  92. package/dist/connector-app-C-L4QqG6.mjs.map +0 -1
  93. package/dist/constants-D-GQzpHZ.mjs.map +0 -1
  94. package/dist/demo-B30Vlkk2.mjs.map +0 -1
  95. package/dist/iceberg-D6L8I6vA.mjs +0 -39
  96. package/dist/iceberg-D6L8I6vA.mjs.map +0 -1
  97. package/dist/index-CUPP2A_m.d.mts +0 -27
  98. package/dist/ingestor-D4L-HPkg.mjs.map +0 -1
  99. package/dist/metrics-BaEX__MN.mjs.map +0 -1
  100. package/dist/runtime-config-Oa55gAew.mjs.map +0 -1
  101. package/dist/table-V0tgUC5i.mjs.map +0 -1
  102. package/dist/wings-I56hGtNv.mjs.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"file":"demo-B30Vlkk2.mjs","names":["Arr"],"sources":["../src/demo/definition.ts","../src/demo/generate.ts","../src/demo/run.ts","../src/demo/index.ts"],"sourcesContent":["import type { Schema } from \"effect\";\n\nimport type { ResourceRequiredField, ResourceSchema } from \"../core/types\";\nimport type { DemoContext } from \"./generate\";\n\n/** A table a demo writes: the same name, row schema and version as its resource. */\nexport type DemoTable<\n Name extends string = string,\n S extends ResourceSchema = ResourceSchema,\n Version extends string = string,\n> = {\n readonly name: Name;\n readonly rowSchema: S;\n readonly version: Version;\n};\n\nexport const table = <\n const Name extends string,\n S extends ResourceSchema,\n const Version extends ResourceRequiredField<S>,\n>(\n definition: DemoTable<Name, S, Version>,\n): DemoTable<Name, S, Version> => definition;\n\n/** Rows by table. Required fields a row leaves out get placeholder values. */\nexport type DemoRows<Tables extends ReadonlyArray<DemoTable>> = {\n readonly [Table in Tables[number] as Table[\"name\"]]?: ReadonlyArray<\n Partial<Schema.Schema.Type<Table[\"rowSchema\"]>>\n >;\n};\n\nexport type DemoDefinition<\n Setup extends ReadonlyArray<DemoTable> = ReadonlyArray<DemoTable>,\n Group extends ReadonlyArray<DemoTable> = ReadonlyArray<DemoTable>,\n> = {\n readonly name: string;\n /** Tables written once, before any group, such as a product catalog. */\n readonly setup: {\n readonly tables: Setup;\n readonly rows: (context: DemoContext) => DemoRows<Setup>;\n };\n /**\n * Tables for one related unit, such as a customer and their orders. The run\n * adds groups until it reaches the size. Build keys from the index, so they\n * are unique and other groups can point to them.\n */\n readonly group: {\n readonly tables: Group;\n readonly rows: (index: number, context: DemoContext) => DemoRows<Group>;\n /**\n * Groups written per chunk, 100 by default. A run can go over the size by\n * one chunk, so lower it when a group is big.\n */\n readonly groupsPerChunk?: number;\n /**\n * The number of groups there are, when the provider only keeps so much\n * history. The run stops there, even below the size.\n */\n readonly count?: number;\n };\n};\n\nexport const define = <\n const Setup extends ReadonlyArray<DemoTable>,\n const Group extends ReadonlyArray<DemoTable>,\n>(\n definition: DemoDefinition<Setup, Group>,\n): DemoDefinition<Setup, Group> => definition;\n","import type { Faker } from \"@faker-js/faker\";\n\nimport { Duration, Effect, Schema, type SchemaRepresentation } from \"effect\";\n\nimport { ConnectorError } from \"../errors\";\nimport { checkHasRepresentation } from \"../iceberg/table\";\n\n/** What one run shares: the seeded Faker and the time the run started. */\nexport type DemoContext = {\n readonly faker: Faker;\n readonly now: Date;\n};\n\n/** Completes a row: keeps what it has, and fills the required fields it lacks. */\nexport type RowFiller = (context: DemoContext, row: object) => Record<string, unknown>;\n\ntype Representation = SchemaRepresentation.Representation;\ntype Value = (context: DemoContext) => unknown;\n\nconst twoYears = Duration.toMillis(Duration.days(730));\n\nclass Unsupported extends Error {}\n\nconst unsupported = (path: string, what: string): never => {\n throw new Unsupported(`${path}: ${what} is not supported in demo data`);\n};\n\n/**\n * Compiles a row schema into a filler for demo rows. It reads the same\n * representation as `compileTable`, so values fit the Iceberg types. It fills\n * only required fields the row lacks, so optional ones such as `_deleted` stay\n * out.\n */\nexport const compileRow = (schema: Schema.Top): Effect.Effect<RowFiller, ConnectorError> =>\n Effect.try({\n try: () => {\n const { representation, references } = Schema.toRepresentation(Schema.toType(schema));\n\n const resolve = (node: Representation, path: string): Representation => {\n if (node._tag !== \"Reference\") return node;\n const target = references[node.$ref];\n\n return target === undefined ? unsupported(path, `reference ${node.$ref}`) : target;\n };\n\n const requiredFields = (node: Representation, path: string) => {\n const resolved = resolve(node, path);\n\n if (resolved._tag !== \"Objects\" || resolved.indexSignatures.length > 0) {\n return unsupported(path, resolved._tag);\n }\n\n return resolved.propertySignatures\n .filter((property) => !property.isOptional)\n .map((property) => {\n const name = String(property.name);\n return [name, value(property.type, `${path}.${name}`)] as const;\n });\n };\n\n const object = (node: Representation, path: string): Value => {\n const fields = requiredFields(node, path);\n return (context) => Object.fromEntries(fields.map(([name, make]) => [name, make(context)]));\n };\n\n const value = (node: Representation, path: string): Value => {\n const resolved = resolve(node, path);\n\n switch (resolved._tag) {\n case \"String\":\n return ({ faker }) => faker.word.words({ count: { min: 1, max: 3 } });\n case \"Boolean\":\n return ({ faker }) => faker.datatype.boolean();\n case \"BigInt\":\n return ({ faker }) => BigInt(faker.number.int({ max: 100_000 }));\n case \"Number\":\n return checkHasRepresentation(resolved.checks, \"effect/schema/isInt\")\n ? ({ faker }) => faker.number.int({ max: 1000 })\n : ({ faker }) => faker.number.float({ max: 1000, fractionDigits: 2 });\n case \"Literal\": {\n const literal = resolved.literal;\n return () => literal;\n }\n case \"Union\": {\n // Fill every field, so nullable unions get their value type.\n const members = resolved.types.filter(\n (member) => member._tag !== \"Null\" && member._tag !== \"Undefined\",\n );\n\n const literals = members.flatMap((member) =>\n member._tag === \"Literal\" ? [member.literal] : [],\n );\n\n if (literals.length > 0 && literals.length === members.length) {\n return ({ faker }) => faker.helpers.arrayElement(literals);\n }\n\n const [only] = members;\n\n return only !== undefined && members.length === 1\n ? value(only, path)\n : unsupported(path, \"a union of several types\");\n }\n case \"Objects\":\n return object(resolved, path);\n case \"Arrays\": {\n const [element] = resolved.rest;\n\n if (resolved.elements.length > 0 || resolved.rest.length !== 1 || !element) {\n return unsupported(path, \"a tuple\");\n }\n\n const item = value(element, `${path}[]`);\n\n return (context) =>\n Array.from({ length: context.faker.number.int({ max: 3 }) }, () => item(context));\n }\n case \"Declaration\":\n return declaration(resolved, path);\n case \"Suspend\":\n return value(resolved.thunk, path);\n default:\n return unsupported(path, resolved._tag);\n }\n };\n\n const declaration = (node: SchemaRepresentation.Declaration, path: string): Value => {\n switch (node.representation?.id) {\n case \"effect/schema/Date\":\n return ({ faker, now }) =>\n faker.date.between({ from: now.getTime() - twoYears, to: now });\n case \"effect/schema/Uint8Array\":\n return ({ faker }) => Uint8Array.from({ length: 8 }, () => faker.number.int(255));\n case \"effect/schema/ReadonlyMap\": {\n const [keyNode, valueNode] = node.typeParameters;\n if (!keyNode || !valueNode) return unsupported(path, \"a map without key or value\");\n const key = value(keyNode, `${path}.key`);\n const item = value(valueNode, `${path}.value`);\n\n return (context) =>\n new Map(\n Array.from({ length: context.faker.number.int({ max: 3 }) }, () => [\n key(context),\n item(context),\n ]),\n );\n }\n default:\n return unsupported(path, node.representation?.id ?? \"an unnamed declaration\");\n }\n };\n\n const fields = requiredFields(representation, \"$\");\n\n return (context, row) => ({\n ...Object.fromEntries(\n fields.filter(([name]) => !(name in row)).map(([name, make]) => [name, make(context)]),\n ),\n ...row,\n });\n },\n catch: (cause) =>\n new ConnectorError({\n message: cause instanceof Unsupported ? cause.message : \"Failed to compile demo rows\",\n cause,\n }),\n });\n","import { Faker, base, en } from \"@faker-js/faker\";\nimport { Array as Arr, Effect, Option, Schema, Stream } from \"effect\";\n\nimport type { DemoDefinition, DemoTable } from \"./definition\";\n\nimport { ConnectorError } from \"../errors\";\nimport { ingestBatch } from \"../ingestor/instrumented\";\nimport { Ingestor, type IngestResult } from \"../ingestor/service\";\nimport { compileRow, type DemoContext } from \"./generate\";\n\nexport type RunOptions = {\n /** Stop once this many Arrow bytes are written. */\n readonly bytes: number;\n readonly seed: number;\n /** The time data is made around. Same seed, time and tables give the same rows. */\n readonly now: Date;\n /** Groups per chunk. Overrides the demo's. */\n readonly groupsPerChunk?: number;\n};\n\nexport type DemoTotals = IngestResult & {\n readonly tables: Readonly<Record<string, IngestResult>>;\n};\n\nconst empty: DemoTotals = { rows: 0, bytes: 0, tables: {} };\n\n// Wings rejects Flight messages over 4 MiB. 500 rows keeps a batch of the\n// widest demo rows well under that.\nconst batchRows = 500;\n\nconst sum = (results: ReadonlyArray<IngestResult>): IngestResult => ({\n rows: results.reduce((total, result) => total + result.rows, 0),\n bytes: results.reduce((total, result) => total + result.bytes, 0),\n});\n\nconst add = (totals: DemoTotals, written: ReadonlyArray<readonly [string, IngestResult]>) =>\n written.reduce<DemoTotals>(\n (current, [name, result]) => ({\n rows: current.rows + result.rows,\n bytes: current.bytes + result.bytes,\n tables: {\n ...current.tables,\n [name]: {\n rows: (current.tables[name]?.rows ?? 0) + result.rows,\n bytes: (current.tables[name]?.bytes ?? 0) + result.bytes,\n },\n },\n }),\n totals,\n );\n\n/**\n * Writes the setup rows, then groups, until it reaches the size or the demo's\n * count. It can go over the size by one chunk. Only bound tables are\n * written; keys still point to the others.\n */\nexport const run = Effect.fnUntraced(function* (demo: DemoDefinition, options: RunOptions) {\n const ingestor = yield* Ingestor;\n\n const bound = (table: DemoTable) =>\n ingestor.resourceNames === undefined || ingestor.resourceNames.includes(table.name);\n\n // A fresh Faker per run, so its sequence depends only on the seed.\n const faker = new Faker({ locale: [en, base] });\n faker.seed(options.seed);\n const context: DemoContext = { faker, now: options.now };\n\n const prepare = (tables: ReadonlyArray<DemoTable>) =>\n Effect.forEach(tables.filter(bound), (table) =>\n compileRow(table.rowSchema).pipe(\n Effect.map((fill) => ({\n table,\n fill,\n decode: Schema.decodeUnknownEffect(Schema.toType(table.rowSchema)),\n })),\n ),\n );\n\n const write = (\n tables: Effect.Success<ReturnType<typeof prepare>>,\n rowsOf: (name: string) => ReadonlyArray<object>,\n ) =>\n Effect.forEach(tables, ({ table, fill, decode }) =>\n Effect.forEach(rowsOf(table.name), (row) =>\n decode(fill(context, row)).pipe(\n Effect.mapError(\n (cause) => new ConnectorError({ message: `Invalid demo row for ${table.name}`, cause }),\n ),\n ),\n ).pipe(\n Effect.flatMap((rows) =>\n Effect.forEach(Arr.chunksOf(rows, batchRows), (batch) =>\n ingestBatch({\n connector: demo.name,\n resource: table.name,\n source: \"demo\",\n batch: { rows: batch },\n }),\n ),\n ),\n Effect.map((results) => [table.name, sum(results)] as const),\n ),\n );\n\n const setupTables = yield* prepare(demo.setup.tables);\n const groupTables = yield* prepare(demo.group.tables);\n\n const setup = demo.setup.rows(context);\n const afterSetup = add(empty, yield* write(setupTables, (name) => setup[name] ?? []));\n\n const totals =\n afterSetup.bytes >= options.bytes || groupTables.length === 0\n ? afterSetup\n : yield* Stream.range(0, (demo.group.count ?? Infinity) - 1).pipe(\n Stream.grouped(options.groupsPerChunk ?? demo.group.groupsPerChunk ?? 100),\n Stream.mapEffect((indexes) => {\n const groups = indexes.map((index) => demo.group.rows(index, context));\n return write(groupTables, (name) => groups.flatMap((group) => group[name] ?? []));\n }),\n Stream.scan(() => afterSetup, add),\n Stream.takeUntil((current) => current.bytes >= options.bytes),\n Stream.tap((current) =>\n Effect.logInfo(\"demo progress\").pipe(\n Effect.annotateLogs({ rows: current.rows, bytes: current.bytes }),\n ),\n ),\n Stream.runLast,\n Effect.map(Option.getOrElse(() => afterSetup)),\n );\n\n if (totals.bytes < options.bytes) {\n yield* Effect.logWarning(\n \"The selected tables ran out of rows, so the run wrote less than the size asked for\",\n ).pipe(Effect.annotateLogs({ bytes: totals.bytes, target: options.bytes }));\n }\n\n yield* Effect.logInfo(\"demo done\").pipe(\n Effect.annotateLogs({ rows: totals.rows, bytes: totals.bytes, tables: totals.tables }),\n );\n\n return totals;\n});\n","export { type DemoContext } from \"./generate\";\nexport { define, table, type DemoDefinition, type DemoRows, type DemoTable } from \"./definition\";\nexport { run, type DemoTotals, type RunOptions } from \"./run\";\n"],"mappings":"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"}
@@ -1,39 +0,0 @@
1
- import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
2
- import { a as IcebergSchemaError, i as makeCreateTableCommitRequest } from "./table-V0tgUC5i.mjs";
3
- import { Schema } from "effect";
4
- //#region src/iceberg/annotations.ts
5
- /** Sets a field's Iceberg ID, and any other annotations. */
6
- const field = (fieldId, annotations = {}) => (schema) => schema.pipe(Schema.annotateKey({
7
- ...annotations,
8
- fieldId
9
- }));
10
- /** Adds an offset to a base ID for reusable schemas. */
11
- const ids = (baseId) => (offset) => baseId + offset;
12
- /**
13
- * Marks the fields that identify a row. Wings upserts rows by them.
14
- *
15
- * Put it last. A later `.annotate()` keeps the runtime annotation, but the type
16
- * loses the key, so `Resource.entity` stops compiling.
17
- *
18
- * @example
19
- * ```ts
20
- * const Post = Schema.Struct({
21
- * id: Schema.String.pipe(Iceberg.field(1)),
22
- * updatedAt: Schema.String.pipe(Iceberg.field(2)),
23
- * }).pipe(Iceberg.identifier("id"));
24
- * ```
25
- */
26
- const identifier = (...keys) => (schema) => schema.annotate({ icebergIdentifierFields: keys });
27
- //#endregion
28
- //#region src/iceberg/index.ts
29
- var iceberg_exports = /* @__PURE__ */ __exportAll({
30
- IcebergSchemaError: () => IcebergSchemaError,
31
- field: () => field,
32
- identifier: () => identifier,
33
- ids: () => ids,
34
- makeCreateTableCommitRequest: () => makeCreateTableCommitRequest
35
- });
36
- //#endregion
37
- export { ids as i, field as n, identifier as r, iceberg_exports as t };
38
-
39
- //# sourceMappingURL=iceberg-D6L8I6vA.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"iceberg-D6L8I6vA.mjs","names":[],"sources":["../src/iceberg/annotations.ts","../src/iceberg/index.ts"],"sourcesContent":["import { Schema } from \"effect\";\n\ndeclare module \"effect/Schema\" {\n namespace Annotations {\n interface Annotations {\n readonly fieldId?: number | undefined;\n readonly icebergIdentifierFields?: ReadonlyArray<string> | undefined;\n }\n }\n}\n\n/** Sets a field's Iceberg ID, and any other annotations. */\nexport const field =\n <A = unknown>(fieldId: number, annotations: Schema.Annotations.Key<A> = {}) =>\n <S extends Schema.Schema<A>>(schema: S): S[\"Rebuild\"] =>\n schema.pipe(Schema.annotateKey({ ...annotations, fieldId }));\n\n/** Adds an offset to a base ID for reusable schemas. */\nexport const ids =\n (baseId: number) =>\n (offset: number): number =>\n baseId + offset;\n\ntype KnownField<S extends Schema.Top> = keyof S[\"Type\"] & string;\n\n/** A row field that cannot be null or undefined. */\nexport type RequiredField<S extends Schema.Top> = [KnownField<S>] extends [never]\n ? string\n : {\n readonly [Field in KnownField<S>]-?: undefined extends S[\"Type\"][Field]\n ? never\n : null extends S[\"Type\"][Field]\n ? never\n : Field;\n }[KnownField<S>];\n\n/** A row schema whose identifier fields are `Key`. Only the type has it. */\nexport interface Identified<Key extends string> {\n readonly \"~iceberg.identifier\": Key;\n}\n\n/**\n * Marks the fields that identify a row. Wings upserts rows by them.\n *\n * Put it last. A later `.annotate()` keeps the runtime annotation, but the type\n * loses the key, so `Resource.entity` stops compiling.\n *\n * @example\n * ```ts\n * const Post = Schema.Struct({\n * id: Schema.String.pipe(Iceberg.field(1)),\n * updatedAt: Schema.String.pipe(Iceberg.field(2)),\n * }).pipe(Iceberg.identifier(\"id\"));\n * ```\n */\nexport const identifier =\n <S extends Schema.Top, const Key extends RequiredField<S>>(\n ...keys: readonly [Key, ...ReadonlyArray<Key>]\n ) =>\n (schema: S): S[\"Rebuild\"] & Identified<Key> =>\n // Effect has no slot for the key in the schema type, so we add it.\n schema.annotate({ icebergIdentifierFields: keys }) as S[\"Rebuild\"] & Identified<Key>;\n","export { field, identifier, ids } from \"./annotations\";\nexport { IcebergSchemaError } from \"./error\";\nexport { makeCreateTableCommitRequest, type CreateTableCommitOptions } from \"./table\";\n"],"mappings":";;;;;AAYA,MAAa,SACG,SAAiB,cAAyC,CAAC,OAC5C,WAC3B,OAAO,KAAK,OAAO,YAAY;CAAE,GAAG;CAAa;AAAQ,CAAC,CAAC;;AAG/D,MAAa,OACV,YACA,WACC,SAAS;;;;;;;;;;;;;;;AAkCb,MAAa,cAET,GAAG,UAEJ,WAEC,OAAO,SAAS,EAAE,yBAAyB,KAAK,CAAC"}
@@ -1,27 +0,0 @@
1
- import { t as ConnectorError } from "./index-DkVNO6ks.mjs";
2
- import { E as TableSource } from "./types-xZtSmrGA.mjs";
3
- import { a as IngestorService, i as Ingestor, n as IngestResult, r as IngestSource, t as IngestOptions } from "./service-DLkhuxYl.mjs";
4
- import { n as ResolvedTableBindings, t as index_d_exports$1 } from "./index-ygpml2kC.mjs";
5
- import { Layer } from "effect";
6
- import * as Wings from "@useairfoil/wings";
7
- //#region src/ingestor/console.d.ts
8
- /** Logs batches without sending them to Wings. */
9
- declare const layerConsole: Layer.Layer<Ingestor, never, never>;
10
- //#endregion
11
- //#region src/ingestor/wings.d.ts
12
- /** One catalog and an Iceberg table for each resource that runs. */
13
- type WingsIngestorConfig<Source extends TableSource = TableSource> = {
14
- readonly connector: Source;
15
- readonly catalog: string;
16
- readonly tables: ResolvedTableBindings<Source>;
17
- };
18
- /** Loads each table schema and opens one Wings stream per bound resource. */
19
- declare const layerWings: <const Source extends TableSource>(config: WingsIngestorConfig<Source>) => Layer.Layer<Ingestor, ConnectorError, Wings.CatalogManager.CatalogManager>;
20
- /** Reads the Wings URL, catalog and table bindings from hosted config. */
21
- declare const layerWingsConfig: (connector: TableSource) => Layer.Layer<Ingestor, ConnectorError, never>;
22
- declare namespace index_d_exports {
23
- export { IngestOptions, IngestResult, IngestSource, Ingestor, IngestorService, WingsIngestorConfig, layerConsole, layerWings, layerWingsConfig };
24
- }
25
- //#endregion
26
- export { layerConsole as a, layerWingsConfig as i, WingsIngestorConfig as n, layerWings as r, index_d_exports as t };
27
- //# sourceMappingURL=index-CUPP2A_m.d.mts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ingestor-D4L-HPkg.mjs","names":[],"sources":["../src/ingestor/console.ts","../src/ingestor/index.ts"],"sourcesContent":["import { Effect, Layer } from \"effect\";\n\nimport { Ingestor } from \"./service\";\n\n/** Logs batches without sending them to Wings. */\nexport const layerConsole = Layer.succeed(Ingestor)({\n ingest: ({ resource, source, batch }) =>\n Effect.logInfo(`[ingestor] -> Source: ${source} | Resource: ${resource}`).pipe(\n Effect.annotateLogs({ rows: batch.rows.length, cursor: batch.cursor, source }),\n // Nothing is encoded, so there are no bytes to count.\n Effect.as({ rows: batch.rows.length, bytes: 0 }),\n ),\n});\n","export { layerConsole } from \"./console\";\nexport {\n Ingestor,\n type IngestOptions,\n type IngestorService,\n type IngestResult,\n type IngestSource,\n} from \"./service\";\nexport { layerWings, layerWingsConfig, type WingsIngestorConfig } from \"./wings\";\n"],"mappings":";;;;;;AAKA,MAAa,eAAe,MAAM,QAAQ,QAAQ,CAAC,CAAC,EAClD,SAAS,EAAE,UAAU,QAAQ,YAC3B,OAAO,QAAQ,yBAAyB,OAAO,eAAe,UAAU,CAAC,CAAC,KACxE,OAAO,aAAa;CAAE,MAAM,MAAM,KAAK;CAAQ,QAAQ,MAAM;CAAQ;AAAO,CAAC,GAE7E,OAAO,GAAG;CAAE,MAAM,MAAM,KAAK;CAAQ,OAAO;AAAE,CAAC,CACjD,EACJ,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"metrics-BaEX__MN.mjs","names":[],"sources":["../src/telemetry.ts","../src/metrics.ts"],"sourcesContent":["import { Cause, Config, Effect, Layer, Metric, Option, type Duration } from \"effect\";\nimport { Headers } from \"effect/http\";\nimport * as Observability from \"effect/observability\";\n\nimport { PlatformRuntimeKey } from \"./runtime-config/constants\";\n\n/** Canonical span names emitted by connector-kit runtime instrumentation. */\nexport const SpanName = {\n batchProcess: \"connector.batch.process\",\n webhookDecode: \"connector.webhook.decode\",\n webhookHandle: \"connector.webhook.handle\",\n ingest: \"connector.ingest\",\n stateSet: \"connector.state.set\",\n apiFetch: \"connector.api.fetch\",\n} as const;\n\n/** Canonical span attribute names. Keep these stable for collector queries. */\nexport const Attr = {\n connectorName: \"airfoil.connector.name\",\n connectorResourcesCount: \"airfoil.connector.resources.count\",\n resourceName: \"airfoil.resource.name\",\n resourceSource: \"airfoil.resource.source\",\n batchRows: \"airfoil.batch.rows\",\n batchOutcome: \"airfoil.batch.outcome\",\n webhookPath: \"airfoil.webhook.path\",\n webhookOutcome: \"airfoil.webhook.outcome\",\n syncState: \"airfoil.connector.sync.state\",\n apiRetryReason: \"airfoil.connector.api.retry.reason\",\n ingestionSuccess: \"airfoil.ingestion.success\",\n stateKey: \"airfoil.state.key\",\n apiPath: \"airfoil.api.path\",\n errorPhase: \"airfoil.error.phase\",\n errorType: \"airfoil.error.type\",\n errorMessage: \"airfoil.error.message\",\n errorDetails: \"airfoil.error.details\",\n} as const;\n\n/** Resource attributes injected by the hosted operator through standard OTel environment keys. */\nexport const ResourceAttr = {\n serviceInstanceId: \"service.instance.id\",\n connectorRevision: \"airfoil.connector.revision\",\n teamId: \"airfoil.team.id\",\n} as const;\n\n/** Span event names for high-cardinality reproduction details. */\nexport const EventName = {\n batchCheckpoint: \"airfoil.batch.checkpoint\",\n} as const;\n\n/** Event-only attributes. These are intentionally not span attributes. */\nexport const EventAttr = {\n batchCursor: \"airfoil.batch.cursor\",\n} as const;\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === \"object\" && value !== null;\n\nconst maxErrorMessageLength = 500;\n\nconst OtlpEnvConfig = Config.all({\n enabled: Config.Boolean(PlatformRuntimeKey.otelEnabled).pipe(Config.withDefault(false)),\n baseUrl: Config.option(Config.String(PlatformRuntimeKey.otelExporterOtlpEndpoint)),\n rawHeaders: Config.option(Config.String(PlatformRuntimeKey.otelExporterOtlpHeaders)),\n});\n\nconst defaultRedactedHeaders: ReadonlyArray<string | RegExp> = [\n \"authorization\",\n \"cookie\",\n \"set-cookie\",\n \"x-api-key\",\n /api[-_]?key/i,\n /secret/i,\n /signature/i,\n /token/i,\n];\n\nconst parseOtelHeaders = (value: string): Record<string, string> =>\n Object.fromEntries(\n value\n .split(\",\")\n .map((entry) => entry.trim())\n .filter(Boolean)\n .flatMap((entry) => {\n const separator = entry.indexOf(\"=\");\n if (separator < 1) return [];\n return [[entry.slice(0, separator).trim(), entry.slice(separator + 1).trim()]];\n }),\n );\n\nconst appendPath = (baseUrl: string, path: string) =>\n `${baseUrl.replace(/\\/$/, \"\")}/${path.replace(/^\\//, \"\")}`;\n\n/**\n * Best-effort stable error classifier for span metadata.\n *\n * Effect/Data tagged errors expose `_tag`; that is the most useful value for\n * connector bugs (`ConnectorError`, `InvalidWebhookPayloadError`, etc.). For\n * non-tagged errors we fall back to the JS `Error.name`, then constructor name,\n * then the primitive type.\n */\nconst errorType = (error: unknown) => {\n if (isRecord(error) && typeof error._tag === \"string\") {\n return String(error._tag);\n }\n if (error instanceof Error) {\n return error.name;\n }\n if (isRecord(error) && typeof error.constructor?.name === \"string\") {\n return error.constructor.name;\n }\n return typeof error;\n};\n\n/**\n * Human-readable error summary for span metadata.\n *\n * Tagged errors in this package carry a `message` field, so this preserves the\n * important diagnostic text. Unknown object failures are intentionally reduced\n * to their type; full structured error payloads belong in logs, not span attrs.\n */\nconst errorMessage = (error: unknown) => {\n const message = (() => {\n if (isRecord(error) && typeof error.message === \"string\") {\n return error.message;\n }\n if (typeof error === \"string\") {\n return error;\n }\n return errorType(error);\n })();\n\n if (message.length > maxErrorMessageLength) {\n return `${message.slice(0, maxErrorMessageLength)}...`;\n }\n\n return message;\n};\n\nconst errorDetails = (error: unknown): string | undefined => {\n if (!isRecord(error) || error.cause === undefined) return undefined;\n return Cause.pretty(Cause.die(error.cause));\n};\n\n/** Annotates the active span with phase-aware error metadata before re-failing. */\nexport const annotateError = (phase: string, error: unknown) => {\n const details = errorDetails(error);\n return Effect.annotateCurrentSpan({\n [Attr.errorPhase]: phase,\n [Attr.errorType]: errorType(error),\n [Attr.errorMessage]: errorMessage(error),\n ...(details !== undefined ? { [Attr.errorDetails]: details } : {}),\n });\n};\n\n/** Adds an event to the active span, or no-ops when no span is active. */\nexport const addCurrentSpanEvent = (name: string, attributes?: Record<string, unknown>) =>\n Effect.currentSpan.pipe(\n Effect.flatMap((span) =>\n Effect.clockWith((clock) =>\n Effect.sync(() => span.event(name, clock.currentTimeNanosUnsafe(), attributes)),\n ),\n ),\n Effect.ignore,\n );\n\n/** Transport configuration for OTLP trace export. All fields are direct values. */\nexport type OtlpTracingConfig = {\n readonly enabled?: boolean;\n readonly endpoint?: string;\n readonly headers?: Record<string, string>;\n};\n\n/** Runtime options — not config-wrappable since RegExp cannot live in Config. */\nexport type OtlpTracingOptions = {\n /** Additional connector-specific header names or regexes to redact from HTTP logs/traces. */\n readonly redactedHeaders?: ReadonlyArray<string | RegExp>;\n};\n\n/** OTLP metric export settings. */\nexport type OtlpMetricsOptions = {\n readonly exportInterval?: Duration.Input;\n};\n\nconst buildOtlpTracingLayer = (config: OtlpTracingConfig, options: OtlpTracingOptions) =>\n Effect.gen(function* () {\n const allRedacted = [...defaultRedactedHeaders, ...(options.redactedHeaders ?? [])];\n const RedactionLayer = Layer.succeed(Headers.CurrentRedactedNames)(allRedacted);\n\n if (!config.enabled) {\n return RedactionLayer;\n }\n\n if (!config.endpoint) {\n return yield* Effect.fail(new Error(\"enabled=true requires endpoint\"));\n }\n\n yield* Effect.logInfo(\"telemetry enabled\").pipe(\n Effect.annotateLogs({\n endpoint: config.endpoint,\n headers: config.headers ? Object.keys(config.headers) : [],\n }),\n );\n\n return Layer.mergeAll(\n RedactionLayer,\n Observability.OtlpTracer.layer({\n url: appendPath(config.endpoint, \"/v1/traces\"),\n headers: config.headers,\n }).pipe(Layer.provide(Observability.OtlpSerialization.layerJson)),\n );\n });\n\n/**\n * Trace-only OTLP export with sensitive HTTP header redaction.\n * Takes direct config values — no `ConfigProvider` required.\n */\nexport const layer = (config: OtlpTracingConfig = {}, options: OtlpTracingOptions = {}) =>\n Layer.unwrap(buildOtlpTracingLayer(config, options));\n\n/**\n * Trace-only OTLP export with sensitive HTTP header redaction.\n * Takes Effect Config-wrapped values — reads from `ConfigProvider`.\n *\n * @example\n * Telemetry.layerConfig({\n * enabled: Config.Boolean(\"MY_OTEL_ENABLED\"),\n * endpoint: Config.String(\"MY_COLLECTOR_URL\"),\n * })\n */\nexport const layerConfig = (\n config: Config.Wrap<OtlpTracingConfig>,\n options: OtlpTracingOptions = {},\n) =>\n Layer.unwrap(\n Effect.gen(function* () {\n const resolved = yield* Config.unwrap(config);\n return yield* buildOtlpTracingLayer(resolved, options);\n }),\n );\n\n/**\n * Trace-only OTLP export with sensitive HTTP header redaction.\n * Zero-config shortcut that reads the standard `OTEL_*` env var names.\n *\n * Reads `OTEL_ENABLED`, `OTEL_EXPORTER_OTLP_ENDPOINT`, and\n * `OTEL_EXPORTER_OTLP_HEADERS`. Effect's OTLP resource handling reads\n * `OTEL_SERVICE_NAME`, `OTEL_SERVICE_VERSION`, and `OTEL_RESOURCE_ATTRIBUTES`.\n */\nexport const layerOtlpTracing = (options: OtlpTracingOptions = {}) =>\n Layer.unwrap(\n Effect.gen(function* () {\n const raw = yield* OtlpEnvConfig;\n return yield* buildOtlpTracingLayer(\n {\n enabled: raw.enabled,\n endpoint: Option.getOrUndefined(raw.baseUrl),\n headers: Option.isSome(raw.rawHeaders)\n ? parseOtelHeaders(raw.rawHeaders.value)\n : undefined,\n },\n options,\n );\n }),\n );\n\n/** Exports connector metrics over OTLP when telemetry is enabled. */\nexport const layerOtlpMetrics = (options: OtlpMetricsOptions = {}) =>\n Layer.unwrap(\n Effect.gen(function* () {\n const raw = yield* OtlpEnvConfig;\n if (!raw.enabled) return Layer.empty;\n const endpoint = Option.getOrUndefined(raw.baseUrl);\n if (!endpoint)\n return yield* Effect.fail(\n new Error(\"OTEL_ENABLED=true requires OTEL_EXPORTER_OTLP_ENDPOINT\"),\n );\n return Observability.OtlpMetrics.layer({\n url: appendPath(endpoint, \"/v1/metrics\"),\n headers: Option.isSome(raw.rawHeaders) ? parseOtelHeaders(raw.rawHeaders.value) : undefined,\n exportInterval: options.exportInterval,\n temporality: \"cumulative\",\n }).pipe(Layer.provide(Observability.OtlpSerialization.layerJson));\n }),\n );\n\n/** Enables OTLP traces and metrics with shared environment configuration. */\nexport const layerOtlp = (options: OtlpTracingOptions & OtlpMetricsOptions = {}) =>\n Layer.mergeAll(layerOtlpTracing(options), layerOtlpMetrics(options));\n\n/** Periodically logs the in-memory metric snapshot for local debugging. */\nexport const layerMetricsConsoleDump = (interval: Duration.Input = \"30 seconds\") =>\n Layer.effectDiscard(\n Effect.gen(function* () {\n yield* Effect.forkScoped(\n Effect.forever(\n Metric.dump.pipe(\n Effect.flatMap((snapshot) => Effect.logInfo(snapshot)),\n Effect.andThen(Effect.sleep(interval)),\n ),\n ),\n );\n }),\n );\n","import {\n Cause,\n DateTime,\n type Duration,\n Effect,\n Metric,\n Option,\n Predicate,\n Schedule,\n} from \"effect\";\nimport { HttpClientError, HttpClientResponse } from \"effect/http\";\n\nimport type { SyncState } from \"./core/types\";\n\nimport { Attr } from \"./telemetry\";\n\nexport type BatchSource = \"backfill\" | \"changes\" | \"webhook\" | \"demo\";\nexport type BatchOutcome = \"success\" | \"error\";\nexport type ApiRetryReason = \"transport\" | \"timeout\" | \"rate_limit\" | \"server_error\";\nexport type WebhookOutcome =\n | \"ok\"\n | \"read_error\"\n | \"invalid_json\"\n | \"invalid_payload\"\n | \"rejected\"\n | \"handler_error\";\n\nexport type ResourceMetricAttrs = {\n readonly connector: string;\n readonly resource: string;\n readonly source: BatchSource;\n};\n\nexport type WebhookMetricAttrs = {\n readonly connector: string;\n readonly path: string;\n readonly outcome: WebhookOutcome;\n};\n\nexport type SyncStateAttrs = {\n readonly connector: string;\n readonly resource: string;\n};\n\nexport type LastSuccessMetricAttrs = {\n readonly connector: string;\n readonly resource: string;\n readonly source: \"backfill\" | \"changes\";\n};\n\nexport type ApiRetryMetricAttrs = {\n readonly connector: string;\n readonly reason: ApiRetryReason;\n};\n\nexport const batches = Metric.counter(\"airfoil.connector.batches\", {\n description: \"Total resource batches ingested by connector sources\",\n incremental: true,\n attributes: { unit: \"{batch}\" },\n});\n\nexport const rowsIngested = Metric.counter(\"airfoil.connector.rows.ingested\", {\n description: \"Total resource rows successfully ingested\",\n incremental: true,\n attributes: { unit: \"{row}\" },\n});\n\nexport const batchSize = Metric.histogram(\"airfoil.connector.batch.size\", {\n description: \"Distribution of resource row batch sizes\",\n boundaries: [1, 5, 10, 25, 50, 100, 250, 500, 1000],\n attributes: { unit: \"{row}\" },\n});\n\nexport const ingestDuration = Metric.timer(\"airfoil.connector.ingest.duration\", {\n description: \"Ingestor call duration in milliseconds\",\n boundaries: [1, 5, 10, 25, 50, 100, 250, 500, 1000, 2500, 5000, 10000],\n attributes: { unit: \"ms\" },\n});\n\nexport const webhookRequests = Metric.counter(\"airfoil.connector.webhook.requests\", {\n description: \"Total webhook HTTP requests handled by connector routes\",\n incremental: true,\n attributes: { unit: \"{request}\" },\n});\n\nexport const webhookQueueDepth = Metric.gauge(\"airfoil.connector.webhook.queue.depth\", {\n description: \"Current queued webhook batches waiting for ingestion\",\n attributes: { unit: \"{batch}\" },\n});\n\nexport const syncState = Metric.gauge(\"airfoil.connector.sync.state\", {\n description: \"Connector resource sync state as a Prometheus state-set gauge\",\n attributes: { unit: \"1\" },\n});\n\nexport const lastSuccessTimestamp = Metric.gauge(\"airfoil.connector.last_success.timestamp\", {\n description: \"Unix timestamp of the last successful durable source checkpoint\",\n attributes: { unit: \"s\" },\n});\n\nexport const apiRetries = Metric.counter(\"airfoil.connector.api.retries\", {\n description: \"Total provider API retries performed by the connector\",\n incremental: true,\n attributes: { unit: \"{retry}\" },\n});\n\nconst resourceAttributes = (attrs: ResourceMetricAttrs) => ({\n [Attr.connectorName]: attrs.connector,\n [Attr.resourceName]: attrs.resource,\n [Attr.resourceSource]: attrs.source,\n});\n\nconst syncAttributes = (attrs: SyncStateAttrs) => ({\n [Attr.connectorName]: attrs.connector,\n [Attr.resourceName]: attrs.resource,\n});\n\nexport const recordWebhookRequest = (attrs: WebhookMetricAttrs) =>\n Metric.update(\n Metric.withAttributes(webhookRequests, {\n [Attr.connectorName]: attrs.connector,\n [Attr.webhookPath]: attrs.path,\n [Attr.webhookOutcome]: attrs.outcome,\n }),\n 1,\n );\n\nexport const setWebhookQueueDepth = (connector: string, depth: number) =>\n Metric.update(\n Metric.withAttributes(webhookQueueDepth, { [Attr.connectorName]: connector }),\n depth,\n );\n\nexport const setLastSuccessTimestamp = (attrs: LastSuccessMetricAttrs, lastSuccessAt?: string) => {\n const timestamp =\n lastSuccessAt === undefined\n ? 0\n : DateTime.make(lastSuccessAt).pipe(\n Option.map((dateTime) => DateTime.toEpochMillis(dateTime) / 1000),\n Option.getOrElse(() => 0),\n );\n return Metric.update(\n Metric.withAttributes(lastSuccessTimestamp, {\n [Attr.connectorName]: attrs.connector,\n [Attr.resourceName]: attrs.resource,\n [Attr.resourceSource]: attrs.source,\n }),\n timestamp,\n );\n};\n\nexport const recordApiRetry = (attrs: ApiRetryMetricAttrs) =>\n Metric.update(\n Metric.withAttributes(apiRetries, {\n [Attr.connectorName]: attrs.connector,\n [Attr.apiRetryReason]: attrs.reason,\n }),\n 1,\n );\n\n// Same statuses as `HttpClient.retryTransient`.\nconst transientStatuses = new Set([408, 429, 500, 502, 503, 504]);\n\n// A connector only retries a `403` when the provider uses it for rate limits.\nconst reasonForStatus = (status: number): ApiRetryReason =>\n status === 408 ? \"timeout\" : status === 429 || status === 403 ? \"rate_limit\" : \"server_error\";\n\n// Effect exports the response type ID, not a guard.\nconst isResponse = (value: unknown): value is HttpClientResponse.HttpClientResponse =>\n Predicate.hasProperty(value, HttpClientResponse.TypeId);\n\n/** Why `HttpClient.retryTransient` retries. Undefined for a response it keeps. */\nconst retryReason = (value: unknown): ApiRetryReason | undefined => {\n if (isResponse(value)) {\n return transientStatuses.has(value.status) ? reasonForStatus(value.status) : undefined;\n }\n if (HttpClientError.isHttpClientError(value) && value.reason._tag === \"StatusCodeError\") {\n return reasonForStatus(value.reason.response.status);\n }\n return Cause.isTimeoutError(value) ? \"timeout\" : \"transport\";\n};\n\n/**\n * A jittered exponential schedule for `HttpClient.retryTransient` that records\n * each retry with its reason.\n */\nexport const retrySchedule = (options: {\n readonly connector: string;\n readonly baseDelay: Duration.Input;\n readonly times: number;\n}) =>\n Schedule.exponential(options.baseDelay).pipe(\n Schedule.jittered,\n Schedule.upTo({ times: options.times }),\n Schedule.tap(({ input }) => {\n const reason = retryReason(input);\n return reason === undefined\n ? Effect.void\n : recordApiRetry({ connector: options.connector, reason });\n }),\n );\n\nconst syncStates = [\"pending\", \"backfilling\", \"live\", \"error\"] as const;\n\nexport const setSyncState = (attrs: SyncStateAttrs, current: SyncState) =>\n Effect.forEach(\n syncStates,\n (state) =>\n Metric.update(\n Metric.withAttributes(syncState, {\n ...syncAttributes(attrs),\n [Attr.syncState]: state,\n }),\n state === current ? 1 : 0,\n ),\n { discard: true },\n );\n\n/** @internal Converts the ergonomic SDK input to canonical OTel attributes. */\nexport const withResourceAttributes = resourceAttributes;\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"runtime-config-Oa55gAew.mjs","names":[],"sources":["../src/runtime-config/config.ts","../src/runtime-config/error.ts","../src/runtime-config/layer.ts","../src/runtime-config/table-bindings.ts","../src/runtime-config/index.ts"],"sourcesContent":["import { Config } from \"effect\";\n\nimport { PlatformRuntimeDefault, PlatformRuntimeKey } from \"./constants\";\n\n/** Shared HTTP port used by hosted and sandbox connector entrypoints. */\nexport const httpPort = Config.Port(PlatformRuntimeKey.httpPort).pipe(\n Config.withDefault(PlatformRuntimeDefault.httpPort),\n);\n\n/** Wings URL, including the protocol. */\nexport const wingsUri = Config.URL(PlatformRuntimeKey.wingsUri);\n\n/** Wings catalog ID. */\nexport const catalog = Config.NonEmptyString(PlatformRuntimeKey.catalog);\n","import { Data } from \"effect\";\n\nexport type RuntimeConfigErrorCode =\n | \"CONFIG_PATH_MISSING\"\n | \"CONFIG_FILE_UNREADABLE\"\n | \"CONFIG_JSON_INVALID\"\n | \"TABLE_BINDINGS_MISSING\"\n | \"TABLE_BINDINGS_INVALID\"\n | \"TABLE_BINDINGS_MISMATCH\";\n\n/** Expected hosted-config failure with a stable code and diagnostic cause. */\nexport class RuntimeConfigError extends Data.TaggedError(\"RuntimeConfigError\")<{\n readonly code: RuntimeConfigErrorCode;\n readonly message: string;\n readonly cause: Error;\n}> {}\n","import { Config, ConfigProvider, Effect, FileSystem, Schema } from \"effect\";\n\nimport { PlatformRuntimeKey } from \"./constants\";\nimport { RuntimeConfigError } from \"./error\";\n\nconst providerFromFile: Effect.Effect<\n ConfigProvider.ConfigProvider,\n RuntimeConfigError,\n FileSystem.FileSystem\n> = Effect.gen(function* () {\n const configPath = yield* Config.NonEmptyString(PlatformRuntimeKey.configPath).pipe(\n Effect.mapError(\n (error) =>\n new RuntimeConfigError({\n code: \"CONFIG_PATH_MISSING\",\n message: `${PlatformRuntimeKey.configPath} is required in hosted mode`,\n cause: error.cause,\n }),\n ),\n );\n const fileSystem = yield* FileSystem.FileSystem;\n const contents = yield* fileSystem.readFileString(configPath).pipe(\n Effect.mapError(\n (cause) =>\n new RuntimeConfigError({\n code: \"CONFIG_FILE_UNREADABLE\",\n message: \"Connector config file could not be read\",\n cause,\n }),\n ),\n );\n const document = yield* Schema.decodeUnknownEffect(Schema.fromJsonString(Schema.Unknown))(\n contents,\n ).pipe(\n Effect.mapError(\n (error) =>\n new RuntimeConfigError({\n code: \"CONFIG_JSON_INVALID\",\n message: \"Connector config is not valid JSON\",\n cause: error,\n }),\n ),\n );\n return ConfigProvider.fromUnknown(document, { preserveEmptyStrings: true });\n});\n\n/**\n * Loads the required JSON file and lets environment values override it per key.\n * Connector field validation remains in the connector's Effect Config.\n *\n * @example\n * ```ts\n * program.pipe(Effect.provide(layerHosted()));\n * ```\n */\nexport const layerHosted = () => ConfigProvider.layerAdd(providerFromFile);\n","import type { TableIdentifier } from \"iceberg-js\";\n\nimport { Config, Effect, Schema } from \"effect\";\n\nimport type { TableSource } from \"../core/types\";\n\nimport { PlatformRuntimeKey } from \"./constants\";\nimport { RuntimeConfigError } from \"./error\";\n\n/** An Iceberg table and its storage location for each connector resource. */\nexport type TableBinding = TableIdentifier & { readonly location?: string | undefined };\n\nexport type ResolvedTableBindings<Source extends TableSource> = Readonly<\n Partial<Record<Source[\"resources\"][number][\"name\"], TableBinding>>\n>;\n\nconst TableIdentifierSchema = Schema.Struct({\n namespace: Schema.NonEmptyArray(Schema.NonEmptyString),\n name: Schema.NonEmptyString,\n location: Schema.optional(Schema.NonEmptyString),\n});\n\nconst RawBindingsSchema = Schema.fromJsonString(\n Schema.Record(Schema.String, TableIdentifierSchema),\n);\n\nconst asError = (cause: unknown): Error =>\n cause instanceof Error ? cause : new Error(String(cause));\n\nconst fail = (code: \"TABLE_BINDINGS_INVALID\" | \"TABLE_BINDINGS_MISMATCH\", message: string) =>\n new RuntimeConfigError({ code, message, cause: new Error(message) });\n\n/** Reads hosted table bindings and checks they name resources of the connector. */\nexport const loadTableBindings = <const Source extends TableSource>(\n connector: Source,\n): Effect.Effect<ResolvedTableBindings<Source>, RuntimeConfigError> =>\n Effect.gen(function* () {\n const raw = yield* Config.NonEmptyString(PlatformRuntimeKey.tableBindings).pipe(\n Effect.mapError(\n (cause) =>\n new RuntimeConfigError({\n code: \"TABLE_BINDINGS_MISSING\",\n message: `${PlatformRuntimeKey.tableBindings} is required in hosted mode`,\n cause: asError(cause),\n }),\n ),\n );\n\n const decoded = yield* Schema.decodeUnknownEffect(RawBindingsSchema)(raw, {\n onExcessProperty: \"error\",\n }).pipe(\n Effect.mapError(\n (cause) =>\n new RuntimeConfigError({\n code: \"TABLE_BINDINGS_INVALID\",\n message: \"Hosted table bindings are invalid\",\n cause: asError(cause),\n }),\n ),\n );\n\n const actual = Object.keys(decoded);\n if (actual.length === 0) {\n return yield* Effect.fail(\n fail(\"TABLE_BINDINGS_INVALID\", \"Hosted table bindings name no resources\"),\n );\n }\n\n // Bindings come from the platform, resources from the connector. An unknown name\n // means one of them is out of date, and we could write to the wrong table.\n const expected = new Set(connector.resources.map((resource) => resource.name));\n const unknown = actual.filter((name) => !expected.has(name));\n if (unknown.length > 0) {\n return yield* Effect.fail(\n fail(\n \"TABLE_BINDINGS_MISMATCH\",\n `Hosted table bindings name resources the connector doesn't have (${unknown.length})`,\n ),\n );\n }\n\n return Object.fromEntries(\n Object.entries(decoded).map(([resource, identifier]) => [\n resource,\n {\n namespace: Array.from(identifier.namespace),\n name: identifier.name,\n ...(identifier.location === undefined ? {} : { location: identifier.location }),\n },\n ]),\n ) as ResolvedTableBindings<Source>;\n });\n","export { RuntimeConfigError, type RuntimeConfigErrorCode } from \"./error\";\nexport { catalog, httpPort, wingsUri } from \"./config\";\nexport { PlatformRuntimeDefault, PlatformRuntimeKey } from \"./constants\";\nexport { layerHosted } from \"./layer\";\nexport { type ResolvedTableBindings, type TableBinding, loadTableBindings } from \"./table-bindings\";\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"table-V0tgUC5i.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 CommitTableRequest,\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 CreateTableCommitOptions = {\n /** Where the table's files go. The catalog may choose this when omitted. */\n readonly location?: string | undefined;\n /** UUID for the table. Random by default. */\n readonly uuid?: 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\n// Iceberg reserves its highest 200 field IDs.\nconst maxFieldId = 2_147_483_447;\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 readonly #fieldIds = new Map<number, string>();\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 #readId(annotations: Annotations | undefined, path: string, source: string): number {\n const id = annotations?.fieldId;\n\n if (typeof id !== \"number\") {\n return fail(path, `Missing fieldId; add it with ${source}`);\n }\n if (!Number.isInteger(id)) return fail(path, \"fieldId must be a whole number\");\n if (id < 1 || id > maxFieldId) {\n return fail(path, `fieldId must be between 1 and ${maxFieldId}`);\n }\n const previousPath = this.#fieldIds.get(id);\n if (previousPath !== undefined) {\n return fail(path, `fieldId ${id} is already used at ${previousPath}`);\n }\n\n this.#fieldIds.set(id, path);\n return id;\n }\n\n #readNodeId(representation: Representation, path: string): number {\n return this.#withReference(representation, path, (resolved) =>\n this.#readId(\n resolveAnnotations(resolved),\n path,\n \".annotate({ fieldId }) on the schema itself\",\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.#readId(property.annotations, fieldPath, \"Iceberg.field(id)\");\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.#readNodeId(elementRepresentation, elementPath);\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.#readNodeId(keyRepresentation, keyPath);\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.#readNodeId(valueRepresentation, valuePath);\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 makeCommitRequest = (\n table: CompiledTable,\n options: CreateTableCommitOptions,\n): CommitTableRequest => {\n const properties = {\n ...(table.description === undefined ? {} : { comment: table.description }),\n ...options.properties,\n };\n\n return {\n requirements: [{ type: \"assert-create\" }],\n updates: [\n { action: \"assign-uuid\", uuid: options.uuid ?? crypto.randomUUID() },\n { action: \"upgrade-format-version\", \"format-version\": 2 },\n { action: \"add-schema\", schema: table.schema },\n { action: \"set-current-schema\", \"schema-id\": -1 },\n { action: \"add-spec\", spec: { \"spec-id\": 0, fields: [] } },\n { action: \"set-default-spec\", \"spec-id\": -1 },\n { action: \"add-sort-order\", \"sort-order\": { \"order-id\": 0, fields: [] } },\n { action: \"set-default-sort-order\", \"sort-order-id\": -1 },\n ...(options.location === undefined\n ? []\n : [{ action: \"set-location\" as const, location: options.location }]),\n ...(Object.keys(properties).length === 0\n ? []\n : [{ action: \"set-properties\" as const, updates: properties }]),\n ],\n };\n};\n\n/**\n * Builds the commit that creates an Iceberg table from an Effect schema.\n *\n * The field IDs come from the schema, so the table has to keep them. Send the\n * commit with `commitTable`. Then load the table and check the IDs before you\n * write any rows. Don't use `createTable` here, because it can change the 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(Iceberg.field(1, { description: \"Stable row identifier\" })),\n * })\n * .annotate({ description: \"Connector rows\" })\n * .pipe(Iceberg.identifier(\"id\"))\n *\n * const request = yield* Iceberg.makeCreateTableCommitRequest(Row, {\n * location: \"s3://warehouse/rows\"\n * })\n * ```\n */\nexport const makeCreateTableCommitRequest = (\n schema: Schema.Top,\n options: CreateTableCommitOptions,\n): Effect.Effect<CommitTableRequest, IcebergSchemaError> =>\n Effect.map(compileTable(schema), (table) => makeCommitRequest(table, options));\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"wings-I56hGtNv.mjs","names":["Struct","ArrowSchema","RuntimeConfig.catalog","RuntimeConfig.wingsUri","RuntimeConfig.loadTableBindings"],"sources":["../src/catalog/table.ts","../src/ingestor/arrow.ts","../src/ingestor/wings.ts"],"sourcesContent":["import type {\n IcebergType,\n StructField,\n TableIdentifier,\n TableMetadata,\n TableSchema,\n} from \"iceberg-js\";\n\nimport * as Wings from \"@useairfoil/wings\";\nimport { Effect, type Schema } from \"effect\";\nimport { HttpClient } from \"effect/http\";\nimport { getCurrentSchema } from \"iceberg-js\";\n\nimport { ConnectorError } from \"../errors\";\nimport { IcebergSchemaError } from \"../iceberg/error\";\nimport { compileTable, makeCommitRequest } from \"../iceberg/table\";\n\ntype Catalog = Effect.Success<\n ReturnType<Wings.CatalogManager.CatalogManagerService[\"getIcebergCatalog\"]>\n>;\n\ntype TableOptions = {\n readonly catalog: Catalog;\n readonly identifier: TableIdentifier;\n readonly location?: string | undefined;\n};\n\ntype WingsTableOptions = {\n readonly wingsUri: string;\n readonly catalogId: string;\n readonly identifier: TableIdentifier;\n readonly location?: string | undefined;\n};\n\nconst tableError = (cause: unknown): ConnectorError => {\n if (cause instanceof ConnectorError) return cause;\n\n const message = cause instanceof Error ? cause.message : \"Failed to prepare Iceberg table\";\n return new ConnectorError({\n message: cause instanceof IcebergSchemaError ? `${cause.path}: ${message}` : message,\n cause,\n });\n};\n\nconst compareTypes = (\n expected: IcebergType,\n actual: IcebergType,\n path: string,\n): string | undefined => {\n if (typeof expected === \"string\" || typeof actual === \"string\") {\n return expected === actual ? undefined : path;\n }\n\n if (expected.type !== actual.type) return path;\n\n switch (expected.type) {\n case \"struct\":\n if (actual.type !== \"struct\") return path;\n return compareFields(expected.fields, actual.fields, path);\n case \"list\":\n if (\n actual.type !== \"list\" ||\n expected[\"element-id\"] !== actual[\"element-id\"] ||\n expected[\"element-required\"] !== actual[\"element-required\"]\n ) {\n return path;\n }\n return compareTypes(expected.element, actual.element, `${path}.element`);\n case \"map\":\n if (\n actual.type !== \"map\" ||\n expected[\"key-id\"] !== actual[\"key-id\"] ||\n expected[\"value-id\"] !== actual[\"value-id\"] ||\n expected[\"value-required\"] !== actual[\"value-required\"]\n ) {\n return path;\n }\n return (\n compareTypes(expected.key, actual.key, `${path}.key`) ??\n compareTypes(expected.value, actual.value, `${path}.value`)\n );\n }\n};\n\nconst compareFields = (\n expected: ReadonlyArray<StructField>,\n actual: ReadonlyArray<StructField>,\n path: string,\n): string | undefined => {\n if (expected.length !== actual.length) return path;\n\n for (const field of expected) {\n const fieldPath = `${path}.${field.name}`;\n const other = actual.find((candidate) => candidate.name === field.name);\n\n if (!other || field.id !== other.id || field.required !== other.required) return fieldPath;\n\n const mismatch = compareTypes(field.type, other.type, fieldPath);\n if (mismatch) return mismatch;\n }\n};\n\nconst verifyTable = (\n metadata: TableMetadata,\n expected: TableSchema,\n): Effect.Effect<TableSchema, ConnectorError> =>\n Effect.try({\n try: () => {\n if (!Array.isArray(metadata.schemas)) throw new Error(\"Invalid table metadata\");\n const actual = getCurrentSchema(metadata);\n if (!actual) throw new Error(\"Table has no current schema\");\n\n const path = compareFields(expected.fields, actual.fields, \"$\");\n if (path) {\n throw new Error(\n `Table schema does not match at ${path}. Migrate the table or revert the schema change.`,\n );\n }\n\n const expectedIds = new Set(expected[\"identifier-field-ids\"]);\n const actualIds = new Set(actual[\"identifier-field-ids\"]);\n if (\n expectedIds.size !== actualIds.size ||\n [...expectedIds].some((id) => !actualIds.has(id))\n ) {\n throw new Error(\n \"Table identifier fields do not match. Recreate the table or revert the schema change.\",\n );\n }\n\n return actual;\n },\n catch: (cause) =>\n new ConnectorError({\n message: cause instanceof Error ? cause.message : \"Invalid table metadata\",\n cause,\n }),\n });\n\n/** Creates a table with the IDs from its Effect schema, then checks the loaded schema. */\nexport const createTable = (\n schema: Schema.Top,\n options: TableOptions,\n): Effect.Effect<TableSchema, ConnectorError> =>\n Effect.gen(function* () {\n const table = yield* compileTable(schema);\n yield* options.catalog.commitTable(\n options.identifier,\n makeCommitRequest(table, { location: options.location }),\n );\n\n const metadata = yield* options.catalog.loadTable(options.identifier);\n return yield* verifyTable(metadata, table.schema);\n }).pipe(Effect.mapError(tableError));\n\n/** Creates a table through a Wings catalog. */\nexport const createTableFromWings = (\n schema: Schema.Top,\n options: WingsTableOptions,\n): Effect.Effect<TableSchema, ConnectorError, HttpClient.HttpClient> =>\n Effect.scoped(\n Effect.gen(function* () {\n const manager = yield* Wings.CatalogManager.make({ baseUrl: options.wingsUri });\n const catalog = yield* manager.getIcebergCatalog(options.catalogId);\n return yield* createTable(schema, {\n catalog,\n identifier: options.identifier,\n location: options.location,\n });\n }),\n ).pipe(Effect.mapError(tableError));\n\n/** Loads a table, creating it when it is missing. */\nexport const ensureTable = (\n schema: Schema.Top,\n options: TableOptions,\n): Effect.Effect<TableSchema, ConnectorError> =>\n Effect.gen(function* () {\n const table = yield* compileTable(schema);\n const metadata = yield* options.catalog.loadTable(options.identifier).pipe(\n Effect.catchIf(\n (error) => error.status === 404,\n () =>\n options.catalog\n .commitTable(\n options.identifier,\n makeCommitRequest(table, { location: options.location }),\n )\n .pipe(\n // Another instance may have created the table. Reload and check it.\n Effect.catchIf(\n (error) => error.status === 409 || error.status === 412,\n () => Effect.void,\n ),\n Effect.flatMap(() => options.catalog.loadTable(options.identifier)),\n ),\n ),\n );\n\n return yield* verifyTable(metadata, table.schema);\n }).pipe(Effect.mapError(tableError));\n","import {\n Bool,\n DateDay,\n Decimal,\n Field,\n FixedSizeBinary,\n Float32,\n Float64,\n Int32,\n Int64,\n LargeBinary,\n List,\n Map_,\n RecordBatch,\n Schema as ArrowSchema,\n Struct,\n TimeMicrosecond,\n TimestampMicrosecond,\n Utf8,\n makeBuilder,\n type DataType,\n type TypeMap,\n} from \"apache-arrow\";\nimport { Effect, Schema } from \"effect\";\nimport {\n parseDecimalType,\n parseFixedType,\n type IcebergType,\n type PrimitiveType,\n type TableSchema,\n} from \"iceberg-js\";\n\nimport { ConnectorError } from \"../errors\";\n\n// Nothing converts an Iceberg schema to Arrow for us, so we do it here.\n// Each type also gets a schema for its values, because Arrow does not reject a bad\n// value, it converts it: \"1\" becomes 1, and 1.5 becomes 1.\n\ntype RowSchema = Schema.Codec<unknown, unknown>;\n\n/** One Iceberg type: the Arrow type, and the values it accepts. */\ntype Compiled = {\n readonly type: DataType;\n readonly row: RowSchema;\n};\n\n// Arrow pads or cuts binary values to fit.\nconst bytes = (length: number) =>\n Schema.Uint8Array.check(\n Schema.makeFilter(\n (value: Uint8Array) => value.byteLength === length || `expected ${length} bytes`,\n ),\n );\n\n// Arrow wraps big integers instead of failing, so check the range.\nconst int32 = Schema.Number.check(\n Schema.isInt(),\n Schema.isBetween({ minimum: -2_147_483_648, maximum: 2_147_483_647 }),\n);\n\nconst int64 = Schema.BigInt.check(\n Schema.isBetweenBigInt({ minimum: -(2n ** 63n), maximum: 2n ** 63n - 1n }),\n);\n\n// Arrow turns a number outside the 32-bit range into Infinity.\nconst float32 = Schema.Finite.check(\n Schema.makeFilter(\n (value: number) => Number.isFinite(Math.fround(value)) || \"expected a 32-bit number\",\n ),\n);\n\nconst microsecondsInDay = Schema.BigInt.check(\n Schema.isBetweenBigInt({ minimum: 0n, maximum: 86_399_999_999n }),\n);\n\nconst primitives: Record<string, Compiled> = {\n boolean: { type: new Bool(), row: Schema.Boolean },\n int: { type: new Int32(), row: int32 },\n long: { type: new Int64(), row: int64 },\n float: { type: new Float32(), row: float32 },\n double: { type: new Float64(), row: Schema.Finite },\n string: { type: new Utf8(), row: Schema.String },\n uuid: { type: new FixedSizeBinary(16), row: bytes(16) },\n binary: { type: new LargeBinary(), row: Schema.Uint8Array },\n date: { type: new DateDay(), row: Schema.Date },\n time: { type: new TimeMicrosecond(), row: microsecondsInDay },\n timestamp: { type: new TimestampMicrosecond(), row: Schema.Date },\n timestamptz: { type: new TimestampMicrosecond(\"UTC\"), row: Schema.Date },\n};\n\nconst primitive = (type: PrimitiveType): Compiled => {\n const known = primitives[type];\n\n if (known) return known;\n\n // Nothing checks the catalog metadata, and Arrow takes any precision.\n // Better to fail here than at write time.\n const decimal = parseDecimalType(type);\n\n if (decimal) {\n if (decimal.precision < 1 || decimal.precision > 38 || decimal.scale > decimal.precision) {\n throw new Error(`Invalid Iceberg decimal type ${type}`);\n }\n\n return {\n type: new Decimal(decimal.scale, decimal.precision),\n row: Schema.instanceOf(Uint32Array).check(\n Schema.makeFilter((value: Uint32Array) => value.length === 4 || \"expected four words\"),\n ),\n };\n }\n\n const fixed = parseFixedType(type);\n\n if (fixed) {\n if (fixed.length < 1) throw new Error(`Invalid Iceberg fixed type ${type}`);\n\n return { type: new FixedSizeBinary(fixed.length), row: bytes(fixed.length) };\n }\n\n throw new Error(`Unsupported Iceberg type ${type}`);\n};\n\n/** Absent and null both become null in Arrow. */\nconst optional = (row: RowSchema) => Schema.optional(Schema.NullOr(row));\n\nconst fieldMetadata = (id: number): Map<string, string> =>\n new Map([[\"PARQUET:field_id\", String(id)]]);\n\n/** Same as `primitive`, plus struct, list and map. */\nconst compileType = (type: IcebergType): Compiled => {\n if (typeof type === \"string\") return primitive(type);\n\n if (type.type === \"struct\") {\n const fields = type.fields.map((field) => ({ ...field, compiled: compileType(field.type) }));\n\n return {\n type: new Struct(\n fields.map(\n (field) =>\n new Field(field.name, field.compiled.type, !field.required, fieldMetadata(field.id)),\n ),\n ),\n row: Schema.Struct(\n Object.fromEntries(\n fields.map((field) => [\n field.name,\n field.required ? field.compiled.row : optional(field.compiled.row),\n ]),\n ),\n ),\n };\n }\n\n if (type.type === \"list\") {\n const element = compileType(type.element);\n const required = type[\"element-required\"];\n\n return {\n type: new List(\n new Field(\"element\", element.type, !required, fieldMetadata(type[\"element-id\"])),\n ),\n row: Schema.Array(required ? element.row : Schema.NullishOr(element.row)),\n };\n }\n\n const key = compileType(type.key);\n const value = compileType(type.value);\n const required = type[\"value-required\"];\n const entries = new Struct([\n new Field(\"key\", key.type, false, fieldMetadata(type[\"key-id\"])),\n new Field(\"value\", value.type, !required, fieldMetadata(type[\"value-id\"])),\n ]);\n\n return {\n type: new Map_(new Field(\"entries\", entries, false)),\n row: Schema.ReadonlyMap(key.row, required ? value.row : Schema.NullishOr(value.row)),\n };\n};\n\nexport type RowEncoder = (\n rows: ReadonlyArray<object>,\n) => Effect.Effect<RecordBatch<TypeMap>, ConnectorError>;\n\nexport const makeRowEncoder = (\n tableSchema: TableSchema,\n version: string,\n): Effect.Effect<RowEncoder, ConnectorError> =>\n Effect.try({\n try: () => {\n const fields = tableSchema.fields.map((field) => ({\n id: field.id,\n name: field.name,\n ...compileType(field.type),\n }));\n const fieldNames = new Set(fields.map((field) => field.name));\n const identifierIds = new Set(tableSchema[\"identifier-field-ids\"]);\n const keys = tableSchema.fields\n .filter((field) => identifierIds.has(field.id))\n .map((field) => field.name);\n // Other columns may be missing: a delete only sends the key and version.\n const required = new Set([...keys, version]);\n\n if (!fieldNames.has(version)) throw new Error(`Missing version column ${version}`);\n\n const struct = new Struct(\n fields.map((field) => new Field(field.name, field.type, true, fieldMetadata(field.id))),\n );\n const schema = new ArrowSchema(struct.children);\n\n const decodeRow = Schema.decodeUnknownSync(\n Schema.Struct(\n Object.fromEntries(\n fields.map((field) => [\n field.name,\n required.has(field.name) ? field.row : optional(field.row),\n ]),\n ),\n ),\n { onExcessProperty: \"error\" },\n );\n\n // Schema says which field is wrong. This adds the row number.\n const decodeAt = (row: object, index: number) => {\n try {\n return decodeRow(row) as Record<string, unknown>;\n } catch (cause) {\n const detail = cause instanceof Error ? cause.message : String(cause);\n throw new Error(`row ${index}: ${detail}`, { cause });\n }\n };\n\n return (rows: ReadonlyArray<object>) =>\n Effect.try({\n try: () => {\n const builder = makeBuilder({ type: struct, nullValues: [null, undefined] });\n\n for (const [index, row] of rows.entries()) {\n builder.append(decodeAt(row, index) as Struct<TypeMap>[\"TValue\"]);\n }\n\n return new RecordBatch(schema, builder.finish().flush());\n },\n catch: (cause) => new ConnectorError({ message: \"Failed to encode rows\", cause }),\n });\n },\n catch: (cause) => new ConnectorError({ message: \"Failed to convert Iceberg schema\", cause }),\n });\n","import type { RecordBatch, TypeMap } from \"apache-arrow\";\nimport type { TableIdentifier } from \"iceberg-js\";\n\nimport * as Wings from \"@useairfoil/wings\";\nimport { Config, Effect, Layer } from \"effect\";\nimport { FetchHttpClient } from \"effect/http\";\n\nimport type { TableSource } from \"../core/types\";\n\nimport { ensureTable } from \"../catalog/table\";\nimport { ConnectorError } from \"../errors\";\nimport * as RuntimeConfig from \"../runtime-config\";\nimport { makeRowEncoder, type RowEncoder } from \"./arrow\";\nimport { Ingestor, type IngestorService } from \"./service\";\n\n/** One catalog and an Iceberg table for each resource that runs. */\nexport type WingsIngestorConfig<Source extends TableSource = TableSource> = {\n readonly connector: Source;\n readonly catalog: string;\n readonly tables: RuntimeConfig.ResolvedTableBindings<Source>;\n};\n\ntype IngestorEntry = {\n readonly encode: RowEncoder;\n readonly push: (batch: RecordBatch<TypeMap>) => Effect.Effect<void, ConnectorError>;\n};\n\ntype PreparedTable = {\n readonly resource: string;\n readonly identifier: TableIdentifier;\n readonly encode: RowEncoder;\n};\n\nconst connectorError = (message: string, cause?: unknown) => new ConnectorError({ message, cause });\n\n/** Loads each table schema and opens one Wings stream per bound resource. */\nexport const layerWings = <const Source extends TableSource>(\n config: WingsIngestorConfig<Source>,\n): Layer.Layer<Ingestor, ConnectorError, Wings.CatalogManager.CatalogManager> =>\n Layer.effect(Ingestor)(\n Effect.gen(function* () {\n const manager = yield* Wings.CatalogManager.CatalogManager;\n const catalog = yield* manager\n .getIcebergCatalog(config.catalog)\n .pipe(Effect.mapError((cause) => connectorError(\"Failed to load Wings catalog\", cause)));\n\n const bindings: Partial<Record<string, RuntimeConfig.TableBinding>> = config.tables;\n\n const prepared: Array<PreparedTable> = [];\n for (const resource of config.connector.resources) {\n const binding = bindings[resource.name];\n if (!binding) continue;\n\n const { namespace, name, location } = binding;\n const identifier = { namespace, name };\n const schema = yield* ensureTable(resource.rowSchema, {\n catalog,\n identifier,\n location,\n }).pipe(\n Effect.mapError((cause) =>\n connectorError(`Failed to prepare table for ${resource.name}: ${cause.message}`, cause),\n ),\n );\n\n const encode = yield* makeRowEncoder(schema, resource.version);\n prepared.push({ resource: resource.name, identifier, encode });\n }\n\n const entries = new Map<string, IngestorEntry>();\n for (const { resource, identifier, encode } of prepared) {\n const ingestor = yield* manager\n .ingestor({\n catalog: config.catalog,\n namespace: identifier.namespace,\n table: identifier.name,\n })\n .pipe(\n Effect.mapError((cause) =>\n connectorError(`Failed to open ingestor for ${resource}`, cause),\n ),\n );\n\n entries.set(resource, {\n encode,\n push: (batch) =>\n ingestor\n .push(batch)\n .pipe(\n Effect.mapError((cause) =>\n connectorError(`Failed to ingest rows for ${resource}`, cause),\n ),\n ),\n });\n }\n\n const service: IngestorService = {\n resourceNames: prepared.map(({ resource }) => resource),\n ingest: ({ resource, batch }) => {\n const entry = entries.get(resource);\n\n if (!entry) return Effect.fail(connectorError(`Unknown resource ${resource}`));\n if (batch.rows.length === 0) return Effect.succeed({ rows: 0, bytes: 0 });\n\n return entry\n .encode(batch.rows)\n .pipe(\n Effect.flatMap((encoded) =>\n entry\n .push(encoded)\n .pipe(Effect.as({ rows: batch.rows.length, bytes: encoded.data.byteLength })),\n ),\n );\n },\n };\n\n return Ingestor.of(service);\n }),\n );\n\n/** Reads the Wings URL, catalog and table bindings from hosted config. */\nexport const layerWingsConfig = (connector: TableSource) =>\n Layer.unwrap(\n Effect.gen(function* () {\n const { catalog, uri } = yield* Config.all({\n catalog: RuntimeConfig.catalog,\n uri: RuntimeConfig.wingsUri,\n }).pipe(Effect.mapError((cause) => connectorError(\"Invalid Wings configuration\", cause)));\n\n if (uri.protocol !== \"http:\" && uri.protocol !== \"https:\") {\n return yield* Effect.fail(connectorError(\"Invalid Wings URL\"));\n }\n\n const tables = yield* RuntimeConfig.loadTableBindings(connector).pipe(\n Effect.mapError((cause) => connectorError(cause.message, cause)),\n );\n const manager = Wings.CatalogManager.layer({ baseUrl: uri.href }).pipe(\n Layer.provide(FetchHttpClient.layer),\n );\n\n return layerWings({ connector, catalog, tables }).pipe(Layer.provide(manager));\n }),\n );\n"],"mappings":"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"}