@@ -11,16 +11,10 @@ import {
1111 defineConnector ,
1212 defineEntity ,
1313 defineEvent ,
14- makePullStream ,
15- makeWebhookQueue ,
14+ Ingestion ,
1615 Publisher ,
17- runConnector ,
18- StateStore ,
19- StateStoreInMemory ,
20- WingsPublisherLayer ,
21- ConnectorRuntimeContext ,
22- ConnectorRuntimeContextLayer ,
23- buildWebhookRouter ,
16+ Streams ,
17+ Webhook ,
2418} from " @useairfoil/connector-kit" ;
2519
2620import type {
@@ -37,11 +31,8 @@ import type {
3731 IngestionState ,
3832 LiveSource ,
3933 LiveStream ,
40- RunConnectorOptions ,
4134 StreamState ,
4235 Transform ,
43- WebhookRoute ,
44- WebhookStream ,
4536} from " @useairfoil/connector-kit" ;
4637```
4738
@@ -232,12 +223,12 @@ runConnector(
232223): Effect .Effect < void , ConnectorError , StateStore | Publisher > ;
233224
234225// With webhook: also requires HttpServer
235- runConnector < TPayload > (
226+ runConnector (
236227 connector ,
237228 options : {
238229 initialCutoff?: Cursor ;
239230 webhook : {
240- routes: ReadonlyArray < WebhookRoute < TPayload > > ;
231+ routes: ReadonlyArray < Webhook . WebhookRoute > ;
241232 healthPath ?: HttpRouter .PathInput ; // default "/health"
242233 disableHttpLogger ?: boolean ; // default true
243234 };
@@ -247,15 +238,35 @@ runConnector<TPayload>(
247238
248239Internally:
249240
250- - Provides ` ConnectorRuntimeContextLayer( connector) ` so downstream spans can
251- tag metrics with ` connector.name ` .
241+ - Provides an internal connector runtime context so downstream spans can tag
242+ metrics with ` connector.name ` .
252243- Wraps the whole run in an ` Effect.withSpan("connector.run", ...) ` .
253244- Emits ` connector_batches_total ` , ` connector_rows_total ` , and
254245 ` connector_batch_size ` via ` effect/Metric ` .
255246- For webhooks, composes ` buildWebhookRouter(routes) ` with a ` /health `
256247 route and serves it via ` HttpRouter.serve(app, { disableLogger }) ` .
257248
258- ### ` RunConnectorOptions<TWebhookPayload> `
249+ Current runtime composition pattern around ` runConnector(...) ` :
250+
251+ ``` ts
252+ const ConnectorLayer = layerConfig .pipe (Layer .provide (EnvLayer ));
253+
254+ const program = Effect .gen (function * () {
255+ const { connector, routes } = yield * MyConnector ;
256+ const serverLayer = NodeHttpServer .layer (createServer , { port: 8080 });
257+
258+ return yield * Ingestion .runConnector (connector , {
259+ initialCutoff: new Date (),
260+ webhook: {
261+ routes ,
262+ healthPath: " /health" ,
263+ disableHttpLogger: true ,
264+ },
265+ }).pipe (Effect .provide (serverLayer ));
266+ });
267+ ```
268+
269+ ### ` Ingestion.RunConnectorOptions `
259270
260271Exposed type for callers who build options programmatically.
261272
@@ -282,7 +293,7 @@ class StateStore extends Context.Service<
282293
283294Keyed by entity/event name. One row per stream.
284295
285- ### ` StateStoreInMemory `
296+ ### ` Ingestion.layerMemory `
286297
287298In-process ` Map<string, IngestionState> ` backed ` StateStore ` layer. Use for
288299the sandbox runner and tests. Production deployments provide a durable
@@ -310,10 +321,10 @@ class Publisher extends Context.Service<
310321` PublishAck = { readonly success: boolean } ` . The engine fails the stream
311322if ` publish ` fails.
312323
313- ### ` WingsPublisherLayer (config)`
324+ ### ` Publisher.layerWings (config)`
314325
315326``` ts
316- WingsPublisherLayer ({
327+ Publisher . layerWings ({
317328 connector ,
318329 topics: { customers: customerTopic , orders: orderTopic },
319330 partitionValues: { customers: " account_id" },
@@ -323,24 +334,27 @@ WingsPublisherLayer({
323334Production-grade publisher that fans each entity into a Wings topic. For
324335the sandbox / tests, use a hand-written console publisher instead.
325336
337+ Current tag access pattern in this repo is ` Publisher.Publisher ` from the root
338+ module namespace.
339+
326340---
327341
328342## Streams
329343
330- ### ` makeWebhookQueue<T>(options?) `
344+ ### ` Streams. makeWebhookQueue<T>(options?)`
331345
332346``` ts
333- makeWebhookQueue <T >({ capacity?: number }): Effect .Effect < WebhookStream < T >> ;
347+ Streams . makeWebhookQueue <T >({ capacity?: number }): Effect .Effect < WebhookStream < T >> ;
334348```
335349
336350Creates a bounded ` Queue ` (default capacity 1024) and its ` Stream.fromQueue `
337351view. Always keep the queue bounded — unbounded queues can let a noisy
338352webhook drown the publisher.
339353
340- ### ` makePullStream<T, R>(options) `
354+ ### ` Streams. makePullStream<T, R>(options)`
341355
342356``` ts
343- makePullStream ({
357+ Streams . makePullStream ({
344358 initialCursor?: Cursor ,
345359 fetchPage : (cursor : Cursor | undefined ) => Effect .Effect < PullPage < T > , ConnectorError , R>,
346360}): Stream .Stream < Batch < T > , ConnectorError , R > ;
@@ -360,14 +374,14 @@ list endpoint.
360374
361375## Webhooks
362376
363- ### ` WebhookRoute<TPayload > `
377+ ### ` Webhook. WebhookRoute<S >`
364378
365379``` ts
366- type WebhookRoute <TPayload > = {
380+ type WebhookRoute <S extends Schema . Schema < any > > = {
367381 readonly path: HttpRouter .PathInput ;
368- readonly schema: Schema . Schema < TPayload > ;
382+ readonly schema: S ;
369383 readonly handle: (
370- payload : TPayload ,
384+ payload : Schema . Schema . Type < S > ,
371385 request : HttpServerRequest .HttpServerRequest ,
372386 rawBody ? : Uint8Array ,
373387 ) => Effect .Effect <void , ConnectorError >;
@@ -378,7 +392,7 @@ The framework decodes the request body, validates against `schema`, and
378392invokes ` handle(payload, request, rawBody) ` . Use ` rawBody ` for HMAC
379393verification; use ` payload ` for dispatch.
380394
381- ### ` buildWebhookRouter(routes) `
395+ ### ` Webhook. buildWebhookRouter(routes)`
382396
383397Low-level helper that turns an array of routes into an ` HttpRouter ` Layer.
384398` runConnector(...) ` uses this internally; you rarely call it directly.
@@ -387,19 +401,6 @@ Low-level helper that turns an array of routes into an `HttpRouter` Layer.
387401
388402## Runtime context
389403
390- ### ` ConnectorRuntimeContext `
391-
392- Service tag exposing ` { connector: ConnectorDefinition } ` . The engine sets
393- this via ` ConnectorRuntimeContextLayer(connector) ` . Metrics attributes use
394- it to tag batches with ` connector.name ` .
395-
396- ### ` ConnectorRuntimeContextLayer(connector) `
397-
398- Returns a ` Layer.succeed(ConnectorRuntimeContext)({ connector }) ` . Call this
399- in custom test harnesses if you bypass ` runConnector ` .
400-
401- ---
402-
403404## Observability (provided by the engine)
404405
405406### Spans
@@ -429,27 +430,36 @@ sandbox uses `Observability.Otlp.layerJson({ baseUrl, resource })` from
429430## Typical composition recipe
430431
431432``` ts
432- const runtimeLayer = Layer .mergeAll (
433- StateStoreInMemory ,
434- ConsolePublisherLayer , // or WingsPublisherLayer(...)
435- MyConnectorConfig (), // Layer<MyConnector, ConnectorError, HttpClient>
433+ const EnvLayer = Layer .mergeAll (
434+ FetchHttpClient .layer ,
435+ Layer .succeed (ConfigProvider .ConfigProvider , ConfigProvider .fromEnv ()),
436+ )
437+
438+ const ConnectorLayer = layerConfig .pipe (Layer .provide (EnvLayer ))
439+
440+ const TelemetryLayer = Layer .unwrap (... ).pipe (Layer .provide (EnvLayer ))
441+
442+ const RuntimeLayer = Layer .mergeAll (
443+ Ingestion .layerMemory ,
444+ ConsolePublisherLayer , // or Publisher.layerWings(...)
445+ ConnectorLayer ,
436446 Logger .layer ([Logger .consolePretty ()]),
437- TelemetryLayer , // optional
438- Layer .mergeAll (
439- FetchHttpClient .layer ,
440- Layer .succeed (ConfigProvider .ConfigProvider , ConfigProvider .fromEnv ()),
441- ),
447+ TelemetryLayer ,
442448);
443449
444450const program = Effect .gen (function * () {
445451 const { connector, routes } = yield * MyConnector ;
446- return yield * runConnector (connector , {
452+ return yield * Ingestion . runConnector (connector , {
447453 initialCutoff: new Date (),
448- webhook: { routes },
454+ webhook: {
455+ routes ,
456+ healthPath: " /health" ,
457+ disableHttpLogger: true ,
458+ },
449459 }).pipe (Effect .provide (NodeHttpServer .layer (createServer , { port: 8080 })));
450- });
460+ }). pipe ( Effect . annotateLogs ({ component: " producer-foo " })) ;
451461
452- Effect .runPromise (Effect .scoped (program ).pipe (Effect .provide (runtimeLayer )));
462+ Effect .runPromise (Effect .scoped (program ).pipe (Effect .provide (RuntimeLayer )));
453463```
454464
455465See ` connectors/producer-polar/src/sandbox.ts ` for the live reference.
0 commit comments