@jini-ai/integrations 0.3.2 → 0.3.4

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.
@@ -0,0 +1,166 @@
1
+ /**
2
+ * `AsyncOperationStore` — the durable operation row behind submit-then-poll media generation.
3
+ *
4
+ * Why this exists alongside `task-store.ts`'s `MediaTaskStore`: they model different things and
5
+ * only one of them survives a restart usefully. `MediaTaskStore` is a *task tracker* — it records
6
+ * that a generation happened and its `reconcileOnBoot` deliberately marks every still-in-flight
7
+ * task `'interrupted'`, because a synchronous `fetch` that died with its process genuinely cannot
8
+ * be resumed. This store is the opposite case: a vendor-side job that is still running *on the
9
+ * vendor* after our process died, and whose result is still retrievable by polling. It therefore
10
+ * carries the four columns a poll loop needs and a task tracker does not — `attempts`,
11
+ * `nextPollAt`, a worker `lease`, and an absolute `deadlineAt` — and its `reconcileOnBoot`
12
+ * *releases* leases rather than terminating the work.
13
+ *
14
+ * Two independent bounds are mandatory, not redundant: `maxAttempts` catches a vendor that answers
15
+ * "pending" forever, and `deadlineAt` catches a vendor that stops answering at all. Neither one
16
+ * subsumes the other.
17
+ *
18
+ * `state` is the vendor's own resumption handle (a job id, a poll URL). It is deliberately
19
+ * validated on every write to reject credential material: the row outlives the process and is the
20
+ * one place a leaked key would become durable. Credentials are re-resolved per poll tick through
21
+ * the signer seam instead — see `polling-adapter.ts`.
22
+ */
23
+ /**
24
+ * `unknown` is a real terminal-ish state, not a failure: it means the operation may or may not
25
+ * have taken effect at the vendor and cannot be safely retried without an idempotency proof. It is
26
+ * reachable only from a crash gap or a blown deadline, and exists so those never masquerade as
27
+ * either success or a retryable failure.
28
+ */
29
+ export type AsyncOperationStatus = 'submitted' | 'polling' | 'succeeded' | 'failed' | 'unknown';
30
+ /**
31
+ * The persisted shape's version discriminator. Bumped whenever `AsyncOperationRecord`'s stored
32
+ * shape changes; `hydrateAsyncOperationRecord` branches on it so an old row is upgraded on read
33
+ * rather than rescued by a migration script.
34
+ *
35
+ * This is deliberately the same mechanism `ffb5ce44` used to close the AAD gap — a version column,
36
+ * a read path that branches on it, and an idempotent backfill only where one is actually needed —
37
+ * rather than a second migration playbook.
38
+ */
39
+ export declare const ASYNC_OPERATION_SCHEMA_VERSION = 1;
40
+ export declare const CREDENTIAL_IN_STATE_MESSAGE = "async operation state must never carry credential material \u2014 credentials are re-resolved per poll tick through the signer seam";
41
+ export interface AsyncOperationError {
42
+ readonly message: string;
43
+ readonly status?: number;
44
+ readonly code?: string;
45
+ }
46
+ /** The generated bytes, held base64-encoded so the row stays JSON-serializable for a durable adapter. */
47
+ export interface AsyncOperationResult {
48
+ readonly bytesBase64: string;
49
+ readonly providerNote: string;
50
+ readonly suggestedExt?: string;
51
+ }
52
+ export interface AsyncOperationRecord {
53
+ /** Shape discriminator — see `ASYNC_OPERATION_SCHEMA_VERSION`. Stamped once at create and never rewritten. */
54
+ readonly schemaVersion: number;
55
+ readonly id: string;
56
+ readonly providerId: string;
57
+ readonly routeKey: string;
58
+ /** Opaque host-supplied scoping key (a run id, a workspace id) — never a domain noun this package knows. */
59
+ readonly ownerRef: string;
60
+ readonly status: AsyncOperationStatus;
61
+ readonly attempts: number;
62
+ /** Bound 1: caps a vendor that answers "pending" forever. */
63
+ readonly maxAttempts: number;
64
+ /** Absolute epoch ms after which this operation may not be polled again. Bound 2: caps a vendor that stops answering. */
65
+ readonly deadlineAt: number;
66
+ readonly nextPollAt: number;
67
+ readonly leaseOwner: string | null;
68
+ readonly leaseExpiresAt: number | null;
69
+ /** The vendor's resumption handle. Never credential material — see `CREDENTIAL_IN_STATE_MESSAGE`. */
70
+ readonly state: Readonly<Record<string, unknown>> | null;
71
+ readonly result: AsyncOperationResult | null;
72
+ readonly error: AsyncOperationError | null;
73
+ readonly createdAt: number;
74
+ readonly updatedAt: number;
75
+ }
76
+ export interface AsyncOperationCreateInput {
77
+ readonly id: string;
78
+ readonly providerId: string;
79
+ readonly routeKey: string;
80
+ readonly ownerRef: string;
81
+ readonly maxAttempts: number;
82
+ readonly deadlineAt: number;
83
+ readonly nextPollAt?: number;
84
+ readonly status?: AsyncOperationStatus;
85
+ readonly state?: Readonly<Record<string, unknown>> | null;
86
+ }
87
+ export interface AsyncOperationPatch {
88
+ readonly status?: AsyncOperationStatus;
89
+ readonly attempts?: number;
90
+ readonly nextPollAt?: number;
91
+ readonly state?: Readonly<Record<string, unknown>> | null;
92
+ readonly result?: AsyncOperationResult | null;
93
+ readonly error?: AsyncOperationError | null;
94
+ readonly leaseOwner?: string | null;
95
+ readonly leaseExpiresAt?: number | null;
96
+ }
97
+ export interface AsyncOperationClaimOptions {
98
+ readonly now: number;
99
+ readonly leaseOwner: string;
100
+ readonly leaseMs: number;
101
+ readonly limit?: number;
102
+ }
103
+ export interface AsyncOperationReconcileResult {
104
+ /** Rows whose worker died holding a lease — released for another worker, status untouched. */
105
+ readonly leasesReleased: number;
106
+ /** Rows that blew their absolute deadline while unattended — moved to `unknown`, never to `failed`. */
107
+ readonly deadlineExpired: number;
108
+ }
109
+ export interface AsyncOperationStore {
110
+ create(input: AsyncOperationCreateInput): Promise<AsyncOperationRecord>;
111
+ get(id: string): Promise<AsyncOperationRecord | null>;
112
+ update(id: string, patch: AsyncOperationPatch): Promise<AsyncOperationRecord | null>;
113
+ listByOwner(ownerRef: string): Promise<AsyncOperationRecord[]>;
114
+ /** Atomically leases every due, unleased, non-terminal operation and returns the leased rows. */
115
+ claimDue(options: AsyncOperationClaimOptions): Promise<AsyncOperationRecord[]>;
116
+ /**
117
+ * Releases a lease this caller believes it holds. Fenced on `leaseOwner`: a release only takes
118
+ * effect while the row's current `leaseOwner` still equals the one passed here (the equivalent
119
+ * SQL is a conditional `UPDATE ... WHERE id = ? AND lease_owner = ?`). Without this fence, a
120
+ * worker that outlives its own lease (e.g. a slow poll past `leaseMs`) can clear whichever
121
+ * worker legitimately reclaimed the row after it expired, breaking the single-worker guarantee
122
+ * `claimDue` exists to provide. A release for a row the caller no longer owns — because it
123
+ * never claimed it, or another worker has since reclaimed it — is a no-op, not an error: the
124
+ * caller's intent ("I'm done, let someone else have it") is already satisfied either way.
125
+ */
126
+ releaseLease(id: string, leaseOwner: string): Promise<void>;
127
+ /**
128
+ * Boot-time recovery. Unlike `MediaTaskStore.reconcileOnBoot`, this does NOT terminate in-flight
129
+ * work: a vendor-side job outlives our process, so the row stays pollable and only its dead
130
+ * lease is cleared. Rows already past their absolute deadline go to `unknown` — never `failed`,
131
+ * because an unattended deadline says nothing about whether the vendor did the work.
132
+ */
133
+ reconcileOnBoot(options: {
134
+ now: number;
135
+ }): Promise<AsyncOperationReconcileResult>;
136
+ }
137
+ /**
138
+ * Rejects anything in an operation `state` object outside the resumption-handle allowlist —
139
+ * which, as a consequence, rejects credential material regardless of what key name it arrives
140
+ * under (see `ALLOWED_STATE_KEYS`).
141
+ *
142
+ * @throws `Error` (message starts with `CREDENTIAL_IN_STATE_MESSAGE`, naming the offending key)
143
+ * when any key at any depth is not in `ALLOWED_STATE_KEYS`.
144
+ * @complexity O(n) in the total number of keys, bounded by `MAX_STATE_DEPTH` against a cyclic or
145
+ * pathologically nested object.
146
+ */
147
+ export declare function assertNoCredentialMaterial(state: Readonly<Record<string, unknown>> | null | undefined): void;
148
+ /**
149
+ * The branching read path for a persisted operation row.
150
+ *
151
+ * A durable adapter calls this on every row it loads. A row with no discriminator predates
152
+ * versioning (v0) and is upgraded in place on read; a row from a newer build is refused loudly
153
+ * rather than misread, because silently reinterpreting an unknown shape is how a stored operation
154
+ * becomes a duplicate vendor charge.
155
+ *
156
+ * @throws When `schemaVersion` is newer than this build understands.
157
+ * @complexity O(1).
158
+ */
159
+ export declare function hydrateAsyncOperationRecord(raw: Record<string, unknown>): AsyncOperationRecord;
160
+ /**
161
+ * Creates the in-memory reference `AsyncOperationStore`. No persistence — a durable adapter
162
+ * implements the same interface; every method here is written so the equivalent SQL is a direct
163
+ * translation (`claimDue` in particular is a single conditional UPDATE ... RETURNING).
164
+ */
165
+ export declare function createInMemoryAsyncOperationStore(): AsyncOperationStore;
166
+ //# sourceMappingURL=async-operation-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"async-operation-store.d.ts","sourceRoot":"","sources":["../../../src/media-providers/dispatch/async-operation-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH;;;;;GAKG;AACH,MAAM,MAAM,oBAAoB,GAAG,WAAW,GAAG,SAAS,GAAG,WAAW,GAAG,QAAQ,GAAG,SAAS,CAAC;AAEhG;;;;;;;;GAQG;AACH,eAAO,MAAM,8BAA8B,IAAI,CAAC;AA6BhD,eAAO,MAAM,2BAA2B,wIAC0F,CAAC;AAEnI,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,yGAAyG;AACzG,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;CAChC;AAED,MAAM,WAAW,oBAAoB;IACnC,8GAA8G;IAC9G,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,4GAA4G;IAC5G,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,oBAAoB,CAAC;IACtC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,6DAA6D;IAC7D,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,yHAAyH;IACzH,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,QAAQ,CAAC,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IACvC,qGAAqG;IACrG,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC;IACzD,QAAQ,CAAC,MAAM,EAAE,oBAAoB,GAAG,IAAI,CAAC;IAC7C,QAAQ,CAAC,KAAK,EAAE,mBAAmB,GAAG,IAAI,CAAC;IAC3C,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,yBAAyB;IACxC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,MAAM,CAAC,EAAE,oBAAoB,CAAC;IACvC,QAAQ,CAAC,KAAK,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC;CAC3D;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,MAAM,CAAC,EAAE,oBAAoB,CAAC;IACvC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,KAAK,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC;IAC1D,QAAQ,CAAC,MAAM,CAAC,EAAE,oBAAoB,GAAG,IAAI,CAAC;IAC9C,QAAQ,CAAC,KAAK,CAAC,EAAE,mBAAmB,GAAG,IAAI,CAAC;IAC5C,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACzC;AAED,MAAM,WAAW,0BAA0B;IACzC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,6BAA6B;IAC5C,8FAA8F;IAC9F,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,uGAAuG;IACvG,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;CAClC;AAED,MAAM,WAAW,mBAAmB;IAClC,MAAM,CAAC,KAAK,EAAE,yBAAyB,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAAC;IACxE,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC,CAAC;IACtD,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,mBAAmB,GAAG,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC,CAAC;IACrF,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,EAAE,CAAC,CAAC;IAC/D,iGAAiG;IACjG,QAAQ,CAAC,OAAO,EAAE,0BAA0B,GAAG,OAAO,CAAC,oBAAoB,EAAE,CAAC,CAAC;IAC/E;;;;;;;;;OASG;IACH,YAAY,CAAC,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5D;;;;;OAKG;IACH,eAAe,CAAC,OAAO,EAAE;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,6BAA6B,CAAC,CAAC;CACnF;AAED;;;;;;;;;GASG;AACH,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,IAAI,GAAG,SAAS,GAAG,IAAI,CAqB5G;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,2BAA2B,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,oBAAoB,CA6B9F;AAoBD;;;;GAIG;AACH,wBAAgB,iCAAiC,IAAI,mBAAmB,CAiJvE"}
@@ -0,0 +1,291 @@
1
+ /**
2
+ * `AsyncOperationStore` — the durable operation row behind submit-then-poll media generation.
3
+ *
4
+ * Why this exists alongside `task-store.ts`'s `MediaTaskStore`: they model different things and
5
+ * only one of them survives a restart usefully. `MediaTaskStore` is a *task tracker* — it records
6
+ * that a generation happened and its `reconcileOnBoot` deliberately marks every still-in-flight
7
+ * task `'interrupted'`, because a synchronous `fetch` that died with its process genuinely cannot
8
+ * be resumed. This store is the opposite case: a vendor-side job that is still running *on the
9
+ * vendor* after our process died, and whose result is still retrievable by polling. It therefore
10
+ * carries the four columns a poll loop needs and a task tracker does not — `attempts`,
11
+ * `nextPollAt`, a worker `lease`, and an absolute `deadlineAt` — and its `reconcileOnBoot`
12
+ * *releases* leases rather than terminating the work.
13
+ *
14
+ * Two independent bounds are mandatory, not redundant: `maxAttempts` catches a vendor that answers
15
+ * "pending" forever, and `deadlineAt` catches a vendor that stops answering at all. Neither one
16
+ * subsumes the other.
17
+ *
18
+ * `state` is the vendor's own resumption handle (a job id, a poll URL). It is deliberately
19
+ * validated on every write to reject credential material: the row outlives the process and is the
20
+ * one place a leaked key would become durable. Credentials are re-resolved per poll tick through
21
+ * the signer seam instead — see `polling-adapter.ts`.
22
+ */
23
+ /**
24
+ * The persisted shape's version discriminator. Bumped whenever `AsyncOperationRecord`'s stored
25
+ * shape changes; `hydrateAsyncOperationRecord` branches on it so an old row is upgraded on read
26
+ * rather than rescued by a migration script.
27
+ *
28
+ * This is deliberately the same mechanism `ffb5ce44` used to close the AAD gap — a version column,
29
+ * a read path that branches on it, and an idempotent backfill only where one is actually needed —
30
+ * rather than a second migration playbook.
31
+ */
32
+ export const ASYNC_OPERATION_SCHEMA_VERSION = 1;
33
+ const TERMINAL_STATUSES = new Set(['succeeded', 'failed', 'unknown']);
34
+ const ALLOWED_TRANSITIONS = {
35
+ submitted: new Set(['submitted', 'polling', 'succeeded', 'failed', 'unknown']),
36
+ polling: new Set(['polling', 'succeeded', 'failed', 'unknown']),
37
+ succeeded: new Set(['succeeded']),
38
+ failed: new Set(['failed']),
39
+ unknown: new Set(['unknown']),
40
+ };
41
+ /**
42
+ * The complete set of key names an operation `state` object may carry, at any depth — this
43
+ * package's own `PollingVendorAdapter`s' resumption handles (currently only `jobId`; see
44
+ * `providers/imagerouter-video-async.ts`), never anything a `RequestSigner` needs.
45
+ *
46
+ * This is deliberately an allowlist, not a denylist. A denylist of "known credential-shaped
47
+ * names" was tried first (`apiKey`, `authorization`, `secret`, ...) and it missed `clientSecret` /
48
+ * `client_secret` on the very first adapter shape that could plausibly return one — and it can
49
+ * never be complete, because the set of names a vendor's response body (and the adapter written
50
+ * against it) might use for a credential is unbounded and outside this package's control. An
51
+ * allowlist inverts the failure mode: it fails *closed*. A legitimate new field an adapter starts
52
+ * returning is a loud registration error here — extend this set, deliberately, one entry at a
53
+ * time — never a silent path for a secret to become durable under a name this file never
54
+ * anticipated.
55
+ */
56
+ const ALLOWED_STATE_KEYS = new Set(['jobId']);
57
+ export const CREDENTIAL_IN_STATE_MESSAGE = 'async operation state must never carry credential material — credentials are re-resolved per poll tick through the signer seam';
58
+ /**
59
+ * Rejects anything in an operation `state` object outside the resumption-handle allowlist —
60
+ * which, as a consequence, rejects credential material regardless of what key name it arrives
61
+ * under (see `ALLOWED_STATE_KEYS`).
62
+ *
63
+ * @throws `Error` (message starts with `CREDENTIAL_IN_STATE_MESSAGE`, naming the offending key)
64
+ * when any key at any depth is not in `ALLOWED_STATE_KEYS`.
65
+ * @complexity O(n) in the total number of keys, bounded by `MAX_STATE_DEPTH` against a cyclic or
66
+ * pathologically nested object.
67
+ */
68
+ export function assertNoCredentialMaterial(state) {
69
+ if (state == null)
70
+ return;
71
+ const seen = new Set();
72
+ const walk = (value, depth) => {
73
+ if (depth > 12 || value === null || typeof value !== 'object')
74
+ return;
75
+ if (seen.has(value))
76
+ return;
77
+ seen.add(value);
78
+ if (Array.isArray(value)) {
79
+ for (const entry of value)
80
+ walk(entry, depth + 1);
81
+ return;
82
+ }
83
+ for (const [key, entry] of Object.entries(value)) {
84
+ if (!ALLOWED_STATE_KEYS.has(key)) {
85
+ throw new Error(`${CREDENTIAL_IN_STATE_MESSAGE} (key "${key}" is not in the resumption-handle allowlist — add it there if it is genuinely not credential material)`);
86
+ }
87
+ walk(entry, depth + 1);
88
+ }
89
+ };
90
+ walk(state, 0);
91
+ }
92
+ /**
93
+ * The branching read path for a persisted operation row.
94
+ *
95
+ * A durable adapter calls this on every row it loads. A row with no discriminator predates
96
+ * versioning (v0) and is upgraded in place on read; a row from a newer build is refused loudly
97
+ * rather than misread, because silently reinterpreting an unknown shape is how a stored operation
98
+ * becomes a duplicate vendor charge.
99
+ *
100
+ * @throws When `schemaVersion` is newer than this build understands.
101
+ * @complexity O(1).
102
+ */
103
+ export function hydrateAsyncOperationRecord(raw) {
104
+ const stored = typeof raw.schemaVersion === 'number' ? raw.schemaVersion : 0;
105
+ if (stored > ASYNC_OPERATION_SCHEMA_VERSION) {
106
+ throw new Error(`async operation row was written at schema version ${stored}, newer than this build understands (${ASYNC_OPERATION_SCHEMA_VERSION}) — upgrade rather than risk misreading it`);
107
+ }
108
+ // v0 -> v1 added only the discriminator itself, so the upgrade is a stamp. A later version adds
109
+ // its own branch here; the row is never rewritten on disk just to be readable.
110
+ const now = Date.now();
111
+ return {
112
+ schemaVersion: ASYNC_OPERATION_SCHEMA_VERSION,
113
+ id: String(raw.id),
114
+ providerId: String(raw.providerId),
115
+ routeKey: String(raw.routeKey),
116
+ ownerRef: String(raw.ownerRef),
117
+ status: raw.status ?? 'submitted',
118
+ attempts: typeof raw.attempts === 'number' ? raw.attempts : 0,
119
+ maxAttempts: Number(raw.maxAttempts),
120
+ deadlineAt: Number(raw.deadlineAt),
121
+ nextPollAt: typeof raw.nextPollAt === 'number' ? raw.nextPollAt : now,
122
+ leaseOwner: raw.leaseOwner ?? null,
123
+ leaseExpiresAt: raw.leaseExpiresAt ?? null,
124
+ state: raw.state ?? null,
125
+ result: raw.result ?? null,
126
+ error: raw.error ?? null,
127
+ createdAt: typeof raw.createdAt === 'number' ? raw.createdAt : now,
128
+ updatedAt: typeof raw.updatedAt === 'number' ? raw.updatedAt : now,
129
+ };
130
+ }
131
+ function cloneRecord(row) {
132
+ return {
133
+ ...row,
134
+ state: row.state === null ? null : structuredClone(row.state),
135
+ result: row.result === null ? null : { ...row.result },
136
+ error: row.error === null ? null : { ...row.error },
137
+ };
138
+ }
139
+ function assertTransition(from, to) {
140
+ if (!ALLOWED_TRANSITIONS[from]) {
141
+ throw new RangeError(`Invalid async operation status: "${from}"`);
142
+ }
143
+ if (!ALLOWED_TRANSITIONS[from].has(to)) {
144
+ throw new RangeError(`Invalid async operation transition: "${from}" -> "${to}"`);
145
+ }
146
+ }
147
+ /**
148
+ * Creates the in-memory reference `AsyncOperationStore`. No persistence — a durable adapter
149
+ * implements the same interface; every method here is written so the equivalent SQL is a direct
150
+ * translation (`claimDue` in particular is a single conditional UPDATE ... RETURNING).
151
+ */
152
+ export function createInMemoryAsyncOperationStore() {
153
+ const rows = new Map();
154
+ const requireRow = (id) => rows.get(id);
155
+ return {
156
+ async create(input) {
157
+ if (rows.has(input.id)) {
158
+ throw new Error(`async operation "${input.id}" already exists`);
159
+ }
160
+ if (!Number.isFinite(input.maxAttempts) || input.maxAttempts < 1) {
161
+ throw new RangeError(`Invalid maxAttempts: ${input.maxAttempts} must be a finite number >= 1`);
162
+ }
163
+ if (!Number.isFinite(input.deadlineAt)) {
164
+ throw new RangeError(`Invalid deadlineAt: ${input.deadlineAt} must be a finite epoch-ms timestamp`);
165
+ }
166
+ assertNoCredentialMaterial(input.state);
167
+ const now = Date.now();
168
+ const row = {
169
+ schemaVersion: ASYNC_OPERATION_SCHEMA_VERSION,
170
+ id: input.id,
171
+ providerId: input.providerId,
172
+ routeKey: input.routeKey,
173
+ ownerRef: input.ownerRef,
174
+ status: input.status ?? 'submitted',
175
+ attempts: 0,
176
+ maxAttempts: input.maxAttempts,
177
+ deadlineAt: input.deadlineAt,
178
+ nextPollAt: input.nextPollAt ?? now,
179
+ leaseOwner: null,
180
+ leaseExpiresAt: null,
181
+ state: input.state === undefined || input.state === null ? null : structuredClone(input.state),
182
+ result: null,
183
+ error: null,
184
+ createdAt: now,
185
+ updatedAt: now,
186
+ };
187
+ rows.set(row.id, row);
188
+ return cloneRecord(row);
189
+ },
190
+ async get(id) {
191
+ const row = requireRow(id);
192
+ return row ? cloneRecord(row) : null;
193
+ },
194
+ async update(id, patch) {
195
+ const existing = requireRow(id);
196
+ if (!existing)
197
+ return null;
198
+ if ('state' in patch)
199
+ assertNoCredentialMaterial(patch.state);
200
+ const status = patch.status ?? existing.status;
201
+ assertTransition(existing.status, status);
202
+ const next = {
203
+ ...existing,
204
+ schemaVersion: existing.schemaVersion,
205
+ status,
206
+ attempts: patch.attempts ?? existing.attempts,
207
+ nextPollAt: patch.nextPollAt ?? existing.nextPollAt,
208
+ state: 'state' in patch ? (patch.state == null ? null : structuredClone(patch.state)) : existing.state,
209
+ result: 'result' in patch ? (patch.result ?? null) : existing.result,
210
+ error: 'error' in patch ? (patch.error ?? null) : existing.error,
211
+ leaseOwner: 'leaseOwner' in patch ? (patch.leaseOwner ?? null) : existing.leaseOwner,
212
+ leaseExpiresAt: 'leaseExpiresAt' in patch ? (patch.leaseExpiresAt ?? null) : existing.leaseExpiresAt,
213
+ updatedAt: Date.now(),
214
+ };
215
+ rows.set(id, next);
216
+ return cloneRecord(next);
217
+ },
218
+ async listByOwner(ownerRef) {
219
+ return [...rows.values()]
220
+ .filter((row) => row.ownerRef === ownerRef)
221
+ .sort((a, b) => a.createdAt - b.createdAt)
222
+ .map(cloneRecord);
223
+ },
224
+ async claimDue(options) {
225
+ const { now, leaseOwner, leaseMs } = options;
226
+ const limit = options.limit ?? 10;
227
+ const claimed = [];
228
+ for (const row of [...rows.values()].sort((a, b) => a.nextPollAt - b.nextPollAt)) {
229
+ if (claimed.length >= limit)
230
+ break;
231
+ if (TERMINAL_STATUSES.has(row.status))
232
+ continue;
233
+ if (row.nextPollAt > now)
234
+ continue;
235
+ // A live lease held by anyone (including this worker's previous tick) blocks the claim;
236
+ // an expired one does not, which is what makes a dead worker's rows recoverable.
237
+ if (row.leaseExpiresAt !== null && row.leaseExpiresAt > now)
238
+ continue;
239
+ const leased = {
240
+ ...row,
241
+ leaseOwner,
242
+ leaseExpiresAt: now + leaseMs,
243
+ updatedAt: now,
244
+ };
245
+ rows.set(row.id, leased);
246
+ claimed.push(cloneRecord(leased));
247
+ }
248
+ return claimed;
249
+ },
250
+ async releaseLease(id, leaseOwner) {
251
+ const row = requireRow(id);
252
+ if (!row)
253
+ return;
254
+ // Fenced: a stale owner's late release must not clear a lease another worker has since
255
+ // legitimately reclaimed. See the interface doc for why this is not merely defensive.
256
+ if (row.leaseOwner !== leaseOwner)
257
+ return;
258
+ rows.set(id, { ...row, leaseOwner: null, leaseExpiresAt: null, updatedAt: Date.now() });
259
+ },
260
+ async reconcileOnBoot(options) {
261
+ const { now } = options;
262
+ let leasesReleased = 0;
263
+ let deadlineExpired = 0;
264
+ for (const row of [...rows.values()]) {
265
+ if (TERMINAL_STATUSES.has(row.status))
266
+ continue;
267
+ if (row.deadlineAt <= now) {
268
+ rows.set(row.id, {
269
+ ...row,
270
+ status: 'unknown',
271
+ leaseOwner: null,
272
+ leaseExpiresAt: null,
273
+ error: {
274
+ message: 'async operation passed its absolute deadline while unattended — vendor-side effect is undetermined',
275
+ code: 'DEADLINE_EXPIRED',
276
+ },
277
+ updatedAt: now,
278
+ });
279
+ deadlineExpired += 1;
280
+ continue;
281
+ }
282
+ if (row.leaseOwner !== null && (row.leaseExpiresAt === null || row.leaseExpiresAt <= now)) {
283
+ rows.set(row.id, { ...row, leaseOwner: null, leaseExpiresAt: null, updatedAt: now });
284
+ leasesReleased += 1;
285
+ }
286
+ }
287
+ return { leasesReleased, deadlineExpired };
288
+ },
289
+ };
290
+ }
291
+ //# sourceMappingURL=async-operation-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"async-operation-store.js","sourceRoot":"","sources":["../../../src/media-providers/dispatch/async-operation-store.ts"],"names":[],"mappings":"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"}
@@ -21,5 +21,13 @@ export { dispatchVendorRequest, requireApiKey } from './vendor-adapter.js';
21
21
  export type { VendorAdapter, VendorCredentialGuard, VendorRequest, VendorRequestBuilder, VendorResponseParser } from './vendor-adapter.js';
22
22
  export { createVendorAdapterRegistry, mediaVendorRegistry, VendorAdapterRegistry } from './vendor-registry.js';
23
23
  export { createHexEnvelopeAudioParser, createRawBytesParser } from './response-parsers.js';
24
+ export { ASYNC_OPERATION_SCHEMA_VERSION, assertNoCredentialMaterial, createInMemoryAsyncOperationStore, CREDENTIAL_IN_STATE_MESSAGE, hydrateAsyncOperationRecord, } from './async-operation-store.js';
25
+ export type { AsyncOperationClaimOptions, AsyncOperationCreateInput, AsyncOperationError, AsyncOperationPatch, AsyncOperationReconcileResult, AsyncOperationRecord, AsyncOperationResult, AsyncOperationStatus, AsyncOperationStore, } from './async-operation-store.js';
26
+ export { createBearerSigner, withUnsignedRequestInit } from './polling-adapter.js';
27
+ export type { AnyPollingVendorAdapter, ExpectedLatencyClass, PollOutcome, PollingVendorAdapter, RequestSigner, SignedVendorRequest, SubmitOutcome, UnsignedVendorRequest, } from './polling-adapter.js';
28
+ export { DEFAULT_DEADLINE_MS, DEFAULT_GRACE_MS, DEFAULT_MAX_ATTEMPTS, DEFAULT_PERSIST_RETRY_DELAYS_MS, DEFAULT_POLL_INTERVAL_MS, pollDueOperations, recoverAfterRestart, startOperation, } from './operation-runtime.js';
29
+ export type { OperationRuntimeDeps, PollDueParams, PollDueStats, RecoverParams, RecoverResult, StartOperationOutcome, StartOperationParams, } from './operation-runtime.js';
30
+ export { createImageRouterVideoPollingAdapter } from './providers/imagerouter-video-async.js';
31
+ export type { ImageRouterVideoConfig, ImageRouterVideoMeta } from './providers/imagerouter-video-async.js';
24
32
  export type { HexEnvelopeAudioMeta, HexEnvelopeAudioParserOptions, RawBytesParserOptions } from './response-parsers.js';
25
33
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/media-providers/dispatch/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,EAAE,iCAAiC,EAAE,MAAM,kBAAkB,CAAC;AACrE,OAAO,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAC;AACxD,OAAO,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AACjF,OAAO,EAAE,uBAAuB,EAAE,+BAA+B,EAAE,qBAAqB,EAAE,MAAM,6BAA6B,CAAC;AAC9H,OAAO,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AACrF,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACnF,OAAO,EAAE,sBAAsB,EAAE,sBAAsB,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAChH,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAC9E,OAAO,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AACvF,OAAO,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AACvF,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AACvD,OAAO,EAAE,2BAA2B,EAAE,sBAAsB,EAAE,4BAA4B,EAAE,iBAAiB,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAChK,YAAY,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AACrE,YAAY,EACV,mBAAmB,EACnB,0BAA0B,EAC1B,sBAAsB,EACtB,0BAA0B,EAC1B,qBAAqB,EACrB,mBAAmB,EACnB,iBAAiB,EACjB,mBAAmB,GACpB,MAAM,YAAY,CAAC;AAIpB,OAAO,EAAE,qBAAqB,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAC3E,YAAY,EAAE,aAAa,EAAE,qBAAqB,EAAE,aAAa,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3I,OAAO,EAAE,2BAA2B,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAC/G,OAAO,EAAE,4BAA4B,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAC3F,YAAY,EAAE,oBAAoB,EAAE,6BAA6B,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/media-providers/dispatch/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,EAAE,iCAAiC,EAAE,MAAM,kBAAkB,CAAC;AACrE,OAAO,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAC;AACxD,OAAO,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AACjF,OAAO,EAAE,uBAAuB,EAAE,+BAA+B,EAAE,qBAAqB,EAAE,MAAM,6BAA6B,CAAC;AAC9H,OAAO,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AACrF,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACnF,OAAO,EAAE,sBAAsB,EAAE,sBAAsB,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAChH,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAC9E,OAAO,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AACvF,OAAO,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AACvF,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AACvD,OAAO,EAAE,2BAA2B,EAAE,sBAAsB,EAAE,4BAA4B,EAAE,iBAAiB,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAChK,YAAY,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AACrE,YAAY,EACV,mBAAmB,EACnB,0BAA0B,EAC1B,sBAAsB,EACtB,0BAA0B,EAC1B,qBAAqB,EACrB,mBAAmB,EACnB,iBAAiB,EACjB,mBAAmB,GACpB,MAAM,YAAY,CAAC;AAIpB,OAAO,EAAE,qBAAqB,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAC3E,YAAY,EAAE,aAAa,EAAE,qBAAqB,EAAE,aAAa,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3I,OAAO,EAAE,2BAA2B,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAC/G,OAAO,EAAE,4BAA4B,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAI3F,OAAO,EACL,8BAA8B,EAC9B,0BAA0B,EAC1B,iCAAiC,EACjC,2BAA2B,EAC3B,2BAA2B,GAC5B,MAAM,4BAA4B,CAAC;AACpC,YAAY,EACV,0BAA0B,EAC1B,yBAAyB,EACzB,mBAAmB,EACnB,mBAAmB,EACnB,6BAA6B,EAC7B,oBAAoB,EACpB,oBAAoB,EACpB,oBAAoB,EACpB,mBAAmB,GACpB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,kBAAkB,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AACnF,YAAY,EACV,uBAAuB,EACvB,oBAAoB,EACpB,WAAW,EACX,oBAAoB,EACpB,aAAa,EACb,mBAAmB,EACnB,aAAa,EACb,qBAAqB,GACtB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,mBAAmB,EACnB,gBAAgB,EAChB,oBAAoB,EACpB,+BAA+B,EAC/B,wBAAwB,EACxB,iBAAiB,EACjB,mBAAmB,EACnB,cAAc,GACf,MAAM,wBAAwB,CAAC;AAChC,YAAY,EACV,oBAAoB,EACpB,aAAa,EACb,YAAY,EACZ,aAAa,EACb,aAAa,EACb,qBAAqB,EACrB,oBAAoB,GACrB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,oCAAoC,EAAE,MAAM,wCAAwC,CAAC;AAC9F,YAAY,EAAE,sBAAsB,EAAE,oBAAoB,EAAE,MAAM,wCAAwC,CAAC;AAC3G,YAAY,EAAE,oBAAoB,EAAE,6BAA6B,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC"}
@@ -21,4 +21,11 @@ export { assertAndFetchExternalAsset, assertExternalAssetUrl, isBlockedExternalA
21
21
  export { dispatchVendorRequest, requireApiKey } from './vendor-adapter.js';
22
22
  export { createVendorAdapterRegistry, mediaVendorRegistry, VendorAdapterRegistry } from './vendor-registry.js';
23
23
  export { createHexEnvelopeAudioParser, createRawBytesParser } from './response-parsers.js';
24
+ // The submit-then-poll tier (added 2026-09-02) — purely additive alongside `VendorAdapter`, for
25
+ // vendors that hand back a job handle instead of finishing inside one request/response. See
26
+ // `operation-runtime.ts`'s module doc for the persist-before-fetch design.
27
+ export { ASYNC_OPERATION_SCHEMA_VERSION, assertNoCredentialMaterial, createInMemoryAsyncOperationStore, CREDENTIAL_IN_STATE_MESSAGE, hydrateAsyncOperationRecord, } from './async-operation-store.js';
28
+ export { createBearerSigner, withUnsignedRequestInit } from './polling-adapter.js';
29
+ export { DEFAULT_DEADLINE_MS, DEFAULT_GRACE_MS, DEFAULT_MAX_ATTEMPTS, DEFAULT_PERSIST_RETRY_DELAYS_MS, DEFAULT_POLL_INTERVAL_MS, pollDueOperations, recoverAfterRestart, startOperation, } from './operation-runtime.js';
30
+ export { createImageRouterVideoPollingAdapter } from './providers/imagerouter-video-async.js';
24
31
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/media-providers/dispatch/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,EAAE,iCAAiC,EAAE,MAAM,kBAAkB,CAAC;AACrE,OAAO,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAC;AACxD,OAAO,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AACjF,OAAO,EAAE,uBAAuB,EAAE,+BAA+B,EAAE,qBAAqB,EAAE,MAAM,6BAA6B,CAAC;AAC9H,OAAO,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AACrF,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACnF,OAAO,EAAE,sBAAsB,EAAE,sBAAsB,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAChH,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAC9E,OAAO,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AACvF,OAAO,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AACvF,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AACvD,OAAO,EAAE,2BAA2B,EAAE,sBAAsB,EAAE,4BAA4B,EAAE,iBAAiB,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAYhK,sEAAsE;AACtE,0EAA0E;AAC1E,wCAAwC;AACxC,OAAO,EAAE,qBAAqB,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAE3E,OAAO,EAAE,2BAA2B,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAC/G,OAAO,EAAE,4BAA4B,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/media-providers/dispatch/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,EAAE,iCAAiC,EAAE,MAAM,kBAAkB,CAAC;AACrE,OAAO,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAC;AACxD,OAAO,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AACjF,OAAO,EAAE,uBAAuB,EAAE,+BAA+B,EAAE,qBAAqB,EAAE,MAAM,6BAA6B,CAAC;AAC9H,OAAO,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AACrF,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACnF,OAAO,EAAE,sBAAsB,EAAE,sBAAsB,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAChH,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAC9E,OAAO,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AACvF,OAAO,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AACvF,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AACvD,OAAO,EAAE,2BAA2B,EAAE,sBAAsB,EAAE,4BAA4B,EAAE,iBAAiB,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAYhK,sEAAsE;AACtE,0EAA0E;AAC1E,wCAAwC;AACxC,OAAO,EAAE,qBAAqB,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAE3E,OAAO,EAAE,2BAA2B,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAC/G,OAAO,EAAE,4BAA4B,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAC3F,gGAAgG;AAChG,4FAA4F;AAC5F,2EAA2E;AAC3E,OAAO,EACL,8BAA8B,EAC9B,0BAA0B,EAC1B,iCAAiC,EACjC,2BAA2B,EAC3B,2BAA2B,GAC5B,MAAM,4BAA4B,CAAC;AAYpC,OAAO,EAAE,kBAAkB,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAWnF,OAAO,EACL,mBAAmB,EACnB,gBAAgB,EAChB,oBAAoB,EACpB,+BAA+B,EAC/B,wBAAwB,EACxB,iBAAiB,EACjB,mBAAmB,EACnB,cAAc,GACf,MAAM,wBAAwB,CAAC;AAUhC,OAAO,EAAE,oCAAoC,EAAE,MAAM,wCAAwC,CAAC"}
@@ -0,0 +1,101 @@
1
+ import type { AsyncOperationRecord, AsyncOperationStore } from './async-operation-store.js';
2
+ import type { AnyPollingVendorAdapter, PollingVendorAdapter, RequestSigner } from './polling-adapter.js';
3
+ import type { RenderContext, RenderResult } from './types.js';
4
+ /** Interactive budget for the inline attempt. Deliberately NOT `FETCH_TIMEOUT_MS.GENERATE` (10min) — that is the backstop for the *request*, this is the ceiling on making a human wait. */
5
+ export declare const DEFAULT_GRACE_MS = 4000;
6
+ export declare const DEFAULT_MAX_ATTEMPTS = 60;
7
+ export declare const DEFAULT_DEADLINE_MS: number;
8
+ export declare const DEFAULT_POLL_INTERVAL_MS = 5000;
9
+ /**
10
+ * Backoff between retries of the write that records a vendor job handle after a successful
11
+ * submit. A handle that made it past the vendor round trip must not be dropped just because the
12
+ * very next write is transiently unlucky — see `startOperation`'s post-submit persistence.
13
+ */
14
+ export declare const DEFAULT_PERSIST_RETRY_DELAYS_MS: readonly number[];
15
+ export interface OperationRuntimeDeps {
16
+ readonly store: AsyncOperationStore;
17
+ readonly signer: RequestSigner;
18
+ readonly fetchImpl?: typeof fetch;
19
+ readonly now?: () => number;
20
+ readonly newId?: () => string;
21
+ /** Overrides `DEFAULT_PERSIST_RETRY_DELAYS_MS`. Tests pass a short/empty array to avoid real delays. */
22
+ readonly persistRetryDelaysMs?: readonly number[];
23
+ }
24
+ export interface StartOperationParams<Meta> {
25
+ readonly adapter: PollingVendorAdapter<Meta>;
26
+ readonly ctx: RenderContext;
27
+ readonly providerId: string;
28
+ readonly routeKey: string;
29
+ readonly ownerRef: string;
30
+ readonly maxAttempts?: number;
31
+ readonly deadlineMs?: number;
32
+ readonly graceMs?: number;
33
+ }
34
+ export type StartOperationOutcome = {
35
+ readonly done: true;
36
+ readonly operationId: string;
37
+ readonly result: RenderResult;
38
+ } | {
39
+ readonly done: false;
40
+ readonly operationId: string;
41
+ };
42
+ /**
43
+ * Persists the operation row, issues the submit, and races it against the grace window.
44
+ *
45
+ * @returns `{done: true, result}` when the vendor finished inside the grace window, else
46
+ * `{done: false, operationId}` — the row is already durable in both cases.
47
+ * @complexity O(1) plus one vendor round trip.
48
+ */
49
+ export declare function startOperation<Meta>(deps: OperationRuntimeDeps, params: StartOperationParams<Meta>): Promise<StartOperationOutcome>;
50
+ export interface PollDueParams {
51
+ /** Resolves the adapter registered for a row's `(providerId, routeKey)`. */
52
+ readonly adapters: (providerId: string, routeKey: string) => AnyPollingVendorAdapter | undefined;
53
+ /** Rehydrates the render context for a row. The row deliberately does not persist the context — it can hold reference-image data URLs, and none of it is needed to identify the vendor-side job. */
54
+ readonly resolveContext: (row: AsyncOperationRecord) => RenderContext;
55
+ readonly leaseOwner: string;
56
+ readonly leaseMs: number;
57
+ readonly limit?: number;
58
+ }
59
+ export interface PollDueStats {
60
+ readonly claimed: number;
61
+ readonly completed: number;
62
+ readonly failed: number;
63
+ readonly pending: number;
64
+ readonly unknown: number;
65
+ }
66
+ /**
67
+ * One leased worker tick: claims every due operation, advances each by exactly one vendor poll,
68
+ * and releases the lease. Safe to run concurrently on several workers — `claimDue` is the
69
+ * exclusion mechanism.
70
+ *
71
+ * Both bounds are enforced here, and in this order: the absolute deadline is checked *before* any
72
+ * vendor call (a blown deadline must not cost another request), the attempt cap after it.
73
+ *
74
+ * @complexity O(k) vendor round trips for k claimed operations.
75
+ */
76
+ export declare function pollDueOperations(deps: OperationRuntimeDeps, params: PollDueParams): Promise<PollDueStats>;
77
+ export interface RecoverParams {
78
+ readonly adapters: (providerId: string, routeKey: string) => AnyPollingVendorAdapter | undefined;
79
+ readonly now?: number;
80
+ }
81
+ export interface RecoverResult {
82
+ readonly leasesReleased: number;
83
+ readonly deadlineExpired: number;
84
+ /** Rows whose submit may or may not have reached the vendor and cannot be safely re-issued. */
85
+ readonly unknownCrashGap: number;
86
+ /** Rows whose adapter declares its submit idempotent — left `submitted` for the host to re-issue. */
87
+ readonly resubmittable: readonly string[];
88
+ }
89
+ /**
90
+ * Boot-time recovery. Releases dead leases and expires blown deadlines via the store, then handles
91
+ * the one case the store cannot decide alone: a row still at `submitted`, meaning the process died
92
+ * between persisting the row and learning whether the vendor accepted the submit.
93
+ *
94
+ * Retry safety is gated on idempotency, not assumed. An adapter that has not declared
95
+ * `submitIsIdempotent` sends that row to `unknown` for reconciliation — media generation is billed
96
+ * per call, so a silent re-issue can double a real charge.
97
+ *
98
+ * @complexity O(n) in stored operations.
99
+ */
100
+ export declare function recoverAfterRestart(deps: OperationRuntimeDeps, params: RecoverParams): Promise<RecoverResult>;
101
+ //# sourceMappingURL=operation-runtime.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"operation-runtime.d.ts","sourceRoot":"","sources":["../../../src/media-providers/dispatch/operation-runtime.ts"],"names":[],"mappings":"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"}