@fabricorg/platform 1.10.0 → 1.10.1
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 +46 -0
- package/README.md +31 -2
- package/dist/actions/index.cjs +45 -26
- package/dist/actions/index.cjs.map +1 -1
- package/dist/actions/index.d.cts +225 -226
- package/dist/actions/index.d.ts +225 -226
- package/dist/actions/index.js +41 -2
- package/dist/actions/index.js.map +1 -1
- package/dist/adapters/index.cjs +696 -66
- package/dist/adapters/index.cjs.map +1 -1
- package/dist/adapters/index.d.cts +367 -365
- package/dist/adapters/index.d.ts +367 -365
- package/dist/adapters/index.js +682 -2
- package/dist/adapters/index.js.map +1 -1
- package/dist/agent-hitl/index.cjs +21 -10
- package/dist/agent-hitl/index.cjs.map +1 -1
- package/dist/agent-hitl/index.d.cts +30 -30
- package/dist/agent-hitl/index.d.ts +30 -30
- package/dist/agent-hitl/index.js +21 -2
- package/dist/agent-hitl/index.js.map +1 -1
- package/dist/certification/index.cjs +109 -24
- package/dist/certification/index.cjs.map +1 -1
- package/dist/certification/index.d.cts +33 -39
- package/dist/certification/index.d.ts +33 -39
- package/dist/certification/index.js +107 -8
- package/dist/certification/index.js.map +1 -1
- package/dist/discovery/index.cjs +12 -10
- package/dist/discovery/index.cjs.map +1 -1
- package/dist/discovery/index.d.cts +2 -10
- package/dist/discovery/index.d.ts +2 -10
- package/dist/discovery/index.js +12 -2
- package/dist/discovery/index.js.map +1 -1
- package/dist/engine-B4csEOEc.js +223 -0
- package/dist/engine-B4csEOEc.js.map +1 -0
- package/dist/engine-BqScuhrT.cjs +246 -0
- package/dist/engine-BqScuhrT.cjs.map +1 -0
- package/dist/events/index.cjs +39 -10
- package/dist/events/index.cjs.map +1 -1
- package/dist/events/index.d.cts +43 -43
- package/dist/events/index.d.ts +43 -43
- package/dist/events/index.js +39 -2
- package/dist/events/index.js.map +1 -1
- package/dist/evidence/index.cjs +12 -50
- package/dist/evidence/index.d.cts +2 -229
- package/dist/evidence/index.d.ts +2 -229
- package/dist/evidence/index.js +1 -5
- package/dist/evidence-BuCICb0c.js +516 -0
- package/dist/evidence-BuCICb0c.js.map +1 -0
- package/dist/evidence-Cq48eDvA.cjs +575 -0
- package/dist/evidence-Cq48eDvA.cjs.map +1 -0
- package/dist/governance/index.cjs +24 -18
- package/dist/governance/index.cjs.map +1 -1
- package/dist/governance/index.d.cts +80 -83
- package/dist/governance/index.d.ts +80 -83
- package/dist/governance/index.js +22 -2
- package/dist/governance/index.js.map +1 -1
- package/dist/ids/index.cjs +52 -22
- package/dist/ids/index.cjs.map +1 -1
- package/dist/ids/index.d.cts +17 -17
- package/dist/ids/index.d.ts +17 -17
- package/dist/ids/index.js +49 -2
- package/dist/ids/index.js.map +1 -1
- package/dist/index-9jasmw76.d.cts +124 -0
- package/dist/index-BXpeFdk2.d.cts +190 -0
- package/dist/index-BXpeFdk2.d.ts +190 -0
- package/dist/index-BnbsKZsT.d.cts +231 -0
- package/dist/index-CIl1rYRv.d.cts +11 -0
- package/dist/index-CIl1rYRv.d.ts +11 -0
- package/dist/index-CVHA1ypT.d.cts +262 -0
- package/dist/index-DZ4mnNb7.d.cts +78 -0
- package/dist/index-DZ4mnNb7.d.ts +78 -0
- package/dist/index-IqcDvl69.d.ts +124 -0
- package/dist/index-fmUiRBXu.d.cts +57 -0
- package/dist/index-fmUiRBXu.d.ts +57 -0
- package/dist/index-sPUPs8pr.d.ts +262 -0
- package/dist/index-z9-CYOIo.d.ts +231 -0
- package/dist/index.cjs +111 -393
- package/dist/index.d.cts +18 -17
- package/dist/index.d.ts +18 -17
- package/dist/index.js +19 -20
- package/dist/manifest/index.cjs +224 -35
- package/dist/manifest/index.cjs.map +1 -1
- package/dist/manifest/index.d.cts +130 -131
- package/dist/manifest/index.d.ts +130 -131
- package/dist/manifest/index.js +219 -7
- package/dist/manifest/index.js.map +1 -1
- package/dist/modules/index.cjs +281 -42
- package/dist/modules/index.cjs.map +1 -1
- package/dist/modules/index.d.cts +157 -159
- package/dist/modules/index.d.ts +157 -159
- package/dist/modules/index.js +274 -6
- package/dist/modules/index.js.map +1 -1
- package/dist/objects/index.cjs +355 -22
- package/dist/objects/index.cjs.map +1 -1
- package/dist/objects/index.d.cts +2 -77
- package/dist/objects/index.d.ts +2 -77
- package/dist/objects/index.js +352 -2
- package/dist/objects/index.js.map +1 -1
- package/dist/policies/index.cjs +14 -56
- package/dist/policies/index.d.cts +2 -261
- package/dist/policies/index.d.ts +2 -261
- package/dist/policies/index.js +1 -3
- package/dist/policies-DH_GCXQ-.js +627 -0
- package/dist/policies-DH_GCXQ-.js.map +1 -0
- package/dist/policies-Nxbp1CH8.cjs +698 -0
- package/dist/policies-Nxbp1CH8.cjs.map +1 -0
- package/dist/privacy/index.cjs +26 -43
- package/dist/privacy/index.cjs.map +1 -1
- package/dist/privacy/index.d.cts +2 -189
- package/dist/privacy/index.d.ts +2 -189
- package/dist/privacy/index.js +18 -3
- package/dist/privacy/index.js.map +1 -1
- package/dist/projections/index.cjs +241 -23
- package/dist/projections/index.cjs.map +1 -1
- package/dist/projections/index.d.cts +2 -125
- package/dist/projections/index.d.ts +2 -125
- package/dist/projections/index.js +238 -3
- package/dist/projections/index.js.map +1 -1
- package/dist/state-machines/index.cjs +76 -18
- package/dist/state-machines/index.cjs.map +1 -1
- package/dist/state-machines/index.d.cts +2 -55
- package/dist/state-machines/index.d.ts +2 -55
- package/dist/state-machines/index.js +74 -2
- package/dist/state-machines/index.js.map +1 -1
- package/dist/testing/index.cjs +27 -19
- package/dist/testing/index.cjs.map +1 -1
- package/dist/testing/index.d.cts +17 -19
- package/dist/testing/index.d.ts +17 -19
- package/dist/testing/index.js +25 -3
- package/dist/testing/index.js.map +1 -1
- package/package.json +6 -5
- package/dist/chunk-2AE6TMAX.cjs +0 -44
- package/dist/chunk-2AE6TMAX.cjs.map +0 -1
- package/dist/chunk-6HY35TKB.cjs +0 -491
- package/dist/chunk-6HY35TKB.cjs.map +0 -1
- package/dist/chunk-6UGEIDLC.cjs +0 -26
- package/dist/chunk-6UGEIDLC.cjs.map +0 -1
- package/dist/chunk-7GAWSUOG.js +0 -64
- package/dist/chunk-7GAWSUOG.js.map +0 -1
- package/dist/chunk-A42JJIPL.cjs +0 -699
- package/dist/chunk-A42JJIPL.cjs.map +0 -1
- package/dist/chunk-AFXKSIVI.cjs +0 -540
- package/dist/chunk-AFXKSIVI.cjs.map +0 -1
- package/dist/chunk-B5DOGDPG.js +0 -42
- package/dist/chunk-B5DOGDPG.js.map +0 -1
- package/dist/chunk-BJGZE3GE.js +0 -20
- package/dist/chunk-BJGZE3GE.js.map +0 -1
- package/dist/chunk-CRZXTZ36.cjs +0 -258
- package/dist/chunk-CRZXTZ36.cjs.map +0 -1
- package/dist/chunk-D4SWRBUH.cjs +0 -22
- package/dist/chunk-D4SWRBUH.cjs.map +0 -1
- package/dist/chunk-DBTAUI6C.cjs +0 -395
- package/dist/chunk-DBTAUI6C.cjs.map +0 -1
- package/dist/chunk-EMSAFNPX.js +0 -98
- package/dist/chunk-EMSAFNPX.js.map +0 -1
- package/dist/chunk-F3E5SXPN.cjs +0 -28
- package/dist/chunk-F3E5SXPN.cjs.map +0 -1
- package/dist/chunk-HEYMMVDP.js +0 -480
- package/dist/chunk-HEYMMVDP.js.map +0 -1
- package/dist/chunk-IFW43ELT.cjs +0 -331
- package/dist/chunk-IFW43ELT.cjs.map +0 -1
- package/dist/chunk-LFE74IJX.js +0 -20
- package/dist/chunk-LFE74IJX.js.map +0 -1
- package/dist/chunk-LZSE6QGQ.cjs +0 -60
- package/dist/chunk-LZSE6QGQ.cjs.map +0 -1
- package/dist/chunk-MCWSUGB3.cjs +0 -102
- package/dist/chunk-MCWSUGB3.cjs.map +0 -1
- package/dist/chunk-MLBALEUR.js +0 -290
- package/dist/chunk-MLBALEUR.js.map +0 -1
- package/dist/chunk-NNXQZPB3.cjs +0 -31
- package/dist/chunk-NNXQZPB3.cjs.map +0 -1
- package/dist/chunk-OFCCZ27Z.js +0 -26
- package/dist/chunk-OFCCZ27Z.js.map +0 -1
- package/dist/chunk-PDN5DOLQ.js +0 -242
- package/dist/chunk-PDN5DOLQ.js.map +0 -1
- package/dist/chunk-PIDZQAEL.js +0 -50
- package/dist/chunk-PIDZQAEL.js.map +0 -1
- package/dist/chunk-PXD7NG6X.js +0 -686
- package/dist/chunk-PXD7NG6X.js.map +0 -1
- package/dist/chunk-Q4Q4JPR3.js +0 -524
- package/dist/chunk-Q4Q4JPR3.js.map +0 -1
- package/dist/chunk-RALMUSOX.js +0 -55
- package/dist/chunk-RALMUSOX.js.map +0 -1
- package/dist/chunk-SNTV45LH.cjs +0 -295
- package/dist/chunk-SNTV45LH.cjs.map +0 -1
- package/dist/chunk-TBS2S5AX.cjs +0 -40
- package/dist/chunk-TBS2S5AX.cjs.map +0 -1
- package/dist/chunk-TYNIFC7J.js +0 -253
- package/dist/chunk-TYNIFC7J.js.map +0 -1
- package/dist/chunk-UGWGHTNC.cjs +0 -56
- package/dist/chunk-UGWGHTNC.cjs.map +0 -1
- package/dist/chunk-WI7CWNYI.cjs +0 -68
- package/dist/chunk-WI7CWNYI.cjs.map +0 -1
- package/dist/chunk-WNZP53GI.js +0 -386
- package/dist/chunk-WNZP53GI.js.map +0 -1
- package/dist/chunk-WQ3BYI7T.cjs +0 -249
- package/dist/chunk-WQ3BYI7T.cjs.map +0 -1
- package/dist/chunk-Y2PJLRIY.js +0 -36
- package/dist/chunk-Y2PJLRIY.js.map +0 -1
- package/dist/chunk-ZAEVQSB5.js +0 -326
- package/dist/chunk-ZAEVQSB5.js.map +0 -1
- package/dist/chunk-ZMQTV5OJ.js +0 -27
- package/dist/chunk-ZMQTV5OJ.js.map +0 -1
- package/dist/evidence/index.cjs.map +0 -1
- package/dist/evidence/index.js.map +0 -1
- package/dist/index.cjs.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/policies/index.cjs.map +0 -1
- package/dist/policies/index.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,51 @@
|
|
|
1
1
|
# @fabricorg/platform
|
|
2
2
|
|
|
3
|
+
## 1.10.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- a205c48: Reconcile unknown adapter outcomes (issue #76). Platform's README describes the Host behavior; Platform runtime code is unchanged.
|
|
8
|
+
|
|
9
|
+
**Release note: failure semantics (issue #76).** Returned `timeout` outcomes, timeouts thrown from `adapter.execute` (including an aborted adapter deadline), contradictory results in either direction (`success: true` with a non-success outcome, or `success: false` with `outcome: "success"`), uninterpretable replies (non-objects, `null`, or arrays), getters that throw before Host interprets the reply, and unrecognised outcome strings such as `"timed_out"` now end `reconciliation_required` instead of `failed`, using the existing `adapter_outcome_ambiguous` kind and `AdapterInvocationAmbiguous` event payload and stable ID. Returned `ambiguous` outcomes use the same settlement path. These unknown outcomes are not retried by the retry helper. Governance stores receive `ExternalReconciliation` evidence even without provider `outcomeEvidence`, because a timed-out call may have applied its effect without returning an external reference.
|
|
10
|
+
|
|
11
|
+
Host detects a timeout thrown from `adapter.execute` from the adapter deadline's aborted signal or an error message matching `/timeout|deadline|timed?\s*out/i`. A definite rejection whose message matches therefore also routes to reconciliation; the matcher does not prove a provider timeout. Reverse contradictions are classified as ambiguous for retry and circuit-breaker accounting, rather than as success.
|
|
12
|
+
|
|
13
|
+
Host copies the reply's contract fields and other own enumerable fields into a plain object before interpretation, reading each top-level field once. A getter that throws during the copy takes the unreadable-reply path. Object replies retain Host's previous truthiness reading of `success`, including truthy non-boolean values from JavaScript adapters.
|
|
14
|
+
|
|
15
|
+
Unknown-outcome settlement uses `transactionWithEvents` when the transaction has `updateAdapterInvocation`, governance `appendExternalReconciliation` where applicable, and leased `updateLeasedActionInvocation` where required. Host commits the ambiguous checkpoint, stable ambiguity event, reconciliation record, and fenced terminal verdict together, in that write order. It retries the transaction once on a non-lease error; a second non-lease failure selects the verdict-first fallback. Lease loss raises `RecoverableFinalizationError` without retry or fallback.
|
|
16
|
+
|
|
17
|
+
The fallback writes `reconciliation_required` first through the existing verdict helper (one retry except on lease loss), then writes checkpoint, event, and reconciliation evidence. After the verdict commits, Host attempts each remaining evidence write (checkpoint, event, record), then surfaces the first error as `RecoverableFinalizationError`. This includes attempting the reconciliation record after an event-write failure and attempting both event and record when both checkpoint shapes fail. Evidence failure can leave a terminal evidence gap that recovery does not repair. If both verdict attempts fail, Host raises `RecoverableFinalizationError` without attempting an unfenced checkpoint. With the original action definition and step order available, recovery re-settles a saved ambiguous row before parked-handoff shortcuts, stale-action gates, authorization, or handler execution, for idempotent and non-idempotent actions. The pending-handoff shortcut retains its base condition (running with a pending handoff and no lease owner, without requiring `parkedAt`); its position after the new recorded-ambiguity check is the change. For a running invocation whose action resolves, `executeInvocation` reads each adapter step's row before the shortcut, stopping on recorded ambiguity or a failed read. A failed read surfaces `RecoverableFinalizationError`, where base 939bcad returned the parked result. If the action no longer resolves, the shortcut still returns the handoff before the unknown-action failure.
|
|
18
|
+
|
|
19
|
+
The optional `AdapterInvocationRecord.reconciliation` checkpoint preserves redacted reason, external reference, and the original event subject; the subject is excluded from the returned `AdapterReconciliationOutcome`. Recovery does not scan the space's event log. Legacy rows use the recorded error as message and reason, and default to the `AdapterInvocation` subject keyed by `adapterInvocationId`. Stable event and reconciliation IDs retain deduplication.
|
|
20
|
+
|
|
21
|
+
Ordinary adapter writes omit the migration 8 column. On checkpoint-write failure, fallback retries once without `reconciliation`, retaining legacy `status: "ambiguous"` plus `error`. Schemas without migration 8 still settle unknown outcomes, without the checkpoint metadata. Atomic PostgreSQL failures roll back before this legacy write runs outside the transaction. Apply migration 8 (`adapter_reconciliation_checkpoint`) through controlled `ensureSchema()` to retain metadata. Existing migration checksums are unchanged. Custom stores should persist the optional checkpoint through adapter create/update/read methods.
|
|
22
|
+
|
|
23
|
+
On a store without atomic support, if the verdict cannot be written at all, no durable write after the call succeeds (neither verdict nor checkpoint), as after a crash mid-call. Idempotent recovery may re-run a leftover running step under the same `adapterInvocationId` idempotency key. The same exposure applies if two atomic attempts roll back and the fallback verdict cannot be written. Non-idempotent recovery retains its stale-action gate without an ambiguous checkpoint. Before another provider attempt, Host resets a prior failed row to `running` and clears its old error.
|
|
24
|
+
|
|
25
|
+
Post-success Host write failures still end `failed`, as in 7.6.0, even though the provider succeeded. Accepted-handoff persistence and its `ExternalOperationAccepted` event, the succeeded marker, attestation extraction and recording, and `AdapterInvocationSucceeded` failures again write the adapter row `failed` and fail the invocation. Later execution returns that terminal verdict; lease loss retains its fencing error. If fencing refuses the failure verdict after the adapter row was saved as `failed`, idempotent recovery can re-run the step; this pre-existing 7.6.0 case remains for follow-up. A follow-up issue will cover these post-success failures. The existing 7.6.0 degraded-success paths for withheld output and refused handoffs retain their reconciliation semantics and documented re-call exposure when the verdict cannot be persisted. Final `after_adapters` domain-event/invocation completion retains its recovery path.
|
|
26
|
+
|
|
27
|
+
A deadline sweep followed by a late completion callback can settle `completed` when the `ambiguous` evidence of a later step was never written.
|
|
28
|
+
|
|
29
|
+
Circuit-open refusals, deadline expiry before execution (including between retry attempts), `prepareAttempt` store errors, returned `permanent_failure`, exhausted `transient_failure`, and exhausted non-timeout adapter throws retain `failed` and their existing event shapes. Adapters already express definite non-effects through `permanent_failure` and `transient_failure`; there is no new adapter-side definite-failure flag. `after_adapters` completion events remain withheld while reconciliation is required.
|
|
30
|
+
|
|
31
|
+
- 939bcad: Build packages with tsdown in place of tsup. Preserve the published ESM/CommonJS
|
|
32
|
+
entry paths, ES2022 target, declaration filenames, and raw external module
|
|
33
|
+
specifier spellings, including the existing Node built-in spellings.
|
|
34
|
+
|
|
35
|
+
Generated JavaScript, source-map contents, declaration formatting, and internal
|
|
36
|
+
chunk layout change. Comparison with the saved tsup build found unchanged named
|
|
37
|
+
runtime exports and public declaration signatures. Declaration maps remain
|
|
38
|
+
unpublished. Facade maps are no longer published for Platform's root, evidence,
|
|
39
|
+
and policies entries, or experience-runtime's contracts entry (both `.js.map`
|
|
40
|
+
and `.cjs.map`). Their new JavaScript output has no source-map URL comment.
|
|
41
|
+
|
|
42
|
+
CommonJS interop: 29 of 72 baseline CJS files expose an `__esModule` marker;
|
|
43
|
+
0 of 57 tsdown CJS files do. The compared package entries have no default runtime
|
|
44
|
+
export, and the emitted `.d.cts` files declare none. Typed consumers of the
|
|
45
|
+
unchanged declared exports are unaffected. For entries whose marker was removed,
|
|
46
|
+
an untyped CJS `import X from` compiled with a Babel-style default-interop helper
|
|
47
|
+
now yields the namespace instead of `undefined`.
|
|
48
|
+
|
|
3
49
|
## 1.10.0
|
|
4
50
|
|
|
5
51
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -118,7 +118,9 @@ Every `invokeAction(id, params)` call goes through:
|
|
|
118
118
|
leased, idempotent invocation below its `retryableExecutionMaxAttempts` cap (default 5), after
|
|
119
119
|
lease expiry, before policy evidence is written. Inline execution, non-idempotent actions,
|
|
120
120
|
approval resume, and exhausted attempts fail terminally. Obligation resolution and persistence
|
|
121
|
-
are outside this retry region. This signal does not change handler or adapter retry behavior.
|
|
121
|
+
are outside this retry region. This signal does not change handler or adapter retry behavior. Host also applies
|
|
122
|
+
`recoveryMaxAttempts` before resumed leased execution. It uses the same claim counter and defaults
|
|
123
|
+
to `max(5, retryableExecutionMaxAttempts)`. An explicit lower recovery cap is rejected.
|
|
122
124
|
|
|
123
125
|
2. **State-machine validation** — if the action's target entity is bound to a state machine, the Host reads authoritative state at the mutation boundary, validates the requested transition, and executes its guard with trusted entity, actor, parameter, invocation, and database context. A false or throwing guard fails closed.
|
|
124
126
|
3. **Handler** — `actionDef.handler(ctx, params)` runs inside a single `TDb` transaction. Handler parses its own input via its `schema` (single source of truth).
|
|
@@ -139,7 +141,34 @@ Every `invokeAction(id, params)` call goes through:
|
|
|
139
141
|
state-guard, adapter, or finalization failure semantics; see the
|
|
140
142
|
[Host boundary and rollback contract](../platform-host/README.md#atomic-mutation-unit-of-work).
|
|
141
143
|
|
|
142
|
-
4. **Adapters** — for each `actionDef.adapterSteps`, the registered implementation runs via
|
|
144
|
+
4. **Adapters** — for each `actionDef.adapterSteps`, the registered implementation runs via
|
|
145
|
+
`executeWithAdapterRetry` (idempotent retry, exponential backoff, and an optional per-adapter
|
|
146
|
+
circuit breaker; see [Adapter circuit breakers](#adapter-circuit-breakers)). Adapters may
|
|
147
|
+
classify outcomes as `success`, `transient_failure`, `permanent_failure`, `timeout`, or
|
|
148
|
+
`ambiguous`; only transient idempotent outcomes are retried. Platform Host routes returned
|
|
149
|
+
`ambiguous` and `timeout` outcomes, timeouts thrown from `adapter.execute` (detected from the
|
|
150
|
+
adapter deadline's abort signal or an error message matching
|
|
151
|
+
`/timeout|deadline|timed?\s*out/i`), contradictory results in either direction (`success:
|
|
152
|
+
true` with a non-success outcome, or `success: false` with `outcome: "success"`),
|
|
153
|
+
uninterpretable replies (including getters that throw before Host interprets the reply), and
|
|
154
|
+
unrecognised outcome strings to `reconciliation_required`. Settlement is atomic on capable
|
|
155
|
+
stores and verdict-first otherwise; unwritable fallback verdicts can leave the step eligible
|
|
156
|
+
for recovery under its idempotency key, while evidence failures after a committed verdict can
|
|
157
|
+
leave evidence gaps. Post-success Host write failures recover from durable success/handoff
|
|
158
|
+
checkpoints without calling that provider again, or settle `reconciliation_required` when
|
|
159
|
+
Host cannot save the outcome after one write retry. Recovery repairs stable-ID events and
|
|
160
|
+
attestations. The optional Host `recoveryMaxAttempts` (positive integer, default `max(5,
|
|
161
|
+
retryableExecutionMaxAttempts)`) bounds worker claims before execution; exhaustion settles
|
|
162
|
+
reconciliation. With no durable checkpoint or verdict, only idempotent actions replay a
|
|
163
|
+
running step under the stable key within that budget. Non-idempotent reclaim settles running
|
|
164
|
+
or succeeded steps to reconciliation; no rows or only failed rows retain failure. A deadline
|
|
165
|
+
sweep followed by a late callback can settle `completed` if a later step's ambiguous evidence
|
|
166
|
+
was never written. See the [Host recovery limits](../platform-host/README.md). Host store
|
|
167
|
+
errors after a durable success or handoff, including `prepareAttempt` on a later step, are
|
|
168
|
+
recoverable. Pre-call deadline expiry and circuit-open refusals retain `failed` semantics, as
|
|
169
|
+
do returned permanent failures, exhausted transient failures, and exhausted non-timeout
|
|
170
|
+
adapter throws. Adapters use `permanent_failure` or `transient_failure` for definite
|
|
171
|
+
non-effects; no additional definite-failure flag is needed.
|
|
143
172
|
5. **Events** — domain events are appended; projections derive read models on next replay.
|
|
144
173
|
6. **Completion** — invocation status is marked, telemetry emitted.
|
|
145
174
|
|
package/dist/actions/index.cjs
CHANGED
|
@@ -1,28 +1,47 @@
|
|
|
1
|
-
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
//#region actions/index.ts
|
|
3
|
+
const ACTOR_TYPES = [
|
|
4
|
+
"natural_person",
|
|
5
|
+
"agent",
|
|
6
|
+
"system",
|
|
7
|
+
"service_account",
|
|
8
|
+
"external_system",
|
|
9
|
+
"integration"
|
|
10
|
+
];
|
|
11
|
+
function isActorType(value) {
|
|
12
|
+
return ACTOR_TYPES.includes(value);
|
|
13
|
+
}
|
|
14
|
+
function assertActorType(value) {
|
|
15
|
+
if (!isActorType(value)) throw new Error(`Invalid actorType: ${value}`);
|
|
16
|
+
}
|
|
17
|
+
function assertActionId(actionId) {
|
|
18
|
+
if (!/^[a-z][a-z0-9-]*\.[a-z][a-z0-9_]*$/.test(actionId)) throw new Error(`Invalid action ID: ${actionId}`);
|
|
19
|
+
}
|
|
20
|
+
function createActionRegistry(definitions = []) {
|
|
21
|
+
const actions = /* @__PURE__ */ new Map();
|
|
22
|
+
const register = (definition) => {
|
|
23
|
+
assertActionId(definition.actionId);
|
|
24
|
+
if (actions.has(definition.actionId)) throw new Error(`Action "${definition.actionId}" is already registered`);
|
|
25
|
+
if (definition.mutatesDomain && definition.emitsEvents.length === 0) throw new Error(`Action "${definition.actionId}" mutates domain but emits no events. Every mutating action must emit at least one AssetEvent.`);
|
|
26
|
+
if (definition.admitSubmission !== void 0 && typeof definition.admitSubmission !== "function") throw new Error(`Action "${definition.actionId}" declares admitSubmission that is not a function.`);
|
|
27
|
+
actions.set(definition.actionId, definition);
|
|
28
|
+
};
|
|
29
|
+
for (const definition of definitions) register(definition);
|
|
30
|
+
return {
|
|
31
|
+
register,
|
|
32
|
+
registerIfMissing(definition) {
|
|
33
|
+
if (!actions.has(definition.actionId)) register(definition);
|
|
34
|
+
},
|
|
35
|
+
resolve: (actionId) => actions.get(actionId),
|
|
36
|
+
has: (actionId) => actions.has(actionId),
|
|
37
|
+
ids: () => Array.from(actions.keys())
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
//#endregion
|
|
41
|
+
exports.ACTOR_TYPES = ACTOR_TYPES;
|
|
42
|
+
exports.assertActionId = assertActionId;
|
|
43
|
+
exports.assertActorType = assertActorType;
|
|
44
|
+
exports.createActionRegistry = createActionRegistry;
|
|
45
|
+
exports.isActorType = isActorType;
|
|
2
46
|
|
|
3
|
-
var chunkUGWGHTNC_cjs = require('../chunk-UGWGHTNC.cjs');
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
Object.defineProperty(exports, "ACTOR_TYPES", {
|
|
8
|
-
enumerable: true,
|
|
9
|
-
get: function () { return chunkUGWGHTNC_cjs.ACTOR_TYPES; }
|
|
10
|
-
});
|
|
11
|
-
Object.defineProperty(exports, "assertActionId", {
|
|
12
|
-
enumerable: true,
|
|
13
|
-
get: function () { return chunkUGWGHTNC_cjs.assertActionId; }
|
|
14
|
-
});
|
|
15
|
-
Object.defineProperty(exports, "assertActorType", {
|
|
16
|
-
enumerable: true,
|
|
17
|
-
get: function () { return chunkUGWGHTNC_cjs.assertActorType; }
|
|
18
|
-
});
|
|
19
|
-
Object.defineProperty(exports, "createActionRegistry", {
|
|
20
|
-
enumerable: true,
|
|
21
|
-
get: function () { return chunkUGWGHTNC_cjs.createActionRegistry; }
|
|
22
|
-
});
|
|
23
|
-
Object.defineProperty(exports, "isActorType", {
|
|
24
|
-
enumerable: true,
|
|
25
|
-
get: function () { return chunkUGWGHTNC_cjs.isActorType; }
|
|
26
|
-
});
|
|
27
|
-
//# sourceMappingURL=index.cjs.map
|
|
28
47
|
//# sourceMappingURL=index.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":[],"names":[],"mappings":"","file":"index.cjs"}
|
|
1
|
+
{"version":3,"file":"index.cjs","names":[],"sources":["../../actions/index.ts"],"sourcesContent":["import type { SurfaceDeclaration } from \"../discovery\";\nexport type ActionId = `${string}.${string}`;\n\nexport interface SchemaParseIssue {\n\tpath: PropertyKey[];\n\tmessage: string;\n}\n\nexport type SchemaParseResult<T = unknown> =\n\t| { success: true; data: T }\n\t| { success: false; error: { issues: SchemaParseIssue[] } };\n\nexport interface SchemaValidator<T = unknown> {\n\tparse(input: unknown): T;\n\tsafeParse(input: unknown): SchemaParseResult<T>;\n}\n\nexport type ActorType =\n\t| \"natural_person\"\n\t| \"agent\"\n\t| \"system\"\n\t| \"service_account\"\n\t| \"external_system\"\n\t| \"integration\";\n\nexport const ACTOR_TYPES: readonly ActorType[] = [\n\t\"natural_person\",\n\t\"agent\",\n\t\"system\",\n\t\"service_account\",\n\t\"external_system\",\n\t\"integration\",\n] as const;\n\nexport function isActorType(value: string): value is ActorType {\n\treturn (ACTOR_TYPES as readonly string[]).includes(value);\n}\n\nexport function assertActorType(value: string): asserts value is ActorType {\n\tif (!isActorType(value)) {\n\t\tthrow new Error(`Invalid actorType: ${value}`);\n\t}\n}\n\nexport type ActionStatus =\n\t| \"pending\"\n\t| \"running\"\n\t| \"completed\"\n\t| \"failed\"\n\t| \"blocked_by_policy\"\n\t| \"waiting_for_approval\"\n\t| \"reconciliation_required\"\n\t| \"validation_failed\";\n\nexport interface FabricRuntimeServices {\n\treadonly [serviceName: string]: unknown;\n}\n\nexport interface ActionContext<TDb = unknown> {\n\tactionInvocationId: string;\n\ttenantId: string;\n\tspaceId: string;\n\tactorId: string;\n\tactorType: ActorType;\n\tcorrelationId: string;\n\tcausationId?: string;\n\tprovenance?: { source: string; auditAttributes?: Record<string, string> };\n\tdb: TDb;\n\tservices?: FabricRuntimeServices;\n\t/**\n\t * When the host admitted this invocation's submission through the\n\t * action's `admitSubmission` check, read from the durable invocation\n\t * record. Absent when the action declares no check, or when the runtime\n\t * that built this context does not run declared admission checks (a host\n\t * older than the one that introduced them). A handler whose action\n\t * declares `admitSubmission` can refuse to run without it.\n\t */\n\tadmittedAt?: Date;\n}\n\n/**\n * Trusted facts a host gives an action's `admitSubmission` check. Scope and\n * actor come from the host's authenticated submission, never from the\n * parameters.\n */\nexport interface ActionAdmissionInput {\n\treadonly actionId: ActionId;\n\treadonly tenantId: string;\n\treadonly spaceId: string;\n\treadonly actorId: string;\n\treadonly actorType: ActorType;\n\t/**\n\t * The submitted parameters, unvalidated, as a copy made for this check.\n\t * `@fabricorg/platform-host` records its own copy of the same value, taken\n\t * before the check ran, and only if the check admits it; changing this\n\t * copy changes nothing the host records.\n\t */\n\treadonly parameters: Readonly<Record<string, unknown>>;\n\t/**\n\t * Aborted when the host's admission deadline passes. Hosts pass an\n\t * `AbortSignal`. `@fabricorg/platform-host` refuses an answer that settles\n\t * at or after the deadline, even one that settles before the abort.\n\t */\n\treadonly signal: ActionAdmissionSignal;\n}\n\n/**\n * The part of an `AbortSignal` an admission check can rely on. Declared\n * structurally so this module compiles without DOM or Node type libraries; a\n * host passes a real `AbortSignal`, which satisfies it.\n */\nexport interface ActionAdmissionSignal {\n\treadonly aborted: boolean;\n\taddEventListener(type: \"abort\", listener: () => void, options?: { once?: boolean }): void;\n\tremoveEventListener(type: \"abort\", listener: () => void): void;\n}\n\n/**\n * An admission check's answer. Only `{ admitted: true }` admits. A refusal's\n * `code` must be a fixed code chosen by the action (lower-case first letter,\n * then letters, digits, `_`, `.`, `:` or `-`, at most 128 characters), never\n * a submitted value: the host puts it in the error it throws.\n */\nexport type ActionAdmissionDecision =\n\t| { readonly admitted: true }\n\t| { readonly admitted: false; readonly code: string };\n\n/**\n * Decides whether a submission may be recorded at all. A host that supports\n * it runs the check after authorizing the submitter and before it writes\n * anything durable for the submission; a refusal, a throw, a timeout or any\n * answer other than `{ admitted: true }` refuses the submission.\n */\nexport type ActionAdmission = (input: ActionAdmissionInput) => Promise<ActionAdmissionDecision>;\n\nexport interface ActionResult {\n\tsuccess: boolean;\n\tdata?: Record<string, unknown>;\n\terror?: string;\n}\n\nexport type ActionHandler<TDb = unknown> = (\n\tctx: ActionContext<TDb>,\n\tparams: unknown,\n) => Promise<ActionResult>;\n\nexport interface AdapterStepRetryPolicy {\n\tidempotent: boolean;\n\tmaxAttempts?: number;\n\tinitialDelayMs?: number;\n\tbackoffMultiplier?: number;\n\tmaxDelayMs?: number;\n}\n\nexport interface AdapterStep {\n\tadapterType: string;\n\toperation: string;\n\tretryPolicy?: AdapterStepRetryPolicy;\n\tgetInput: (\n\t\tparams: unknown,\n\t\thandlerResult: Record<string, unknown>,\n\t) => Record<string, unknown> | undefined;\n}\n\nexport interface ActionStateMachineBinding {\n\tentityType: string;\n\ttargetState: string | ((params: unknown) => string);\n\tgetEntityId: (params: unknown) => string | undefined;\n}\n\nexport interface ActionDefinition<TDb = unknown> extends SurfaceDeclaration {\n\tactionId: ActionId;\n\tnamespace: string;\n\tversion: number;\n\tschema: SchemaValidator;\n\t/**\n\t * Optional check a host runs on every submission before it records\n\t * anything durable for it (invocation, idempotency key, events, errors).\n\t * Use it when parameters must be validated against trusted context, for\n\t * example a secret reference the tenant's secret store must hold, before\n\t * they may be persisted. `@fabricorg/platform-host` runs it from the\n\t * release that introduced it; an older host ignores it, so a handler that\n\t * relies on it should require `ActionContext.admittedAt`.\n\t */\n\tadmitSubmission?: ActionAdmission;\n\t/** Optional validation contract for the public handler result data. */\n\tresultSchema?: SchemaValidator;\n\thandler?: ActionHandler<TDb>;\n\trequiredRoles?: string[];\n\trequiredPermissions?: string[];\n\tpolicies?: `${string}.v${number}`[];\n\temitsEvents: string[];\n\tidempotent: boolean;\n\tmutatesDomain: boolean;\n\t/** Portable execution semantics used by hosts, gateways, and generated capability contracts. */\n\texecution?: ActionExecutionContract;\n\tstateMachine?: ActionStateMachineBinding;\n\tadapterSteps?: AdapterStep[];\n\t/** Completion actions can attest only after all external adapter work succeeds. */\n\teventPhase?: \"before_adapters\" | \"after_adapters\";\n\t/**\n\t * If \"saga\", the action is a multi-step orchestration. The worker dispatches\n\t * to a registered saga implementation instead of running `handler` directly.\n\t */\n\tkind?: \"atomic\" | \"saga\";\n}\n\nexport type ActionConnectivity = \"online-required\" | \"offline-capturable\";\nexport type AuthorityMoment = \"capture\" | \"execution\" | \"both\";\nexport type ActionIdempotencyStance = \"required\" | \"supported\" | \"prohibited\";\nexport type ActionCompletionMode = \"immediate\" | \"accepted\" | \"long-running\";\nexport type ActionConsistency = \"authoritative-now\" | \"provisional-until-reconciled\";\nexport type ActionDataSensitivity = \"public\" | \"internal\" | \"confidential\" | \"restricted\";\n\nexport interface ActionExecutionContract {\n\tconnectivity: ActionConnectivity;\n\tauthorityMoment: AuthorityMoment;\n\tidempotency: ActionIdempotencyStance;\n\t/**\n\t * `immediate`: the invocation settles within the host's execution.\n\t * `accepted` and `long-running`: an adapter may hand the work to an\n\t * external system and the invocation stays running until that system\n\t * completes it by reference through the host's completion ingress.\n\t * Declare `completionDeadlineMs` on a `long-running` action so a callback\n\t * that never comes is noticed rather than waited on forever.\n\t */\n\tcompletion: ActionCompletionMode;\n\t/**\n\t * How long an accepted handoff may wait for its completion before the host\n\t * moves the invocation to reconciliation. Without it, nothing sweeps the\n\t * handoff. Refused on `immediate`, since nothing external completes it.\n\t */\n\tcompletionDeadlineMs?: number;\n\tconsistency: ActionConsistency;\n\tsensitivity?: ActionDataSensitivity;\n}\n\nexport interface SagaContext {\n\tactionInvocationId: string;\n\ttenantId: string;\n\tspaceId: string;\n\tparameters: unknown;\n\tsleep?: (delayMs: number) => Promise<void>;\n\tquery?: <T = unknown>(model: string, operation: string, args: unknown) => Promise<T>;\n\t/**\n\t * Wait for a named external signal carrying a payload of `T`, with a timeout.\n\t *\n\t * Resolves with the payload of the first signal received, or `null` if the timeout\n\t * fires first. Subsequent distinct signals with the same name received before\n\t * another `awaitSignal` call are buffered in FIFO order so none is lost.\n\t *\n\t * A signal may carry a stable signal ID that the sender keeps the same on each redelivery\n\t * (for example a webhook delivery ID or an approval decision ID). A runtime drops\n\t * a signal whose ID it has already received for this saga, so a sender retrying\n\t * after a timeout does not wake the saga twice. Signals without an ID are not\n\t * deduplicated. `@fabricorg/platform-temporal` provides `createSagaSignalInbox()`\n\t * for Temporal runtimes.\n\t *\n\t * Intended for agent-driven and webhook-driven coordination: replace polling loops\n\t * with push-based wakeups while preserving the saga's deterministic replay\n\t * semantics (the runtime is responsible for capturing signals into workflow history).\n\t *\n\t * Optional. Runtimes that cannot implement push-based signaling (e.g. an in-memory\n\t * test harness) may omit this; sagas should treat absence as a fallback condition\n\t * and use `sleep` + `query` polling instead.\n\t *\n\t * Signal *senders* are runtime-specific (e.g. a Temporal `WorkflowClient.signal()`\n\t * call from an action handler). Apps that need to send signals from action\n\t * handlers should expose a coordination service via `ActionContext.services`\n\t * — the platform does not prescribe the sender API.\n\t *\n\t * @example\n\t * const payload = await ctx.awaitSignal?.<{ result: Record<string, unknown> }>(\n\t * \"userInputProcessed\",\n\t * 5 * 60 * 1000,\n\t * );\n\t * if (payload) { /* handle pushed result *\\/ }\n\t * else { /* timeout — fall back to deterministic path *\\/ }\n\t */\n\tawaitSignal?: <T = unknown>(signalName: string, timeoutMs: number) => Promise<T | null>;\n}\n\nexport interface SagaChildActionInput {\n\tsuffix: string;\n\tactionId: string;\n\tparameters: Record<string, unknown>;\n}\n\nexport type SagaRunChild = (input: SagaChildActionInput) => Promise<Record<string, unknown>>;\n\nexport interface SagaCompletionEvent {\n\teventType: string;\n\tsubjectType: string;\n\tsubjectId: string;\n\tpayload: unknown;\n\teventSchemaVersion?: number;\n}\n\nexport interface SagaCompletion {\n\tresultData: Record<string, unknown>;\n\tevent?: SagaCompletionEvent;\n}\n\nexport type SagaImplementation = (\n\tctx: SagaContext,\n\trunChild: SagaRunChild,\n) => Promise<SagaCompletion>;\n\nexport function assertActionId(actionId: string): asserts actionId is ActionId {\n\tif (!/^[a-z][a-z0-9-]*\\.[a-z][a-z0-9_]*$/.test(actionId)) {\n\t\tthrow new Error(`Invalid action ID: ${actionId}`);\n\t}\n}\n\nexport interface ActionRegistry<TDb = unknown> {\n\tregister(definition: ActionDefinition<TDb>): void;\n\tregisterIfMissing(definition: ActionDefinition<TDb>): void;\n\tresolve(actionId: ActionId): ActionDefinition<TDb> | undefined;\n\thas(actionId: string): actionId is ActionId;\n\tids(): ActionId[];\n}\n\nexport function createActionRegistry<TDb = unknown>(definitions: readonly ActionDefinition<TDb>[] = []): ActionRegistry<TDb> {\n\tconst actions = new Map<ActionId, ActionDefinition<TDb>>();\n\tconst register = (definition: ActionDefinition<TDb>): void => {\n\t\tassertActionId(definition.actionId);\n\t\tif (actions.has(definition.actionId)) throw new Error(`Action \"${definition.actionId}\" is already registered`);\n\t\tif (definition.mutatesDomain && definition.emitsEvents.length === 0) {\n\t\t\tthrow new Error(`Action \"${definition.actionId}\" mutates domain but emits no events. Every mutating action must emit at least one AssetEvent.`);\n\t\t}\n\t\tif (definition.admitSubmission !== undefined && typeof definition.admitSubmission !== \"function\") {\n\t\t\tthrow new Error(`Action \"${definition.actionId}\" declares admitSubmission that is not a function.`);\n\t\t}\n\t\tactions.set(definition.actionId, definition);\n\t};\n\tfor (const definition of definitions) register(definition);\n\treturn {\n\t\tregister,\n\t\tregisterIfMissing(definition) {\n\t\t\tif (!actions.has(definition.actionId)) register(definition);\n\t\t},\n\t\tresolve: (actionId) => actions.get(actionId),\n\t\thas: (actionId): actionId is ActionId => actions.has(actionId as ActionId),\n\t\tids: () => Array.from(actions.keys()),\n\t};\n}\n"],"mappings":";;AAyBA,MAAa,cAAoC;CAChD;CACA;CACA;CACA;CACA;CACA;AACD;AAEA,SAAgB,YAAY,OAAmC;CAC9D,OAAQ,YAAkC,SAAS,KAAK;AACzD;AAEA,SAAgB,gBAAgB,OAA2C;CAC1E,IAAI,CAAC,YAAY,KAAK,GACrB,MAAM,IAAI,MAAM,sBAAsB,OAAO;AAE/C;AA0QA,SAAgB,eAAe,UAAgD;CAC9E,IAAI,CAAC,qCAAqC,KAAK,QAAQ,GACtD,MAAM,IAAI,MAAM,sBAAsB,UAAU;AAElD;AAUA,SAAgB,qBAAoC,cAAgD,CAAC,GAAwB;CAC5H,MAAM,0BAAU,IAAI,IAAqC;CACzD,MAAM,YAAY,eAA4C;EAC7D,eAAe,WAAW,QAAQ;EAClC,IAAI,QAAQ,IAAI,WAAW,QAAQ,GAAG,MAAM,IAAI,MAAM,WAAW,WAAW,SAAS,wBAAwB;EAC7G,IAAI,WAAW,iBAAiB,WAAW,YAAY,WAAW,GACjE,MAAM,IAAI,MAAM,WAAW,WAAW,SAAS,+FAA+F;EAE/I,IAAI,WAAW,oBAAoB,KAAA,KAAa,OAAO,WAAW,oBAAoB,YACrF,MAAM,IAAI,MAAM,WAAW,WAAW,SAAS,mDAAmD;EAEnG,QAAQ,IAAI,WAAW,UAAU,UAAU;CAC5C;CACA,KAAK,MAAM,cAAc,aAAa,SAAS,UAAU;CACzD,OAAO;EACN;EACA,kBAAkB,YAAY;GAC7B,IAAI,CAAC,QAAQ,IAAI,WAAW,QAAQ,GAAG,SAAS,UAAU;EAC3D;EACA,UAAU,aAAa,QAAQ,IAAI,QAAQ;EAC3C,MAAM,aAAmC,QAAQ,IAAI,QAAoB;EACzE,WAAW,MAAM,KAAK,QAAQ,KAAK,CAAC;CACrC;AACD"}
|