@decionis/agent-safe-pipeline 0.1.3 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. package/README.md +477 -16
  2. package/dist/Index.d.ts +9 -0
  3. package/dist/Index.d.ts.map +1 -1
  4. package/dist/Index.js +8 -0
  5. package/dist/Index.js.map +1 -1
  6. package/dist/approval/PresenceApprovalCoordinator.d.ts +25 -0
  7. package/dist/approval/PresenceApprovalCoordinator.d.ts.map +1 -1
  8. package/dist/approval/PresenceApprovalCoordinator.js +54 -6
  9. package/dist/approval/PresenceApprovalCoordinator.js.map +1 -1
  10. package/dist/audit/AuditRecorder.d.ts +122 -0
  11. package/dist/audit/AuditRecorder.d.ts.map +1 -0
  12. package/dist/audit/AuditRecorder.js +312 -0
  13. package/dist/audit/AuditRecorder.js.map +1 -0
  14. package/dist/decision/CreateGate.d.ts +123 -0
  15. package/dist/decision/CreateGate.d.ts.map +1 -0
  16. package/dist/decision/CreateGate.js +211 -0
  17. package/dist/decision/CreateGate.js.map +1 -0
  18. package/dist/decision/DecionisGate.d.ts +109 -3
  19. package/dist/decision/DecionisGate.d.ts.map +1 -1
  20. package/dist/decision/DecionisGate.js +823 -46
  21. package/dist/decision/DecionisGate.js.map +1 -1
  22. package/dist/decision/DecisionAuthority.d.ts +76 -1
  23. package/dist/decision/DecisionAuthority.d.ts.map +1 -1
  24. package/dist/decision/DecisionAuthority.js.map +1 -1
  25. package/dist/decision/FixtureDecisionAuthority.d.ts +27 -1
  26. package/dist/decision/FixtureDecisionAuthority.d.ts.map +1 -1
  27. package/dist/decision/FixtureDecisionAuthority.js +47 -0
  28. package/dist/decision/FixtureDecisionAuthority.js.map +1 -1
  29. package/dist/decision/ImmutableGateDecision.d.ts.map +1 -1
  30. package/dist/decision/ImmutableGateDecision.js +26 -0
  31. package/dist/decision/ImmutableGateDecision.js.map +1 -1
  32. package/dist/decision/Provision.d.ts +33 -0
  33. package/dist/decision/Provision.d.ts.map +1 -0
  34. package/dist/decision/Provision.js +116 -0
  35. package/dist/decision/Provision.js.map +1 -0
  36. package/dist/decision/ShadowGate.d.ts +31 -0
  37. package/dist/decision/ShadowGate.d.ts.map +1 -0
  38. package/dist/decision/ShadowGate.js +79 -0
  39. package/dist/decision/ShadowGate.js.map +1 -0
  40. package/dist/execution/ActionRegistry.d.ts +66 -0
  41. package/dist/execution/ActionRegistry.d.ts.map +1 -1
  42. package/dist/execution/ActionRegistry.js +110 -1
  43. package/dist/execution/ActionRegistry.js.map +1 -1
  44. package/dist/execution/AuthorizationVerifier.d.ts +149 -1
  45. package/dist/execution/AuthorizationVerifier.d.ts.map +1 -1
  46. package/dist/execution/AuthorizationVerifier.js +302 -27
  47. package/dist/execution/AuthorizationVerifier.js.map +1 -1
  48. package/dist/execution/SafeExecutor.d.ts +102 -7
  49. package/dist/execution/SafeExecutor.d.ts.map +1 -1
  50. package/dist/execution/SafeExecutor.js +288 -17
  51. package/dist/execution/SafeExecutor.js.map +1 -1
  52. package/dist/http/ClientIdentification.d.ts +22 -0
  53. package/dist/http/ClientIdentification.d.ts.map +1 -0
  54. package/dist/http/ClientIdentification.js +44 -0
  55. package/dist/http/ClientIdentification.js.map +1 -0
  56. package/dist/http/Credential.d.ts +17 -0
  57. package/dist/http/Credential.d.ts.map +1 -0
  58. package/dist/http/Credential.js +5 -0
  59. package/dist/http/Credential.js.map +1 -0
  60. package/dist/http/StoredCredentials.d.ts +34 -0
  61. package/dist/http/StoredCredentials.d.ts.map +1 -0
  62. package/dist/http/StoredCredentials.js +85 -0
  63. package/dist/http/StoredCredentials.js.map +1 -0
  64. package/dist/intent/CanonicalIntentHasher.d.ts +1 -1
  65. package/dist/intent/CanonicalIntentHasher.d.ts.map +1 -1
  66. package/dist/intent/CanonicalIntentHasher.js +9 -2
  67. package/dist/intent/CanonicalIntentHasher.js.map +1 -1
  68. package/dist/intent/ExecutionIntent.d.ts +26 -2
  69. package/dist/intent/ExecutionIntent.d.ts.map +1 -1
  70. package/dist/intent/ExecutionIntent.js +11 -0
  71. package/dist/intent/ExecutionIntent.js.map +1 -1
  72. package/dist/intent/IntentCapture.d.ts +5 -0
  73. package/dist/intent/IntentCapture.d.ts.map +1 -1
  74. package/dist/intent/IntentCapture.js +15 -1
  75. package/dist/intent/IntentCapture.js.map +1 -1
  76. package/dist/report/DecisionReport.d.ts +22 -0
  77. package/dist/report/DecisionReport.d.ts.map +1 -0
  78. package/dist/report/DecisionReport.js +37 -0
  79. package/dist/report/DecisionReport.js.map +1 -0
  80. package/dist/report/DossierReport.d.ts +43 -0
  81. package/dist/report/DossierReport.d.ts.map +1 -0
  82. package/dist/report/DossierReport.js +130 -0
  83. package/dist/report/DossierReport.js.map +1 -0
  84. package/dist/report/HostedOutcome.d.ts +18 -0
  85. package/dist/report/HostedOutcome.d.ts.map +1 -0
  86. package/dist/report/HostedOutcome.js +24 -0
  87. package/dist/report/HostedOutcome.js.map +1 -0
  88. package/dist/shadow/ShadowPipeline.d.ts +75 -5
  89. package/dist/shadow/ShadowPipeline.d.ts.map +1 -1
  90. package/dist/shadow/ShadowPipeline.js +157 -7
  91. package/dist/shadow/ShadowPipeline.js.map +1 -1
  92. package/dist/testing/Index.d.ts +12 -0
  93. package/dist/testing/Index.d.ts.map +1 -0
  94. package/dist/testing/Index.js +12 -0
  95. package/dist/testing/Index.js.map +1 -0
  96. package/dist/testing/LocalAuthority.d.ts +292 -0
  97. package/dist/testing/LocalAuthority.d.ts.map +1 -0
  98. package/dist/testing/LocalAuthority.js +1124 -0
  99. package/dist/testing/LocalAuthority.js.map +1 -0
  100. package/dist/testing/LocalPresence.d.ts +210 -0
  101. package/dist/testing/LocalPresence.d.ts.map +1 -0
  102. package/dist/testing/LocalPresence.js +473 -0
  103. package/dist/testing/LocalPresence.js.map +1 -0
  104. package/package.json +40 -4
@@ -0,0 +1,79 @@
1
+ import { FailClosedDecision, } from "./DecisionAuthority.js";
2
+ import { immutableGateDecision } from "./ImmutableGateDecision.js";
3
+ /** Higher is more restrictive. The Decionis contract has no fourth verdict. */
4
+ const RESTRICTIVENESS = Object.freeze({
5
+ ALLOW: 0,
6
+ ESCALATE: 1,
7
+ BLOCK: 2,
8
+ });
9
+ /**
10
+ * Runs a local authority and a hosted Decionis gate against the same intent.
11
+ *
12
+ * `SHADOW`: the local decision governs execution exactly as it would alone,
13
+ * and the hosted evaluation rides along as `hosted` for display and audit. A
14
+ * hosted failure is recorded and changes nothing, so setting a key cannot
15
+ * break an integration that works today.
16
+ *
17
+ * `ENFORCEMENT`: the hosted decision governs, because only its grant can be
18
+ * claimed by the enforcement verifier. The local authority can still tighten
19
+ * it: when the local verdict is strictly more restrictive, that decision is
20
+ * returned instead, and it carries no hosted grant.
21
+ *
22
+ * Neither mode returns a decision less restrictive than the local authority's.
23
+ */
24
+ export class ShadowGate {
25
+ local;
26
+ hosted;
27
+ mode;
28
+ evaluationMode;
29
+ constructor(local, hosted, mode) {
30
+ this.local = local;
31
+ this.hosted = hosted;
32
+ this.mode = mode;
33
+ if (mode !== "SHADOW" && mode !== "ENFORCEMENT") {
34
+ throw new Error("DECIONIS_GATE_MODE_INVALID");
35
+ }
36
+ const declared = mode === "ENFORCEMENT" ? mode : local.evaluationMode;
37
+ if (declared !== undefined)
38
+ this.evaluationMode = declared;
39
+ }
40
+ async evaluate(captured, evidence, options = {}) {
41
+ const [local, hosted] = await Promise.all([
42
+ this.local.evaluate(captured, evidence, options),
43
+ this.hostedDecision(captured, evidence, options),
44
+ ]);
45
+ const governs = this.mode === "ENFORCEMENT" &&
46
+ RESTRICTIVENESS[hosted.verdict] >= RESTRICTIVENESS[local.verdict];
47
+ return immutableGateDecision({
48
+ ...(governs ? hosted : local),
49
+ hosted: {
50
+ mode: this.mode,
51
+ governs,
52
+ verdict: hosted.verdict,
53
+ decisionId: hosted.decisionId,
54
+ dossierId: hosted.dossierId,
55
+ reasonCodes: hosted.reasonCodes,
56
+ failClosed: hosted.failClosed,
57
+ verificationUrl: hosted.verificationUrl ?? null,
58
+ },
59
+ });
60
+ }
61
+ /**
62
+ * The hosted side never rejects and never answers about another intent:
63
+ * either would let a network fault or a misbound service reach execution.
64
+ */
65
+ async hostedDecision(captured, evidence, options) {
66
+ let decision;
67
+ try {
68
+ decision = await this.hosted.evaluate(captured, evidence, options);
69
+ }
70
+ catch {
71
+ return FailClosedDecision.create(captured.intentHash, "AUTHORITY_UNAVAILABLE");
72
+ }
73
+ if (decision.intentHash !== captured.intentHash) {
74
+ return FailClosedDecision.create(captured.intentHash, "AUTHORITY_BINDING_MISMATCH");
75
+ }
76
+ return decision;
77
+ }
78
+ }
79
+ //# sourceMappingURL=ShadowGate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ShadowGate.js","sourceRoot":"","sources":["../../src/decision/ShadowGate.ts"],"names":[],"mappings":"AACA,OAAO,EACL,kBAAkB,GAOnB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AAEnE,+EAA+E;AAC/E,MAAM,eAAe,GAA8C,MAAM,CAAC,MAAM,CAAC;IAC/E,KAAK,EAAE,CAAC;IACR,QAAQ,EAAE,CAAC;IACX,KAAK,EAAE,CAAC;CACT,CAAC,CAAC;AAEH;;;;;;;;;;;;;;GAcG;AACH,MAAM,OAAO,UAAU;IAIF;IACA;IACA;IALH,cAAc,CAA0B;IAExD,YACmB,KAAwB,EACxB,MAAyB,EACzB,IAA4B;QAF5B,UAAK,GAAL,KAAK,CAAmB;QACxB,WAAM,GAAN,MAAM,CAAmB;QACzB,SAAI,GAAJ,IAAI,CAAwB;QAE7C,IAAI,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,aAAa,EAAE,CAAC;YAChD,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;QAChD,CAAC;QACD,MAAM,QAAQ,GAAG,IAAI,KAAK,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,cAAc,CAAC;QACtE,IAAI,QAAQ,KAAK,SAAS;YAAE,IAAI,CAAC,cAAc,GAAG,QAAQ,CAAC;IAC7D,CAAC;IAEM,KAAK,CAAC,QAAQ,CACnB,QAAwB,EACxB,QAA2B,EAC3B,UAAqC,EAAE;QAEvC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;YACxC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,CAAC;YAChD,IAAI,CAAC,cAAc,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,CAAC;SACjD,CAAC,CAAC;QACH,MAAM,OAAO,GACX,IAAI,CAAC,IAAI,KAAK,aAAa;YAC3B,eAAe,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,eAAe,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACpE,OAAO,qBAAqB,CAAC;YAC3B,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC;YAC7B,MAAM,EAAE;gBACN,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,OAAO;gBACP,OAAO,EAAE,MAAM,CAAC,OAAO;gBACvB,UAAU,EAAE,MAAM,CAAC,UAAU;gBAC7B,SAAS,EAAE,MAAM,CAAC,SAAS;gBAC3B,WAAW,EAAE,MAAM,CAAC,WAAW;gBAC/B,UAAU,EAAE,MAAM,CAAC,UAAU;gBAC7B,eAAe,EAAE,MAAM,CAAC,eAAe,IAAI,IAAI;aAChD;SACF,CAAC,CAAC;IACL,CAAC;IAED;;;OAGG;IACK,KAAK,CAAC,cAAc,CAC1B,QAAwB,EACxB,QAAsC,EACtC,OAAkC;QAElC,IAAI,QAAsB,CAAC;QAC3B,IAAI,CAAC;YACH,QAAQ,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;QACrE,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,kBAAkB,CAAC,MAAM,CAAC,QAAQ,CAAC,UAAU,EAAE,uBAAuB,CAAC,CAAC;QACjF,CAAC;QACD,IAAI,QAAQ,CAAC,UAAU,KAAK,QAAQ,CAAC,UAAU,EAAE,CAAC;YAChD,OAAO,kBAAkB,CAAC,MAAM,CAAC,QAAQ,CAAC,UAAU,EAAE,4BAA4B,CAAC,CAAC;QACtF,CAAC;QACD,OAAO,QAAQ,CAAC;IAClB,CAAC;CACF"}
@@ -5,18 +5,84 @@ export interface ActionExecutionContext<TParameters> {
5
5
  readonly intent: CapturedIntent;
6
6
  readonly parameters: TParameters;
7
7
  readonly authorization: VerifiedAuthorization;
8
+ /**
9
+ * Trusted handlers must place the provider side effect inside `dispatch.run`.
10
+ * This records the point after which a transport error has an unknown outcome
11
+ * and exposes only the intent-bound idempotency key, never an execution token.
12
+ */
13
+ readonly dispatch: ProviderDispatch;
8
14
  }
15
+ export interface ProviderDispatch {
16
+ readonly idempotencyKey: string;
17
+ run<TResult>(operation: (idempotencyKey: string) => Promise<TResult> | TResult): Promise<TResult>;
18
+ }
19
+ export interface ActionReconciliationContext<TParameters> {
20
+ readonly intent: CapturedIntent;
21
+ readonly parameters: TParameters;
22
+ readonly idempotencyKey: string;
23
+ }
24
+ export type ProviderReconciliation<TResult> = {
25
+ readonly status: "COMPLETED";
26
+ readonly result: TResult;
27
+ } | {
28
+ readonly status: "NOT_EXECUTED";
29
+ } | {
30
+ readonly status: "UNKNOWN";
31
+ };
9
32
  export interface ActionHandler<TParameters, TResult> {
10
33
  readonly parametersSchema: z.ZodType<TParameters>;
11
34
  execute(context: ActionExecutionContext<TParameters>): Promise<TResult> | TResult;
35
+ /** Read-only provider lookup. It must never initiate or retry a side effect. */
36
+ reconcile?(context: ActionReconciliationContext<TParameters>): Promise<ProviderReconciliation<TResult>> | ProviderReconciliation<TResult>;
37
+ }
38
+ export type ActionExecutionAttempt = {
39
+ readonly status: "COMPLETED";
40
+ readonly result: unknown;
41
+ } | {
42
+ readonly status: "FAILED_BEFORE_DISPATCH";
43
+ } | {
44
+ readonly status: "REFUSED_AFTER_DISPATCH";
45
+ readonly reason: string;
46
+ } | {
47
+ readonly status: "UNKNOWN_AFTER_DISPATCH";
48
+ };
49
+ /**
50
+ * What a handler throws when the provider refused, definitively, after the
51
+ * dispatch boundary was crossed.
52
+ *
53
+ * Without this, a handler has two ways to report a refusal and neither is
54
+ * true. Returning normally says the side effect happened. Throwing says the
55
+ * outcome is unknown, which invites a reconciliation of something that never
56
+ * needed one. This says the third thing: the request reached the provider,
57
+ * the provider said no, and nothing was effected.
58
+ *
59
+ * Only the provider's own deterministic refusal belongs here — a 4xx with a
60
+ * body that says which rule refused it. A timeout, a 5xx, a dropped
61
+ * connection or an unreadable answer is not a refusal, and throwing this for
62
+ * one of those would turn "nobody knows" into "definitely not", which is the
63
+ * one direction this boundary must never move in.
64
+ *
65
+ * Thrown before the dispatch, it is a handler failure like any other: a
66
+ * refusal cannot be claimed for a request that was never sent.
67
+ */
68
+ export declare class ProviderRefusal extends Error {
69
+ /** The provider's own reason, as a code; never its response body. */
70
+ readonly reason: string;
71
+ constructor(
72
+ /** The provider's own reason, as a code; never its response body. */
73
+ reason: string);
12
74
  }
13
75
  export declare class ActionRegistry {
14
76
  private readonly actions;
77
+ private readonly pendingReconciliations;
15
78
  private sealed;
16
79
  register<TParameters, TResult>(action: string, handler: ActionHandler<TParameters, TResult>): this;
17
80
  seal(): this;
18
81
  has(action: string): boolean;
19
82
  validate(captured: CapturedIntent): void;
20
83
  execute(captured: CapturedIntent, authorization: VerifiedAuthorization): Promise<unknown>;
84
+ executeTracked(captured: CapturedIntent, authorization: VerifiedAuthorization): Promise<ActionExecutionAttempt>;
85
+ reconcile(captured: CapturedIntent, idempotencyKey: string): Promise<ProviderReconciliation<unknown>>;
86
+ private validReconciliation;
21
87
  }
22
88
  //# sourceMappingURL=ActionRegistry.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ActionRegistry.d.ts","sourceRoot":"","sources":["../../src/execution/ActionRegistry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAC7B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AAExE,MAAM,WAAW,sBAAsB,CAAC,WAAW;IACjD,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAC;IAChC,QAAQ,CAAC,UAAU,EAAE,WAAW,CAAC;IACjC,QAAQ,CAAC,aAAa,EAAE,qBAAqB,CAAC;CAC/C;AAED,MAAM,WAAW,aAAa,CAAC,WAAW,EAAE,OAAO;IACjD,QAAQ,CAAC,gBAAgB,EAAE,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;IAClD,OAAO,CAAC,OAAO,EAAE,sBAAsB,CAAC,WAAW,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;CACnF;AAOD,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAuC;IAC/D,OAAO,CAAC,MAAM,CAAS;IAEhB,QAAQ,CAAC,WAAW,EAAE,OAAO,EAClC,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,aAAa,CAAC,WAAW,EAAE,OAAO,CAAC,GAC3C,IAAI;IAOA,IAAI,IAAI,IAAI;IAKZ,GAAG,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO;IAI5B,QAAQ,CAAC,QAAQ,EAAE,cAAc,GAAG,IAAI;IASlC,OAAO,CAClB,QAAQ,EAAE,cAAc,EACxB,aAAa,EAAE,qBAAqB,GACnC,OAAO,CAAC,OAAO,CAAC;CAQpB"}
1
+ {"version":3,"file":"ActionRegistry.d.ts","sourceRoot":"","sources":["../../src/execution/ActionRegistry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAC7B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AAExE,MAAM,WAAW,sBAAsB,CAAC,WAAW;IACjD,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAC;IAChC,QAAQ,CAAC,UAAU,EAAE,WAAW,CAAC;IACjC,QAAQ,CAAC,aAAa,EAAE,qBAAqB,CAAC;IAC9C;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,CAAC;CACrC;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,GAAG,CAAC,OAAO,EAAE,SAAS,EAAE,CAAC,cAAc,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CACnG;AAED,MAAM,WAAW,2BAA2B,CAAC,WAAW;IACtD,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAC;IAChC,QAAQ,CAAC,UAAU,EAAE,WAAW,CAAC;IACjC,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;CACjC;AAED,MAAM,MAAM,sBAAsB,CAAC,OAAO,IACtC;IAAE,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAA;CAAE,GAC1D;IAAE,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAA;CAAE,GACnC;IAAE,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAA;CAAE,CAAC;AAEnC,MAAM,WAAW,aAAa,CAAC,WAAW,EAAE,OAAO;IACjD,QAAQ,CAAC,gBAAgB,EAAE,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;IAClD,OAAO,CAAC,OAAO,EAAE,sBAAsB,CAAC,WAAW,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;IAClF,gFAAgF;IAChF,SAAS,CAAC,CACR,OAAO,EAAE,2BAA2B,CAAC,WAAW,CAAC,GAChD,OAAO,CAAC,sBAAsB,CAAC,OAAO,CAAC,CAAC,GAAG,sBAAsB,CAAC,OAAO,CAAC,CAAC;CAC/E;AAUD,MAAM,MAAM,sBAAsB,GAC9B;IAAE,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAA;CAAE,GAC1D;IAAE,QAAQ,CAAC,MAAM,EAAE,wBAAwB,CAAA;CAAE,GAC7C;IAAE,QAAQ,CAAC,MAAM,EAAE,wBAAwB,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACtE;IAAE,QAAQ,CAAC,MAAM,EAAE,wBAAwB,CAAA;CAAE,CAAC;AAElD;;;;;;;;;;;;;;;;;;GAkBG;AACH,qBAAa,eAAgB,SAAQ,KAAK;IAEtC,qEAAqE;aACrD,MAAM,EAAE,MAAM;;IAD9B,qEAAqE;IACrD,MAAM,EAAE,MAAM;CAKjC;AAED,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAuC;IAC/D,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAGnC;IACJ,OAAO,CAAC,MAAM,CAAS;IAEhB,QAAQ,CAAC,WAAW,EAAE,OAAO,EAClC,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,aAAa,CAAC,WAAW,EAAE,OAAO,CAAC,GAC3C,IAAI;IAOA,IAAI,IAAI,IAAI;IAKZ,GAAG,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO;IAI5B,QAAQ,CAAC,QAAQ,EAAE,cAAc,GAAG,IAAI;IASlC,OAAO,CAClB,QAAQ,EAAE,cAAc,EACxB,aAAa,EAAE,qBAAqB,GACnC,OAAO,CAAC,OAAO,CAAC;IAMN,cAAc,CACzB,QAAQ,EAAE,cAAc,EACxB,aAAa,EAAE,qBAAqB,GACnC,OAAO,CAAC,sBAAsB,CAAC;IAuCrB,SAAS,CACpB,QAAQ,EAAE,cAAc,EACxB,cAAc,EAAE,MAAM,GACrB,OAAO,CAAC,sBAAsB,CAAC,OAAO,CAAC,CAAC;IA+B3C,OAAO,CAAC,mBAAmB;CAiB5B"}
@@ -1,5 +1,35 @@
1
+ /**
2
+ * What a handler throws when the provider refused, definitively, after the
3
+ * dispatch boundary was crossed.
4
+ *
5
+ * Without this, a handler has two ways to report a refusal and neither is
6
+ * true. Returning normally says the side effect happened. Throwing says the
7
+ * outcome is unknown, which invites a reconciliation of something that never
8
+ * needed one. This says the third thing: the request reached the provider,
9
+ * the provider said no, and nothing was effected.
10
+ *
11
+ * Only the provider's own deterministic refusal belongs here — a 4xx with a
12
+ * body that says which rule refused it. A timeout, a 5xx, a dropped
13
+ * connection or an unreadable answer is not a refusal, and throwing this for
14
+ * one of those would turn "nobody knows" into "definitely not", which is the
15
+ * one direction this boundary must never move in.
16
+ *
17
+ * Thrown before the dispatch, it is a handler failure like any other: a
18
+ * refusal cannot be claimed for a request that was never sent.
19
+ */
20
+ export class ProviderRefusal extends Error {
21
+ reason;
22
+ constructor(
23
+ /** The provider's own reason, as a code; never its response body. */
24
+ reason) {
25
+ super(reason);
26
+ this.reason = reason;
27
+ this.name = "ProviderRefusal";
28
+ }
29
+ }
1
30
  export class ActionRegistry {
2
31
  actions = new Map();
32
+ pendingReconciliations = new Map();
3
33
  sealed = false;
4
34
  register(action, handler) {
5
35
  if (this.sealed)
@@ -27,6 +57,12 @@ export class ActionRegistry {
27
57
  }
28
58
  }
29
59
  async execute(captured, authorization) {
60
+ const attempt = await this.executeTracked(captured, authorization);
61
+ if (attempt.status === "COMPLETED")
62
+ return attempt.result;
63
+ throw new Error(attempt.status);
64
+ }
65
+ async executeTracked(captured, authorization) {
30
66
  if (!this.sealed)
31
67
  throw new Error("ACTION_REGISTRY_NOT_SEALED");
32
68
  const handler = this.actions.get(captured.intent.action);
@@ -35,7 +71,80 @@ export class ActionRegistry {
35
71
  const result = handler.parametersSchema.safeParse(captured.intent.parameters);
36
72
  if (!result.success)
37
73
  throw new Error("ACTION_PARAMETERS_INVALID");
38
- return handler.execute({ intent: captured, parameters: result.data, authorization });
74
+ let dispatched = false;
75
+ const dispatch = Object.freeze({
76
+ idempotencyKey: captured.intent.idempotencyKey,
77
+ run: async (operation) => {
78
+ if (dispatched)
79
+ throw new Error("PROVIDER_DISPATCH_ALREADY_STARTED");
80
+ dispatched = true;
81
+ return await operation(captured.intent.idempotencyKey);
82
+ },
83
+ });
84
+ try {
85
+ return {
86
+ status: "COMPLETED",
87
+ result: await handler.execute({
88
+ intent: captured,
89
+ parameters: result.data,
90
+ authorization,
91
+ dispatch,
92
+ }),
93
+ };
94
+ }
95
+ catch (error) {
96
+ // A refusal the provider made is only a refusal if the request reached
97
+ // it. Before the dispatch it is a handler failure, because nothing was
98
+ // sent for anyone to refuse.
99
+ if (dispatched && error instanceof ProviderRefusal) {
100
+ return { status: "REFUSED_AFTER_DISPATCH", reason: error.reason };
101
+ }
102
+ return { status: dispatched ? "UNKNOWN_AFTER_DISPATCH" : "FAILED_BEFORE_DISPATCH" };
103
+ }
104
+ }
105
+ async reconcile(captured, idempotencyKey) {
106
+ if (!this.sealed)
107
+ throw new Error("ACTION_REGISTRY_NOT_SEALED");
108
+ if (idempotencyKey !== captured.intent.idempotencyKey) {
109
+ throw new Error("RECONCILIATION_BINDING_MISMATCH");
110
+ }
111
+ const handler = this.actions.get(captured.intent.action);
112
+ if (!handler)
113
+ throw new Error("ACTION_NOT_REGISTERED");
114
+ const parameters = handler.parametersSchema.safeParse(captured.intent.parameters);
115
+ if (!parameters.success)
116
+ throw new Error("ACTION_PARAMETERS_INVALID");
117
+ if (handler.reconcile === undefined)
118
+ return { status: "UNKNOWN" };
119
+ const key = `${captured.intentHash}\u0000${idempotencyKey}`;
120
+ const pending = this.pendingReconciliations.get(key);
121
+ if (pending !== undefined)
122
+ return await pending;
123
+ const reconciliation = Promise.resolve()
124
+ .then(async () => this.validReconciliation(await handler.reconcile?.({
125
+ intent: captured,
126
+ parameters: parameters.data,
127
+ idempotencyKey,
128
+ })))
129
+ .catch(() => ({ status: "UNKNOWN" }))
130
+ .finally(() => this.pendingReconciliations.delete(key));
131
+ this.pendingReconciliations.set(key, reconciliation);
132
+ return await reconciliation;
133
+ }
134
+ validReconciliation(value) {
135
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
136
+ return { status: "UNKNOWN" };
137
+ }
138
+ const record = value;
139
+ const keys = Object.keys(record);
140
+ if (record["status"] === "COMPLETED" && keys.length === 2 && "result" in record) {
141
+ return { status: "COMPLETED", result: record["result"] };
142
+ }
143
+ if ((record["status"] === "NOT_EXECUTED" || record["status"] === "UNKNOWN") &&
144
+ keys.length === 1) {
145
+ return { status: record["status"] };
146
+ }
147
+ return { status: "UNKNOWN" };
39
148
  }
40
149
  }
41
150
  //# sourceMappingURL=ActionRegistry.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ActionRegistry.js","sourceRoot":"","sources":["../../src/execution/ActionRegistry.ts"],"names":[],"mappings":"AAoBA,MAAM,OAAO,cAAc;IACR,OAAO,GAAG,IAAI,GAAG,EAA4B,CAAC;IACvD,MAAM,GAAG,KAAK,CAAC;IAEhB,QAAQ,CACb,MAAc,EACd,OAA4C;QAE5C,IAAI,IAAI,CAAC,MAAM;YAAE,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;QAC3D,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;QAC3E,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,OAA2B,CAAC,CAAC;QACtD,OAAO,IAAI,CAAC;IACd,CAAC;IAEM,IAAI;QACT,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;QACnB,OAAO,IAAI,CAAC;IACd,CAAC;IAEM,GAAG,CAAC,MAAc;QACvB,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAClC,CAAC;IAEM,QAAQ,CAAC,QAAwB;QACtC,IAAI,CAAC,IAAI,CAAC,MAAM;YAAE,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;QAChE,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QACzD,IAAI,CAAC,OAAO;YAAE,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC;QACvD,IAAI,CAAC,OAAO,CAAC,gBAAgB,CAAC,SAAS,CAAC,QAAQ,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,OAAO,EAAE,CAAC;YAC5E,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;QAC/C,CAAC;IACH,CAAC;IAEM,KAAK,CAAC,OAAO,CAClB,QAAwB,EACxB,aAAoC;QAEpC,IAAI,CAAC,IAAI,CAAC,MAAM;YAAE,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;QAChE,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QACzD,IAAI,CAAC,OAAO;YAAE,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC;QACvD,MAAM,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,SAAS,CAAC,QAAQ,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QAC9E,IAAI,CAAC,MAAM,CAAC,OAAO;YAAE,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;QAClE,OAAO,OAAO,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,CAAC,IAAI,EAAE,aAAa,EAAE,CAAC,CAAC;IACvF,CAAC;CACF"}
1
+ {"version":3,"file":"ActionRegistry.js","sourceRoot":"","sources":["../../src/execution/ActionRegistry.ts"],"names":[],"mappings":"AAuDA;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,OAAO,eAAgB,SAAQ,KAAK;IAGtB;IAFlB;IACE,qEAAqE;IACrD,MAAc;QAE9B,KAAK,CAAC,MAAM,CAAC,CAAC;QAFE,WAAM,GAAN,MAAM,CAAQ;QAG9B,IAAI,CAAC,IAAI,GAAG,iBAAiB,CAAC;IAChC,CAAC;CACF;AAED,MAAM,OAAO,cAAc;IACR,OAAO,GAAG,IAAI,GAAG,EAA4B,CAAC;IAC9C,sBAAsB,GAAG,IAAI,GAAG,EAG9C,CAAC;IACI,MAAM,GAAG,KAAK,CAAC;IAEhB,QAAQ,CACb,MAAc,EACd,OAA4C;QAE5C,IAAI,IAAI,CAAC,MAAM;YAAE,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;QAC3D,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;QAC3E,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,OAA2B,CAAC,CAAC;QACtD,OAAO,IAAI,CAAC;IACd,CAAC;IAEM,IAAI;QACT,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;QACnB,OAAO,IAAI,CAAC;IACd,CAAC;IAEM,GAAG,CAAC,MAAc;QACvB,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAClC,CAAC;IAEM,QAAQ,CAAC,QAAwB;QACtC,IAAI,CAAC,IAAI,CAAC,MAAM;YAAE,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;QAChE,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QACzD,IAAI,CAAC,OAAO;YAAE,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC;QACvD,IAAI,CAAC,OAAO,CAAC,gBAAgB,CAAC,SAAS,CAAC,QAAQ,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,OAAO,EAAE,CAAC;YAC5E,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;QAC/C,CAAC;IACH,CAAC;IAEM,KAAK,CAAC,OAAO,CAClB,QAAwB,EACxB,aAAoC;QAEpC,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC;QACnE,IAAI,OAAO,CAAC,MAAM,KAAK,WAAW;YAAE,OAAO,OAAO,CAAC,MAAM,CAAC;QAC1D,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAClC,CAAC;IAEM,KAAK,CAAC,cAAc,CACzB,QAAwB,EACxB,aAAoC;QAEpC,IAAI,CAAC,IAAI,CAAC,MAAM;YAAE,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;QAChE,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QACzD,IAAI,CAAC,OAAO;YAAE,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC;QACvD,MAAM,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,SAAS,CAAC,QAAQ,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QAC9E,IAAI,CAAC,MAAM,CAAC,OAAO;YAAE,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;QAClE,IAAI,UAAU,GAAG,KAAK,CAAC;QACvB,MAAM,QAAQ,GAAqB,MAAM,CAAC,MAAM,CAAC;YAC/C,cAAc,EAAE,QAAQ,CAAC,MAAM,CAAC,cAAc;YAC9C,GAAG,EAAE,KAAK,EACR,SAAiE,EAC/C,EAAE;gBACpB,IAAI,UAAU;oBAAE,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;gBACrE,UAAU,GAAG,IAAI,CAAC;gBAClB,OAAO,MAAM,SAAS,CAAC,QAAQ,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC;YACzD,CAAC;SACF,CAAC,CAAC;QAEH,IAAI,CAAC;YACH,OAAO;gBACL,MAAM,EAAE,WAAW;gBACnB,MAAM,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC;oBAC5B,MAAM,EAAE,QAAQ;oBAChB,UAAU,EAAE,MAAM,CAAC,IAAI;oBACvB,aAAa;oBACb,QAAQ;iBACT,CAAC;aACH,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,uEAAuE;YACvE,uEAAuE;YACvE,6BAA6B;YAC7B,IAAI,UAAU,IAAI,KAAK,YAAY,eAAe,EAAE,CAAC;gBACnD,OAAO,EAAE,MAAM,EAAE,wBAAwB,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC;YACpE,CAAC;YACD,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC,wBAAwB,CAAC,CAAC,CAAC,wBAAwB,EAAE,CAAC;QACtF,CAAC;IACH,CAAC;IAEM,KAAK,CAAC,SAAS,CACpB,QAAwB,EACxB,cAAsB;QAEtB,IAAI,CAAC,IAAI,CAAC,MAAM;YAAE,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;QAChE,IAAI,cAAc,KAAK,QAAQ,CAAC,MAAM,CAAC,cAAc,EAAE,CAAC;YACtD,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC;QACrD,CAAC;QACD,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QACzD,IAAI,CAAC,OAAO;YAAE,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC;QACvD,MAAM,UAAU,GAAG,OAAO,CAAC,gBAAgB,CAAC,SAAS,CAAC,QAAQ,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QAClF,IAAI,CAAC,UAAU,CAAC,OAAO;YAAE,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;QACtE,IAAI,OAAO,CAAC,SAAS,KAAK,SAAS;YAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;QAElE,MAAM,GAAG,GAAG,GAAG,QAAQ,CAAC,UAAU,SAAS,cAAc,EAAE,CAAC;QAC5D,MAAM,OAAO,GAAG,IAAI,CAAC,sBAAsB,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACrD,IAAI,OAAO,KAAK,SAAS;YAAE,OAAO,MAAM,OAAO,CAAC;QAEhD,MAAM,cAAc,GAAG,OAAO,CAAC,OAAO,EAAE;aACrC,IAAI,CAAC,KAAK,IAAI,EAAE,CACf,IAAI,CAAC,mBAAmB,CACtB,MAAM,OAAO,CAAC,SAAS,EAAE,CAAC;YACxB,MAAM,EAAE,QAAQ;YAChB,UAAU,EAAE,UAAU,CAAC,IAAI;YAC3B,cAAc;SACf,CAAC,CACH,CACF;aACA,KAAK,CAAC,GAAoC,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC;aACrE,OAAO,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,sBAAsB,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;QAC1D,IAAI,CAAC,sBAAsB,CAAC,GAAG,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC;QACrD,OAAO,MAAM,cAAc,CAAC;IAC9B,CAAC;IAEO,mBAAmB,CAAC,KAAc;QACxC,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YACxE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;QAC/B,CAAC;QACD,MAAM,MAAM,GAAG,KAAgC,CAAC;QAChD,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACjC,IAAI,MAAM,CAAC,QAAQ,CAAC,KAAK,WAAW,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,IAAI,QAAQ,IAAI,MAAM,EAAE,CAAC;YAChF,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC3D,CAAC;QACD,IACE,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,cAAc,IAAI,MAAM,CAAC,QAAQ,CAAC,KAAK,SAAS,CAAC;YACvE,IAAI,CAAC,MAAM,KAAK,CAAC,EACjB,CAAC;YACD,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;QACtC,CAAC;QACD,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;IAC/B,CAAC;CACF"}
@@ -1,4 +1,6 @@
1
+ import { type Credential } from "../http/Credential.js";
1
2
  import type { CapturedIntent } from "../intent/ExecutionIntent.js";
3
+ import type { JsonObject } from "../intent/JsonValue.js";
2
4
  import type { GateDecision } from "../decision/DecisionAuthority.js";
3
5
  export interface VerifiedAuthorization {
4
6
  readonly decisionId: string;
@@ -6,23 +8,169 @@ export interface VerifiedAuthorization {
6
8
  readonly grantId: string;
7
9
  readonly intentHash: string;
8
10
  readonly expiresAt: string;
11
+ /**
12
+ * When the authority stops accepting a commit for this claim, if it said.
13
+ * A lease is shorter than the grant's own expiry and is the real window a
14
+ * side effect has to finish inside: a commit the authority will no longer
15
+ * record leaves an outcome nobody can reconcile from the record, however
16
+ * successful the dispatch was.
17
+ *
18
+ * Absent when the authority did not return one, which is how a deployment
19
+ * whose issuer predates the field behaves. A consumer that ignores this
20
+ * field is exactly as correct as it was before the field existed.
21
+ */
22
+ readonly leaseExpiresAt?: string;
23
+ /**
24
+ * The digest the authority bound over the canonical action parameters, when
25
+ * it exposed one. It has already been checked against this package's own
26
+ * digest of the same parameters before this object exists: a claim whose
27
+ * digest disagreed was refused, not returned. It is carried so a handler
28
+ * can show a downstream what the authority bound, not so anyone re-checks it.
29
+ */
30
+ readonly payloadDigest?: string;
31
+ /**
32
+ * Proof of this claim a system of record can verify without trusting this
33
+ * process: a compact JWS the authority signed over the grant, the decision,
34
+ * the binding and the lease. A handler forwards it downstream, and a
35
+ * downstream that requires it can refuse an instruction the authority never
36
+ * claimed. Absent when the authority predates it.
37
+ */
38
+ readonly claimAttestation?: string;
39
+ }
40
+ /** Outcome of the downstream attempt reported to the authority after a claimed grant. */
41
+ export type ExecutionCommitOutcome = "COMMITTED" | "FAILED" | "INDETERMINATE";
42
+ /**
43
+ * `RECORDED`: the authority accepted the commit evidence. `PENDING`: it could
44
+ * not be delivered and the authority's lease recovery owns it. `UNSUPPORTED`:
45
+ * the verifier has no finalization contract.
46
+ */
47
+ export type ExecutionFinalization = "RECORDED" | "PENDING" | "UNSUPPORTED";
48
+ /**
49
+ * Exact wire shape of the Decionis Protocol 1.1 `EffectEvidence` contract: an
50
+ * observation of what happened downstream, supplied by the trusted runtime that
51
+ * observed it. This package never constructs, interprets, upgrades, or
52
+ * downgrades an observation; it forwards a bounded, validated copy of the one
53
+ * it was handed, and drops anything outside the contract's own shape rather
54
+ * than serialising a caller-controlled object onto an authenticated request.
55
+ */
56
+ export interface AuthorityEffectEvidence {
57
+ readonly version: "1.0";
58
+ readonly status: "CONFIRMED" | "UNCONFIRMED";
59
+ readonly observation_method: "DOWNSTREAM_ACK" | "READ_AFTER_WRITE" | "EVENT_CONFIRMATION" | "STATE_RECONCILIATION" | "SIGNED_RECEIPT" | "EXTERNAL_ATTESTATION" | "HUMAN_VALIDATION";
60
+ readonly observer: {
61
+ readonly id: string;
62
+ readonly version: string | null;
63
+ } | null;
64
+ readonly expected_effect_digest: string;
65
+ readonly observed_effect_digest: string | null;
66
+ readonly observed_at: string | null;
67
+ readonly evidence_digest: string | null;
68
+ readonly evidence_reference: string | null;
69
+ readonly execution_correlation_id: string;
70
+ }
71
+ /**
72
+ * What the authority itself said about an observation it was sent, narrowed by
73
+ * what this executor knows it sent. `effectEvidenceRecorded` and
74
+ * `effectConfirmation` are the authority's statement, but they are only ever
75
+ * reported for a finalization that actually carried the observation: an
76
+ * authority claiming to have recorded evidence it was not sent is not evidence.
77
+ */
78
+ export interface AuthorityEffectReport {
79
+ /** The finalization that was recorded carried the observation. */
80
+ readonly effectEvidenceSent: boolean;
81
+ /**
82
+ * An earlier finalization attempt carried the observation and the authority
83
+ * refused it, so this commit record was recovered without it. Distinguishes a
84
+ * refused observation from one that was dropped or never supplied.
85
+ */
86
+ readonly effectEvidenceRefused: boolean;
87
+ readonly effectEvidenceRecorded: boolean;
88
+ readonly effectConfirmation: "CONFIRMED" | "UNCONFIRMED";
89
+ }
90
+ export interface AuthorizationFinalizationInput {
91
+ readonly captured: CapturedIntent;
92
+ readonly decision: GateDecision;
93
+ readonly authorization: VerifiedAuthorization;
94
+ readonly outcome: ExecutionCommitOutcome;
95
+ /**
96
+ * Optional observation of the downstream effect, forwarded verbatim. It is
97
+ * sent only when the signed grant committed to an expected-effect digest, the
98
+ * evidence names that same digest, and its `execution_correlation_id` equals
99
+ * the commit correlation id this grant was claimed with. Otherwise it is
100
+ * dropped, because the authority refuses the entire finalization for evidence
101
+ * it cannot bind and the commit outcome would be lost with it. It is also
102
+ * dropped when it does not conform to the contract's own bounded shape.
103
+ */
104
+ readonly effectEvidence?: AuthorityEffectEvidence;
9
105
  }
10
106
  export interface AuthorizationVerifier {
11
107
  verifyAndConsume(captured: CapturedIntent, decision: GateDecision): Promise<VerifiedAuthorization | null>;
108
+ /**
109
+ * Reports the downstream attempt outcome for an authorization returned by
110
+ * this verifier's `verifyAndConsume`. Finalization is evidence, never
111
+ * authority: it must not retry a side effect, and it must not throw.
112
+ */
113
+ finalize?(input: AuthorizationFinalizationInput): Promise<"RECORDED" | "PENDING">;
12
114
  }
13
115
  export interface DecionisGrantVerifierOptions {
14
116
  readonly baseUrl: string;
15
- readonly apiKey: string;
117
+ /** The Decionis credential, as a value or as a function read at each request. */
118
+ readonly apiKey: Credential;
16
119
  readonly timeoutMs?: number;
17
120
  readonly fetch?: typeof fetch;
18
121
  readonly allowInsecureLoopback?: boolean;
19
122
  }
123
+ /**
124
+ * Claims a Decionis execution grant through `/v1/execution/claim-token`
125
+ * immediately before dispatch and finalizes the attempt through
126
+ * `/v1/execution/finalize-token` afterwards, so commit evidence joins the
127
+ * Decision Dossier chain.
128
+ */
20
129
  export declare class DecionisGrantVerifier implements AuthorizationVerifier {
21
130
  private readonly baseUrl;
22
131
  private readonly apiKey;
23
132
  private readonly timeoutMs;
24
133
  private readonly fetchImpl;
134
+ /** Claim material is keyed by the frozen authorization it belongs to and never exposed. */
135
+ private readonly claims;
136
+ /** The authority's own answer about an observation, keyed by the frozen authorization. */
137
+ private readonly reports;
138
+ /**
139
+ * The digest the authority binds over the action parameters: SHA-256 of
140
+ * their RFC 8785 canonical form, the same canonicalization the intent hash
141
+ * uses. Exposed so a test, or an authority implementation, can produce the
142
+ * value this verifier will accept.
143
+ */
144
+ static parametersDigest(parameters: JsonObject): `sha256:${string}`;
25
145
  constructor(options: DecionisGrantVerifierOptions);
26
146
  verifyAndConsume(captured: CapturedIntent, decision: GateDecision): Promise<VerifiedAuthorization | null>;
147
+ finalize(input: AuthorizationFinalizationInput): Promise<"RECORDED" | "PENDING">;
148
+ /**
149
+ * What the authority reported about effect evidence for an authorization this
150
+ * verifier finalized. `null` until a finalization was recorded. This is the
151
+ * authority's statement, never this package's inference.
152
+ */
153
+ effectReport(authorization: VerifiedAuthorization): AuthorityEffectReport | null;
154
+ /**
155
+ * `REFUSED` only for the one status a finalization refusal uses (409); every
156
+ * other non-ok status, a throw, a timeout, or an oversize body is `PENDING`,
157
+ * exactly as it was before effect evidence existed. A rate-limited or
158
+ * unauthenticated authority must never be re-posted to.
159
+ */
160
+ private post;
161
+ /**
162
+ * Effect evidence reaches the authority only when this executor can prove the
163
+ * authority will bind it: it must conform to the contract's bounded shape,
164
+ * the grant the authority returned must have committed to an expected-effect
165
+ * digest, the evidence must name that exact digest, and it must carry the
166
+ * correlation id this claim was made with. Unbindable evidence is dropped
167
+ * rather than sent, because the authority answers it with a 409 that aborts
168
+ * the whole finalization rather than discarding the observation.
169
+ *
170
+ * The checks run against the parsed copy, which is also the copy that is
171
+ * serialised, so a caller object with accessors cannot present one value to
172
+ * the drop rule and another to the wire.
173
+ */
174
+ private static bindableEffectEvidence;
27
175
  }
28
176
  //# sourceMappingURL=AuthorizationVerifier.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"AuthorizationVerifier.d.ts","sourceRoot":"","sources":["../../src/execution/AuthorizationVerifier.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAC;AAErE,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,qBAAqB;IACpC,gBAAgB,CACd,QAAQ,EAAE,cAAc,EACxB,QAAQ,EAAE,YAAY,GACrB,OAAO,CAAC,qBAAqB,GAAG,IAAI,CAAC,CAAC;CAC1C;AAmBD,MAAM,WAAW,4BAA4B;IAC3C,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;IAC9B,QAAQ,CAAC,qBAAqB,CAAC,EAAE,OAAO,CAAC;CAC1C;AAED,qBAAa,qBAAsB,YAAW,qBAAqB;IACjE,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAe;gBAEtB,OAAO,EAAE,4BAA4B;IAU3C,gBAAgB,CAC3B,QAAQ,EAAE,cAAc,EACxB,QAAQ,EAAE,YAAY,GACrB,OAAO,CAAC,qBAAqB,GAAG,IAAI,CAAC;CA0DzC"}
1
+ {"version":3,"file":"AuthorizationVerifier.d.ts","sourceRoot":"","sources":["../../src/execution/AuthorizationVerifier.ts"],"names":[],"mappings":"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"}