@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,9 +1,9 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
2
- import { n as layerWingsConfig, t as layerWings } from "./wings-I56hGtNv.mjs";
3
2
  import { t as Ingestor } from "./service-jWxxfEht.mjs";
3
+ import { n as layerArrowFlightConfig, t as layerArrowFlight } from "./arrow-flight-DDQ0ktx9.mjs";
4
4
  import { Effect, Layer } from "effect";
5
5
  //#region src/ingestor/console.ts
6
- /** Logs batches without sending them to Wings. */
6
+ /** Logs batches without sending them over Arrow Flight. */
7
7
  const layerConsole = Layer.succeed(Ingestor)({ ingest: ({ resource, source, batch }) => Effect.logInfo(`[ingestor] -> Source: ${source} | Resource: ${resource}`).pipe(Effect.annotateLogs({
8
8
  rows: batch.rows.length,
9
9
  cursor: batch.cursor,
@@ -16,11 +16,11 @@ const layerConsole = Layer.succeed(Ingestor)({ ingest: ({ resource, source, batc
16
16
  //#region src/ingestor/index.ts
17
17
  var ingestor_exports = /* @__PURE__ */ __exportAll({
18
18
  Ingestor: () => Ingestor,
19
- layerConsole: () => layerConsole,
20
- layerWings: () => layerWings,
21
- layerWingsConfig: () => layerWingsConfig
19
+ layerArrowFlight: () => layerArrowFlight,
20
+ layerArrowFlightConfig: () => layerArrowFlightConfig,
21
+ layerConsole: () => layerConsole
22
22
  });
23
23
  //#endregion
24
24
  export { layerConsole as n, ingestor_exports as t };
25
25
 
26
- //# sourceMappingURL=ingestor-D4L-HPkg.mjs.map
26
+ //# sourceMappingURL=ingestor-DjCEzBzZ.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ingestor-DjCEzBzZ.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 over Arrow Flight. */\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 {\n layerArrowFlight,\n layerArrowFlightConfig,\n type ArrowFlightIngestorConfig,\n} from \"./arrow-flight\";\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,4 +1,4 @@
1
- import { S as addCurrentSpanEvent, _ as withResourceAttributes, b as EventName, i as ingestDuration, n as batchSize, r as batches, u as rowsIngested, v as Attr, x as SpanName, y as EventAttr } from "./metrics-BaEX__MN.mjs";
1
+ import { S as addCurrentSpanEvent, _ as withResourceAttributes, b as EventName, i as ingestDuration, n as batchSize, r as batches, u as rowsIngested, v as Attr, x as SpanName, y as EventAttr } from "./metrics-C901IIYZ.mjs";
2
2
  import { t as Ingestor } from "./service-jWxxfEht.mjs";
3
3
  import { Effect, Metric } from "effect";
4
4
  //#region src/ingestor/instrumented.ts
@@ -26,4 +26,4 @@ const ingestBatch = Effect.fnUntraced(function* (options) {
26
26
  //#endregion
27
27
  export { ingestBatch as t };
28
28
 
29
- //# sourceMappingURL=instrumented-Bhp7fyvh.mjs.map
29
+ //# sourceMappingURL=instrumented-Bq1WX2L5.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"instrumented-Bhp7fyvh.mjs","names":["Metrics.withResourceAttributes","Metrics.batches","Metrics.ingestDuration","Metrics.rowsIngested","Metrics.batchSize"],"sources":["../src/ingestor/instrumented.ts"],"sourcesContent":["import { Effect, Metric } from \"effect\";\n\nimport type { ResourceBatch } from \"../core/types\";\n\nimport * as Metrics from \"../metrics\";\nimport { Attr, EventAttr, EventName, SpanName, addCurrentSpanEvent } from \"../telemetry\";\nimport { Ingestor, type IngestSource } from \"./service\";\n\nexport const ingestBatch = Effect.fnUntraced(function* (options: {\n readonly connector?: string;\n readonly resource: string;\n readonly source: IngestSource;\n readonly batch: ResourceBatch;\n}) {\n const metricAttributes = Metrics.withResourceAttributes({\n connector: options.connector ?? \"unknown\",\n resource: options.resource,\n source: options.source,\n });\n const batchOutcome = (outcome: \"success\" | \"error\") =>\n Metric.withAttributes(Metrics.batches, {\n ...metricAttributes,\n [Attr.batchOutcome]: outcome,\n });\n\n const ingestor = yield* Ingestor;\n\n const ingest = ingestor.ingest(options).pipe(\n Effect.tap(() => Effect.annotateCurrentSpan({ [Attr.ingestionSuccess]: true })),\n Effect.tapError(() =>\n Effect.annotateCurrentSpan({\n [Attr.ingestionSuccess]: false,\n [Attr.errorPhase]: \"ingest\",\n }),\n ),\n );\n\n // onError keeps the failure, so the engine still sees it and skips the checkpoint.\n const result = yield* Effect.withSpan(ingest, SpanName.ingest, { kind: \"producer\" }).pipe(\n Effect.trackDuration(Metric.withAttributes(Metrics.ingestDuration, metricAttributes)),\n Effect.onError(() => Metric.update(batchOutcome(\"error\"), 1)),\n );\n\n yield* Metric.update(batchOutcome(\"success\"), 1);\n yield* Metric.update(\n Metric.withAttributes(Metrics.rowsIngested, metricAttributes),\n options.batch.rows.length,\n );\n yield* Metric.update(\n Metric.withAttributes(Metrics.batchSize, metricAttributes),\n options.batch.rows.length,\n );\n\n if (options.batch.cursor !== undefined) {\n yield* addCurrentSpanEvent(EventName.batchCheckpoint, {\n [EventAttr.batchCursor]: options.batch.cursor,\n });\n }\n\n return result;\n});\n"],"mappings":";;;;AAQA,MAAa,cAAc,OAAO,WAAW,WAAW,SAKrD;CACD,MAAM,mBAAmBA,uBAA+B;EACtD,WAAW,QAAQ,aAAa;EAChC,UAAU,QAAQ;EAClB,QAAQ,QAAQ;CAClB,CAAC;CACD,MAAM,gBAAgB,YACpB,OAAO,eAAeC,SAAiB;EACrC,GAAG;GACF,KAAK,eAAe;CACvB,CAAC;CAIH,MAAM,UAAS,OAFS,SAAA,CAEA,OAAO,OAAO,CAAC,CAAC,KACtC,OAAO,UAAU,OAAO,oBAAoB,GAAG,KAAK,mBAAmB,KAAK,CAAC,CAAC,GAC9E,OAAO,eACL,OAAO,oBAAoB;GACxB,KAAK,mBAAmB;GACxB,KAAK,aAAa;CACrB,CAAC,CACH,CACF;CAGA,MAAM,SAAS,OAAO,OAAO,SAAS,QAAQ,SAAS,QAAQ,EAAE,MAAM,WAAW,CAAC,CAAC,CAAC,KACnF,OAAO,cAAc,OAAO,eAAeC,gBAAwB,gBAAgB,CAAC,GACpF,OAAO,cAAc,OAAO,OAAO,aAAa,OAAO,GAAG,CAAC,CAAC,CAC9D;CAEA,OAAO,OAAO,OAAO,aAAa,SAAS,GAAG,CAAC;CAC/C,OAAO,OAAO,OACZ,OAAO,eAAeC,cAAsB,gBAAgB,GAC5D,QAAQ,MAAM,KAAK,MACrB;CACA,OAAO,OAAO,OACZ,OAAO,eAAeC,WAAmB,gBAAgB,GACzD,QAAQ,MAAM,KAAK,MACrB;CAEA,IAAI,QAAQ,MAAM,WAAW,KAAA,GAC3B,OAAO,oBAAoB,UAAU,iBAAiB,GACnD,UAAU,cAAc,QAAQ,MAAM,OACzC,CAAC;CAGH,OAAO;AACT,CAAC"}
1
+ {"version":3,"file":"instrumented-Bq1WX2L5.mjs","names":["Metrics.withResourceAttributes","Metrics.batches","Metrics.ingestDuration","Metrics.rowsIngested","Metrics.batchSize"],"sources":["../src/ingestor/instrumented.ts"],"sourcesContent":["import { Effect, Metric } from \"effect\";\n\nimport type { ResourceBatch } from \"../core/types\";\n\nimport * as Metrics from \"../metrics\";\nimport { Attr, EventAttr, EventName, SpanName, addCurrentSpanEvent } from \"../telemetry\";\nimport { Ingestor, type IngestSource } from \"./service\";\n\nexport const ingestBatch = Effect.fnUntraced(function* (options: {\n readonly connector?: string;\n readonly resource: string;\n readonly source: IngestSource;\n readonly batch: ResourceBatch;\n}) {\n const metricAttributes = Metrics.withResourceAttributes({\n connector: options.connector ?? \"unknown\",\n resource: options.resource,\n source: options.source,\n });\n const batchOutcome = (outcome: \"success\" | \"error\") =>\n Metric.withAttributes(Metrics.batches, {\n ...metricAttributes,\n [Attr.batchOutcome]: outcome,\n });\n\n const ingestor = yield* Ingestor;\n\n const ingest = ingestor.ingest(options).pipe(\n Effect.tap(() => Effect.annotateCurrentSpan({ [Attr.ingestionSuccess]: true })),\n Effect.tapError(() =>\n Effect.annotateCurrentSpan({\n [Attr.ingestionSuccess]: false,\n [Attr.errorPhase]: \"ingest\",\n }),\n ),\n );\n\n // onError keeps the failure, so the engine still sees it and skips the checkpoint.\n const result = yield* Effect.withSpan(ingest, SpanName.ingest, { kind: \"producer\" }).pipe(\n Effect.trackDuration(Metric.withAttributes(Metrics.ingestDuration, metricAttributes)),\n Effect.onError(() => Metric.update(batchOutcome(\"error\"), 1)),\n );\n\n yield* Metric.update(batchOutcome(\"success\"), 1);\n yield* Metric.update(\n Metric.withAttributes(Metrics.rowsIngested, metricAttributes),\n options.batch.rows.length,\n );\n yield* Metric.update(\n Metric.withAttributes(Metrics.batchSize, metricAttributes),\n options.batch.rows.length,\n );\n\n if (options.batch.cursor !== undefined) {\n yield* addCurrentSpanEvent(EventName.batchCheckpoint, {\n [EventAttr.batchCursor]: options.batch.cursor,\n });\n }\n\n return result;\n});\n"],"mappings":";;;;AAQA,MAAa,cAAc,OAAO,WAAW,WAAW,SAKrD;CACD,MAAM,mBAAmBA,uBAA+B;EACtD,WAAW,QAAQ,aAAa;EAChC,UAAU,QAAQ;EAClB,QAAQ,QAAQ;CAClB,CAAC;CACD,MAAM,gBAAgB,YACpB,OAAO,eAAeC,SAAiB;EACrC,GAAG;GACF,KAAK,eAAe;CACvB,CAAC;CAIH,MAAM,UAAS,OAFS,SAAA,CAEA,OAAO,OAAO,CAAC,CAAC,KACtC,OAAO,UAAU,OAAO,oBAAoB,GAAG,KAAK,mBAAmB,KAAK,CAAC,CAAC,GAC9E,OAAO,eACL,OAAO,oBAAoB;GACxB,KAAK,mBAAmB;GACxB,KAAK,aAAa;CACrB,CAAC,CACH,CACF;CAGA,MAAM,SAAS,OAAO,OAAO,SAAS,QAAQ,SAAS,QAAQ,EAAE,MAAM,WAAW,CAAC,CAAC,CAAC,KACnF,OAAO,cAAc,OAAO,eAAeC,gBAAwB,gBAAgB,CAAC,GACpF,OAAO,cAAc,OAAO,OAAO,aAAa,OAAO,GAAG,CAAC,CAAC,CAC9D;CAEA,OAAO,OAAO,OAAO,aAAa,SAAS,GAAG,CAAC;CAC/C,OAAO,OAAO,OACZ,OAAO,eAAeC,cAAsB,gBAAgB,GAC5D,QAAQ,MAAM,KAAK,MACrB;CACA,OAAO,OAAO,OACZ,OAAO,eAAeC,WAAmB,gBAAgB,GACzD,QAAQ,MAAM,KAAK,MACrB;CAEA,IAAI,QAAQ,MAAM,WAAW,KAAA,GAC3B,OAAO,oBAAoB,UAAU,iBAAiB,GACnD,UAAU,cAAc,QAAQ,MAAM,OACzC,CAAC;CAGH,OAAO;AACT,CAAC"}
@@ -1,2 +1,2 @@
1
- import { a as define, c as number, d as select, f as string, i as toRuntimeDocument, l as optional, n as configSchema, o as boolean, r as decodeConfig, s as define$1, u as secret } from "../manifest-BGKxmKLy.mjs";
1
+ import { a as define, c as number, d as select, f as string, i as toRuntimeDocument, l as optional, n as configSchema, o as boolean, r as decodeConfig, s as define$1, u as secret } from "../manifest-CABeIhAG.mjs";
2
2
  export { boolean, configSchema, decodeConfig, define, define$1 as defineConfig, number, optional, secret, select, string, toRuntimeDocument };
@@ -1,5 +1,5 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
2
- import { r as isPlatformRuntimeKey } from "./constants-D-GQzpHZ.mjs";
2
+ import { r as isPlatformRuntimeKey } from "./constants-v3UX-hf6.mjs";
3
3
  import { Config, Predicate, Schema, SchemaTransformation, Struct } from "effect";
4
4
  //#region src/manifest/number-schema.ts
5
5
  const makeNumberSchema = (constraints) => {
@@ -213,4 +213,4 @@ var manifest_exports = /* @__PURE__ */ __exportAll({
213
213
  //#endregion
214
214
  export { define as a, number as c, select as d, string as f, toRuntimeDocument as i, optional as l, configSchema as n, boolean as o, decodeConfig as r, define$1 as s, manifest_exports as t, secret as u };
215
215
 
216
- //# sourceMappingURL=manifest-BGKxmKLy.mjs.map
216
+ //# sourceMappingURL=manifest-CABeIhAG.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"manifest-BGKxmKLy.mjs","names":["define"],"sources":["../src/manifest/number-schema.ts","../src/manifest/config.ts","../src/manifest/manifest.ts","../src/manifest/schema.ts","../src/manifest/index.ts"],"sourcesContent":["import { Schema } from \"effect\";\n\nexport type NumberConstraints = {\n readonly integer?: boolean;\n readonly minimum?: number;\n};\n\nexport const makeNumberSchema = (constraints: NumberConstraints) => {\n if (constraints.integer) {\n return constraints.minimum === undefined\n ? Schema.Int\n : Schema.Int.check(Schema.isGreaterThanOrEqualTo(constraints.minimum));\n }\n return constraints.minimum === undefined\n ? Schema.Finite\n : Schema.Finite.check(Schema.isGreaterThanOrEqualTo(constraints.minimum));\n};\n","import { Config, Option, Redacted, Schema, Struct } from \"effect\";\n\nimport { isPlatformRuntimeKey } from \"../runtime-config/constants\";\nimport { makeNumberSchema, type NumberConstraints } from \"./number-schema\";\n\ntype ConfigFieldSpecBase = {\n readonly runtimeKey: string;\n readonly required: boolean;\n readonly description?: string;\n};\n\ntype ConfigFieldDefinition = ConfigFieldSpecBase &\n (\n | {\n readonly type: \"string\";\n readonly secret: false;\n readonly default?: string;\n readonly values?: never;\n }\n | {\n readonly type: \"string\";\n readonly secret: true;\n readonly default?: never;\n readonly values?: never;\n }\n | {\n readonly type: \"number\";\n readonly secret: false;\n readonly default?: number;\n readonly values?: never;\n readonly integer?: boolean;\n readonly minimum?: number;\n }\n | {\n readonly type: \"boolean\";\n readonly secret: false;\n readonly default?: boolean;\n readonly values?: never;\n }\n | {\n readonly type: \"select\";\n readonly secret: false;\n readonly default?: string;\n readonly values: readonly [string, ...Array<string>];\n }\n );\n\n/** Serializable, browser-safe metadata for one user-provided connector setting. */\nexport type ConfigFieldSpec = ConfigFieldDefinition & { readonly name: string };\n\n/** Pairs an Effect runtime config with the metadata used to generate its form field. */\nexport type ConfigField<A> = {\n readonly config: Config.Config<A>;\n readonly spec: ConfigFieldDefinition;\n};\n\ntype FieldBaseOptions = {\n readonly runtimeKey: string;\n readonly description?: string;\n};\n\ntype FieldOptions<A extends string | number | boolean = string | number | boolean> =\n FieldBaseOptions &\n (\n | {\n readonly required?: true;\n readonly default?: A;\n }\n | {\n readonly required: false;\n readonly default: A;\n }\n );\n\ntype NumberFieldOptions = FieldOptions<number> & NumberConstraints;\n\ntype FieldsRecord = Record<string, ConfigField<unknown>>;\n\n/** Preserves each field's value type while `Struct.map` extracts its Effect Config. */\ninterface ConfigFieldToConfig extends Struct.Lambda {\n <A>(field: ConfigField<A>): Config.Config<A>;\n readonly \"~lambda.out\": this[\"~lambda.in\"] extends ConfigField<infer A>\n ? Config.Config<A>\n : never;\n}\n\nconst configFieldToConfig = Struct.lambda<ConfigFieldToConfig>((field) => field.config);\n\ntype ConfigOf<Fields extends FieldsRecord> = {\n readonly [Key in keyof Fields]: Fields[Key] extends ConfigField<infer A> ? A : never;\n};\n\n/** Effect config and serializable manifest metadata produced from one field definition. */\nexport type ConnectorConfigDef<Fields extends FieldsRecord> = {\n readonly fields: {\n readonly [Key in keyof Fields]: Fields[Key] extends ConfigField<infer A>\n ? Config.Config<A>\n : never;\n };\n readonly config: Config.Config<ConfigOf<Fields>>;\n readonly spec: ReadonlyArray<ConfigFieldSpec>;\n};\n\nexport type ConfigValuesOf<Def extends ConnectorConfigDef<FieldsRecord>> =\n Def extends ConnectorConfigDef<infer Fields> ? ConfigOf<Fields> : never;\n\nconst withDefault = <A extends string | number | boolean>(\n config: Config.Config<A>,\n defaultValue: A | undefined,\n) => (defaultValue === undefined ? config : Config.withDefault(config, defaultValue));\n\n/** Defines a required non-empty string, optionally with a default. */\nexport const string = (options: FieldOptions<string>): ConfigField<string> => ({\n config: withDefault(Config.NonEmptyString(options.runtimeKey), options.default),\n spec: {\n runtimeKey: options.runtimeKey,\n type: \"string\",\n required: options.required ?? true,\n secret: false,\n ...(options.description !== undefined ? { description: options.description } : {}),\n ...(options.default !== undefined ? { default: options.default } : {}),\n },\n});\n\n/** Defines a finite number with optional integer, minimum, and default constraints. */\nexport const number = (options: NumberFieldOptions): ConfigField<number> => {\n const schema = makeNumberSchema(options);\n const defaultValue =\n options.default === undefined ? undefined : Schema.decodeUnknownSync(schema)(options.default);\n\n return {\n config: withDefault(Config.schema(schema, options.runtimeKey), defaultValue),\n spec: {\n runtimeKey: options.runtimeKey,\n type: \"number\",\n required: options.required ?? true,\n secret: false,\n ...(options.description !== undefined ? { description: options.description } : {}),\n ...(defaultValue !== undefined ? { default: defaultValue } : {}),\n ...(options.integer !== undefined ? { integer: options.integer } : {}),\n ...(options.minimum !== undefined ? { minimum: options.minimum } : {}),\n },\n };\n};\n\n/** Defines a boolean, optionally with a default. */\nexport const boolean = (options: FieldOptions<boolean>): ConfigField<boolean> => ({\n config: withDefault(Config.Boolean(options.runtimeKey), options.default),\n spec: {\n runtimeKey: options.runtimeKey,\n type: \"boolean\",\n required: options.required ?? true,\n secret: false,\n ...(options.description !== undefined ? { description: options.description } : {}),\n ...(options.default !== undefined ? { default: options.default } : {}),\n },\n});\n\n/** Defines a string literal choice whose values are preserved in the inferred type. */\nexport const select = <const Values extends readonly [string, ...Array<string>]>(\n options: FieldOptions<Values[number]> & { readonly values: Values },\n): ConfigField<Values[number]> => ({\n config: withDefault(Config.Literals(options.values, options.runtimeKey), options.default),\n spec: {\n runtimeKey: options.runtimeKey,\n type: \"select\",\n required: options.required ?? true,\n secret: false,\n values: options.values,\n ...(options.description !== undefined ? { description: options.description } : {}),\n ...(options.default !== undefined ? { default: options.default } : {}),\n },\n});\n\n/** Defines a required, non-empty secret decoded as `Redacted<string>`. */\nexport const secret = (\n options: FieldBaseOptions & { readonly required?: true },\n): ConfigField<Redacted.Redacted<string>> => ({\n config: Config.schema(Schema.Redacted(Schema.NonEmptyString), options.runtimeKey),\n spec: {\n runtimeKey: options.runtimeKey,\n type: \"string\",\n required: options.required ?? true,\n secret: true,\n ...(options.description !== undefined ? { description: options.description } : {}),\n },\n});\n\n/** Makes an existing field optional and represents a missing value as `Option.none()`. */\nexport const optional = <A>(field: ConfigField<A>): ConfigField<Option.Option<A>> => ({\n config: Config.option(field.config),\n spec: {\n ...field.spec,\n required: false,\n },\n});\n\n/**\n * Defines user-facing connector config once for both Effect runtime loading and\n * frontend form generation. The object keys become logical form/API field names;\n * `runtimeKey` remains the key read by Effect Config.\n *\n * @example\n * ```ts\n * const config = define({\n * apiUrl: string({ runtimeKey: \"API_URL\" }),\n * token: secret({ runtimeKey: \"API_TOKEN\" }),\n * });\n *\n * const RuntimeConfig = config.config;\n * const formFields = config.spec;\n * ```\n */\nexport const define = <const Fields extends FieldsRecord>(\n fields: Fields,\n): ConnectorConfigDef<Fields> => {\n const spec = Object.entries(fields).map(([name, field]) => ({ name, ...field.spec }));\n const platformField = spec.find((field) => isPlatformRuntimeKey(field.runtimeKey));\n if (platformField !== undefined) {\n throw new Error(`Connector runtime key is platform-owned: ${platformField.runtimeKey}`);\n }\n\n const configFields = Struct.map(fields, configFieldToConfig);\n\n return {\n fields: configFields,\n // Effect's recursive Config.Wrap cannot reduce this generic mapped type,\n // although ConfigFieldToConfig preserves the value type of every property.\n config: Config.unwrap(configFields as Config.Wrap<ConfigOf<Fields>>),\n spec,\n };\n};\n","import type { ConfigFieldSpec } from \"./config\";\n\nexport type ResourceCapability = \"backfill\" | \"changes\" | \"webhook\";\n\n/** Browser-safe connector metadata consumed by the platform and runtime adapters. */\nexport type ConnectorManifest = {\n readonly name: string;\n readonly title: string;\n readonly description?: string;\n readonly config: ReadonlyArray<ConfigFieldSpec>;\n readonly resources: ReadonlyArray<{\n readonly name: string;\n readonly capabilities: ReadonlyArray<ResourceCapability>;\n }>;\n};\n\n/**\n * Defines browser-safe connector metadata while preserving literal names and capabilities.\n *\n * @example\n * ```ts\n * const manifest = define({\n * name: \"producer-example\",\n * title: \"Example\",\n * config: ExampleConfig.spec,\n * resources: [{ name: \"orders\", capabilities: [\"backfill\"] }],\n * });\n * ```\n */\nexport const define = <const Manifest extends ConnectorManifest>(manifest: Manifest): Manifest =>\n manifest;\n","import { Predicate, Schema, SchemaTransformation, type Types } from \"effect\";\n\nimport type { ConfigFieldSpec } from \"./config\";\nimport type { ConnectorManifest } from \"./manifest\";\n\nimport { makeNumberSchema } from \"./number-schema\";\n\ntype FieldValueOf<Field extends ConfigFieldSpec> = Field[\"type\"] extends \"number\"\n ? number\n : Field[\"type\"] extends \"boolean\"\n ? boolean\n : Field[\"values\"] extends ReadonlyArray<string>\n ? Field[\"values\"][number]\n : string;\n\nexport type ConnectorConfigValues<Manifest extends ConnectorManifest> = Types.Simplify<\n {\n readonly [Field in Manifest[\"config\"][number] as Field[\"required\"] extends true\n ? Field[\"name\"]\n : never]: FieldValueOf<Field>;\n } & {\n readonly [Field in Manifest[\"config\"][number] as Field[\"required\"] extends true\n ? never\n : Field[\"name\"]]?: FieldValueOf<Field> | undefined;\n }\n> &\n object;\n\nexport type ConnectorConfigSchema<Manifest extends ConnectorManifest> = Schema.Codec<\n ConnectorConfigValues<Manifest>,\n unknown\n>;\n\n/** Flat primitive document keyed by the runtime keys consumed by Effect Config. */\nexport type RuntimeConfigDocument = Readonly<Record<string, string | number | boolean>>;\n\n// Browser forms submit numbers and booleans as strings, while API callers may\n// already send their canonical JSON representations. These schemas accept both.\nconst numberFromForm = (field: Extract<ConfigFieldSpec, { readonly type: \"number\" }>) => {\n const numberSchema = makeNumberSchema(field);\n return Schema.Union([\n numberSchema,\n Schema.NonEmptyString.pipe(\n Schema.decodeTo(numberSchema, SchemaTransformation.numberFromString),\n ),\n ]);\n};\n\nconst BooleanFromForm = Schema.Union([\n Schema.Boolean,\n Schema.Literals([\"true\", \"false\"]).pipe(\n Schema.decodeTo(\n Schema.Boolean,\n SchemaTransformation.transform({\n decode: (value) => value === \"true\",\n encode: (value) => (value ? \"true\" : \"false\"),\n }),\n ),\n ),\n]);\n\n// An empty optional form control means \"not supplied\", not an empty config value.\nconst EmptyStringAsUndefined = Schema.Literal(\"\").pipe(\n Schema.decodeTo(\n Schema.Undefined,\n SchemaTransformation.transform({ decode: () => undefined, encode: () => \"\" }),\n ),\n);\n\nconst baseFieldSchema = (field: ConfigFieldSpec): Schema.Codec<unknown, unknown> => {\n switch (field.type) {\n case \"number\":\n return numberFromForm(field);\n case \"boolean\":\n return BooleanFromForm;\n case \"select\":\n return Schema.Literals(field.values);\n case \"string\":\n return Schema.NonEmptyString;\n }\n};\n\nconst fieldSchema = (field: ConfigFieldSpec) =>\n field.required\n ? baseFieldSchema(field)\n : Schema.optional(Schema.Union([EmptyStringAsUndefined, baseFieldSchema(field)]));\n\n/**\n * Builds an Effect Schema for logical form/API values from a connector manifest.\n *\n * @example\n * ```ts\n * const decode = Schema.decodeUnknownEffect(configSchema(manifest));\n * const values = decode({\n * apiUrl: \"https://example.com\",\n * retries: \"3\",\n * });\n * ```\n */\nexport const configSchema = <const Manifest extends ConnectorManifest>(\n manifest: Manifest,\n): ConnectorConfigSchema<Manifest> => {\n const fields = Object.fromEntries(\n manifest.config.map((field) => [field.name, fieldSchema(field)]),\n );\n // Object.fromEntries cannot retain keys discovered from the runtime manifest;\n // the public mapped type restores the same relationship for callers.\n return Schema.Struct(fields) as unknown as ConnectorConfigSchema<Manifest>;\n};\n\n/** Decodes browser/API config, applies manifest defaults, and rejects undeclared fields. */\nexport const decodeConfig = <const Manifest extends ConnectorManifest>(\n manifest: Manifest,\n input: unknown,\n) => {\n const defaults = Object.fromEntries(\n manifest.config.flatMap((field) =>\n field.default === undefined ? [] : [[field.name, field.default]],\n ),\n );\n const optionalFields = new Set(\n manifest.config.flatMap((field) => (field.required ? [] : [field.name])),\n );\n const normalizedInput = Predicate.isObject(input)\n ? Object.fromEntries(\n Object.entries(input).filter(([name, value]) => value !== \"\" || !optionalFields.has(name)),\n )\n : input;\n const inputWithDefaults = Predicate.isObject(normalizedInput)\n ? Object.assign({}, defaults, normalizedInput)\n : normalizedInput;\n\n return Schema.decodeUnknownEffect(configSchema(manifest))(inputWithDefaults, {\n onExcessProperty: \"error\",\n });\n};\n\n/**\n * Maps validated logical values to the flat runtime-key document mounted in a pod.\n * Missing optional values are omitted.\n *\n * @example\n * ```ts\n * toRuntimeDocument(manifest, { apiUrl: \"https://example.com\" });\n * // { API_URL: \"https://example.com\" }\n * ```\n */\nexport const toRuntimeDocument = <const Manifest extends ConnectorManifest>(\n manifest: Manifest,\n values: ConnectorConfigValues<Manifest>,\n): RuntimeConfigDocument => {\n const document: Record<string, string | number | boolean> = {};\n for (const field of manifest.config) {\n const value: unknown = Reflect.get(values, field.name);\n if (typeof value === \"string\" || typeof value === \"number\" || typeof value === \"boolean\") {\n document[field.runtimeKey] = value;\n }\n }\n return document;\n};\n","export {\n boolean,\n define as defineConfig,\n number,\n optional,\n secret,\n select,\n string,\n} from \"./config\";\nexport type { ConfigField, ConfigFieldSpec, ConfigValuesOf, ConnectorConfigDef } from \"./config\";\nexport { define } from \"./manifest\";\nexport type { ConnectorManifest, ResourceCapability } from \"./manifest\";\nexport { configSchema, decodeConfig, toRuntimeDocument } from \"./schema\";\nexport type { ConnectorConfigSchema, ConnectorConfigValues, RuntimeConfigDocument } from \"./schema\";\n"],"mappings":"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"}
1
+ {"version":3,"file":"manifest-CABeIhAG.mjs","names":["define"],"sources":["../src/manifest/number-schema.ts","../src/manifest/config.ts","../src/manifest/manifest.ts","../src/manifest/schema.ts","../src/manifest/index.ts"],"sourcesContent":["import { Schema } from \"effect\";\n\nexport type NumberConstraints = {\n readonly integer?: boolean;\n readonly minimum?: number;\n};\n\nexport const makeNumberSchema = (constraints: NumberConstraints) => {\n if (constraints.integer) {\n return constraints.minimum === undefined\n ? Schema.Int\n : Schema.Int.check(Schema.isGreaterThanOrEqualTo(constraints.minimum));\n }\n return constraints.minimum === undefined\n ? Schema.Finite\n : Schema.Finite.check(Schema.isGreaterThanOrEqualTo(constraints.minimum));\n};\n","import { Config, Option, Redacted, Schema, Struct } from \"effect\";\n\nimport { isPlatformRuntimeKey } from \"../runtime-config/constants\";\nimport { makeNumberSchema, type NumberConstraints } from \"./number-schema\";\n\ntype ConfigFieldSpecBase = {\n readonly runtimeKey: string;\n readonly required: boolean;\n readonly description?: string;\n};\n\ntype ConfigFieldDefinition = ConfigFieldSpecBase &\n (\n | {\n readonly type: \"string\";\n readonly secret: false;\n readonly default?: string;\n readonly values?: never;\n }\n | {\n readonly type: \"string\";\n readonly secret: true;\n readonly default?: never;\n readonly values?: never;\n }\n | {\n readonly type: \"number\";\n readonly secret: false;\n readonly default?: number;\n readonly values?: never;\n readonly integer?: boolean;\n readonly minimum?: number;\n }\n | {\n readonly type: \"boolean\";\n readonly secret: false;\n readonly default?: boolean;\n readonly values?: never;\n }\n | {\n readonly type: \"select\";\n readonly secret: false;\n readonly default?: string;\n readonly values: readonly [string, ...Array<string>];\n }\n );\n\n/** Serializable, browser-safe metadata for one user-provided connector setting. */\nexport type ConfigFieldSpec = ConfigFieldDefinition & { readonly name: string };\n\n/** Pairs an Effect runtime config with the metadata used to generate its form field. */\nexport type ConfigField<A> = {\n readonly config: Config.Config<A>;\n readonly spec: ConfigFieldDefinition;\n};\n\ntype FieldBaseOptions = {\n readonly runtimeKey: string;\n readonly description?: string;\n};\n\ntype FieldOptions<A extends string | number | boolean = string | number | boolean> =\n FieldBaseOptions &\n (\n | {\n readonly required?: true;\n readonly default?: A;\n }\n | {\n readonly required: false;\n readonly default: A;\n }\n );\n\ntype NumberFieldOptions = FieldOptions<number> & NumberConstraints;\n\ntype FieldsRecord = Record<string, ConfigField<unknown>>;\n\n/** Preserves each field's value type while `Struct.map` extracts its Effect Config. */\ninterface ConfigFieldToConfig extends Struct.Lambda {\n <A>(field: ConfigField<A>): Config.Config<A>;\n readonly \"~lambda.out\": this[\"~lambda.in\"] extends ConfigField<infer A>\n ? Config.Config<A>\n : never;\n}\n\nconst configFieldToConfig = Struct.lambda<ConfigFieldToConfig>((field) => field.config);\n\ntype ConfigOf<Fields extends FieldsRecord> = {\n readonly [Key in keyof Fields]: Fields[Key] extends ConfigField<infer A> ? A : never;\n};\n\n/** Effect config and serializable manifest metadata produced from one field definition. */\nexport type ConnectorConfigDef<Fields extends FieldsRecord> = {\n readonly fields: {\n readonly [Key in keyof Fields]: Fields[Key] extends ConfigField<infer A>\n ? Config.Config<A>\n : never;\n };\n readonly config: Config.Config<ConfigOf<Fields>>;\n readonly spec: ReadonlyArray<ConfigFieldSpec>;\n};\n\nexport type ConfigValuesOf<Def extends ConnectorConfigDef<FieldsRecord>> =\n Def extends ConnectorConfigDef<infer Fields> ? ConfigOf<Fields> : never;\n\nconst withDefault = <A extends string | number | boolean>(\n config: Config.Config<A>,\n defaultValue: A | undefined,\n) => (defaultValue === undefined ? config : Config.withDefault(config, defaultValue));\n\n/** Defines a required non-empty string, optionally with a default. */\nexport const string = (options: FieldOptions<string>): ConfigField<string> => ({\n config: withDefault(Config.NonEmptyString(options.runtimeKey), options.default),\n spec: {\n runtimeKey: options.runtimeKey,\n type: \"string\",\n required: options.required ?? true,\n secret: false,\n ...(options.description !== undefined ? { description: options.description } : {}),\n ...(options.default !== undefined ? { default: options.default } : {}),\n },\n});\n\n/** Defines a finite number with optional integer, minimum, and default constraints. */\nexport const number = (options: NumberFieldOptions): ConfigField<number> => {\n const schema = makeNumberSchema(options);\n const defaultValue =\n options.default === undefined ? undefined : Schema.decodeUnknownSync(schema)(options.default);\n\n return {\n config: withDefault(Config.schema(schema, options.runtimeKey), defaultValue),\n spec: {\n runtimeKey: options.runtimeKey,\n type: \"number\",\n required: options.required ?? true,\n secret: false,\n ...(options.description !== undefined ? { description: options.description } : {}),\n ...(defaultValue !== undefined ? { default: defaultValue } : {}),\n ...(options.integer !== undefined ? { integer: options.integer } : {}),\n ...(options.minimum !== undefined ? { minimum: options.minimum } : {}),\n },\n };\n};\n\n/** Defines a boolean, optionally with a default. */\nexport const boolean = (options: FieldOptions<boolean>): ConfigField<boolean> => ({\n config: withDefault(Config.Boolean(options.runtimeKey), options.default),\n spec: {\n runtimeKey: options.runtimeKey,\n type: \"boolean\",\n required: options.required ?? true,\n secret: false,\n ...(options.description !== undefined ? { description: options.description } : {}),\n ...(options.default !== undefined ? { default: options.default } : {}),\n },\n});\n\n/** Defines a string literal choice whose values are preserved in the inferred type. */\nexport const select = <const Values extends readonly [string, ...Array<string>]>(\n options: FieldOptions<Values[number]> & { readonly values: Values },\n): ConfigField<Values[number]> => ({\n config: withDefault(Config.Literals(options.values, options.runtimeKey), options.default),\n spec: {\n runtimeKey: options.runtimeKey,\n type: \"select\",\n required: options.required ?? true,\n secret: false,\n values: options.values,\n ...(options.description !== undefined ? { description: options.description } : {}),\n ...(options.default !== undefined ? { default: options.default } : {}),\n },\n});\n\n/** Defines a required, non-empty secret decoded as `Redacted<string>`. */\nexport const secret = (\n options: FieldBaseOptions & { readonly required?: true },\n): ConfigField<Redacted.Redacted<string>> => ({\n config: Config.schema(Schema.Redacted(Schema.NonEmptyString), options.runtimeKey),\n spec: {\n runtimeKey: options.runtimeKey,\n type: \"string\",\n required: options.required ?? true,\n secret: true,\n ...(options.description !== undefined ? { description: options.description } : {}),\n },\n});\n\n/** Makes an existing field optional and represents a missing value as `Option.none()`. */\nexport const optional = <A>(field: ConfigField<A>): ConfigField<Option.Option<A>> => ({\n config: Config.option(field.config),\n spec: {\n ...field.spec,\n required: false,\n },\n});\n\n/**\n * Defines user-facing connector config once for both Effect runtime loading and\n * frontend form generation. The object keys become logical form/API field names;\n * `runtimeKey` remains the key read by Effect Config.\n *\n * @example\n * ```ts\n * const config = define({\n * apiUrl: string({ runtimeKey: \"API_URL\" }),\n * token: secret({ runtimeKey: \"API_TOKEN\" }),\n * });\n *\n * const RuntimeConfig = config.config;\n * const formFields = config.spec;\n * ```\n */\nexport const define = <const Fields extends FieldsRecord>(\n fields: Fields,\n): ConnectorConfigDef<Fields> => {\n const spec = Object.entries(fields).map(([name, field]) => ({ name, ...field.spec }));\n const platformField = spec.find((field) => isPlatformRuntimeKey(field.runtimeKey));\n if (platformField !== undefined) {\n throw new Error(`Connector runtime key is platform-owned: ${platformField.runtimeKey}`);\n }\n\n const configFields = Struct.map(fields, configFieldToConfig);\n\n return {\n fields: configFields,\n // Effect's recursive Config.Wrap cannot reduce this generic mapped type,\n // although ConfigFieldToConfig preserves the value type of every property.\n config: Config.unwrap(configFields as Config.Wrap<ConfigOf<Fields>>),\n spec,\n };\n};\n","import type { ConfigFieldSpec } from \"./config\";\n\nexport type ResourceCapability = \"backfill\" | \"changes\" | \"webhook\";\n\n/** Browser-safe connector metadata consumed by the platform and runtime adapters. */\nexport type ConnectorManifest = {\n readonly name: string;\n readonly title: string;\n readonly description?: string;\n readonly config: ReadonlyArray<ConfigFieldSpec>;\n readonly resources: ReadonlyArray<{\n readonly name: string;\n readonly capabilities: ReadonlyArray<ResourceCapability>;\n }>;\n};\n\n/**\n * Defines browser-safe connector metadata while preserving literal names and capabilities.\n *\n * @example\n * ```ts\n * const manifest = define({\n * name: \"producer-example\",\n * title: \"Example\",\n * config: ExampleConfig.spec,\n * resources: [{ name: \"orders\", capabilities: [\"backfill\"] }],\n * });\n * ```\n */\nexport const define = <const Manifest extends ConnectorManifest>(manifest: Manifest): Manifest =>\n manifest;\n","import { Predicate, Schema, SchemaTransformation, type Types } from \"effect\";\n\nimport type { ConfigFieldSpec } from \"./config\";\nimport type { ConnectorManifest } from \"./manifest\";\n\nimport { makeNumberSchema } from \"./number-schema\";\n\ntype FieldValueOf<Field extends ConfigFieldSpec> = Field[\"type\"] extends \"number\"\n ? number\n : Field[\"type\"] extends \"boolean\"\n ? boolean\n : Field[\"values\"] extends ReadonlyArray<string>\n ? Field[\"values\"][number]\n : string;\n\nexport type ConnectorConfigValues<Manifest extends ConnectorManifest> = Types.Simplify<\n {\n readonly [Field in Manifest[\"config\"][number] as Field[\"required\"] extends true\n ? Field[\"name\"]\n : never]: FieldValueOf<Field>;\n } & {\n readonly [Field in Manifest[\"config\"][number] as Field[\"required\"] extends true\n ? never\n : Field[\"name\"]]?: FieldValueOf<Field> | undefined;\n }\n> &\n object;\n\nexport type ConnectorConfigSchema<Manifest extends ConnectorManifest> = Schema.Codec<\n ConnectorConfigValues<Manifest>,\n unknown\n>;\n\n/** Flat primitive document keyed by the runtime keys consumed by Effect Config. */\nexport type RuntimeConfigDocument = Readonly<Record<string, string | number | boolean>>;\n\n// Browser forms submit numbers and booleans as strings, while API callers may\n// already send their canonical JSON representations. These schemas accept both.\nconst numberFromForm = (field: Extract<ConfigFieldSpec, { readonly type: \"number\" }>) => {\n const numberSchema = makeNumberSchema(field);\n return Schema.Union([\n numberSchema,\n Schema.NonEmptyString.pipe(\n Schema.decodeTo(numberSchema, SchemaTransformation.numberFromString),\n ),\n ]);\n};\n\nconst BooleanFromForm = Schema.Union([\n Schema.Boolean,\n Schema.Literals([\"true\", \"false\"]).pipe(\n Schema.decodeTo(\n Schema.Boolean,\n SchemaTransformation.transform({\n decode: (value) => value === \"true\",\n encode: (value) => (value ? \"true\" : \"false\"),\n }),\n ),\n ),\n]);\n\n// An empty optional form control means \"not supplied\", not an empty config value.\nconst EmptyStringAsUndefined = Schema.Literal(\"\").pipe(\n Schema.decodeTo(\n Schema.Undefined,\n SchemaTransformation.transform({ decode: () => undefined, encode: () => \"\" }),\n ),\n);\n\nconst baseFieldSchema = (field: ConfigFieldSpec): Schema.Codec<unknown, unknown> => {\n switch (field.type) {\n case \"number\":\n return numberFromForm(field);\n case \"boolean\":\n return BooleanFromForm;\n case \"select\":\n return Schema.Literals(field.values);\n case \"string\":\n return Schema.NonEmptyString;\n }\n};\n\nconst fieldSchema = (field: ConfigFieldSpec) =>\n field.required\n ? baseFieldSchema(field)\n : Schema.optional(Schema.Union([EmptyStringAsUndefined, baseFieldSchema(field)]));\n\n/**\n * Builds an Effect Schema for logical form/API values from a connector manifest.\n *\n * @example\n * ```ts\n * const decode = Schema.decodeUnknownEffect(configSchema(manifest));\n * const values = decode({\n * apiUrl: \"https://example.com\",\n * retries: \"3\",\n * });\n * ```\n */\nexport const configSchema = <const Manifest extends ConnectorManifest>(\n manifest: Manifest,\n): ConnectorConfigSchema<Manifest> => {\n const fields = Object.fromEntries(\n manifest.config.map((field) => [field.name, fieldSchema(field)]),\n );\n // Object.fromEntries cannot retain keys discovered from the runtime manifest;\n // the public mapped type restores the same relationship for callers.\n return Schema.Struct(fields) as unknown as ConnectorConfigSchema<Manifest>;\n};\n\n/** Decodes browser/API config, applies manifest defaults, and rejects undeclared fields. */\nexport const decodeConfig = <const Manifest extends ConnectorManifest>(\n manifest: Manifest,\n input: unknown,\n) => {\n const defaults = Object.fromEntries(\n manifest.config.flatMap((field) =>\n field.default === undefined ? [] : [[field.name, field.default]],\n ),\n );\n const optionalFields = new Set(\n manifest.config.flatMap((field) => (field.required ? [] : [field.name])),\n );\n const normalizedInput = Predicate.isObject(input)\n ? Object.fromEntries(\n Object.entries(input).filter(([name, value]) => value !== \"\" || !optionalFields.has(name)),\n )\n : input;\n const inputWithDefaults = Predicate.isObject(normalizedInput)\n ? Object.assign({}, defaults, normalizedInput)\n : normalizedInput;\n\n return Schema.decodeUnknownEffect(configSchema(manifest))(inputWithDefaults, {\n onExcessProperty: \"error\",\n });\n};\n\n/**\n * Maps validated logical values to the flat runtime-key document mounted in a pod.\n * Missing optional values are omitted.\n *\n * @example\n * ```ts\n * toRuntimeDocument(manifest, { apiUrl: \"https://example.com\" });\n * // { API_URL: \"https://example.com\" }\n * ```\n */\nexport const toRuntimeDocument = <const Manifest extends ConnectorManifest>(\n manifest: Manifest,\n values: ConnectorConfigValues<Manifest>,\n): RuntimeConfigDocument => {\n const document: Record<string, string | number | boolean> = {};\n for (const field of manifest.config) {\n const value: unknown = Reflect.get(values, field.name);\n if (typeof value === \"string\" || typeof value === \"number\" || typeof value === \"boolean\") {\n document[field.runtimeKey] = value;\n }\n }\n return document;\n};\n","export {\n boolean,\n define as defineConfig,\n number,\n optional,\n secret,\n select,\n string,\n} from \"./config\";\nexport type { ConfigField, ConfigFieldSpec, ConfigValuesOf, ConnectorConfigDef } from \"./config\";\nexport { define } from \"./manifest\";\nexport type { ConnectorManifest, ResourceCapability } from \"./manifest\";\nexport { configSchema, decodeConfig, toRuntimeDocument } from \"./schema\";\nexport type { ConnectorConfigSchema, ConnectorConfigValues, RuntimeConfigDocument } from \"./schema\";\n"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
2
- import { n as PlatformRuntimeKey } from "./constants-D-GQzpHZ.mjs";
3
- import { Cause, Config, DateTime, Effect, Layer, Metric, Option, Predicate, Schedule } from "effect";
2
+ import { n as PlatformRuntimeKey } from "./constants-v3UX-hf6.mjs";
3
+ import { Cause, Config, DateTime, Effect, Layer, Metric, Option, Predicate, Schedule, Schema } from "effect";
4
4
  import { Headers, HttpClientError, HttpClientResponse } from "effect/http";
5
5
  import * as Observability from "effect/observability";
6
6
  //#region src/telemetry.ts
@@ -63,7 +63,7 @@ const maxErrorMessageLength = 500;
63
63
  const OtlpEnvConfig = Config.all({
64
64
  enabled: Config.Boolean(PlatformRuntimeKey.otelEnabled).pipe(Config.withDefault(false)),
65
65
  baseUrl: Config.option(Config.String(PlatformRuntimeKey.otelExporterOtlpEndpoint)),
66
- rawHeaders: Config.option(Config.String(PlatformRuntimeKey.otelExporterOtlpHeaders))
66
+ headers: Config.option(Config.Record(Schema.String, Schema.StringFromUriComponent, PlatformRuntimeKey.otelExporterOtlpHeaders, { trim: true }))
67
67
  });
68
68
  const defaultRedactedHeaders = [
69
69
  "authorization",
@@ -75,11 +75,6 @@ const defaultRedactedHeaders = [
75
75
  /signature/i,
76
76
  /token/i
77
77
  ];
78
- const parseOtelHeaders = (value) => Object.fromEntries(value.split(",").map((entry) => entry.trim()).filter(Boolean).flatMap((entry) => {
79
- const separator = entry.indexOf("=");
80
- if (separator < 1) return [];
81
- return [[entry.slice(0, separator).trim(), entry.slice(separator + 1).trim()]];
82
- }));
83
78
  const appendPath = (baseUrl, path) => `${baseUrl.replace(/\/$/, "")}/${path.replace(/^\//, "")}`;
84
79
  /**
85
80
  * Best-effort stable error classifier for span metadata.
@@ -173,7 +168,7 @@ const layerOtlpTracing = (options = {}) => Layer.unwrap(Effect.gen(function* ()
173
168
  return yield* buildOtlpTracingLayer({
174
169
  enabled: raw.enabled,
175
170
  endpoint: Option.getOrUndefined(raw.baseUrl),
176
- headers: Option.isSome(raw.rawHeaders) ? parseOtelHeaders(raw.rawHeaders.value) : void 0
171
+ headers: Option.getOrUndefined(raw.headers)
177
172
  }, options);
178
173
  }));
179
174
  /** Exports connector metrics over OTLP when telemetry is enabled. */
@@ -184,7 +179,7 @@ const layerOtlpMetrics = (options = {}) => Layer.unwrap(Effect.gen(function* ()
184
179
  if (!endpoint) return yield* Effect.fail(/* @__PURE__ */ new Error("OTEL_ENABLED=true requires OTEL_EXPORTER_OTLP_ENDPOINT"));
185
180
  return Observability.OtlpMetrics.layer({
186
181
  url: appendPath(endpoint, "/v1/metrics"),
187
- headers: Option.isSome(raw.rawHeaders) ? parseOtelHeaders(raw.rawHeaders.value) : void 0,
182
+ headers: Option.getOrUndefined(raw.headers),
188
183
  exportInterval: options.exportInterval,
189
184
  temporality: "cumulative"
190
185
  }).pipe(Layer.provide(Observability.OtlpSerialization.layerJson));
@@ -349,4 +344,4 @@ const withResourceAttributes = resourceAttributes;
349
344
  //#endregion
350
345
  export { annotateError as C, addCurrentSpanEvent as S, withResourceAttributes as _, lastSuccessTimestamp as a, EventName as b, recordWebhookRequest as c, setLastSuccessTimestamp as d, setSyncState as f, webhookRequests as g, webhookQueueDepth as h, ingestDuration as i, retrySchedule as l, syncState as m, batchSize as n, metrics_exports as o, setWebhookQueueDepth as p, batches as r, recordApiRetry as s, apiRetries as t, rowsIngested as u, Attr as v, telemetry_exports as w, SpanName as x, EventAttr as y };
351
346
 
352
- //# sourceMappingURL=metrics-BaEX__MN.mjs.map
347
+ //# sourceMappingURL=metrics-C901IIYZ.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metrics-C901IIYZ.mjs","names":[],"sources":["../src/telemetry.ts","../src/metrics.ts"],"sourcesContent":["import { Cause, Config, Effect, Layer, Metric, Option, Schema, 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 headers: Config.option(\n Config.Record(\n Schema.String,\n Schema.StringFromUriComponent,\n PlatformRuntimeKey.otelExporterOtlpHeaders,\n { trim: true },\n ),\n ),\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 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.getOrUndefined(raw.headers),\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.getOrUndefined(raw.headers),\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,4 +1,4 @@
1
- import { w as SyncState } from "./types-xZtSmrGA.mjs";
1
+ import { w as SyncState } from "./types-NtSv6gwl.mjs";
2
2
  import { Duration, Effect, Metric, Schedule } from "effect";
3
3
  declare namespace metrics_d_exports {
4
4
  export { ApiRetryMetricAttrs, ApiRetryReason, BatchOutcome, BatchSource, LastSuccessMetricAttrs, ResourceMetricAttrs, SyncStateAttrs, WebhookMetricAttrs, WebhookOutcome, apiRetries, batchSize, batches, ingestDuration, lastSuccessTimestamp, recordApiRetry, recordWebhookRequest, retrySchedule, rowsIngested, setLastSuccessTimestamp, setSyncState, setWebhookQueueDepth, syncState, webhookQueueDepth, webhookRequests, withResourceAttributes };
@@ -61,4 +61,4 @@ declare const withResourceAttributes: (attrs: ResourceMetricAttrs) => {
61
61
  };
62
62
  //#endregion
63
63
  export { syncState as C, withResourceAttributes as E, setWebhookQueueDepth as S, webhookRequests as T, recordWebhookRequest as _, LastSuccessMetricAttrs as a, setLastSuccessTimestamp as b, WebhookMetricAttrs as c, batchSize as d, batches as f, recordApiRetry as g, metrics_d_exports as h, BatchSource as i, WebhookOutcome as l, lastSuccessTimestamp as m, ApiRetryReason as n, ResourceMetricAttrs as o, ingestDuration as p, BatchOutcome as r, SyncStateAttrs as s, ApiRetryMetricAttrs as t, apiRetries as u, retrySchedule as v, webhookQueueDepth as w, setSyncState as x, rowsIngested as y };
64
- //# sourceMappingURL=metrics-CVXFL7YT.d.mts.map
64
+ //# sourceMappingURL=metrics-DoJ0WeKu.d.mts.map
@@ -1,2 +1,2 @@
1
- import { C as syncState, E as withResourceAttributes, S as setWebhookQueueDepth, T as webhookRequests, _ as recordWebhookRequest, a as LastSuccessMetricAttrs, b as setLastSuccessTimestamp, c as WebhookMetricAttrs, d as batchSize, f as batches, g as recordApiRetry, i as BatchSource, l as WebhookOutcome, m as lastSuccessTimestamp, n as ApiRetryReason, o as ResourceMetricAttrs, p as ingestDuration, r as BatchOutcome, s as SyncStateAttrs, t as ApiRetryMetricAttrs, u as apiRetries, v as retrySchedule, w as webhookQueueDepth, x as setSyncState, y as rowsIngested } from "./metrics-CVXFL7YT.mjs";
1
+ import { C as syncState, E as withResourceAttributes, S as setWebhookQueueDepth, T as webhookRequests, _ as recordWebhookRequest, a as LastSuccessMetricAttrs, b as setLastSuccessTimestamp, c as WebhookMetricAttrs, d as batchSize, f as batches, g as recordApiRetry, i as BatchSource, l as WebhookOutcome, m as lastSuccessTimestamp, n as ApiRetryReason, o as ResourceMetricAttrs, p as ingestDuration, r as BatchOutcome, s as SyncStateAttrs, t as ApiRetryMetricAttrs, u as apiRetries, v as retrySchedule, w as webhookQueueDepth, x as setSyncState, y as rowsIngested } from "./metrics-DoJ0WeKu.mjs";
2
2
  export { ApiRetryMetricAttrs, ApiRetryReason, BatchOutcome, BatchSource, LastSuccessMetricAttrs, ResourceMetricAttrs, SyncStateAttrs, WebhookMetricAttrs, WebhookOutcome, apiRetries, batchSize, batches, ingestDuration, lastSuccessTimestamp, recordApiRetry, recordWebhookRequest, retrySchedule, rowsIngested, setLastSuccessTimestamp, setSyncState, setWebhookQueueDepth, syncState, webhookQueueDepth, webhookRequests, withResourceAttributes };
package/dist/metrics.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import { _ as withResourceAttributes, a as lastSuccessTimestamp, c as recordWebhookRequest, d as setLastSuccessTimestamp, f as setSyncState, g as webhookRequests, h as webhookQueueDepth, i as ingestDuration, l as retrySchedule, m as syncState, n as batchSize, p as setWebhookQueueDepth, r as batches, s as recordApiRetry, t as apiRetries, u as rowsIngested } from "./metrics-BaEX__MN.mjs";
1
+ import { _ as withResourceAttributes, a as lastSuccessTimestamp, c as recordWebhookRequest, d as setLastSuccessTimestamp, f as setSyncState, g as webhookRequests, h as webhookQueueDepth, i as ingestDuration, l as retrySchedule, m as syncState, n as batchSize, p as setWebhookQueueDepth, r as batches, s as recordApiRetry, t as apiRetries, u as rowsIngested } from "./metrics-C901IIYZ.mjs";
2
2
  export { apiRetries, batchSize, batches, ingestDuration, lastSuccessTimestamp, recordApiRetry, recordWebhookRequest, retrySchedule, rowsIngested, setLastSuccessTimestamp, setSyncState, setWebhookQueueDepth, syncState, webhookQueueDepth, webhookRequests, withResourceAttributes };
@@ -1,2 +1,2 @@
1
- import { a as layerHosted, c as catalog, d as RuntimeConfigError, f as RuntimeConfigErrorCode, i as loadTableBindings, l as httpPort, n as ResolvedTableBindings, o as PlatformRuntimeDefault, r as TableBinding, s as PlatformRuntimeKey, u as wingsUri } from "../index-ygpml2kC.mjs";
2
- export { PlatformRuntimeDefault, PlatformRuntimeKey, type ResolvedTableBindings, RuntimeConfigError, type RuntimeConfigErrorCode, type TableBinding, catalog, httpPort, layerHosted, loadTableBindings, wingsUri };
1
+ import { a as layerHosted, c as catalog, d as httpPort, f as RuntimeConfigError, i as loadTableBindings, l as engineUri, n as ResolvedTableBindings, o as PlatformRuntimeDefault, p as RuntimeConfigErrorCode, r as TableBinding, s as PlatformRuntimeKey, u as flightUri } from "../index-fHIJJoRe.mjs";
2
+ export { PlatformRuntimeDefault, PlatformRuntimeKey, type ResolvedTableBindings, RuntimeConfigError, type RuntimeConfigErrorCode, type TableBinding, catalog, engineUri, flightUri, httpPort, layerHosted, loadTableBindings };
@@ -1,3 +1,3 @@
1
- import { n as PlatformRuntimeKey, t as PlatformRuntimeDefault } from "../constants-D-GQzpHZ.mjs";
2
- import { a as catalog, i as RuntimeConfigError, n as loadTableBindings, o as httpPort, r as layerHosted, s as wingsUri } from "../runtime-config-Oa55gAew.mjs";
3
- export { PlatformRuntimeDefault, PlatformRuntimeKey, RuntimeConfigError, catalog, httpPort, layerHosted, loadTableBindings, wingsUri };
1
+ import { n as PlatformRuntimeKey, t as PlatformRuntimeDefault } from "../constants-v3UX-hf6.mjs";
2
+ import { a as catalog, c as httpPort, i as RuntimeConfigError, n as loadTableBindings, o as engineUri, r as layerHosted, s as flightUri } from "../runtime-config-Bn8Fivt1.mjs";
3
+ export { PlatformRuntimeDefault, PlatformRuntimeKey, RuntimeConfigError, catalog, engineUri, flightUri, httpPort, layerHosted, loadTableBindings };
@@ -1,12 +1,14 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
2
- import { n as PlatformRuntimeKey, t as PlatformRuntimeDefault } from "./constants-D-GQzpHZ.mjs";
2
+ import { n as PlatformRuntimeKey, t as PlatformRuntimeDefault } from "./constants-v3UX-hf6.mjs";
3
3
  import { Config, ConfigProvider, Data, Effect, FileSystem, Schema } from "effect";
4
4
  //#region src/runtime-config/config.ts
5
5
  /** Shared HTTP port used by hosted and sandbox connector entrypoints. */
6
6
  const httpPort = Config.Port(PlatformRuntimeKey.httpPort).pipe(Config.withDefault(PlatformRuntimeDefault.httpPort));
7
- /** Wings URL, including the protocol. */
8
- const wingsUri = Config.URL(PlatformRuntimeKey.wingsUri);
9
- /** Wings catalog ID. */
7
+ /** Engine URL, including the protocol. */
8
+ const engineUri = Config.URL(PlatformRuntimeKey.engineUri);
9
+ /** Arrow Flight URL. Uses the engine URL when unset. */
10
+ const flightUri = engineUri.pipe(Config.flatMap((uri) => Config.URL(PlatformRuntimeKey.flightUri).pipe(Config.withDefault(uri))));
11
+ /** Catalog ID. */
10
12
  const catalog = Config.NonEmptyString(PlatformRuntimeKey.catalog);
11
13
  //#endregion
12
14
  //#region src/runtime-config/error.ts
@@ -86,12 +88,13 @@ var runtime_config_exports = /* @__PURE__ */ __exportAll({
86
88
  PlatformRuntimeKey: () => PlatformRuntimeKey,
87
89
  RuntimeConfigError: () => RuntimeConfigError,
88
90
  catalog: () => catalog,
91
+ engineUri: () => engineUri,
92
+ flightUri: () => flightUri,
89
93
  httpPort: () => httpPort,
90
94
  layerHosted: () => layerHosted,
91
- loadTableBindings: () => loadTableBindings,
92
- wingsUri: () => wingsUri
95
+ loadTableBindings: () => loadTableBindings
93
96
  });
94
97
  //#endregion
95
- export { catalog as a, RuntimeConfigError as i, loadTableBindings as n, httpPort as o, layerHosted as r, wingsUri as s, runtime_config_exports as t };
98
+ export { catalog as a, httpPort as c, RuntimeConfigError as i, loadTableBindings as n, engineUri as o, layerHosted as r, flightUri as s, runtime_config_exports as t };
96
99
 
97
- //# sourceMappingURL=runtime-config-Oa55gAew.mjs.map
100
+ //# sourceMappingURL=runtime-config-Bn8Fivt1.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime-config-Bn8Fivt1.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/** Engine URL, including the protocol. */\nexport const engineUri = Config.URL(PlatformRuntimeKey.engineUri);\n\n/** Arrow Flight URL. Uses the engine URL when unset. */\nexport const flightUri = engineUri.pipe(\n Config.flatMap((uri) => Config.URL(PlatformRuntimeKey.flightUri).pipe(Config.withDefault(uri))),\n);\n\n/** 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 { PlatformRuntimeKey } from \"./constants\";\nimport { RuntimeConfigError } from \"./error\";\n\ntype BindingSource = {\n readonly resources: ReadonlyArray<{ readonly name: string }>;\n};\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 BindingSource> = 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 BindingSource>(\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, engineUri, flightUri, httpPort } from \"./config\";\nexport { PlatformRuntimeDefault, PlatformRuntimeKey } from \"./constants\";\nexport { layerHosted } from \"./layer\";\nexport { type ResolvedTableBindings, type TableBinding, loadTableBindings } from \"./table-bindings\";\n"],"mappings":";;;;;AAKA,MAAa,WAAW,OAAO,KAAK,mBAAmB,QAAQ,CAAC,CAAC,KAC/D,OAAO,YAAY,uBAAuB,QAAQ,CACpD;;AAGA,MAAa,YAAY,OAAO,IAAI,mBAAmB,SAAS;;AAGhE,MAAa,YAAY,UAAU,KACjC,OAAO,SAAS,QAAQ,OAAO,IAAI,mBAAmB,SAAS,CAAC,CAAC,KAAK,OAAO,YAAY,GAAG,CAAC,CAAC,CAChG;;AAGA,MAAa,UAAU,OAAO,eAAe,mBAAmB,OAAO;;;;ACPvE,IAAa,qBAAb,cAAwC,KAAK,YAAY,oBAAoB,CAAC,CAI3E,CAAC;;;ACVJ,MAAM,mBAIF,OAAO,IAAI,aAAa;CAC1B,MAAM,aAAa,OAAO,OAAO,eAAe,mBAAmB,UAAU,CAAC,CAAC,KAC7E,OAAO,UACJ,UACC,IAAI,mBAAmB;EACrB,MAAM;EACN,SAAS,GAAG,mBAAmB,WAAW;EAC1C,OAAO,MAAM;CACf,CAAC,CACL,CACF;CAEA,MAAM,WAAW,QAAO,OADE,WAAW,WAAA,CACF,eAAe,UAAU,CAAC,CAAC,KAC5D,OAAO,UACJ,UACC,IAAI,mBAAmB;EACrB,MAAM;EACN,SAAS;EACT;CACF,CAAC,CACL,CACF;CACA,MAAM,WAAW,OAAO,OAAO,oBAAoB,OAAO,eAAe,OAAO,OAAO,CAAC,CAAC,CACvF,QACF,CAAC,CAAC,KACA,OAAO,UACJ,UACC,IAAI,mBAAmB;EACrB,MAAM;EACN,SAAS;EACT,OAAO;CACT,CAAC,CACL,CACF;CACA,OAAO,eAAe,YAAY,UAAU,EAAE,sBAAsB,KAAK,CAAC;AAC5E,CAAC;;;;;;;;;;AAWD,MAAa,oBAAoB,eAAe,SAAS,gBAAgB;;;ACrCzE,MAAM,wBAAwB,OAAO,OAAO;CAC1C,WAAW,OAAO,cAAc,OAAO,cAAc;CACrD,MAAM,OAAO;CACb,UAAU,OAAO,SAAS,OAAO,cAAc;AACjD,CAAC;AAED,MAAM,oBAAoB,OAAO,eAC/B,OAAO,OAAO,OAAO,QAAQ,qBAAqB,CACpD;AAEA,MAAM,WAAW,UACf,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC;AAE1D,MAAM,QAAQ,MAA4D,YACxE,IAAI,mBAAmB;CAAE;CAAM;CAAS,OAAO,IAAI,MAAM,OAAO;AAAE,CAAC;;AAGrE,MAAa,qBACX,cAEA,OAAO,IAAI,aAAa;CACtB,MAAM,MAAM,OAAO,OAAO,eAAe,mBAAmB,aAAa,CAAC,CAAC,KACzE,OAAO,UACJ,UACC,IAAI,mBAAmB;EACrB,MAAM;EACN,SAAS,GAAG,mBAAmB,cAAc;EAC7C,OAAO,QAAQ,KAAK;CACtB,CAAC,CACL,CACF;CAEA,MAAM,UAAU,OAAO,OAAO,oBAAoB,iBAAiB,CAAC,CAAC,KAAK,EACxE,kBAAkB,QACpB,CAAC,CAAC,CAAC,KACD,OAAO,UACJ,UACC,IAAI,mBAAmB;EACrB,MAAM;EACN,SAAS;EACT,OAAO,QAAQ,KAAK;CACtB,CAAC,CACL,CACF;CAEA,MAAM,SAAS,OAAO,KAAK,OAAO;CAClC,IAAI,OAAO,WAAW,GACpB,OAAO,OAAO,OAAO,KACnB,KAAK,0BAA0B,yCAAyC,CAC1E;CAKF,MAAM,WAAW,IAAI,IAAI,UAAU,UAAU,KAAK,aAAa,SAAS,IAAI,CAAC;CAC7E,MAAM,UAAU,OAAO,QAAQ,SAAS,CAAC,SAAS,IAAI,IAAI,CAAC;CAC3D,IAAI,QAAQ,SAAS,GACnB,OAAO,OAAO,OAAO,KACnB,KACE,2BACA,oEAAoE,QAAQ,OAAO,EACrF,CACF;CAGF,OAAO,OAAO,YACZ,OAAO,QAAQ,OAAO,CAAC,CAAC,KAAK,CAAC,UAAU,gBAAgB,CACtD,UACA;EACE,WAAW,MAAM,KAAK,WAAW,SAAS;EAC1C,MAAM,WAAW;EACjB,GAAI,WAAW,aAAa,KAAA,IAAY,CAAC,IAAI,EAAE,UAAU,WAAW,SAAS;CAC/E,CACF,CAAC,CACH;AACF,CAAC"}
@@ -1,6 +1,6 @@
1
1
  import { t as ConnectorError } from "./errors-pT0YVJU5.mjs";
2
- import { C as annotateError, c as recordWebhookRequest, p as setWebhookQueueDepth, v as Attr, x as SpanName } from "./metrics-BaEX__MN.mjs";
3
- import { t as ingestBatch } from "./instrumented-Bhp7fyvh.mjs";
2
+ import { C as annotateError, c as recordWebhookRequest, p as setWebhookQueueDepth, v as Attr, x as SpanName } from "./metrics-C901IIYZ.mjs";
3
+ import { t as ingestBatch } from "./instrumented-Bq1WX2L5.mjs";
4
4
  import { Cause, Context, Effect, Queue, Schema } from "effect";
5
5
  import { HttpRouter, HttpServerRequest, HttpServerResponse } from "effect/http";
6
6
  //#region src/webhook/server.ts
@@ -141,4 +141,4 @@ const router = (routes, options) => HttpRouter.addAll(routes.map((route) => Http
141
141
  //#endregion
142
142
  export { router as n, WebhookQueue as t };
143
143
 
144
- //# sourceMappingURL=server-CMnxz3h0.mjs.map
144
+ //# sourceMappingURL=server-D1TTN0_D.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"server-CMnxz3h0.mjs","names":["Metrics.recordWebhookRequest","Metrics.setWebhookQueueDepth"],"sources":["../src/webhook/server.ts"],"sourcesContent":["import { Cause, Context, Effect, Queue, Schema } from \"effect\";\nimport { HttpRouter, HttpServerRequest, HttpServerResponse } from \"effect/http\";\n\nimport type {\n ResourceBatch,\n ResourceDefinition,\n WebhookRoute,\n WebhookRouteContext,\n} from \"../core/types\";\n\nimport { ConnectorError } from \"../errors\";\nimport { ingestBatch } from \"../ingestor/instrumented\";\nimport * as Metrics from \"../metrics\";\nimport { Attr, SpanName, annotateError } from \"../telemetry\";\n\nexport type QueuedWebhookBatch = {\n readonly resource: string;\n readonly batch: ResourceBatch;\n};\n\nexport class WebhookQueue extends Context.Service<\n WebhookQueue,\n {\n readonly queue: Queue.Queue<QueuedWebhookBatch>;\n }\n>()(\"@useairfoil/connector-kit/WebhookQueue\") {}\n\nconst resourceBatch = <Row extends object>(rows: ReadonlyArray<Row>): ResourceBatch<Row> => ({\n rows,\n});\n\nconst makeRouteContext = (\n request: HttpServerRequest.HttpServerRequest,\n rawBody: Uint8Array,\n payload: unknown,\n batches: Array<QueuedWebhookBatch>,\n resourceNames: ReadonlyArray<string>,\n): WebhookRouteContext<ReadonlyArray<ResourceDefinition>, unknown> => ({\n request,\n rawBody,\n payload,\n to: (resource, payload) =>\n Effect.gen(function* () {\n if (!resourceNames.includes(resource.name)) return;\n if (!resource.webhook) {\n return yield* Effect.fail(\n new ConnectorError({\n message: `Resource ${resource.name} does not define a webhook handler`,\n }),\n );\n }\n\n // The route already decoded the payload, so don't decode it again.\n const rows = yield* resource.webhook.handler({ payload });\n batches.push({\n resource: resource.name,\n batch: resourceBatch(rows),\n });\n }),\n});\n\nconst compactBatches = (batches: ReadonlyArray<QueuedWebhookBatch>) => {\n const grouped = new Map<string, object[]>();\n for (const item of batches) {\n const current = grouped.get(item.resource) ?? [];\n grouped.set(item.resource, [...current, ...item.batch.rows]);\n }\n return Array.from(grouped.entries()).map(([resource, rows]) => ({\n resource,\n batch: resourceBatch(rows),\n }));\n};\n\nconst ingestBatches = (\n batches: ReadonlyArray<QueuedWebhookBatch>,\n options: { readonly connectorName: string },\n) =>\n Effect.gen(function* () {\n yield* Effect.forEach(\n batches,\n (batch) =>\n ingestBatch({\n connector: options.connectorName,\n resource: batch.resource,\n source: \"webhook\",\n batch: batch.batch,\n }),\n { concurrency: \"unbounded\" },\n );\n });\n\nconst badRequest = (message: string) =>\n HttpServerResponse.jsonUnsafe({ ok: false, error: message }, { status: 400 });\n\nconst readRawBody = (request: HttpServerRequest.HttpServerRequest) =>\n request.arrayBuffer.pipe(Effect.map((buffer) => new Uint8Array(buffer)));\n\nconst parseJson = (rawBody: Uint8Array) =>\n Effect.try({\n try: () => JSON.parse(new TextDecoder().decode(rawBody)),\n catch: (cause) => new ConnectorError({ message: \"Invalid webhook JSON\", cause }),\n });\n\ntype RouterOptions = {\n readonly connectorName: string;\n /** Events for other resources are skipped. */\n readonly resourceNames: ReadonlyArray<string>;\n};\n\nconst makeHandler = (route: WebhookRoute, options: RouterOptions) =>\n Effect.gen(function* () {\n const request = yield* HttpServerRequest.HttpServerRequest;\n const collected: Array<QueuedWebhookBatch> = [];\n\n const rawBodyResult = yield* readRawBody(request).pipe(\n Effect.match({\n onFailure: () => ({ _tag: \"Error\" as const, message: \"Failed to read webhook body\" }),\n onSuccess: (value) => ({ _tag: \"Success\" as const, value }),\n }),\n );\n\n if (rawBodyResult._tag === \"Error\") {\n yield* Metrics.recordWebhookRequest({\n connector: options.connectorName,\n path: String(route.path),\n outcome: \"read_error\",\n });\n return badRequest(rawBodyResult.message);\n }\n\n const jsonResult = yield* parseJson(rawBodyResult.value).pipe(\n Effect.match({\n onFailure: (error) => ({ _tag: \"Error\" as const, message: error.message }),\n onSuccess: (value) => ({ _tag: \"Success\" as const, value }),\n }),\n );\n\n if (jsonResult._tag === \"Error\") {\n yield* Metrics.recordWebhookRequest({\n connector: options.connectorName,\n path: String(route.path),\n outcome: \"invalid_json\",\n });\n return badRequest(jsonResult.message);\n }\n\n const payloadResult = yield* Schema.decodeUnknownEffect(route.schema)(jsonResult.value).pipe(\n Effect.match({\n onFailure: () => ({ _tag: \"Error\" as const, message: \"Invalid webhook payload\" }),\n onSuccess: (value) => ({ _tag: \"Success\" as const, value }),\n }),\n );\n\n if (payloadResult._tag === \"Error\") {\n yield* Metrics.recordWebhookRequest({\n connector: options.connectorName,\n path: String(route.path),\n outcome: \"invalid_payload\",\n });\n return badRequest(payloadResult.message);\n }\n\n const response = yield* Effect.withSpan(\n route\n .handler(\n makeRouteContext(\n request,\n rawBodyResult.value,\n payloadResult.value,\n collected,\n options.resourceNames,\n ),\n )\n .pipe(Effect.tapError((error) => annotateError(\"webhook_handle\", error))),\n SpanName.webhookHandle,\n { attributes: { [Attr.webhookPath]: route.path } },\n );\n\n const batches = compactBatches(collected);\n\n if (route.ackMode === \"after-enqueue\") {\n const queue = yield* WebhookQueue;\n yield* Queue.offerAll(queue.queue, batches);\n const depth = yield* Queue.size(queue.queue);\n yield* Metrics.setWebhookQueueDepth(options.connectorName, depth);\n yield* Metrics.recordWebhookRequest({\n connector: options.connectorName,\n path: String(route.path),\n outcome: response.status >= 400 ? \"rejected\" : \"ok\",\n });\n\n return response;\n }\n\n yield* Effect.withSpan(\n ingestBatches(batches, { connectorName: options.connectorName }).pipe(\n Effect.tapError((error) => annotateError(\"webhook_ingest\", error)),\n ),\n SpanName.webhookHandle,\n { attributes: { [Attr.webhookPath]: route.path } },\n );\n\n yield* Metrics.recordWebhookRequest({\n connector: options.connectorName,\n path: String(route.path),\n outcome: response.status >= 400 ? \"rejected\" : \"ok\",\n });\n\n return response;\n }).pipe(\n Effect.catchCause((cause) =>\n Metrics.recordWebhookRequest({\n connector: options.connectorName,\n path: String(route.path),\n outcome: \"handler_error\",\n }).pipe(\n Effect.andThen(Effect.logWarning(`Webhook handler error: ${Cause.pretty(cause)}`)),\n Effect.andThen(\n Effect.succeed(\n HttpServerResponse.jsonUnsafe(\n { ok: false, error: \"Webhook handler failed\" },\n { status: 500 },\n ),\n ),\n ),\n ),\n ),\n );\n\nexport const router = (routes: ReadonlyArray<WebhookRoute>, options: RouterOptions) =>\n HttpRouter.addAll(\n routes.map((route) => HttpRouter.route(\"POST\", route.path, makeHandler(route, options))),\n );\n"],"mappings":"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"}
1
+ {"version":3,"file":"server-D1TTN0_D.mjs","names":["Metrics.recordWebhookRequest","Metrics.setWebhookQueueDepth"],"sources":["../src/webhook/server.ts"],"sourcesContent":["import { Cause, Context, Effect, Queue, Schema } from \"effect\";\nimport { HttpRouter, HttpServerRequest, HttpServerResponse } from \"effect/http\";\n\nimport type {\n ResourceBatch,\n ResourceDefinition,\n WebhookRoute,\n WebhookRouteContext,\n} from \"../core/types\";\n\nimport { ConnectorError } from \"../errors\";\nimport { ingestBatch } from \"../ingestor/instrumented\";\nimport * as Metrics from \"../metrics\";\nimport { Attr, SpanName, annotateError } from \"../telemetry\";\n\nexport type QueuedWebhookBatch = {\n readonly resource: string;\n readonly batch: ResourceBatch;\n};\n\nexport class WebhookQueue extends Context.Service<\n WebhookQueue,\n {\n readonly queue: Queue.Queue<QueuedWebhookBatch>;\n }\n>()(\"@useairfoil/connector-kit/WebhookQueue\") {}\n\nconst resourceBatch = <Row extends object>(rows: ReadonlyArray<Row>): ResourceBatch<Row> => ({\n rows,\n});\n\nconst makeRouteContext = (\n request: HttpServerRequest.HttpServerRequest,\n rawBody: Uint8Array,\n payload: unknown,\n batches: Array<QueuedWebhookBatch>,\n resourceNames: ReadonlyArray<string>,\n): WebhookRouteContext<ReadonlyArray<ResourceDefinition>, unknown> => ({\n request,\n rawBody,\n payload,\n to: (resource, payload) =>\n Effect.gen(function* () {\n if (!resourceNames.includes(resource.name)) return;\n if (!resource.webhook) {\n return yield* Effect.fail(\n new ConnectorError({\n message: `Resource ${resource.name} does not define a webhook handler`,\n }),\n );\n }\n\n // The route already decoded the payload, so don't decode it again.\n const rows = yield* resource.webhook.handler({ payload });\n batches.push({\n resource: resource.name,\n batch: resourceBatch(rows),\n });\n }),\n});\n\nconst compactBatches = (batches: ReadonlyArray<QueuedWebhookBatch>) => {\n const grouped = new Map<string, object[]>();\n for (const item of batches) {\n const current = grouped.get(item.resource) ?? [];\n grouped.set(item.resource, [...current, ...item.batch.rows]);\n }\n return Array.from(grouped.entries()).map(([resource, rows]) => ({\n resource,\n batch: resourceBatch(rows),\n }));\n};\n\nconst ingestBatches = (\n batches: ReadonlyArray<QueuedWebhookBatch>,\n options: { readonly connectorName: string },\n) =>\n Effect.gen(function* () {\n yield* Effect.forEach(\n batches,\n (batch) =>\n ingestBatch({\n connector: options.connectorName,\n resource: batch.resource,\n source: \"webhook\",\n batch: batch.batch,\n }),\n { concurrency: \"unbounded\" },\n );\n });\n\nconst badRequest = (message: string) =>\n HttpServerResponse.jsonUnsafe({ ok: false, error: message }, { status: 400 });\n\nconst readRawBody = (request: HttpServerRequest.HttpServerRequest) =>\n request.arrayBuffer.pipe(Effect.map((buffer) => new Uint8Array(buffer)));\n\nconst parseJson = (rawBody: Uint8Array) =>\n Effect.try({\n try: () => JSON.parse(new TextDecoder().decode(rawBody)),\n catch: (cause) => new ConnectorError({ message: \"Invalid webhook JSON\", cause }),\n });\n\ntype RouterOptions = {\n readonly connectorName: string;\n /** Events for other resources are skipped. */\n readonly resourceNames: ReadonlyArray<string>;\n};\n\nconst makeHandler = (route: WebhookRoute, options: RouterOptions) =>\n Effect.gen(function* () {\n const request = yield* HttpServerRequest.HttpServerRequest;\n const collected: Array<QueuedWebhookBatch> = [];\n\n const rawBodyResult = yield* readRawBody(request).pipe(\n Effect.match({\n onFailure: () => ({ _tag: \"Error\" as const, message: \"Failed to read webhook body\" }),\n onSuccess: (value) => ({ _tag: \"Success\" as const, value }),\n }),\n );\n\n if (rawBodyResult._tag === \"Error\") {\n yield* Metrics.recordWebhookRequest({\n connector: options.connectorName,\n path: String(route.path),\n outcome: \"read_error\",\n });\n return badRequest(rawBodyResult.message);\n }\n\n const jsonResult = yield* parseJson(rawBodyResult.value).pipe(\n Effect.match({\n onFailure: (error) => ({ _tag: \"Error\" as const, message: error.message }),\n onSuccess: (value) => ({ _tag: \"Success\" as const, value }),\n }),\n );\n\n if (jsonResult._tag === \"Error\") {\n yield* Metrics.recordWebhookRequest({\n connector: options.connectorName,\n path: String(route.path),\n outcome: \"invalid_json\",\n });\n return badRequest(jsonResult.message);\n }\n\n const payloadResult = yield* Schema.decodeUnknownEffect(route.schema)(jsonResult.value).pipe(\n Effect.match({\n onFailure: () => ({ _tag: \"Error\" as const, message: \"Invalid webhook payload\" }),\n onSuccess: (value) => ({ _tag: \"Success\" as const, value }),\n }),\n );\n\n if (payloadResult._tag === \"Error\") {\n yield* Metrics.recordWebhookRequest({\n connector: options.connectorName,\n path: String(route.path),\n outcome: \"invalid_payload\",\n });\n return badRequest(payloadResult.message);\n }\n\n const response = yield* Effect.withSpan(\n route\n .handler(\n makeRouteContext(\n request,\n rawBodyResult.value,\n payloadResult.value,\n collected,\n options.resourceNames,\n ),\n )\n .pipe(Effect.tapError((error) => annotateError(\"webhook_handle\", error))),\n SpanName.webhookHandle,\n { attributes: { [Attr.webhookPath]: route.path } },\n );\n\n const batches = compactBatches(collected);\n\n if (route.ackMode === \"after-enqueue\") {\n const queue = yield* WebhookQueue;\n yield* Queue.offerAll(queue.queue, batches);\n const depth = yield* Queue.size(queue.queue);\n yield* Metrics.setWebhookQueueDepth(options.connectorName, depth);\n yield* Metrics.recordWebhookRequest({\n connector: options.connectorName,\n path: String(route.path),\n outcome: response.status >= 400 ? \"rejected\" : \"ok\",\n });\n\n return response;\n }\n\n yield* Effect.withSpan(\n ingestBatches(batches, { connectorName: options.connectorName }).pipe(\n Effect.tapError((error) => annotateError(\"webhook_ingest\", error)),\n ),\n SpanName.webhookHandle,\n { attributes: { [Attr.webhookPath]: route.path } },\n );\n\n yield* Metrics.recordWebhookRequest({\n connector: options.connectorName,\n path: String(route.path),\n outcome: response.status >= 400 ? \"rejected\" : \"ok\",\n });\n\n return response;\n }).pipe(\n Effect.catchCause((cause) =>\n Metrics.recordWebhookRequest({\n connector: options.connectorName,\n path: String(route.path),\n outcome: \"handler_error\",\n }).pipe(\n Effect.andThen(Effect.logWarning(`Webhook handler error: ${Cause.pretty(cause)}`)),\n Effect.andThen(\n Effect.succeed(\n HttpServerResponse.jsonUnsafe(\n { ok: false, error: \"Webhook handler failed\" },\n { status: 500 },\n ),\n ),\n ),\n ),\n ),\n );\n\nexport const router = (routes: ReadonlyArray<WebhookRoute>, options: RouterOptions) =>\n HttpRouter.addAll(\n routes.map((route) => HttpRouter.route(\"POST\", route.path, makeHandler(route, options))),\n );\n"],"mappings":";;;;;;AAoBA,IAAa,eAAb,cAAkC,QAAQ,QAKxC,CAAC,CAAC,wCAAwC,CAAC,CAAC,CAAC;AAE/C,MAAM,iBAAqC,UAAkD,EAC3F,KACF;AAEA,MAAM,oBACJ,SACA,SACA,SACA,SACA,mBACqE;CACrE;CACA;CACA;CACA,KAAK,UAAU,YACb,OAAO,IAAI,aAAa;EACtB,IAAI,CAAC,cAAc,SAAS,SAAS,IAAI,GAAG;EAC5C,IAAI,CAAC,SAAS,SACZ,OAAO,OAAO,OAAO,KACnB,IAAI,eAAe,EACjB,SAAS,YAAY,SAAS,KAAK,oCACrC,CAAC,CACH;EAIF,MAAM,OAAO,OAAO,SAAS,QAAQ,QAAQ,EAAE,QAAQ,CAAC;EACxD,QAAQ,KAAK;GACX,UAAU,SAAS;GACnB,OAAO,cAAc,IAAI;EAC3B,CAAC;CACH,CAAC;AACL;AAEA,MAAM,kBAAkB,YAA+C;CACrE,MAAM,0BAAU,IAAI,IAAsB;CAC1C,KAAK,MAAM,QAAQ,SAAS;EAC1B,MAAM,UAAU,QAAQ,IAAI,KAAK,QAAQ,KAAK,CAAC;EAC/C,QAAQ,IAAI,KAAK,UAAU,CAAC,GAAG,SAAS,GAAG,KAAK,MAAM,IAAI,CAAC;CAC7D;CACA,OAAO,MAAM,KAAK,QAAQ,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,UAAU,WAAW;EAC9D;EACA,OAAO,cAAc,IAAI;CAC3B,EAAE;AACJ;AAEA,MAAM,iBACJ,SACA,YAEA,OAAO,IAAI,aAAa;CACtB,OAAO,OAAO,QACZ,UACC,UACC,YAAY;EACV,WAAW,QAAQ;EACnB,UAAU,MAAM;EAChB,QAAQ;EACR,OAAO,MAAM;CACf,CAAC,GACH,EAAE,aAAa,YAAY,CAC7B;AACF,CAAC;AAEH,MAAM,cAAc,YAClB,mBAAmB,WAAW;CAAE,IAAI;CAAO,OAAO;AAAQ,GAAG,EAAE,QAAQ,IAAI,CAAC;AAE9E,MAAM,eAAe,YACnB,QAAQ,YAAY,KAAK,OAAO,KAAK,WAAW,IAAI,WAAW,MAAM,CAAC,CAAC;AAEzE,MAAM,aAAa,YACjB,OAAO,IAAI;CACT,WAAW,KAAK,MAAM,IAAI,YAAY,CAAC,CAAC,OAAO,OAAO,CAAC;CACvD,QAAQ,UAAU,IAAI,eAAe;EAAE,SAAS;EAAwB;CAAM,CAAC;AACjF,CAAC;AAQH,MAAM,eAAe,OAAqB,YACxC,OAAO,IAAI,aAAa;CACtB,MAAM,UAAU,OAAO,kBAAkB;CACzC,MAAM,YAAuC,CAAC;CAE9C,MAAM,gBAAgB,OAAO,YAAY,OAAO,CAAC,CAAC,KAChD,OAAO,MAAM;EACX,kBAAkB;GAAE,MAAM;GAAkB,SAAS;EAA8B;EACnF,YAAY,WAAW;GAAE,MAAM;GAAoB;EAAM;CAC3D,CAAC,CACH;CAEA,IAAI,cAAc,SAAS,SAAS;EAClC,OAAOA,qBAA6B;GAClC,WAAW,QAAQ;GACnB,MAAM,OAAO,MAAM,IAAI;GACvB,SAAS;EACX,CAAC;EACD,OAAO,WAAW,cAAc,OAAO;CACzC;CAEA,MAAM,aAAa,OAAO,UAAU,cAAc,KAAK,CAAC,CAAC,KACvD,OAAO,MAAM;EACX,YAAY,WAAW;GAAE,MAAM;GAAkB,SAAS,MAAM;EAAQ;EACxE,YAAY,WAAW;GAAE,MAAM;GAAoB;EAAM;CAC3D,CAAC,CACH;CAEA,IAAI,WAAW,SAAS,SAAS;EAC/B,OAAOA,qBAA6B;GAClC,WAAW,QAAQ;GACnB,MAAM,OAAO,MAAM,IAAI;GACvB,SAAS;EACX,CAAC;EACD,OAAO,WAAW,WAAW,OAAO;CACtC;CAEA,MAAM,gBAAgB,OAAO,OAAO,oBAAoB,MAAM,MAAM,CAAC,CAAC,WAAW,KAAK,CAAC,CAAC,KACtF,OAAO,MAAM;EACX,kBAAkB;GAAE,MAAM;GAAkB,SAAS;EAA0B;EAC/E,YAAY,WAAW;GAAE,MAAM;GAAoB;EAAM;CAC3D,CAAC,CACH;CAEA,IAAI,cAAc,SAAS,SAAS;EAClC,OAAOA,qBAA6B;GAClC,WAAW,QAAQ;GACnB,MAAM,OAAO,MAAM,IAAI;GACvB,SAAS;EACX,CAAC;EACD,OAAO,WAAW,cAAc,OAAO;CACzC;CAEA,MAAM,WAAW,OAAO,OAAO,SAC7B,MACG,QACC,iBACE,SACA,cAAc,OACd,cAAc,OACd,WACA,QAAQ,aACV,CACF,CAAC,CACA,KAAK,OAAO,UAAU,UAAU,cAAc,kBAAkB,KAAK,CAAC,CAAC,GAC1E,SAAS,eACT,EAAE,YAAY,GAAG,KAAK,cAAc,MAAM,KAAK,EAAE,CACnD;CAEA,MAAM,UAAU,eAAe,SAAS;CAExC,IAAI,MAAM,YAAY,iBAAiB;EACrC,MAAM,QAAQ,OAAO;EACrB,OAAO,MAAM,SAAS,MAAM,OAAO,OAAO;EAC1C,MAAM,QAAQ,OAAO,MAAM,KAAK,MAAM,KAAK;EAC3C,OAAOC,qBAA6B,QAAQ,eAAe,KAAK;EAChE,OAAOD,qBAA6B;GAClC,WAAW,QAAQ;GACnB,MAAM,OAAO,MAAM,IAAI;GACvB,SAAS,SAAS,UAAU,MAAM,aAAa;EACjD,CAAC;EAED,OAAO;CACT;CAEA,OAAO,OAAO,SACZ,cAAc,SAAS,EAAE,eAAe,QAAQ,cAAc,CAAC,CAAC,CAAC,KAC/D,OAAO,UAAU,UAAU,cAAc,kBAAkB,KAAK,CAAC,CACnE,GACA,SAAS,eACT,EAAE,YAAY,GAAG,KAAK,cAAc,MAAM,KAAK,EAAE,CACnD;CAEA,OAAOA,qBAA6B;EAClC,WAAW,QAAQ;EACnB,MAAM,OAAO,MAAM,IAAI;EACvB,SAAS,SAAS,UAAU,MAAM,aAAa;CACjD,CAAC;CAED,OAAO;AACT,CAAC,CAAC,CAAC,KACD,OAAO,YAAY,UACjBA,qBAA6B;CAC3B,WAAW,QAAQ;CACnB,MAAM,OAAO,MAAM,IAAI;CACvB,SAAS;AACX,CAAC,CAAC,CAAC,KACD,OAAO,QAAQ,OAAO,WAAW,0BAA0B,MAAM,OAAO,KAAK,GAAG,CAAC,GACjF,OAAO,QACL,OAAO,QACL,mBAAmB,WACjB;CAAE,IAAI;CAAO,OAAO;AAAyB,GAC7C,EAAE,QAAQ,IAAI,CAChB,CACF,CACF,CACF,CACF,CACF;AAEF,MAAa,UAAU,QAAqC,YAC1D,WAAW,OACT,OAAO,KAAK,UAAU,WAAW,MAAM,QAAQ,MAAM,MAAM,YAAY,OAAO,OAAO,CAAC,CAAC,CACzF"}
@@ -1,5 +1,5 @@
1
1
  import { t as ConnectorError } from "./index-DkVNO6ks.mjs";
2
- import { u as ResourceBatch } from "./types-xZtSmrGA.mjs";
2
+ import { u as ResourceBatch } from "./types-NtSv6gwl.mjs";
3
3
  import { Context, Effect } from "effect";
4
4
  //#region src/ingestor/service.d.ts
5
5
  type IngestSource = "backfill" | "changes" | "webhook" | "demo";
@@ -24,4 +24,4 @@ declare const Ingestor_base: Context.ServiceClass<Ingestor, "@useairfoil/connect
24
24
  declare class Ingestor extends Ingestor_base {}
25
25
  //#endregion
26
26
  export { IngestorService as a, Ingestor as i, IngestResult as n, IngestSource as r, IngestOptions as t };
27
- //# sourceMappingURL=service-DLkhuxYl.d.mts.map
27
+ //# sourceMappingURL=service-BRoy_EId.d.mts.map
@@ -1,2 +1,2 @@
1
- import { n as layerSql, o as StateStore, r as layerMemory } from "../state-store-uFvHY7Ax.mjs";
1
+ import { n as layerSql, o as StateStore, r as layerMemory } from "../state-store-DhSrKVEH.mjs";
2
2
  export { StateStore, layerMemory, layerSql };
@@ -1,6 +1,6 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
2
2
  import { t as ConnectorError } from "./errors-pT0YVJU5.mjs";
3
- import { n as PlatformRuntimeKey, t as PlatformRuntimeDefault } from "./constants-D-GQzpHZ.mjs";
3
+ import { n as PlatformRuntimeKey, t as PlatformRuntimeDefault } from "./constants-v3UX-hf6.mjs";
4
4
  import { Config, Context, DateTime, Effect, Layer, Option, Schema } from "effect";
5
5
  import { KeyValueStore } from "effect/persistence";
6
6
  import "effect/sql";
@@ -188,4 +188,4 @@ var state_store_exports = /* @__PURE__ */ __exportAll({
188
188
  //#endregion
189
189
  export { ResourceStateSchema as a, ResourceErrorSchema as i, layerSql as n, StateStore as o, layerMemory as r, state_store_exports as t };
190
190
 
191
- //# sourceMappingURL=state-store-uFvHY7Ax.mjs.map
191
+ //# sourceMappingURL=state-store-DhSrKVEH.mjs.map