@pattern-stack/codegen 0.12.2 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +66 -0
- package/README.md +44 -0
- package/dist/runtime/subsystems/index.d.ts +6 -2
- package/dist/runtime/subsystems/index.js +171 -1
- package/dist/runtime/subsystems/index.js.map +1 -1
- package/dist/runtime/subsystems/integration/detection-config.schema.d.ts +110 -1
- package/dist/runtime/subsystems/integration/detection-config.schema.js +25 -2
- package/dist/runtime/subsystems/integration/detection-config.schema.js.map +1 -1
- package/dist/runtime/subsystems/integration/incremental-read.d.ts +221 -0
- package/dist/runtime/subsystems/integration/incremental-read.js +146 -0
- package/dist/runtime/subsystems/integration/incremental-read.js.map +1 -0
- package/dist/runtime/subsystems/integration/index.d.ts +2 -1
- package/dist/runtime/subsystems/integration/index.js +169 -2
- package/dist/runtime/subsystems/integration/index.js.map +1 -1
- package/dist/runtime/subsystems/jobs/job-worker.module.d.ts +1 -1
- package/dist/src/cli/index.js +629 -35
- package/dist/src/cli/index.js.map +1 -1
- package/dist/src/index.d.ts +78 -0
- package/dist/src/index.js +11 -1
- package/dist/src/index.js.map +1 -1
- package/package.json +1 -1
- package/runtime/subsystems/index.ts +34 -0
- package/runtime/subsystems/integration/detection-config.schema.ts +55 -0
- package/runtime/subsystems/integration/incremental-read.ts +345 -0
- package/runtime/subsystems/integration/index.ts +15 -0
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,72 @@ All notable changes to this project will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [0.13.0] — 2026-05-31
|
|
8
|
+
|
|
9
|
+
Track D round-2/3 — the integration codegen now emits the **full** integration
|
|
10
|
+
layer. Where 0.12.x stopped at the read side (provider module, adapter scaffold,
|
|
11
|
+
registry, typed views), 0.13.0 adds the **module assembly** (the write/run side —
|
|
12
|
+
RFC-0002) and reshapes the read body into the **`IncrementalRead` primitive**
|
|
13
|
+
(RFC-0003). After this release the author fills only the irreducible vendor seam:
|
|
14
|
+
the `enumerate` / `hydrate` / `toCanonical` read methods and any non-generic sink
|
|
15
|
+
write logic.
|
|
16
|
+
|
|
17
|
+
Core and the four surface packages (`codegen-{mail,calendar,transcript,crm}`)
|
|
18
|
+
**release together** — the surfaces carry the BREAKING port change below and
|
|
19
|
+
require the matching core (peer dep `^0.13.0`).
|
|
20
|
+
|
|
21
|
+
### BREAKING
|
|
22
|
+
|
|
23
|
+
- **Surface ports declare `changeSources`, not `sources`.** The four surface
|
|
24
|
+
ports (`MailPort` / `CalendarPort` / `TranscriptPort` / `CrmPort`) now require
|
|
25
|
+
`readonly changeSources: Record<string, IChangeSource<unknown>>` — the
|
|
26
|
+
per-entity change sources the adapter *contributes*, keyed by entity name —
|
|
27
|
+
instead of the old `readonly sources: IEntityChangeSourceRegistry`. The folded,
|
|
28
|
+
entity-keyed registry (`<SURFACE>_ENTITY_SOURCES`) is now the **surface
|
|
29
|
+
module's** concern: the surface aggregator folds every provider's
|
|
30
|
+
`changeSources` into it, and entity-agnostic consumers read it at runtime. This
|
|
31
|
+
drops a vestigial registry injection from the adapter (it was read by nothing
|
|
32
|
+
and formed a latent DI cycle — RFC-0002 §3 E0), making the adapter
|
|
33
|
+
standalone-importable. The four surface packages bump to **0.2.0**; their peer
|
|
34
|
+
dep on `@pattern-stack/codegen` moves to **^0.13.0**. Conformance helpers
|
|
35
|
+
(`assert<Surface>Adapter`) check `changeSources` membership accordingly.
|
|
36
|
+
|
|
37
|
+
### Added
|
|
38
|
+
|
|
39
|
+
- **Integration module assembly emission (RFC-0002).** Per `(surface, provider,
|
|
40
|
+
entity-with-surface)`, codegen now emits the assembly that turns a registry of
|
|
41
|
+
change sources into a runnable integration per entity:
|
|
42
|
+
- `<surface>/modules/<provider>/<entity>-integration.module.ts` — `@generated`
|
|
43
|
+
per-entity feature module binding `INTEGRATION_CHANGE_SOURCE`
|
|
44
|
+
(= `adapter.changeSources['<entity>']`, Option A) + `INTEGRATION_SINK`, a
|
|
45
|
+
local `ExecuteIntegrationUseCase`, and a uniquely-tokened handle
|
|
46
|
+
(`<ENTITY>_INTEGRATION_USE_CASE__<PROVIDER>`) a trigger can grab.
|
|
47
|
+
- `<surface>/sinks/<entity>.sink.ts` — emit-once **default sink** scaffold
|
|
48
|
+
(`// <CODEGEN-SCAFFOLD-V1>`) over the entity's generated `Integrated`
|
|
49
|
+
repository (`pattern: Integrated` only — hard-errors otherwise); author fills
|
|
50
|
+
any non-generic `canonical ↔ local` mapping.
|
|
51
|
+
- `<surface>/<surface>-integration.module.ts` — `@generated` aggregator over
|
|
52
|
+
the per-entity modules.
|
|
53
|
+
- `<surface>/<surface>-integration.tokens.ts` — `@generated` use-case tokens.
|
|
54
|
+
- **`IncrementalRead` read primitive (RFC-0003).** A universal read capability
|
|
55
|
+
(`IncrementalRead<T, F>` / `RandomRead<T>` / `IncrementalReadBase` +
|
|
56
|
+
`SourcedRecord` / `Ref` / `ReadMode` / `ReadRequest` / `mapConcurrent`) in
|
|
57
|
+
`runtime/subsystems/integration/`, exported from
|
|
58
|
+
`@pattern-stack/codegen/subsystems`. The base decomposes the read into
|
|
59
|
+
`enumerate(mode, filter) → AsyncIterable<Ref>` (cheap delta/backfill walk) and
|
|
60
|
+
`hydrate(ids) → Map<id, raw>` (batched fetch-by-id), and owns the orchestration
|
|
61
|
+
(drain, **filter-before-hydrate**, bounded-concurrency hydrate, per-ref cursor
|
|
62
|
+
emission, `listChanges` adaptation). Cursor divisibility is kind-keyed
|
|
63
|
+
(`CURSOR_DIVISIBILITY` / `isDivisibleCursor`); atomic strategies (`historyId` /
|
|
64
|
+
`syncToken`) withhold the per-ref cursor until a safe boundary so an
|
|
65
|
+
interrupted backfill never persists an unresumable token.
|
|
66
|
+
- **Read-side scaffold reshape.** For interaction surfaces (mail / calendar /
|
|
67
|
+
transcript), `generateAdapterScaffold` now emits each `changeSources` entry as
|
|
68
|
+
an emit-once `IncrementalReadBase<Canonical<Entity>, ResolvedFilter[]>`
|
|
69
|
+
subclass — the buffer-all/serial/run-final-cursor regression becomes
|
|
70
|
+
structurally unwritable. CRM keeps its author-filled `changeSources` seam
|
|
71
|
+
(field-reader model, no single canonical `T`).
|
|
72
|
+
|
|
7
73
|
## [0.12.2] — 2026-05-31
|
|
8
74
|
|
|
9
75
|
Track D consumer-CLI fix. The 0.12.0/0.12.1 generator was correct in the
|
package/README.md
CHANGED
|
@@ -138,6 +138,50 @@ modules/{plural}/
|
|
|
138
138
|
use-cases/ FindById, List, declarative queries
|
|
139
139
|
```
|
|
140
140
|
|
|
141
|
+
## Integration Codegen (provider/adapter + assembly + read primitive)
|
|
142
|
+
|
|
143
|
+
When an entity carries a `surface:` tag and `definitions/providers/*.yaml` exist,
|
|
144
|
+
re-running `codegen entity new` emits the **full** integration layer for each
|
|
145
|
+
`(surface, provider, entity)` — not just the read side. The author fills only the
|
|
146
|
+
irreducible vendor seam: the `enumerate` / `hydrate` / `toCanonical` read methods
|
|
147
|
+
and any non-generic sink write logic.
|
|
148
|
+
|
|
149
|
+
**Read side** (provider/adapter — RFC-0001):
|
|
150
|
+
```
|
|
151
|
+
integrations/providers/<provider>/ Auth strategy + client (provider module)
|
|
152
|
+
integrations/<surface>/adapters/<provider>/ Adapter scaffold: changeSources container
|
|
153
|
+
integrations/<surface>/<surface>-adapters.module.ts Aggregator → <SURFACE>_ENTITY_SOURCES registry
|
|
154
|
+
integrations/<surface>/types.generated.ts Typed views
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
The adapter *contributes* `changeSources` (per-entity, keyed by entity name); the
|
|
158
|
+
aggregator folds every provider's contributions into the entity-keyed
|
|
159
|
+
`<SURFACE>_ENTITY_SOURCES` registry consumers read at runtime.
|
|
160
|
+
|
|
161
|
+
**Read primitive** (RFC-0003): for interaction surfaces (mail / calendar /
|
|
162
|
+
transcript) each `changeSources` entry is emitted as an emit-once
|
|
163
|
+
`IncrementalReadBase<Canonical<Entity>, ResolvedFilter[]>` subclass — the
|
|
164
|
+
enumerate/hydrate read capability (`@pattern-stack/codegen/subsystems`). The base
|
|
165
|
+
owns streaming, **filter-before-hydrate**, bounded-concurrency hydration, and
|
|
166
|
+
per-ref cursor emission, so the buffer-all/serial/run-final-cursor regression is
|
|
167
|
+
structurally unwritable; the author fills only `enumerate` / `hydrate` /
|
|
168
|
+
`toCanonical`.
|
|
169
|
+
|
|
170
|
+
**Write/run side** (assembly — RFC-0002):
|
|
171
|
+
```
|
|
172
|
+
integrations/<surface>/modules/<provider>/<entity>-integration.module.ts @generated per-entity assembly
|
|
173
|
+
integrations/<surface>/sinks/<entity>.sink.ts emit-once default sink scaffold
|
|
174
|
+
integrations/<surface>/<surface>-integration.module.ts @generated aggregator
|
|
175
|
+
integrations/<surface>/<surface>-integration.tokens.ts @generated use-case tokens
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
Each per-entity module binds `INTEGRATION_CHANGE_SOURCE`
|
|
179
|
+
(= `adapter.changeSources['<entity>']`) + `INTEGRATION_SINK`, provides a local
|
|
180
|
+
`ExecuteIntegrationUseCase`, and exports a uniquely-tokened handle
|
|
181
|
+
(`<ENTITY>_INTEGRATION_USE_CASE__<PROVIDER>`) a trigger grabs to run a sync. The
|
|
182
|
+
default sink scaffolds over the entity's generated `Integrated` repository
|
|
183
|
+
(`pattern: Integrated` only); the author overrides any non-generic write logic.
|
|
184
|
+
|
|
141
185
|
## Entity Families
|
|
142
186
|
|
|
143
187
|
Families provide pre-built base classes with domain-specific query patterns:
|
|
@@ -19,12 +19,16 @@ export { IObservability } from './observability/observability.protocol.js';
|
|
|
19
19
|
export { OBSERVABILITY, OBSERVABILITY_MODULE_OPTIONS } from './observability/observability.tokens.js';
|
|
20
20
|
export { ObservabilityModule, ObservabilityModuleOptions } from './observability/observability.module.js';
|
|
21
21
|
export { ObservabilityError } from './observability/observability-errors.js';
|
|
22
|
-
export { IChangeSource } from './integration/integration-change-source.protocol.js';
|
|
22
|
+
export { IChangeSource, IntegrationSubscriptionView } from './integration/integration-change-source.protocol.js';
|
|
23
23
|
export { CursorSnapshot } from './integration/integration-cursor-store.protocol.js';
|
|
24
|
+
export { IIntegrationSink } from './integration/integration-sink.protocol.js';
|
|
24
25
|
export { IntegrationRunSummary } from './integration/integration-run-recorder.protocol.js';
|
|
25
26
|
export { IEntityChangeSourceRegistry, UnknownEntityError } from './integration/entity-change-source-registry.protocol.js';
|
|
26
27
|
export { MemoryEntityChangeSourceRegistry } from './integration/entity-change-source-registry.memory.js';
|
|
27
|
-
export {
|
|
28
|
+
export { CURSOR_DIVISIBILITY, ResolvedFilter, isDivisibleCursor } from './integration/detection-config.schema.js';
|
|
29
|
+
export { IncrementalRead, IncrementalReadBase, RandomRead, ReadMode, ReadRequest, Ref, SourcedRecord, mapConcurrent } from './integration/incremental-read.js';
|
|
30
|
+
export { ENTITY_CHANGE_SOURCE_REGISTRY, INTEGRATION_CHANGE_SOURCE, INTEGRATION_SINK } from './integration/integration.tokens.js';
|
|
31
|
+
export { ExecuteIntegrationUseCase } from './integration/execute-integration.use-case.js';
|
|
28
32
|
export { AuthCredentials, AuthResolveOptions, IAuthStrategy } from './auth/protocols/auth-strategy.js';
|
|
29
33
|
export { IEncryptionKey } from './auth/protocols/encryption-key.js';
|
|
30
34
|
export { IOAuthStateStore, OAuthStateError, OAuthStateRecord } from './auth/protocols/oauth-state-store.js';
|
|
@@ -4360,12 +4360,33 @@ var EventIdCursorSchema = z3.object({
|
|
|
4360
4360
|
kind: z3.literal("eventId"),
|
|
4361
4361
|
field: z3.string().min(1)
|
|
4362
4362
|
});
|
|
4363
|
+
var HistoryIdCursorSchema = z3.object({
|
|
4364
|
+
kind: z3.literal("historyId"),
|
|
4365
|
+
field: z3.string().min(1)
|
|
4366
|
+
});
|
|
4367
|
+
var SyncTokenCursorSchema = z3.object({
|
|
4368
|
+
kind: z3.literal("syncToken"),
|
|
4369
|
+
field: z3.string().min(1)
|
|
4370
|
+
});
|
|
4363
4371
|
var CursorStrategySchema = z3.discriminatedUnion("kind", [
|
|
4364
4372
|
SystemModstampCursorSchema,
|
|
4365
4373
|
ReplayIdCursorSchema,
|
|
4366
4374
|
TimestampCursorSchema,
|
|
4367
|
-
EventIdCursorSchema
|
|
4375
|
+
EventIdCursorSchema,
|
|
4376
|
+
HistoryIdCursorSchema,
|
|
4377
|
+
SyncTokenCursorSchema
|
|
4368
4378
|
]);
|
|
4379
|
+
var CURSOR_DIVISIBILITY = {
|
|
4380
|
+
systemModstamp: true,
|
|
4381
|
+
timestamp: true,
|
|
4382
|
+
replayId: true,
|
|
4383
|
+
eventId: false,
|
|
4384
|
+
historyId: false,
|
|
4385
|
+
syncToken: false
|
|
4386
|
+
};
|
|
4387
|
+
function isDivisibleCursor(kind) {
|
|
4388
|
+
return CURSOR_DIVISIBILITY[kind];
|
|
4389
|
+
}
|
|
4369
4390
|
var PollDetectionSchema = z3.object({
|
|
4370
4391
|
cursor: CursorStrategySchema,
|
|
4371
4392
|
provenance: z3.enum(["poll", "cdc"]).optional()
|
|
@@ -4390,6 +4411,148 @@ var DetectionConfigSchema = z3.discriminatedUnion("mode", [
|
|
|
4390
4411
|
WebhookModeSchema
|
|
4391
4412
|
]);
|
|
4392
4413
|
|
|
4414
|
+
// runtime/subsystems/integration/incremental-read.ts
|
|
4415
|
+
async function mapConcurrent(ids, fn, limit) {
|
|
4416
|
+
const out = /* @__PURE__ */ new Map();
|
|
4417
|
+
if (ids.length === 0) return out;
|
|
4418
|
+
const width = Math.max(1, Math.min(limit, ids.length));
|
|
4419
|
+
let next = 0;
|
|
4420
|
+
const worker = async () => {
|
|
4421
|
+
while (next < ids.length) {
|
|
4422
|
+
const idx = next++;
|
|
4423
|
+
const id = ids[idx];
|
|
4424
|
+
out.set(id, await fn(id));
|
|
4425
|
+
}
|
|
4426
|
+
};
|
|
4427
|
+
await Promise.all(Array.from({ length: width }, worker));
|
|
4428
|
+
return out;
|
|
4429
|
+
}
|
|
4430
|
+
var IncrementalReadBase = class {
|
|
4431
|
+
/**
|
|
4432
|
+
* Whether the vendor takes the request predicate server-side. Declared, not
|
|
4433
|
+
* enforced here — surfaced into the emission manifest (R3) so the falsifier
|
|
4434
|
+
* suite (R4) can record which adapters filter post-hydrate. `false` is the
|
|
4435
|
+
* honest floor (e.g. Gmail without `q=`), handled via `matchesRecord`.
|
|
4436
|
+
*/
|
|
4437
|
+
filterPushdown = false;
|
|
4438
|
+
/** Max concurrent in-flight calls for a `mapConcurrent`-built `hydrate`. */
|
|
4439
|
+
hydrateConcurrency = 10;
|
|
4440
|
+
/** `Change<T>.source` provenance stamped by `listChanges`. */
|
|
4441
|
+
changeSource = "poll";
|
|
4442
|
+
/**
|
|
4443
|
+
* Whether this source's cursor strategy is divisible (RFC-0003 §3). When
|
|
4444
|
+
* `true` (default — sortable watermarks like `systemModstamp`/`timestamp`/
|
|
4445
|
+
* `replayId`), `listChanges` emits each record's per-ref cursor, so the
|
|
4446
|
+
* orchestrator may checkpoint mid-walk and a crash resumes from the last
|
|
4447
|
+
* delivered ref.
|
|
4448
|
+
*
|
|
4449
|
+
* When `false` (atomic opaque tokens — Gmail `historyId`, Calendar
|
|
4450
|
+
* `syncToken`), `listChanges` WITHHOLDS per-ref cursors and emits the
|
|
4451
|
+
* end-of-walk token only on the final record, so the orchestrator's
|
|
4452
|
+
* persist-last-yielded lifecycle can never persist an unresumable mid-walk
|
|
4453
|
+
* token. The cost is blast-radius: an interrupted atomic run resumes
|
|
4454
|
+
* all-or-nothing from the prior persisted token. For atomic *backfills* that
|
|
4455
|
+
* radius is the whole enumerate walk — bound it with `ReadRequest.pageSize`
|
|
4456
|
+
* (smaller pages ⇒ shorter walks per run). Per-page atomic checkpointing is a
|
|
4457
|
+
* future refinement; R2 gates at end-of-walk.
|
|
4458
|
+
*
|
|
4459
|
+
* Codegen (R3) sets this from the strategy kind via `isDivisibleCursor`.
|
|
4460
|
+
*/
|
|
4461
|
+
cursorDivisible = true;
|
|
4462
|
+
// ---- Optional filter hooks — exactly one is live per `filterPushdown` ----
|
|
4463
|
+
/** Pre-hydrate predicate over the cheap ref (preferred — avoids hydration). */
|
|
4464
|
+
matchesRef(_ref, _filter) {
|
|
4465
|
+
return true;
|
|
4466
|
+
}
|
|
4467
|
+
/** Post-hydrate predicate over the canonical record (the no-pushdown floor). */
|
|
4468
|
+
matchesRecord(_record, _filter) {
|
|
4469
|
+
return true;
|
|
4470
|
+
}
|
|
4471
|
+
/**
|
|
4472
|
+
* Resolve the filter for a subscription when adapting to `listChanges`
|
|
4473
|
+
* (which has no filter argument). Defaults to none; codegen wiring (R3)
|
|
4474
|
+
* overrides this to thread `DetectionConfig.filters`.
|
|
4475
|
+
*/
|
|
4476
|
+
filterFor(_subscription) {
|
|
4477
|
+
return void 0;
|
|
4478
|
+
}
|
|
4479
|
+
// ---- PROVIDED by the base ----
|
|
4480
|
+
/**
|
|
4481
|
+
* Stream canonical records for a request. Filter is applied BEFORE hydrate
|
|
4482
|
+
* (structural: a kept ref is hydrated, a rejected one never is), so an
|
|
4483
|
+
* adapter cannot hydrate-then-discard. A hydrate miss (deleted mid-run) is
|
|
4484
|
+
* skipped, never fabricated.
|
|
4485
|
+
*/
|
|
4486
|
+
async *read(req) {
|
|
4487
|
+
for await (const refPage of this.enumerate(req.mode, req.filter, req.pageSize)) {
|
|
4488
|
+
const kept = refPage.filter((ref) => this.matchesRef(ref, req.filter));
|
|
4489
|
+
if (kept.length === 0) continue;
|
|
4490
|
+
const raws = await this.hydrate(kept.map((ref) => ref.externalId));
|
|
4491
|
+
for (const ref of kept) {
|
|
4492
|
+
const raw = raws.get(ref.externalId);
|
|
4493
|
+
if (raw === void 0 || raw === null) continue;
|
|
4494
|
+
const record = this.toCanonical(raw);
|
|
4495
|
+
if (record !== null && this.matchesRecord(record, req.filter)) {
|
|
4496
|
+
yield { externalId: ref.externalId, record, raw, cursor: ref.cursor };
|
|
4497
|
+
}
|
|
4498
|
+
}
|
|
4499
|
+
}
|
|
4500
|
+
}
|
|
4501
|
+
/**
|
|
4502
|
+
* `RandomRead<T>` — single-record read, provided for free as
|
|
4503
|
+
* `toCanonical ∘ hydrate([id])`. Reuses the adapter's batched fetch + miss
|
|
4504
|
+
* tolerance; returns `null` for a missing or undecodable record.
|
|
4505
|
+
*/
|
|
4506
|
+
async get(id) {
|
|
4507
|
+
const raws = await this.hydrate([id]);
|
|
4508
|
+
const raw = raws.get(id);
|
|
4509
|
+
if (raw === void 0 || raw === null) return null;
|
|
4510
|
+
return this.toCanonical(raw);
|
|
4511
|
+
}
|
|
4512
|
+
/**
|
|
4513
|
+
* `IChangeSource<T>` adaptation. Maps the orchestrator's by-value cursor to a
|
|
4514
|
+
* `ReadMode` (`null` → `full` backfill, else `delta`), streams `read()`, and
|
|
4515
|
+
* stamps each `SourcedRecord` into a `Change<T>`. All records surface as
|
|
4516
|
+
* `'updated'`; the orchestrator's diff stage classifies create-vs-update and
|
|
4517
|
+
* deletes arrive as tombstone refs (`toCanonical` may flag them).
|
|
4518
|
+
*
|
|
4519
|
+
* Cursor emission honors `cursorDivisible` (RFC-0003 §3). Divisible: each
|
|
4520
|
+
* record carries its own per-ref cursor. Atomic: per-ref cursors are withheld
|
|
4521
|
+
* (`undefined`, which the orchestrator skips persisting) and the end-of-walk
|
|
4522
|
+
* token rides only on the final record — so a mid-walk crash never persists
|
|
4523
|
+
* an unresumable token. If an atomic run yields no surviving records, no
|
|
4524
|
+
* cursor is persisted and the next run re-reads the same (empty) delta — a
|
|
4525
|
+
* bounded inefficiency, never data loss.
|
|
4526
|
+
*/
|
|
4527
|
+
async *listChanges(subscription, cursor) {
|
|
4528
|
+
const mode = cursor === null || cursor === void 0 ? { kind: "full" } : { kind: "delta", cursor };
|
|
4529
|
+
const filter = this.filterFor(subscription);
|
|
4530
|
+
const stream = this.read({ mode, filter });
|
|
4531
|
+
if (this.cursorDivisible) {
|
|
4532
|
+
for await (const sourced of stream) {
|
|
4533
|
+
yield this.toChange(sourced, sourced.cursor);
|
|
4534
|
+
}
|
|
4535
|
+
return;
|
|
4536
|
+
}
|
|
4537
|
+
let prev = null;
|
|
4538
|
+
for await (const sourced of stream) {
|
|
4539
|
+
if (prev !== null) yield this.toChange(prev, void 0);
|
|
4540
|
+
prev = sourced;
|
|
4541
|
+
}
|
|
4542
|
+
if (prev !== null) yield this.toChange(prev, prev.cursor);
|
|
4543
|
+
}
|
|
4544
|
+
/** Stamp a `SourcedRecord` into a `Change<T>` with an explicit emitted cursor. */
|
|
4545
|
+
toChange(sourced, cursor) {
|
|
4546
|
+
return {
|
|
4547
|
+
externalId: sourced.externalId,
|
|
4548
|
+
operation: "updated",
|
|
4549
|
+
record: sourced.record,
|
|
4550
|
+
cursor,
|
|
4551
|
+
source: this.changeSource
|
|
4552
|
+
};
|
|
4553
|
+
}
|
|
4554
|
+
};
|
|
4555
|
+
|
|
4393
4556
|
// runtime/subsystems/integration/integration-errors.ts
|
|
4394
4557
|
var MissingTenantIdError3 = class extends Error {
|
|
4395
4558
|
name = "MissingTenantIdError";
|
|
@@ -5741,6 +5904,7 @@ export {
|
|
|
5741
5904
|
AuthController,
|
|
5742
5905
|
AuthModule,
|
|
5743
5906
|
CACHE,
|
|
5907
|
+
CURSOR_DIVISIBILITY,
|
|
5744
5908
|
CacheModule,
|
|
5745
5909
|
ConnectionBrokenError,
|
|
5746
5910
|
DrizzleCacheService,
|
|
@@ -5751,6 +5915,10 @@ export {
|
|
|
5751
5915
|
EVENT_BUS,
|
|
5752
5916
|
EnvEncryptionKey,
|
|
5753
5917
|
EventsModule,
|
|
5918
|
+
ExecuteIntegrationUseCase,
|
|
5919
|
+
INTEGRATION_CHANGE_SOURCE,
|
|
5920
|
+
INTEGRATION_SINK,
|
|
5921
|
+
IncrementalReadBase,
|
|
5754
5922
|
LocalStorageBackend,
|
|
5755
5923
|
MemoryCacheService,
|
|
5756
5924
|
MemoryEntityChangeSourceRegistry,
|
|
@@ -5771,6 +5939,7 @@ export {
|
|
|
5771
5939
|
UnknownEntityError,
|
|
5772
5940
|
authOAuthState,
|
|
5773
5941
|
collisionModeEnum,
|
|
5942
|
+
isDivisibleCursor,
|
|
5774
5943
|
isSessionExpiredError,
|
|
5775
5944
|
jobRunStatusEnum,
|
|
5776
5945
|
jobRuns,
|
|
@@ -5778,6 +5947,7 @@ export {
|
|
|
5778
5947
|
jobStepStatusEnum,
|
|
5779
5948
|
jobSteps,
|
|
5780
5949
|
jobs,
|
|
5950
|
+
mapConcurrent,
|
|
5781
5951
|
parentClosePolicyEnum,
|
|
5782
5952
|
replayFromEnum,
|
|
5783
5953
|
triggerSourceEnum,
|