@fabricorg/platform-host 7.6.0 → 8.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +196 -0
- package/MIGRATION-8.md +247 -0
- package/README.md +376 -47
- package/dist/index.cjs +5400 -4392
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1513 -1405
- package/dist/index.d.ts +1513 -1405
- package/dist/index.js +5393 -4387
- package/dist/index.js.map +1 -1
- package/package.json +9 -7
package/dist/index.d.cts
CHANGED
|
@@ -1,193 +1,194 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import { ActionDefinition, ActionId, ActionStatus, ActorType, AdapterCircuitBreakerProvider, AdapterImplementation, AgentActionPolicyEvaluator, AgentActionRiskTier, AgentActionRoute, AssetEventEnvelope, EvidencePacketReference, ExecutionAttestation, ExecutionPrincipal, ExternalReconciliation, FabricRuntimeServices, GovernanceRuntimeEvidence, ModuleRegistry, MutationFootprint, MutationGovernanceResolver, PolicyObligation, PolicyObligationStatus, PolicyOutcome, RuntimePolicyDefinition, canonicalJson } from "@fabricorg/platform";
|
|
2
|
+
import { AssemblyLockfile } from "@fabricorg/assembly";
|
|
3
|
+
//#region src/observability.d.ts
|
|
5
4
|
/** Version of the vendor-neutral health/readiness contract. */
|
|
6
|
-
declare const PLATFORM_HOST_HEALTH_CONTRACT_VERSION: 1;
|
|
5
|
+
export declare const PLATFORM_HOST_HEALTH_CONTRACT_VERSION: 1;
|
|
7
6
|
/**
|
|
8
7
|
* Stable metric names. Adapters may translate these names to a vendor's
|
|
9
8
|
* naming convention, but applications should not derive names from labels.
|
|
10
9
|
*/
|
|
11
|
-
declare const PLATFORM_HOST_METRIC_NAMES: {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
10
|
+
export declare const PLATFORM_HOST_METRIC_NAMES: {
|
|
11
|
+
readonly workerCyclesStarted: "fabric.platform.worker.cycles.started";
|
|
12
|
+
readonly workerCyclesCompleted: "fabric.platform.worker.cycles.completed";
|
|
13
|
+
readonly workerCyclesFailed: "fabric.platform.worker.cycles.failed";
|
|
14
|
+
readonly invocationSubmitted: "fabric.platform.invocation.submitted";
|
|
15
|
+
readonly invocationAdmissionRefused: "fabric.platform.invocation.admission_refused";
|
|
16
|
+
readonly invocationExecutionStarted: "fabric.platform.invocation.execution_started";
|
|
17
|
+
readonly invocationLeaseClaimed: "fabric.platform.invocation.lease_claimed";
|
|
18
|
+
readonly invocationCompleted: "fabric.platform.invocation.completed";
|
|
19
|
+
readonly invocationFailed: "fabric.platform.invocation.failed";
|
|
20
|
+
readonly invocationPolicyBlocked: "fabric.platform.invocation.policy_blocked";
|
|
21
|
+
readonly invocationValidationFailed: "fabric.platform.invocation.validation_failed";
|
|
22
|
+
readonly invocationApprovalWaited: "fabric.platform.invocation.approval_waited";
|
|
23
|
+
readonly invocationReconciliationRequired: "fabric.platform.invocation.reconciliation_required";
|
|
24
|
+
readonly adapterEvidenceRefused: "fabric.platform.invocation.adapter_evidence_refused";
|
|
25
|
+
readonly outboxRelayCyclesStarted: "fabric.platform.outbox.relay_cycles.started";
|
|
26
|
+
readonly outboxRelayCyclesCompleted: "fabric.platform.outbox.relay_cycles.completed";
|
|
27
|
+
readonly outboxRelayCyclesFailed: "fabric.platform.outbox.relay_cycles.failed";
|
|
28
|
+
readonly outboxLeaseClaimed: "fabric.platform.outbox.lease_claimed";
|
|
29
|
+
readonly outboxPublished: "fabric.platform.outbox.published";
|
|
30
|
+
readonly outboxFailed: "fabric.platform.outbox.failed";
|
|
31
|
+
readonly outboxDeadLettered: "fabric.platform.outbox.dead_lettered";
|
|
32
|
+
readonly outboxRequeued: "fabric.platform.outbox.requeued";
|
|
33
|
+
readonly outboxRequeueRefused: "fabric.platform.outbox.requeue_refused";
|
|
34
|
+
readonly invocationBacklog: "fabric.platform.invocation.backlog";
|
|
35
|
+
readonly invocationRunning: "fabric.platform.invocation.running";
|
|
36
|
+
readonly invocationExpiredLeases: "fabric.platform.invocation.expired_leases";
|
|
37
|
+
readonly invocationApprovalWaits: "fabric.platform.invocation.approval_waits";
|
|
38
|
+
readonly invocationReconciliationRequiredGauge: "fabric.platform.invocation.reconciliation_required.count";
|
|
39
|
+
readonly outboxBacklog: "fabric.platform.outbox.backlog";
|
|
40
|
+
readonly outboxExpiredLeases: "fabric.platform.outbox.expired_leases";
|
|
41
|
+
readonly outboxDeadLetters: "fabric.platform.outbox.dead_letters";
|
|
42
42
|
};
|
|
43
|
-
type PlatformHostMetricName = (typeof PLATFORM_HOST_METRIC_NAMES)[keyof typeof PLATFORM_HOST_METRIC_NAMES];
|
|
44
|
-
type PlatformHostTelemetryEventName = "worker.cycle.started" | "worker.cycle.completed" | "worker.cycle.failed" | "invocation.submitted" | "invocation.admission_refused" | "invocation.execution_started" | "invocation.lease_claimed" | "invocation.completed" | "invocation.failed" | "invocation.policy_blocked" | "invocation.validation_failed" | "invocation.approval_waited" | "invocation.reconciliation_required" | "outbox.relay.started" | "outbox.relay.completed" | "outbox.relay.failed" | "outbox.lease_claimed" | "outbox.published" | "outbox.failed" | "outbox.dead_lettered" | "outbox.requeued" | "outbox.requeue_refused";
|
|
45
|
-
type PlatformHostMetricType = "counter" | "gauge";
|
|
46
|
-
type PlatformHostTelemetryAttribute = string | number | boolean;
|
|
47
|
-
interface PlatformHostLifecycleTelemetry {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
}
|
|
57
|
-
interface PlatformHostMetricTelemetry {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
}
|
|
66
|
-
type PlatformHostTelemetryRecord = PlatformHostLifecycleTelemetry | PlatformHostMetricTelemetry;
|
|
67
|
-
type PlatformHostTelemetryHook = (record: PlatformHostTelemetryRecord) => void | Promise<void>;
|
|
43
|
+
export type PlatformHostMetricName = (typeof PLATFORM_HOST_METRIC_NAMES)[keyof typeof PLATFORM_HOST_METRIC_NAMES];
|
|
44
|
+
export type PlatformHostTelemetryEventName = "worker.cycle.started" | "worker.cycle.completed" | "worker.cycle.failed" | "invocation.submitted" | "invocation.admission_refused" | "invocation.execution_started" | "invocation.lease_claimed" | "invocation.completed" | "invocation.failed" | "invocation.policy_blocked" | "invocation.validation_failed" | "invocation.approval_waited" | "invocation.reconciliation_required" | "invocation.adapter_evidence_refused" | "outbox.relay.started" | "outbox.relay.completed" | "outbox.relay.failed" | "outbox.lease_claimed" | "outbox.published" | "outbox.failed" | "outbox.dead_lettered" | "outbox.requeued" | "outbox.requeue_refused";
|
|
45
|
+
export type PlatformHostMetricType = "counter" | "gauge";
|
|
46
|
+
export type PlatformHostTelemetryAttribute = string | number | boolean;
|
|
47
|
+
export interface PlatformHostLifecycleTelemetry {
|
|
48
|
+
kind: "event";
|
|
49
|
+
name: PlatformHostTelemetryEventName;
|
|
50
|
+
metricName: PlatformHostMetricName;
|
|
51
|
+
metricType: "counter";
|
|
52
|
+
occurredAt: Date;
|
|
53
|
+
tenantId?: string;
|
|
54
|
+
spaceId?: string;
|
|
55
|
+
attributes?: Readonly<Record<string, PlatformHostTelemetryAttribute>>;
|
|
56
|
+
}
|
|
57
|
+
export interface PlatformHostMetricTelemetry {
|
|
58
|
+
kind: "metric";
|
|
59
|
+
name: PlatformHostMetricName;
|
|
60
|
+
metricType: PlatformHostMetricType;
|
|
61
|
+
value: number;
|
|
62
|
+
observedAt: Date;
|
|
63
|
+
tenantId?: string;
|
|
64
|
+
spaceId?: string;
|
|
65
|
+
}
|
|
66
|
+
export type PlatformHostTelemetryRecord = PlatformHostLifecycleTelemetry | PlatformHostMetricTelemetry;
|
|
67
|
+
export type PlatformHostTelemetryHook = (record: PlatformHostTelemetryRecord) => void | Promise<void>;
|
|
68
68
|
/**
|
|
69
69
|
* A deliberately small sink contract. No OpenTelemetry, Prometheus, or
|
|
70
70
|
* vendor SDK is required by Platform Host.
|
|
71
71
|
*/
|
|
72
|
-
type PlatformHostTelemetry = PlatformHostTelemetryHook | {
|
|
73
|
-
|
|
72
|
+
export type PlatformHostTelemetry = PlatformHostTelemetryHook | {
|
|
73
|
+
record: PlatformHostTelemetryHook;
|
|
74
74
|
};
|
|
75
|
-
type PlatformHostTelemetryInput = Omit<PlatformHostLifecycleTelemetry, "occurredAt" | "metricType"> & {
|
|
76
|
-
|
|
75
|
+
export type PlatformHostTelemetryInput = Omit<PlatformHostLifecycleTelemetry, "occurredAt" | "metricType"> & {
|
|
76
|
+
occurredAt?: Date;
|
|
77
77
|
} | Omit<PlatformHostMetricTelemetry, "observedAt"> & {
|
|
78
|
-
|
|
78
|
+
observedAt?: Date;
|
|
79
79
|
};
|
|
80
80
|
/**
|
|
81
81
|
* Telemetry is best effort and must never change governed mutation behavior.
|
|
82
82
|
* Promise-returning hooks are detached and rejected hooks are swallowed.
|
|
83
83
|
*/
|
|
84
|
-
declare function emitPlatformHostTelemetry(telemetry: PlatformHostTelemetry | undefined, input: PlatformHostTelemetryInput): void;
|
|
85
|
-
interface PlatformHostHealthQuery {
|
|
84
|
+
export declare function emitPlatformHostTelemetry(telemetry: PlatformHostTelemetry | undefined, input: PlatformHostTelemetryInput): void;
|
|
85
|
+
export interface PlatformHostHealthQuery {
|
|
86
|
+
tenantId?: string;
|
|
87
|
+
spaceId?: string;
|
|
88
|
+
now: Date;
|
|
89
|
+
}
|
|
90
|
+
export interface PlatformHostHealthCounts {
|
|
91
|
+
invocationBacklog: number;
|
|
92
|
+
invocationRunning: number;
|
|
93
|
+
invocationExpiredLeases: number;
|
|
94
|
+
invocationApprovalWaits: number;
|
|
95
|
+
invocationReconciliationRequired: number;
|
|
96
|
+
outboxBacklog: number;
|
|
97
|
+
outboxExpiredLeases: number;
|
|
98
|
+
outboxDeadLetters: number;
|
|
99
|
+
}
|
|
100
|
+
export interface PlatformHostWorkerHealthInput {
|
|
101
|
+
lastHeartbeatAt: Date;
|
|
102
|
+
staleAfterMs: number;
|
|
103
|
+
}
|
|
104
|
+
export interface PlatformHostHealthOptions<TDb> {
|
|
105
|
+
store: PlatformHostStore<TDb>;
|
|
106
|
+
tenantId?: string;
|
|
107
|
+
spaceId?: string;
|
|
108
|
+
now?: () => Date;
|
|
109
|
+
/**
|
|
110
|
+
* Worker liveness is supplied by the deployment's supervisor or telemetry
|
|
111
|
+
* bridge. Only aggregate healthy/stale counts are returned.
|
|
112
|
+
*/
|
|
113
|
+
workers?: readonly PlatformHostWorkerHealthInput[];
|
|
114
|
+
telemetry?: PlatformHostTelemetry;
|
|
115
|
+
}
|
|
116
|
+
export interface PlatformHostHealthStore<TDb> extends RecoverablePlatformHostStore<TDb> {
|
|
117
|
+
getHealthCounts(input: PlatformHostHealthQuery): Promise<PlatformHostHealthCounts>;
|
|
118
|
+
}
|
|
119
|
+
export type PlatformHostHealthStatus = "healthy" | "degraded" | "unhealthy";
|
|
120
|
+
export interface PlatformHostHealthSnapshot {
|
|
121
|
+
contractVersion: typeof PLATFORM_HOST_HEALTH_CONTRACT_VERSION;
|
|
122
|
+
generatedAt: Date;
|
|
123
|
+
scope: {
|
|
86
124
|
tenantId?: string;
|
|
87
125
|
spaceId?: string;
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
telemetry?: PlatformHostTelemetry;
|
|
115
|
-
}
|
|
116
|
-
interface PlatformHostHealthStore<TDb> extends RecoverablePlatformHostStore<TDb> {
|
|
117
|
-
getHealthCounts(input: PlatformHostHealthQuery): Promise<PlatformHostHealthCounts>;
|
|
118
|
-
}
|
|
119
|
-
type PlatformHostHealthStatus = "healthy" | "degraded" | "unhealthy";
|
|
120
|
-
interface PlatformHostHealthSnapshot {
|
|
121
|
-
contractVersion: typeof PLATFORM_HOST_HEALTH_CONTRACT_VERSION;
|
|
122
|
-
generatedAt: Date;
|
|
123
|
-
scope: {
|
|
124
|
-
tenantId?: string;
|
|
125
|
-
spaceId?: string;
|
|
126
|
-
};
|
|
127
|
-
dataAvailable: boolean;
|
|
128
|
-
status: PlatformHostHealthStatus;
|
|
129
|
-
readiness: {
|
|
130
|
-
ready: boolean;
|
|
131
|
-
reasonCodes: readonly PlatformHostReadinessReason[];
|
|
132
|
-
};
|
|
133
|
-
workers: {
|
|
134
|
-
reported: number;
|
|
135
|
-
healthy: number;
|
|
136
|
-
stale: number;
|
|
137
|
-
};
|
|
138
|
-
invocations: {
|
|
139
|
-
backlog: number;
|
|
140
|
-
running: number;
|
|
141
|
-
expiredLeases: number;
|
|
142
|
-
approvalWaits: number;
|
|
143
|
-
reconciliationRequired: number;
|
|
144
|
-
};
|
|
145
|
-
outbox: {
|
|
146
|
-
backlog: number;
|
|
147
|
-
expiredLeases: number;
|
|
148
|
-
deadLetters: number;
|
|
149
|
-
};
|
|
150
|
-
}
|
|
151
|
-
type PlatformHostReadinessReason = "health_source_unavailable" | "workers_stale" | "invocation_expired_leases" | "outbox_expired_leases" | "outbox_dead_letters" | "reconciliation_required";
|
|
126
|
+
};
|
|
127
|
+
dataAvailable: boolean;
|
|
128
|
+
status: PlatformHostHealthStatus;
|
|
129
|
+
readiness: {
|
|
130
|
+
ready: boolean;
|
|
131
|
+
reasonCodes: readonly PlatformHostReadinessReason[];
|
|
132
|
+
};
|
|
133
|
+
workers: {
|
|
134
|
+
reported: number;
|
|
135
|
+
healthy: number;
|
|
136
|
+
stale: number;
|
|
137
|
+
};
|
|
138
|
+
invocations: {
|
|
139
|
+
backlog: number;
|
|
140
|
+
running: number;
|
|
141
|
+
expiredLeases: number;
|
|
142
|
+
approvalWaits: number;
|
|
143
|
+
reconciliationRequired: number;
|
|
144
|
+
};
|
|
145
|
+
outbox: {
|
|
146
|
+
backlog: number;
|
|
147
|
+
expiredLeases: number;
|
|
148
|
+
deadLetters: number;
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
export type PlatformHostReadinessReason = "health_source_unavailable" | "workers_stale" | "invocation_expired_leases" | "outbox_expired_leases" | "outbox_dead_letters" | "reconciliation_required";
|
|
152
152
|
/**
|
|
153
153
|
* Read tenant/space-scoped operational counts without returning invocation,
|
|
154
154
|
* actor, parameter, error, event, or adapter data.
|
|
155
155
|
*/
|
|
156
|
-
declare function getPlatformHostHealthSnapshot<TDb>(options: PlatformHostHealthOptions<TDb>): Promise<PlatformHostHealthSnapshot>;
|
|
157
|
-
|
|
156
|
+
export declare function getPlatformHostHealthSnapshot<TDb>(options: PlatformHostHealthOptions<TDb>): Promise<PlatformHostHealthSnapshot>;
|
|
157
|
+
//#endregion
|
|
158
|
+
//#region src/types.d.ts
|
|
158
159
|
/** Durable Host lifecycle generation, independent from the npm package version. */
|
|
159
|
-
declare const PLATFORM_HOST_CONTRACT_VERSION: 2;
|
|
160
|
-
type InvocationSource = "ui" | "api" | "agent" | "worker" | "system" | (string & {});
|
|
161
|
-
type NamespacedAttributes = Record<string, string>;
|
|
162
|
-
interface InvocationProvenance {
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
}
|
|
169
|
-
type AuthorizationGoverningMoment = "capture" | "execution" | "both";
|
|
170
|
-
interface AuthorizationBinding {
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
}
|
|
181
|
-
interface IdempotencyConflict {
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
}
|
|
187
|
-
declare class IdempotencyConflictError extends Error {
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
160
|
+
export declare const PLATFORM_HOST_CONTRACT_VERSION: 2;
|
|
161
|
+
export type InvocationSource = "ui" | "api" | "agent" | "worker" | "system" | (string & {});
|
|
162
|
+
export type NamespacedAttributes = Record<string, string>;
|
|
163
|
+
export interface InvocationProvenance {
|
|
164
|
+
source: InvocationSource;
|
|
165
|
+
correlationId: string;
|
|
166
|
+
causationId?: string;
|
|
167
|
+
traceAttributes?: NamespacedAttributes;
|
|
168
|
+
auditAttributes?: NamespacedAttributes;
|
|
169
|
+
}
|
|
170
|
+
export type AuthorizationGoverningMoment = "capture" | "execution" | "both";
|
|
171
|
+
export interface AuthorizationBinding {
|
|
172
|
+
id: string;
|
|
173
|
+
tenantId: string;
|
|
174
|
+
actorId: string;
|
|
175
|
+
actionId: string;
|
|
176
|
+
parameterDigest: string;
|
|
177
|
+
resourceScope?: string;
|
|
178
|
+
capturedAt: string;
|
|
179
|
+
expiresAt?: string;
|
|
180
|
+
governingMoment: AuthorizationGoverningMoment;
|
|
181
|
+
}
|
|
182
|
+
export interface IdempotencyConflict {
|
|
183
|
+
code: "IDEMPOTENCY_CONFLICT";
|
|
184
|
+
idempotencyKey: string;
|
|
185
|
+
existingInvocationId: string;
|
|
186
|
+
reasons: Array<"actor" | "authority_binding" | "action_version" | "parameters">;
|
|
187
|
+
}
|
|
188
|
+
export declare class IdempotencyConflictError extends Error {
|
|
189
|
+
readonly conflict: IdempotencyConflict;
|
|
190
|
+
readonly code: "IDEMPOTENCY_CONFLICT";
|
|
191
|
+
constructor(conflict: IdempotencyConflict);
|
|
191
192
|
}
|
|
192
193
|
/**
|
|
193
194
|
* Why `submitAction` did not admit a submission of an action that declares
|
|
@@ -199,7 +200,7 @@ declare class IdempotencyConflictError extends Error {
|
|
|
199
200
|
* JSON-data object Host could copy at submission (a Proxy, a function, a
|
|
200
201
|
* Date, a typed array or SharedArrayBuffer, a cycle, a getter that throws).
|
|
201
202
|
*/
|
|
202
|
-
type ActionAdmissionRefusal = "refused" | "failed" | "timed_out" | "invalid_decision" | "invalid_parameters";
|
|
203
|
+
export type ActionAdmissionRefusal = "refused" | "failed" | "timed_out" | "invalid_decision" | "invalid_parameters";
|
|
203
204
|
/**
|
|
204
205
|
* Thrown by `submitAction` when a declared admission check did not admit the
|
|
205
206
|
* submission. Host wrote nothing for it: no invocation, idempotency key,
|
|
@@ -207,17 +208,17 @@ type ActionAdmissionRefusal = "refused" | "failed" | "timed_out" | "invalid_deci
|
|
|
207
208
|
* refusal and, for `refused`, the check's code; never a submitted value or
|
|
208
209
|
* anything the check threw.
|
|
209
210
|
*/
|
|
210
|
-
declare class ActionAdmissionError extends Error {
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
}
|
|
220
|
-
type ExternalCompletionRefusal = "still_executing" | "not_found" | "not_awaiting" | "immediate_contract" | "reference_mismatch" | "provider_mismatch" | "invalid_completion" | "result_invalid" | "redaction_failed";
|
|
211
|
+
export declare class ActionAdmissionError extends Error {
|
|
212
|
+
readonly actionId: string;
|
|
213
|
+
readonly refusal: ActionAdmissionRefusal;
|
|
214
|
+
/** The check's own code, present only for `refused`. */
|
|
215
|
+
readonly refusalCode?: string | undefined;
|
|
216
|
+
readonly code: "ACTION_ADMISSION_REFUSED";
|
|
217
|
+
constructor(actionId: string, refusal: ActionAdmissionRefusal,
|
|
218
|
+
/** The check's own code, present only for `refused`. */
|
|
219
|
+
refusalCode?: string | undefined);
|
|
220
|
+
}
|
|
221
|
+
export type ExternalCompletionRefusal = "still_executing" | "not_found" | "not_awaiting" | "immediate_contract" | "reference_mismatch" | "provider_mismatch" | "invalid_completion" | "result_invalid" | "redaction_failed";
|
|
221
222
|
/**
|
|
222
223
|
* Why a completion was not applied, typed so a webhook handler can answer
|
|
223
224
|
* the external system correctly: `retryable` means the invocation is still
|
|
@@ -227,159 +228,162 @@ type ExternalCompletionRefusal = "still_executing" | "not_found" | "not_awaiting
|
|
|
227
228
|
* `redaction_failed` means completion result or error-text redaction failed before writes;
|
|
228
229
|
* it is not retryable.
|
|
229
230
|
*/
|
|
230
|
-
declare class ExternalCompletionError extends Error {
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
}
|
|
236
|
-
interface PendingAssetEvent {
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
}
|
|
243
|
-
interface ActionInvocationRecord {
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
231
|
+
export declare class ExternalCompletionError extends Error {
|
|
232
|
+
readonly refusal: ExternalCompletionRefusal;
|
|
233
|
+
readonly code: "EXTERNAL_COMPLETION_REFUSED";
|
|
234
|
+
constructor(refusal: ExternalCompletionRefusal, message: string);
|
|
235
|
+
get retryable(): boolean;
|
|
236
|
+
}
|
|
237
|
+
export interface PendingAssetEvent {
|
|
238
|
+
eventType: string;
|
|
239
|
+
subjectType: string;
|
|
240
|
+
subjectId: string;
|
|
241
|
+
payload: unknown;
|
|
242
|
+
eventSchemaVersion?: number;
|
|
243
|
+
}
|
|
244
|
+
export interface ActionInvocationRecord {
|
|
245
|
+
id: string;
|
|
246
|
+
tenantId: string;
|
|
247
|
+
spaceId: string;
|
|
248
|
+
actionId: ActionId;
|
|
249
|
+
actionVersion: number;
|
|
250
|
+
actorId: string;
|
|
251
|
+
actorType: ActorType;
|
|
252
|
+
status: ActionStatus;
|
|
253
|
+
parameters: Record<string, unknown>;
|
|
254
|
+
result: Record<string, unknown>;
|
|
255
|
+
correlationId: string;
|
|
256
|
+
causationId?: string;
|
|
257
|
+
idempotencyKey?: string;
|
|
258
|
+
parameterDigest?: string;
|
|
259
|
+
parameterDigestAlgorithm?: "fabric-canonical-json-sha256-v1";
|
|
260
|
+
idempotencyActorId?: string;
|
|
261
|
+
idempotencyAuthorizationBindingId?: string;
|
|
262
|
+
provenance?: Omit<InvocationProvenance, "traceAttributes">;
|
|
263
|
+
authorizationBinding?: AuthorizationBinding;
|
|
264
|
+
executionReason?: ActionExecutionReason;
|
|
265
|
+
authorizationReconciliation?: AuthorizationReconciliationOutcome;
|
|
266
|
+
/** Durable evidence when an adapter returned an ambiguous outcome requiring reconciliation. */
|
|
267
|
+
adapterReconciliation?: AdapterReconciliationOutcome;
|
|
268
|
+
/**
|
|
269
|
+
* Transition Host validated for an idempotent after_adapters action, saved
|
|
270
|
+
* after handler/result/event validation inside a mutation transaction, or before
|
|
271
|
+
* the handler otherwise. Supports recovered StateTransitioned emission and is
|
|
272
|
+
* retained as evidence after completion.
|
|
273
|
+
*/
|
|
274
|
+
pendingStateTransition?: {
|
|
275
|
+
entityType: string;
|
|
276
|
+
entityId: string;
|
|
277
|
+
fromState: string;
|
|
278
|
+
toState: string;
|
|
279
|
+
};
|
|
280
|
+
/**
|
|
281
|
+
* A handoff the host is waiting on. While present the invocation is
|
|
282
|
+
* `running` without a lease: it is not stuck, it is somebody else's turn,
|
|
283
|
+
* and the recovery worker must not re-execute it.
|
|
284
|
+
*/
|
|
285
|
+
pendingCompletion?: PendingExternalCompletion;
|
|
286
|
+
/** The completion an external system delivered, kept so a repeat is recognised and a contradiction is caught. */
|
|
287
|
+
externalCompletion?: RecordedExternalCompletion;
|
|
288
|
+
/** Opaque, non-secret reference used to revalidate delegated execution authority. */
|
|
289
|
+
authorizationBindingId?: string;
|
|
290
|
+
/** Worker claims including the first; approval acceptance sets a minimum of 1. */
|
|
291
|
+
attemptCount: number;
|
|
292
|
+
leaseOwner?: string;
|
|
293
|
+
leaseExpiresAt?: Date;
|
|
294
|
+
/** Monotonic claim generation used to reject writes from expired workers. */
|
|
295
|
+
leaseToken?: number;
|
|
296
|
+
hitlRoute?: AgentActionRoute;
|
|
297
|
+
hitlRiskTier?: AgentActionRiskTier;
|
|
298
|
+
hitlReason?: string;
|
|
299
|
+
hitlPolicyVersion?: string;
|
|
300
|
+
approvalDecision?: PersistedActionApprovalDecision;
|
|
301
|
+
mutationFootprint?: MutationFootprint;
|
|
302
|
+
executionPrincipal?: ExecutionPrincipal;
|
|
303
|
+
runtimeEvidence?: GovernanceRuntimeEvidence;
|
|
304
|
+
/**
|
|
305
|
+
* When `submitAction` admitted the submission through the action's
|
|
306
|
+
* `admitSubmission` check, set on creation and never patched. Host refuses
|
|
307
|
+
* to execute an invocation of an action that declares the check when this
|
|
308
|
+
* is absent, and passes it to the handler as `ActionContext.admittedAt`.
|
|
309
|
+
*/
|
|
310
|
+
admittedAt?: Date;
|
|
311
|
+
error?: string;
|
|
312
|
+
createdAt: Date;
|
|
313
|
+
updatedAt: Date;
|
|
314
|
+
}
|
|
315
|
+
export interface AuthorizationReconciliationOutcome {
|
|
316
|
+
kind: "authorization_expired" | "authorization_denied" | "authorization_missing_capture_evidence";
|
|
317
|
+
governingMoment: AuthorizationGoverningMoment;
|
|
318
|
+
executionReason: ActionExecutionReason;
|
|
319
|
+
authorizationBindingId?: string;
|
|
320
|
+
provenance?: Omit<InvocationProvenance, "traceAttributes">;
|
|
321
|
+
message: string;
|
|
322
|
+
}
|
|
323
|
+
export interface HitlDecisionEvidence {
|
|
324
|
+
route: AgentActionRoute;
|
|
325
|
+
riskTier: AgentActionRiskTier;
|
|
326
|
+
reason: string;
|
|
327
|
+
policyVersion?: string;
|
|
328
|
+
evaluatedAt: Date;
|
|
329
|
+
}
|
|
330
|
+
export interface ActionApprovalDecision {
|
|
331
|
+
approved: boolean;
|
|
332
|
+
approverId: string;
|
|
333
|
+
approverType: ActorType;
|
|
334
|
+
reason?: string;
|
|
335
|
+
editsReference?: string;
|
|
336
|
+
decidedAt?: Date;
|
|
337
|
+
}
|
|
338
|
+
export interface PersistedActionApprovalDecision extends Omit<ActionApprovalDecision, "decidedAt"> {
|
|
339
|
+
decidedAt: Date;
|
|
340
|
+
}
|
|
341
|
+
export interface PolicyEvaluationRecord {
|
|
342
|
+
id: string;
|
|
343
|
+
actionInvocationId: string;
|
|
344
|
+
tenantId: string;
|
|
345
|
+
spaceId: string;
|
|
346
|
+
outcome: PolicyOutcome;
|
|
347
|
+
createdAt: Date;
|
|
348
|
+
}
|
|
349
|
+
export interface PolicyObligationRecord extends PolicyObligation {
|
|
350
|
+
actionInvocationId: string;
|
|
351
|
+
tenantId: string;
|
|
352
|
+
spaceId: string;
|
|
353
|
+
createdAt: Date;
|
|
354
|
+
updatedAt: Date;
|
|
355
|
+
}
|
|
356
|
+
export interface ExecutionAttestationRecord extends ExecutionAttestation {
|
|
357
|
+
id: string;
|
|
358
|
+
actionInvocationId: string;
|
|
359
|
+
tenantId: string;
|
|
360
|
+
spaceId: string;
|
|
361
|
+
adapterInvocationId?: string;
|
|
362
|
+
recordedAt: Date;
|
|
363
|
+
}
|
|
364
|
+
export interface ExternalReconciliationRecord extends ExternalReconciliation {
|
|
365
|
+
id: string;
|
|
366
|
+
actionInvocationId: string;
|
|
367
|
+
tenantId: string;
|
|
368
|
+
spaceId: string;
|
|
369
|
+
}
|
|
370
|
+
export interface PendingExternalCompletion {
|
|
371
|
+
provider: string;
|
|
372
|
+
adapterType: string;
|
|
373
|
+
operation: string;
|
|
374
|
+
adapterInvocationId: string;
|
|
375
|
+
externalReference: string;
|
|
376
|
+
acceptedAt: Date;
|
|
377
|
+
/** Past this instant the host moves the invocation to reconciliation. */
|
|
378
|
+
dueAt?: Date;
|
|
379
|
+
/**
|
|
380
|
+
* Set when the invocation finished executing and parked. A handoff is
|
|
381
|
+
* recorded before the remaining steps run, so until this is set a
|
|
382
|
+
* completion has nothing settled to settle into; it is asked to retry.
|
|
383
|
+
*/
|
|
384
|
+
parkedAt?: Date;
|
|
385
|
+
/** Set with the overdue sweep verdict; does not prove execution parked. */
|
|
386
|
+
overdueAt?: Date;
|
|
383
387
|
}
|
|
384
388
|
/**
|
|
385
389
|
* What an external system reports when it finishes work the host accepted.
|
|
@@ -389,109 +393,180 @@ interface PendingExternalCompletion {
|
|
|
389
393
|
* refused, because completing the wrong invocation is worse than dropping a
|
|
390
394
|
* callback.
|
|
391
395
|
*/
|
|
392
|
-
interface ExternalCompletion {
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
}
|
|
402
|
-
interface RecordedExternalCompletion extends ExternalCompletion {
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
}
|
|
413
|
-
interface ReconcileOverdueCompletionsInput {
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
}
|
|
419
|
-
type AdapterInvocationStatus = "running" | "succeeded" | "failed" | "ambiguous";
|
|
420
|
-
interface AdapterReconciliationOutcome {
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
}
|
|
431
|
-
interface AdapterInvocationRecord {
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
396
|
+
export interface ExternalCompletion {
|
|
397
|
+
externalReference: string;
|
|
398
|
+
outcome: "completed" | "failed";
|
|
399
|
+
/** Merged over the handler's result on completion. */
|
|
400
|
+
result?: Record<string, unknown>;
|
|
401
|
+
error?: string;
|
|
402
|
+
provider?: string;
|
|
403
|
+
evidenceReferences?: EvidencePacketReference[];
|
|
404
|
+
observedAt: Date | string;
|
|
405
|
+
}
|
|
406
|
+
export interface RecordedExternalCompletion extends ExternalCompletion {
|
|
407
|
+
recordedAt: Date;
|
|
408
|
+
/**
|
|
409
|
+
* Canonical digest of provider, reference, outcome, result, error, and
|
|
410
|
+
* evidence. A repeat with the same digest is the same news; a repeat with
|
|
411
|
+
* the same outcome and a different digest is changed evidence, and is a
|
|
412
|
+
* contradiction like a flipped outcome. Observation time is left out,
|
|
413
|
+
* since a redelivery legitimately carries a new one.
|
|
414
|
+
*/
|
|
415
|
+
digest: string;
|
|
416
|
+
}
|
|
417
|
+
export interface ReconcileOverdueCompletionsInput {
|
|
418
|
+
tenantId?: string;
|
|
419
|
+
spaceId?: string;
|
|
420
|
+
limit?: number;
|
|
421
|
+
now?: Date;
|
|
422
|
+
}
|
|
423
|
+
export type AdapterInvocationStatus = "running" | "succeeded" | "failed" | "ambiguous";
|
|
424
|
+
export interface AdapterReconciliationOutcome {
|
|
425
|
+
kind: "adapter_outcome_ambiguous";
|
|
426
|
+
adapterType: string;
|
|
427
|
+
operation: string;
|
|
428
|
+
vendor: string;
|
|
429
|
+
adapterInvocationId: string;
|
|
430
|
+
reason?: string;
|
|
431
|
+
/** Opaque, non-secret reference to external operation state for reconciliation. */
|
|
432
|
+
externalReference?: string;
|
|
433
|
+
message: string;
|
|
434
|
+
}
|
|
435
|
+
export interface AdapterInvocationRecord {
|
|
436
|
+
id: string;
|
|
437
|
+
actionInvocationId: string;
|
|
438
|
+
tenantId: string;
|
|
439
|
+
spaceId: string;
|
|
440
|
+
adapterType: string;
|
|
441
|
+
operation: string;
|
|
442
|
+
vendor: string;
|
|
443
|
+
status: AdapterInvocationStatus;
|
|
444
|
+
input: Record<string, unknown>;
|
|
445
|
+
output?: Record<string, unknown>;
|
|
446
|
+
error?: string;
|
|
447
|
+
/** Redacted checkpoint for replaying an ambiguous settlement without another provider call. */
|
|
448
|
+
reconciliation?: AdapterReconciliationOutcome & {
|
|
449
|
+
/** Original event subject, stored only for settlement recovery. */
|
|
450
|
+
adapterEventSubject?: {
|
|
451
|
+
subjectType: string;
|
|
452
|
+
subjectId: string;
|
|
453
|
+
};
|
|
454
|
+
};
|
|
455
|
+
attempt: number;
|
|
456
|
+
createdAt: Date;
|
|
457
|
+
updatedAt: Date;
|
|
448
458
|
}
|
|
459
|
+
export interface CreateActionInvocationInput extends Omit<ActionInvocationRecord, "createdAt" | "updatedAt" | "attemptCount" | "leaseOwner" | "leaseExpiresAt" | "leaseToken"> {}
|
|
449
460
|
/** Scope of an adapter checkpoint within its owning action invocation. */
|
|
450
|
-
interface AdapterInvocationScope {
|
|
451
|
-
|
|
452
|
-
|
|
461
|
+
export interface AdapterInvocationScope {
|
|
462
|
+
tenantId: string;
|
|
463
|
+
spaceId: string;
|
|
464
|
+
actionInvocationId: string;
|
|
465
|
+
}
|
|
466
|
+
/** Authority for an adapter mutation; verdict evidence uses exact status/error equality. */
|
|
467
|
+
export type AdapterInvocationWriteCondition = {
|
|
468
|
+
kind: "lease";
|
|
469
|
+
leaseOwner: string;
|
|
470
|
+
leaseToken: number;
|
|
471
|
+
} | {
|
|
472
|
+
kind: "verdict";
|
|
473
|
+
status: Exclude<ActionInvocationRecord["status"], "pending" | "running" | "waiting_for_approval">;
|
|
474
|
+
error?: string;
|
|
475
|
+
/** Absent requires no recorded completion; a digest requires that same completion. */
|
|
476
|
+
externalCompletionDigest?: string;
|
|
477
|
+
/** Captured handoff row; other adapter rows need only status/error and row-status fencing.
|
|
478
|
+
* Omit to retain the conservative completion check for adapter writes. Parent enrichment
|
|
479
|
+
* compares the completion digest regardless of this member. */
|
|
480
|
+
completionAdapterInvocationId?: string;
|
|
481
|
+
};
|
|
482
|
+
/** Conditionally enrich this execution's settled parent without changing its status. */
|
|
483
|
+
export interface UpdateSettledActionInvocationInput {
|
|
484
|
+
id: string;
|
|
485
|
+
tenantId: string;
|
|
486
|
+
spaceId: string;
|
|
487
|
+
condition: Extract<AdapterInvocationWriteCondition, {
|
|
488
|
+
kind: "verdict";
|
|
489
|
+
}>;
|
|
490
|
+
patch: Pick<ActionInvocationPatch, "error" | "adapterReconciliation">;
|
|
491
|
+
}
|
|
492
|
+
export type AdapterInvocationPatch = Partial<Pick<AdapterInvocationRecord, "status" | "output" | "error" | "attempt" | "updatedAt" | "reconciliation">>;
|
|
493
|
+
export interface AdapterInvocationWriteInput {
|
|
494
|
+
scope: AdapterInvocationScope;
|
|
495
|
+
condition: AdapterInvocationWriteCondition;
|
|
496
|
+
/** Compare against the current row, inside the same atomic operation. */
|
|
497
|
+
expectedStatuses?: readonly AdapterInvocationRecord["status"][];
|
|
498
|
+
mutation: {
|
|
499
|
+
kind: "create";
|
|
500
|
+
record: AdapterInvocationRecord;
|
|
501
|
+
} | {
|
|
502
|
+
kind: "update";
|
|
503
|
+
id: string;
|
|
504
|
+
patch: AdapterInvocationPatch;
|
|
505
|
+
};
|
|
506
|
+
}
|
|
507
|
+
export interface PlatformHostStore<TDb> {
|
|
508
|
+
readonly db: TDb;
|
|
509
|
+
/**
|
|
510
|
+
* Run against the store's domain handle. This base seam does not promise a
|
|
511
|
+
* database transaction. Use `transactionWithEvents` when domain writes,
|
|
512
|
+
* canonical events, and invocation state must commit atomically.
|
|
513
|
+
*/
|
|
514
|
+
transaction<TResult>(run: (db: TDb) => Promise<TResult>): Promise<TResult>;
|
|
515
|
+
createActionInvocation(input: CreateActionInvocationInput): Promise<ActionInvocationRecord>;
|
|
516
|
+
getActionInvocation(id: string, tenantId: string, spaceId: string): Promise<ActionInvocationRecord | undefined>;
|
|
517
|
+
updateActionInvocation(id: string, tenantId: string, spaceId: string, patch: ActionInvocationPatch): Promise<void>;
|
|
518
|
+
appendPolicyEvaluation(record: PolicyEvaluationRecord): Promise<void>;
|
|
519
|
+
createAdapterInvocation(record: AdapterInvocationRecord): Promise<void>;
|
|
520
|
+
/**
|
|
521
|
+
* Optional atomic parent-authorized adapter create/update. Lease authority
|
|
522
|
+
* requires a running parent with the supplied owner/token; verdict authority
|
|
523
|
+
* requires the exact parent status/error (undefined error equals no error).
|
|
524
|
+
* The completion digest guards the captured completionAdapterInvocationId;
|
|
525
|
+
* other rows retain status/error and expectedStatuses checks. Without a captured
|
|
526
|
+
* row ID the digest check applies conservatively to the mutation too.
|
|
527
|
+
* Match tenant, space and invocation on both rows, locking the parent before
|
|
528
|
+
* the adapter. Return false for a predicate miss, missing parent/row, or a
|
|
529
|
+
* duplicate create. Updates cannot move succeeded/ambiguous to running/failed,
|
|
530
|
+
* even when expectedStatuses is omitted. Creation must match input.scope.
|
|
531
|
+
* Transaction implementations recheck predicates at commit or retain locks.
|
|
532
|
+
* Host uses unchecked legacy writes when this capability is absent: custom
|
|
533
|
+
* stores without it do not protect adapter rows against stale workers.
|
|
534
|
+
*/
|
|
535
|
+
writeAdapterInvocation?(input: AdapterInvocationWriteInput): Promise<boolean>;
|
|
536
|
+
/**
|
|
537
|
+
* Atomic scoped status/error/completion compare-and-set for post-verdict enrichment.
|
|
538
|
+
* Expected alongside writeAdapterInvocation. When absent, Host skips only parent
|
|
539
|
+
* enrichment and still attempts the remaining evidence writes. Refusal is telemetry;
|
|
540
|
+
* thrown errors join the evidence collector.
|
|
541
|
+
*/
|
|
542
|
+
updateSettledActionInvocation?(input: UpdateSettledActionInvocationInput): Promise<boolean>;
|
|
543
|
+
/**
|
|
544
|
+
* Host supplies scope from its store-loaded invocation at adapter call sites.
|
|
545
|
+
* When supplied, stores must match tenant, space, and action invocation:
|
|
546
|
+
* an out-of-scope record returns undefined. Optional for compatibility with
|
|
547
|
+
* existing custom stores and direct callers; tenantIsolationChecks tests
|
|
548
|
+
* scoped read and write conformance.
|
|
549
|
+
*/
|
|
550
|
+
getAdapterInvocation(id: string, scope?: AdapterInvocationScope): Promise<AdapterInvocationRecord | undefined>;
|
|
551
|
+
/**
|
|
552
|
+
* Match all three scope fields when supplied, changing nothing outside it
|
|
553
|
+
* (a not-found error is permitted). Host supplies scope as described above;
|
|
554
|
+
* optional only for compatibility with existing stores and direct callers.
|
|
555
|
+
*/
|
|
556
|
+
updateAdapterInvocation(id: string, patch: Partial<Pick<AdapterInvocationRecord, "status" | "output" | "error" | "attempt" | "updatedAt" | "reconciliation">>, scope?: AdapterInvocationScope): Promise<void>;
|
|
557
|
+
appendEvent(event: AssetEventEnvelope): Promise<void>;
|
|
558
|
+
nextEventSequence(tenantId: string, spaceId: string): Promise<number>;
|
|
559
|
+
/**
|
|
560
|
+
* Return the state and invocation writer of the same event selected by
|
|
561
|
+
* getEntityState, scoped to this subject and tenant/space. Return undefined
|
|
562
|
+
* when that event or its invocation provenance is unavailable. Transaction
|
|
563
|
+
* implementations include pending events visible to getEntityState.
|
|
564
|
+
*/
|
|
565
|
+
getEntityStateSource?(tenantId: string, spaceId: string, entityType: string, entityId: string): Promise<{
|
|
566
|
+
state: string;
|
|
453
567
|
actionInvocationId: string;
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
readonly db: TDb;
|
|
457
|
-
/**
|
|
458
|
-
* Run against the store's domain handle. This base seam does not promise a
|
|
459
|
-
* database transaction. Use `transactionWithEvents` when domain writes,
|
|
460
|
-
* canonical events, and invocation state must commit atomically.
|
|
461
|
-
*/
|
|
462
|
-
transaction<TResult>(run: (db: TDb) => Promise<TResult>): Promise<TResult>;
|
|
463
|
-
createActionInvocation(input: CreateActionInvocationInput): Promise<ActionInvocationRecord>;
|
|
464
|
-
getActionInvocation(id: string, tenantId: string, spaceId: string): Promise<ActionInvocationRecord | undefined>;
|
|
465
|
-
updateActionInvocation(id: string, tenantId: string, spaceId: string, patch: ActionInvocationPatch): Promise<void>;
|
|
466
|
-
appendPolicyEvaluation(record: PolicyEvaluationRecord): Promise<void>;
|
|
467
|
-
createAdapterInvocation(record: AdapterInvocationRecord): Promise<void>;
|
|
468
|
-
/**
|
|
469
|
-
* Host supplies scope from its store-loaded invocation at adapter call sites.
|
|
470
|
-
* When supplied, stores must match tenant, space, and action invocation:
|
|
471
|
-
* an out-of-scope record returns undefined. Optional for compatibility with
|
|
472
|
-
* existing custom stores and direct callers; tenantIsolationChecks tests
|
|
473
|
-
* scoped read and write conformance.
|
|
474
|
-
*/
|
|
475
|
-
getAdapterInvocation(id: string, scope?: AdapterInvocationScope): Promise<AdapterInvocationRecord | undefined>;
|
|
476
|
-
/**
|
|
477
|
-
* Match all three scope fields when supplied, changing nothing outside it
|
|
478
|
-
* (a not-found error is permitted). Host supplies scope as described above;
|
|
479
|
-
* optional only for compatibility with existing stores and direct callers.
|
|
480
|
-
*/
|
|
481
|
-
updateAdapterInvocation(id: string, patch: Partial<Pick<AdapterInvocationRecord, "status" | "output" | "error" | "attempt" | "updatedAt">>, scope?: AdapterInvocationScope): Promise<void>;
|
|
482
|
-
appendEvent(event: AssetEventEnvelope): Promise<void>;
|
|
483
|
-
nextEventSequence(tenantId: string, spaceId: string): Promise<number>;
|
|
484
|
-
/**
|
|
485
|
-
* Return the state and invocation writer of the same event selected by
|
|
486
|
-
* getEntityState, scoped to this subject and tenant/space. Return undefined
|
|
487
|
-
* when that event or its invocation provenance is unavailable. Transaction
|
|
488
|
-
* implementations include pending events visible to getEntityState.
|
|
489
|
-
*/
|
|
490
|
-
getEntityStateSource?(tenantId: string, spaceId: string, entityType: string, entityId: string): Promise<{
|
|
491
|
-
state: string;
|
|
492
|
-
actionInvocationId: string;
|
|
493
|
-
} | undefined>;
|
|
494
|
-
getEntityState(tenantId: string, spaceId: string, entityType: string, entityId: string): Promise<string | undefined>;
|
|
568
|
+
} | undefined>;
|
|
569
|
+
getEntityState(tenantId: string, spaceId: string, entityType: string, entityId: string): Promise<string | undefined>;
|
|
495
570
|
}
|
|
496
571
|
/**
|
|
497
572
|
* Transaction-scoped Host operations used to commit domain writes and their
|
|
@@ -501,154 +576,159 @@ interface PlatformHostStore<TDb> {
|
|
|
501
576
|
* lifecycle method on this object. Implementations must roll the whole unit
|
|
502
577
|
* back when `run` throws.
|
|
503
578
|
*/
|
|
504
|
-
interface PlatformHostMutationTransaction<TDb> {
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
579
|
+
export interface PlatformHostMutationTransaction<TDb> {
|
|
580
|
+
readonly db: TDb;
|
|
581
|
+
/**
|
|
582
|
+
* Read and lock an invocation until this transaction completes.
|
|
583
|
+
* Required by serialized saga parent lifecycle transitions.
|
|
584
|
+
*/
|
|
585
|
+
getActionInvocationForUpdate?(id: string, tenantId: string, spaceId: string): Promise<ActionInvocationRecord | undefined>;
|
|
586
|
+
/**
|
|
587
|
+
* Read one event by its stable identity inside the transaction.
|
|
588
|
+
* Required by serialized saga parent lifecycle transitions.
|
|
589
|
+
*/
|
|
590
|
+
getEvent?(id: string, tenantId: string, spaceId: string): Promise<AssetEventEnvelope | undefined>;
|
|
591
|
+
appendEvent(event: AssetEventEnvelope): Promise<void>;
|
|
592
|
+
appendEventWithOutbox?(event: AssetEventEnvelope, metadata: OutboxEventMetadata): Promise<void>;
|
|
593
|
+
nextEventSequence(tenantId: string, spaceId: string): Promise<number>;
|
|
594
|
+
listEvents(tenantId: string, spaceId: string): Promise<AssetEventEnvelope[]>;
|
|
595
|
+
/**
|
|
596
|
+
* Return the state and invocation writer of the same event selected by
|
|
597
|
+
* getEntityState, scoped to this subject and tenant/space. Return undefined
|
|
598
|
+
* when that event or its invocation provenance is unavailable. Transaction
|
|
599
|
+
* implementations include pending events visible to getEntityState.
|
|
600
|
+
*/
|
|
601
|
+
getEntityStateSource?(tenantId: string, spaceId: string, entityType: string, entityId: string): Promise<{
|
|
602
|
+
state: string;
|
|
603
|
+
actionInvocationId: string;
|
|
604
|
+
} | undefined>;
|
|
605
|
+
getEntityState?(tenantId: string, spaceId: string, entityType: string, entityId: string): Promise<string | undefined>;
|
|
606
|
+
updateActionInvocation(id: string, tenantId: string, spaceId: string, patch: ActionInvocationPatch): Promise<void>;
|
|
607
|
+
updateLeasedActionInvocation?(input: UpdateLeasedActionInvocationInput): Promise<boolean>;
|
|
608
|
+
/**
|
|
609
|
+
* Update an adapter row in this transaction, with the same optional
|
|
610
|
+
* tenant/space/invocation scope semantics as the store method. Host uses
|
|
611
|
+
* this to commit degraded adapter evidence and its terminal verdict together.
|
|
612
|
+
* Omit this member if the adapter row cannot share this transaction.
|
|
613
|
+
*/
|
|
614
|
+
updateAdapterInvocation?: PlatformHostStore<TDb>["updateAdapterInvocation"];
|
|
615
|
+
/** Same conditional write, sharing this transaction and its rollback. */
|
|
616
|
+
writeAdapterInvocation?: PlatformHostStore<TDb>["writeAdapterInvocation"];
|
|
617
|
+
/**
|
|
618
|
+
* Append governance reconciliation evidence in this transaction. Host uses
|
|
619
|
+
* this for overdue sweeps and degraded finalization when adapter output is
|
|
620
|
+
* withheld or a handoff is refused. Implement it alongside the transaction's
|
|
621
|
+
* invocation row lock; an outer-store append while that lock is held can
|
|
622
|
+
* block on a foreign key referencing the invocation. Omit this member if
|
|
623
|
+
* governance evidence cannot share the event/verdict transaction.
|
|
624
|
+
*/
|
|
625
|
+
appendExternalReconciliation?: GovernancePlatformHostStore<TDb>["appendExternalReconciliation"];
|
|
626
|
+
}
|
|
627
|
+
export type OutboxStatus = "pending" | "published" | "dead_letter";
|
|
628
|
+
export type EventPayloadClassification = "public" | "internal" | "confidential" | "restricted";
|
|
629
|
+
export interface OutboxEventMetadata {
|
|
630
|
+
producerModuleVersion: string;
|
|
631
|
+
payloadClassification: EventPayloadClassification;
|
|
632
|
+
traceContext?: Record<string, string>;
|
|
633
|
+
includeProvenance?: boolean;
|
|
634
|
+
/**
|
|
635
|
+
* Only `true` puts the event's `actorId` and `actorType` on the outbox envelope. Absent or any
|
|
636
|
+
* other value leaves them off, and the outbox record says the actor was `suppressed`.
|
|
637
|
+
*/
|
|
638
|
+
includeActor?: boolean;
|
|
559
639
|
}
|
|
560
640
|
/**
|
|
561
641
|
* Whether Host put actor identity on an outbox record's envelope, decided by `includeActor` when
|
|
562
642
|
* the record was written. A record has no value when it predates the decision (`legacy`).
|
|
563
643
|
*/
|
|
564
|
-
type OutboxActorDisclosure = "included" | "suppressed";
|
|
644
|
+
export type OutboxActorDisclosure = "included" | "suppressed";
|
|
565
645
|
/**
|
|
566
646
|
* What the relay tells a publisher about an envelope's actor identity: the record's
|
|
567
647
|
* `OutboxActorDisclosure`, or `legacy` for a record with none. The memory and PostgreSQL stores
|
|
568
648
|
* hydrate actor identity only for `included` records, so their legacy and suppressed envelopes carry
|
|
569
649
|
* none; a consumer that needs it reads the canonical event.
|
|
570
650
|
*/
|
|
571
|
-
type EnterpriseEventActorDisclosure = OutboxActorDisclosure | "legacy";
|
|
572
|
-
interface EnterpriseEventEnvelope {
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
}
|
|
601
|
-
interface OutboxRecord {
|
|
651
|
+
export type EnterpriseEventActorDisclosure = OutboxActorDisclosure | "legacy";
|
|
652
|
+
export interface EnterpriseEventEnvelope {
|
|
653
|
+
eventId: string;
|
|
654
|
+
eventType: string;
|
|
655
|
+
eventSchemaVersion: number;
|
|
656
|
+
tenantId: string;
|
|
657
|
+
spaceId: string;
|
|
658
|
+
subjectType: string;
|
|
659
|
+
subjectId: string;
|
|
660
|
+
sequence: number;
|
|
661
|
+
actionInvocationId?: string;
|
|
662
|
+
correlationId: string;
|
|
663
|
+
causationId?: string;
|
|
664
|
+
/** Present only when `includeActor` opted this event in; the key is absent otherwise. */
|
|
665
|
+
actorId?: string;
|
|
666
|
+
/** Present only when `includeActor` opted this event in; the key is absent otherwise. */
|
|
667
|
+
actorType?: string;
|
|
668
|
+
occurredAt: Date;
|
|
669
|
+
recordedAt: Date;
|
|
670
|
+
producerModuleVersion: string;
|
|
671
|
+
payloadClassification: EventPayloadClassification;
|
|
672
|
+
traceContext?: Record<string, string>;
|
|
673
|
+
provenance?: {
|
|
674
|
+
source: InvocationSource;
|
|
675
|
+
auditAttributes?: NamespacedAttributes;
|
|
676
|
+
};
|
|
677
|
+
/** Present only for events an action declaring provisional consistency emitted. */
|
|
678
|
+
consistency?: "authoritative-now" | "provisional-until-reconciled";
|
|
679
|
+
payload: unknown;
|
|
680
|
+
}
|
|
681
|
+
export interface OutboxRecord {
|
|
682
|
+
id: string;
|
|
683
|
+
tenantId: string;
|
|
684
|
+
spaceId: string;
|
|
685
|
+
event: EnterpriseEventEnvelope;
|
|
686
|
+
/** Absent for a record written before Host recorded the `includeActor` decision. */
|
|
687
|
+
actorDisclosure?: OutboxActorDisclosure;
|
|
688
|
+
status: OutboxStatus;
|
|
689
|
+
attemptCount: number;
|
|
690
|
+
availableAt: Date;
|
|
691
|
+
leaseOwner?: string;
|
|
692
|
+
leaseExpiresAt?: Date;
|
|
693
|
+
leaseToken?: number;
|
|
694
|
+
lastError?: string;
|
|
695
|
+
createdAt: Date;
|
|
696
|
+
publishedAt?: Date;
|
|
697
|
+
}
|
|
698
|
+
export interface ClaimOutboxInput {
|
|
699
|
+
workerId: string;
|
|
700
|
+
leaseDurationMs: number;
|
|
701
|
+
limit?: number;
|
|
702
|
+
tenantId?: string;
|
|
703
|
+
spaceId?: string;
|
|
704
|
+
now?: Date;
|
|
705
|
+
}
|
|
706
|
+
export interface OutboxPlatformHostStore<TDb> extends PlatformHostStore<TDb> {
|
|
707
|
+
/** True only when transactionWithEvents supplies appendEventWithOutbox in the same unit of work. */
|
|
708
|
+
readonly transactionalOutbox?: boolean;
|
|
709
|
+
appendEventWithOutbox(event: AssetEventEnvelope, metadata: OutboxEventMetadata): Promise<void>;
|
|
710
|
+
claimOutbox(input: ClaimOutboxInput): Promise<OutboxRecord[]>;
|
|
711
|
+
markOutboxPublished(id: string, workerId: string, publishedAt: Date, leaseToken?: number): Promise<void>;
|
|
712
|
+
markOutboxFailed(input: {
|
|
602
713
|
id: string;
|
|
603
|
-
|
|
604
|
-
spaceId: string;
|
|
605
|
-
event: EnterpriseEventEnvelope;
|
|
606
|
-
/** Absent for a record written before Host recorded the `includeActor` decision. */
|
|
607
|
-
actorDisclosure?: OutboxActorDisclosure;
|
|
608
|
-
status: OutboxStatus;
|
|
609
|
-
attemptCount: number;
|
|
610
|
-
availableAt: Date;
|
|
611
|
-
leaseOwner?: string;
|
|
612
|
-
leaseExpiresAt?: Date;
|
|
714
|
+
workerId: string;
|
|
613
715
|
leaseToken?: number;
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
}
|
|
618
|
-
|
|
716
|
+
error: string;
|
|
717
|
+
availableAt: Date;
|
|
718
|
+
deadLetter: boolean;
|
|
719
|
+
}): Promise<void>;
|
|
720
|
+
renewOutboxLease(input: {
|
|
721
|
+
id: string;
|
|
619
722
|
workerId: string;
|
|
723
|
+
leaseToken: number;
|
|
620
724
|
leaseDurationMs: number;
|
|
621
|
-
|
|
725
|
+
now?: Date;
|
|
726
|
+
}): Promise<boolean>;
|
|
727
|
+
listOutbox(input?: {
|
|
622
728
|
tenantId?: string;
|
|
623
729
|
spaceId?: string;
|
|
624
|
-
|
|
625
|
-
}
|
|
626
|
-
interface OutboxPlatformHostStore<TDb> extends PlatformHostStore<TDb> {
|
|
627
|
-
/** True only when transactionWithEvents supplies appendEventWithOutbox in the same unit of work. */
|
|
628
|
-
readonly transactionalOutbox?: boolean;
|
|
629
|
-
appendEventWithOutbox(event: AssetEventEnvelope, metadata: OutboxEventMetadata): Promise<void>;
|
|
630
|
-
claimOutbox(input: ClaimOutboxInput): Promise<OutboxRecord[]>;
|
|
631
|
-
markOutboxPublished(id: string, workerId: string, publishedAt: Date, leaseToken?: number): Promise<void>;
|
|
632
|
-
markOutboxFailed(input: {
|
|
633
|
-
id: string;
|
|
634
|
-
workerId: string;
|
|
635
|
-
leaseToken?: number;
|
|
636
|
-
error: string;
|
|
637
|
-
availableAt: Date;
|
|
638
|
-
deadLetter: boolean;
|
|
639
|
-
}): Promise<void>;
|
|
640
|
-
renewOutboxLease(input: {
|
|
641
|
-
id: string;
|
|
642
|
-
workerId: string;
|
|
643
|
-
leaseToken: number;
|
|
644
|
-
leaseDurationMs: number;
|
|
645
|
-
now?: Date;
|
|
646
|
-
}): Promise<boolean>;
|
|
647
|
-
listOutbox(input?: {
|
|
648
|
-
tenantId?: string;
|
|
649
|
-
spaceId?: string;
|
|
650
|
-
statuses?: OutboxStatus[];
|
|
651
|
-
}): Promise<OutboxRecord[]>;
|
|
730
|
+
statuses?: OutboxStatus[];
|
|
731
|
+
}): Promise<OutboxRecord[]>;
|
|
652
732
|
}
|
|
653
733
|
/**
|
|
654
734
|
* Append-only evidence of one operator requeue of a dead-lettered outbox
|
|
@@ -656,42 +736,42 @@ interface OutboxPlatformHostStore<TDb> extends PlatformHostStore<TDb> {
|
|
|
656
736
|
* so the failure that exhausted the record stays readable after its attempt
|
|
657
737
|
* budget is reset.
|
|
658
738
|
*/
|
|
659
|
-
interface OutboxRequeueRecord {
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
}
|
|
677
|
-
interface RequeueOutboxDeadLetterStoreInput {
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
739
|
+
export interface OutboxRequeueRecord {
|
|
740
|
+
id: string;
|
|
741
|
+
outboxId: string;
|
|
742
|
+
tenantId: string;
|
|
743
|
+
spaceId: string;
|
|
744
|
+
eventId: string;
|
|
745
|
+
actorId: string;
|
|
746
|
+
actorType: ActorType;
|
|
747
|
+
/** Operator-supplied justification, persisted as audit evidence. Must not carry secrets. */
|
|
748
|
+
reason: string;
|
|
749
|
+
requeuedAt: Date;
|
|
750
|
+
/** When the requeued record became claimable again. */
|
|
751
|
+
availableAt: Date;
|
|
752
|
+
priorAttemptCount: number;
|
|
753
|
+
priorLastError?: string;
|
|
754
|
+
priorAvailableAt: Date;
|
|
755
|
+
priorLeaseToken: number;
|
|
756
|
+
}
|
|
757
|
+
export interface RequeueOutboxDeadLetterStoreInput {
|
|
758
|
+
id: string;
|
|
759
|
+
tenantId: string;
|
|
760
|
+
spaceId: string;
|
|
761
|
+
/** Identity of the evidence row written with the transition. */
|
|
762
|
+
requeueId: string;
|
|
763
|
+
actorId: string;
|
|
764
|
+
actorType: ActorType;
|
|
765
|
+
reason: string;
|
|
766
|
+
requeuedAt: Date;
|
|
767
|
+
availableAt: Date;
|
|
768
|
+
/**
|
|
769
|
+
* The lease token of the dead letter the caller read and authorized. Every
|
|
770
|
+
* claim increments the token and a requeue never lowers it, so a record
|
|
771
|
+
* that was requeued, claimed and dead-lettered again carries a higher token
|
|
772
|
+
* than the one observed, and the requeue is refused as `stale`.
|
|
773
|
+
*/
|
|
774
|
+
expectedLeaseToken: number;
|
|
695
775
|
}
|
|
696
776
|
/**
|
|
697
777
|
* `not_found`: no record with this id in the tenant and space, including a
|
|
@@ -700,74 +780,74 @@ interface RequeueOutboxDeadLetterStoreInput {
|
|
|
700
780
|
* requeue won the compare-and-set. `stale`: the record is a dead letter
|
|
701
781
|
* again, but not the one the caller observed; read and authorize it afresh.
|
|
702
782
|
*/
|
|
703
|
-
type OutboxRequeueRefusal = "not_found" | "not_dead_letter" | "stale";
|
|
704
|
-
type RequeueOutboxDeadLetterStoreResult = {
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
783
|
+
export type OutboxRequeueRefusal = "not_found" | "not_dead_letter" | "stale";
|
|
784
|
+
export type RequeueOutboxDeadLetterStoreResult = {
|
|
785
|
+
applied: true;
|
|
786
|
+
record: OutboxRecord;
|
|
787
|
+
requeue: OutboxRequeueRecord;
|
|
708
788
|
} | {
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
789
|
+
applied: false;
|
|
790
|
+
refusal: OutboxRequeueRefusal;
|
|
791
|
+
currentStatus?: OutboxStatus;
|
|
712
792
|
};
|
|
713
793
|
/**
|
|
714
794
|
* Optional outbox capability that moves a dead-lettered record back to
|
|
715
795
|
* pending. Kept apart from `OutboxPlatformHostStore` so a custom outbox store
|
|
716
796
|
* that predates it still satisfies that interface.
|
|
717
797
|
*/
|
|
718
|
-
interface OutboxRequeuePlatformHostStore<TDb> extends OutboxPlatformHostStore<TDb> {
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
tenantId: string;
|
|
734
|
-
spaceId: string;
|
|
735
|
-
outboxId?: string;
|
|
736
|
-
}): Promise<OutboxRequeueRecord[]>;
|
|
737
|
-
}
|
|
738
|
-
interface RequeueOutboxDeadLetterInput {
|
|
739
|
-
outboxId: string;
|
|
798
|
+
export interface OutboxRequeuePlatformHostStore<TDb> extends OutboxPlatformHostStore<TDb> {
|
|
799
|
+
getOutboxRecord(id: string, tenantId: string, spaceId: string): Promise<OutboxRecord | undefined>;
|
|
800
|
+
/**
|
|
801
|
+
* Compare-and-set from `dead_letter` at `expectedLeaseToken` to `pending`
|
|
802
|
+
* within the tenant and space: resets `attemptCount` to 0, sets
|
|
803
|
+
* `availableAt`, clears any lease owner while keeping the lease token,
|
|
804
|
+
* keeps `lastError`, and appends one `OutboxRequeueRecord` in the same
|
|
805
|
+
* atomic step. A record in any other state, at another lease token, or in
|
|
806
|
+
* another scope is refused and nothing is written. The returned requeue
|
|
807
|
+
* evidence shares nothing with stored history. The returned outbox record
|
|
808
|
+
* has its own Date fields; its event payload and provenance are shallow.
|
|
809
|
+
*/
|
|
810
|
+
requeueOutboxDeadLetter(input: RequeueOutboxDeadLetterStoreInput): Promise<RequeueOutboxDeadLetterStoreResult>;
|
|
811
|
+
/** Requeue evidence for a scope, oldest first; `outboxId` narrows it to one record. */
|
|
812
|
+
listOutboxRequeues(input: {
|
|
740
813
|
tenantId: string;
|
|
741
814
|
spaceId: string;
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
815
|
+
outboxId?: string;
|
|
816
|
+
}): Promise<OutboxRequeueRecord[]>;
|
|
817
|
+
}
|
|
818
|
+
export interface RequeueOutboxDeadLetterInput {
|
|
819
|
+
outboxId: string;
|
|
820
|
+
tenantId: string;
|
|
821
|
+
spaceId: string;
|
|
822
|
+
/** Trusted operator identity from the caller's authenticated session, never from request input. */
|
|
823
|
+
actorId: string;
|
|
824
|
+
actorType: ActorType;
|
|
825
|
+
/** Required justification, at most 1,000 characters, persisted as audit evidence. */
|
|
826
|
+
reason: string;
|
|
827
|
+
/** When the record becomes claimable again; defaults to the host clock. */
|
|
828
|
+
availableAt?: Date;
|
|
829
|
+
}
|
|
830
|
+
export type RequeueOutboxDeadLetterRefusal = OutboxRequeueRefusal | "not_authorized";
|
|
831
|
+
export type RequeueOutboxDeadLetterResult = {
|
|
832
|
+
status: "requeued";
|
|
833
|
+
record: OutboxRecord;
|
|
834
|
+
requeue: OutboxRequeueRecord;
|
|
755
835
|
} | {
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
836
|
+
status: "refused";
|
|
837
|
+
refusal: RequeueOutboxDeadLetterRefusal;
|
|
838
|
+
/** Present for `not_dead_letter` and `stale`: the state the record was found in. */
|
|
839
|
+
currentStatus?: OutboxStatus;
|
|
840
|
+
message: string;
|
|
761
841
|
};
|
|
762
842
|
/** Facts given to `authorizeOutboxRequeue`. `record` is absent when no record with this id exists in the scope. */
|
|
763
|
-
interface OutboxRequeueAuthorizationInput {
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
843
|
+
export interface OutboxRequeueAuthorizationInput {
|
|
844
|
+
tenantId: string;
|
|
845
|
+
spaceId: string;
|
|
846
|
+
actorId: string;
|
|
847
|
+
actorType: ActorType;
|
|
848
|
+
outboxId: string;
|
|
849
|
+
reason: string;
|
|
850
|
+
record?: Pick<OutboxRecord["event"], "eventId" | "eventType" | "payloadClassification"> & Pick<OutboxRecord, "status" | "attemptCount">;
|
|
771
851
|
}
|
|
772
852
|
/**
|
|
773
853
|
* Optional production capability for atomic domain/event persistence.
|
|
@@ -776,60 +856,60 @@ interface OutboxRequeueAuthorizationInput {
|
|
|
776
856
|
* not implement it retain the legacy transaction boundary for compatibility,
|
|
777
857
|
* but cannot claim atomic domain-write/event persistence.
|
|
778
858
|
*/
|
|
779
|
-
interface AtomicMutationPlatformHostStore<TDb> extends PlatformHostStore<TDb> {
|
|
780
|
-
|
|
781
|
-
}
|
|
782
|
-
interface BeginApprovalDecisionInput {
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
}
|
|
791
|
-
interface ApprovalDecisionTransitionResult {
|
|
792
|
-
|
|
793
|
-
|
|
859
|
+
export interface AtomicMutationPlatformHostStore<TDb> extends PlatformHostStore<TDb> {
|
|
860
|
+
transactionWithEvents<TResult>(run: (transaction: PlatformHostMutationTransaction<TDb>) => Promise<TResult>): Promise<TResult>;
|
|
861
|
+
}
|
|
862
|
+
export interface BeginApprovalDecisionInput {
|
|
863
|
+
actionInvocationId: string;
|
|
864
|
+
tenantId: string;
|
|
865
|
+
spaceId: string;
|
|
866
|
+
decision: PersistedActionApprovalDecision;
|
|
867
|
+
leaseOwner: string;
|
|
868
|
+
leaseDurationMs: number;
|
|
869
|
+
now: Date;
|
|
870
|
+
}
|
|
871
|
+
export interface ApprovalDecisionTransitionResult {
|
|
872
|
+
applied: boolean;
|
|
873
|
+
invocation?: ActionInvocationRecord;
|
|
794
874
|
}
|
|
795
875
|
/** Optional store capability required only when agent HITL or approval resume is used. */
|
|
796
|
-
interface ApprovalPlatformHostStore<TDb> extends PlatformHostStore<TDb> {
|
|
797
|
-
|
|
798
|
-
|
|
876
|
+
export interface ApprovalPlatformHostStore<TDb> extends PlatformHostStore<TDb> {
|
|
877
|
+
recordHitlDecision(actionInvocationId: string, tenantId: string, spaceId: string, decision: HitlDecisionEvidence): Promise<ActionInvocationRecord>;
|
|
878
|
+
beginApprovalDecision(input: BeginApprovalDecisionInput): Promise<ApprovalDecisionTransitionResult>;
|
|
799
879
|
}
|
|
800
880
|
/** Optional durable capabilities used when external-governance enrichment is configured. */
|
|
801
|
-
interface GovernancePlatformHostStore<TDb> extends PlatformHostStore<TDb> {
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
}
|
|
813
|
-
interface ListActionInvocationsInput {
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
}
|
|
826
|
-
interface ClaimActionInvocationsInput {
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
881
|
+
export interface GovernancePlatformHostStore<TDb> extends PlatformHostStore<TDb> {
|
|
882
|
+
recordMutationGovernance(actionInvocationId: string, tenantId: string, spaceId: string, context: {
|
|
883
|
+
footprint: MutationFootprint;
|
|
884
|
+
executionPrincipal: ExecutionPrincipal;
|
|
885
|
+
}): Promise<ActionInvocationRecord>;
|
|
886
|
+
appendPolicyObligations(records: PolicyObligationRecord[]): Promise<void>;
|
|
887
|
+
listPolicyObligations(actionInvocationId: string, tenantId: string, spaceId: string): Promise<PolicyObligationRecord[]>;
|
|
888
|
+
updatePolicyObligation(actionInvocationId: string, obligationId: string, status: PolicyObligationStatus, evidenceReferences?: PolicyObligation["evidenceReferences"]): Promise<void>;
|
|
889
|
+
appendExecutionAttestation(record: ExecutionAttestationRecord): Promise<void>;
|
|
890
|
+
listExecutionAttestations(actionInvocationId: string, tenantId: string, spaceId: string): Promise<ExecutionAttestationRecord[]>;
|
|
891
|
+
appendExternalReconciliation(record: ExternalReconciliationRecord): Promise<void>;
|
|
892
|
+
}
|
|
893
|
+
export interface ListActionInvocationsInput {
|
|
894
|
+
tenantId?: string;
|
|
895
|
+
spaceId?: string;
|
|
896
|
+
statuses?: readonly ActionStatus[];
|
|
897
|
+
updatedBefore?: Date;
|
|
898
|
+
/** Only invocations holding a pending external completion. */
|
|
899
|
+
awaitingCompletion?: boolean;
|
|
900
|
+
/** Only pending completions due at or before this instant. Implies `awaitingCompletion`. */
|
|
901
|
+
completionDueBefore?: Date;
|
|
902
|
+
/** Only invocations no worker holds a lease on. */
|
|
903
|
+
unleased?: boolean;
|
|
904
|
+
limit?: number;
|
|
905
|
+
}
|
|
906
|
+
export interface ClaimActionInvocationsInput {
|
|
907
|
+
workerId: string;
|
|
908
|
+
leaseDurationMs: number;
|
|
909
|
+
limit?: number;
|
|
910
|
+
tenantId?: string;
|
|
911
|
+
spaceId?: string;
|
|
912
|
+
now?: Date;
|
|
833
913
|
}
|
|
834
914
|
/**
|
|
835
915
|
* What the host writes back to an invocation.
|
|
@@ -844,55 +924,55 @@ interface ClaimActionInvocationsInput {
|
|
|
844
924
|
* - `claimActionInvocations` must never claim a running invocation without a
|
|
845
925
|
* lease, which is what a parked invocation is.
|
|
846
926
|
*/
|
|
847
|
-
type ActionInvocationPatch = Partial<Pick<ActionInvocationRecord, "status" | "result" | "error" | "authorizationReconciliation" | "adapterReconciliation" | "pendingStateTransition" | "pendingCompletion" | "externalCompletion">>;
|
|
848
|
-
interface UpdateLeasedActionInvocationInput {
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
}
|
|
856
|
-
interface RenewActionInvocationLeaseInput {
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
927
|
+
export type ActionInvocationPatch = Partial<Pick<ActionInvocationRecord, "status" | "result" | "error" | "authorizationReconciliation" | "adapterReconciliation" | "pendingStateTransition" | "pendingCompletion" | "externalCompletion">>;
|
|
928
|
+
export interface UpdateLeasedActionInvocationInput {
|
|
929
|
+
id: string;
|
|
930
|
+
tenantId: string;
|
|
931
|
+
spaceId: string;
|
|
932
|
+
workerId: string;
|
|
933
|
+
leaseToken: number;
|
|
934
|
+
patch: ActionInvocationPatch;
|
|
935
|
+
}
|
|
936
|
+
export interface RenewActionInvocationLeaseInput {
|
|
937
|
+
id: string;
|
|
938
|
+
tenantId: string;
|
|
939
|
+
spaceId: string;
|
|
940
|
+
workerId: string;
|
|
941
|
+
leaseToken: number;
|
|
942
|
+
leaseDurationMs: number;
|
|
943
|
+
now?: Date;
|
|
864
944
|
}
|
|
865
945
|
/** Store capabilities required by the durable polling worker and operator tooling. */
|
|
866
|
-
interface RecoverablePlatformHostStore<TDb> extends PlatformHostStore<TDb> {
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
}
|
|
873
|
-
interface ActionAuthorizationInput {
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
}
|
|
883
|
-
type KnownActionExecutionReason = "initial" | "approval_resume" | "recovery" | "offline_replay";
|
|
884
|
-
type ActionExecutionReason = KnownActionExecutionReason | (string & {});
|
|
946
|
+
export interface RecoverablePlatformHostStore<TDb> extends PlatformHostStore<TDb> {
|
|
947
|
+
listActionInvocations(input?: ListActionInvocationsInput): Promise<ActionInvocationRecord[]>;
|
|
948
|
+
claimActionInvocations(input: ClaimActionInvocationsInput): Promise<ActionInvocationRecord[]>;
|
|
949
|
+
updateLeasedActionInvocation(input: UpdateLeasedActionInvocationInput): Promise<boolean>;
|
|
950
|
+
renewActionInvocationLease(input: RenewActionInvocationLeaseInput): Promise<boolean>;
|
|
951
|
+
listEvents(tenantId: string, spaceId: string): Promise<AssetEventEnvelope[]>;
|
|
952
|
+
}
|
|
953
|
+
export interface ActionAuthorizationInput {
|
|
954
|
+
actionId: ActionId;
|
|
955
|
+
namespace: string;
|
|
956
|
+
requiredPermissions: readonly string[];
|
|
957
|
+
requiredRoles: readonly string[];
|
|
958
|
+
tenantId: string;
|
|
959
|
+
spaceId: string;
|
|
960
|
+
actorId: string;
|
|
961
|
+
actorType: ActorType;
|
|
962
|
+
}
|
|
963
|
+
export type KnownActionExecutionReason = "initial" | "approval_resume" | "recovery" | "offline_replay";
|
|
964
|
+
export type ActionExecutionReason = KnownActionExecutionReason | (string & {});
|
|
885
965
|
/**
|
|
886
966
|
* Trusted execution-boundary authorization input.
|
|
887
967
|
*
|
|
888
968
|
* Parameters are the schema-parsed durable parameters, never caller-supplied
|
|
889
969
|
* transient values. `invocation` is the canonical record that will execute.
|
|
890
970
|
*/
|
|
891
|
-
interface ActionExecutionAuthorizationInput extends ActionAuthorizationInput {
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
971
|
+
export interface ActionExecutionAuthorizationInput extends ActionAuthorizationInput {
|
|
972
|
+
actionInvocationId: string;
|
|
973
|
+
parameters: unknown;
|
|
974
|
+
invocation: Readonly<ActionInvocationRecord>;
|
|
975
|
+
executionReason: ActionExecutionReason;
|
|
896
976
|
}
|
|
897
977
|
/**
|
|
898
978
|
* Input to `resolvePolicies`. Carries the invocation identity and the
|
|
@@ -901,41 +981,41 @@ interface ActionExecutionAuthorizationInput extends ActionAuthorizationInput {
|
|
|
901
981
|
* persisted evaluation per invocation and policy, so return the same snapshot
|
|
902
982
|
* for an `actionInvocationId` on every attempt.
|
|
903
983
|
*/
|
|
904
|
-
interface ResolvePoliciesInput extends ActionExecutionAuthorizationInput {
|
|
905
|
-
|
|
906
|
-
}
|
|
907
|
-
interface PlatformHostAuthorization {
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
}
|
|
926
|
-
interface DispatchActionInput {
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
}
|
|
933
|
-
interface DispatchActionResult {
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
}
|
|
937
|
-
interface PlatformActionDispatcher {
|
|
938
|
-
|
|
984
|
+
export interface ResolvePoliciesInput extends ActionExecutionAuthorizationInput {
|
|
985
|
+
declaredPolicyIds: readonly string[];
|
|
986
|
+
}
|
|
987
|
+
export interface PlatformHostAuthorization {
|
|
988
|
+
checkEntitlement(input: ActionAuthorizationInput): Promise<boolean>;
|
|
989
|
+
authorize(input: ActionAuthorizationInput): Promise<boolean>;
|
|
990
|
+
/**
|
|
991
|
+
* Optional final authorization immediately before policies and mutation
|
|
992
|
+
* execution. When absent, the Host reuses `authorize` at this boundary.
|
|
993
|
+
*/
|
|
994
|
+
authorizeExecution?(input: ActionExecutionAuthorizationInput): Promise<boolean>;
|
|
995
|
+
/** Optional distinct authorization boundary for human/system approval decisions. */
|
|
996
|
+
authorizeApproval?(input: ActionAuthorizationInput & {
|
|
997
|
+
decision: ActionApprovalDecision;
|
|
998
|
+
}): Promise<boolean>;
|
|
999
|
+
/**
|
|
1000
|
+
* Authorization for `requeueOutboxDeadLetter`. There is no action to fall
|
|
1001
|
+
* back to, so when this is absent every requeue is refused as
|
|
1002
|
+
* `not_authorized`. A throw propagates and nothing is requeued.
|
|
1003
|
+
*/
|
|
1004
|
+
authorizeOutboxRequeue?(input: OutboxRequeueAuthorizationInput): Promise<boolean>;
|
|
1005
|
+
}
|
|
1006
|
+
export interface DispatchActionInput {
|
|
1007
|
+
actionInvocationId: string;
|
|
1008
|
+
actionId: ActionId;
|
|
1009
|
+
tenantId: string;
|
|
1010
|
+
spaceId: string;
|
|
1011
|
+
workflowId: string;
|
|
1012
|
+
}
|
|
1013
|
+
export interface DispatchActionResult {
|
|
1014
|
+
workflowId: string;
|
|
1015
|
+
runId?: string;
|
|
1016
|
+
}
|
|
1017
|
+
export interface PlatformActionDispatcher {
|
|
1018
|
+
dispatch(input: DispatchActionInput): Promise<DispatchActionResult>;
|
|
939
1019
|
}
|
|
940
1020
|
/**
|
|
941
1021
|
* One submission. `submitAction` reads the scalar fields (`actionId`, scope,
|
|
@@ -949,452 +1029,474 @@ interface PlatformActionDispatcher {
|
|
|
949
1029
|
* as the caller's objects, read where and as often as before (README,
|
|
950
1030
|
* "Submission snapshot").
|
|
951
1031
|
*/
|
|
952
|
-
interface SubmitActionInput {
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
}
|
|
969
|
-
interface SubmitActionResult {
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
}
|
|
985
|
-
interface ExecuteActionResult {
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
}
|
|
999
|
-
interface ExecuteInvocationOptions {
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
}
|
|
1005
|
-
interface PlatformActionWorkerOptions<TDb> {
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
}
|
|
1025
|
-
interface PlatformActionWorkerCycleResult {
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1032
|
+
export interface SubmitActionInput {
|
|
1033
|
+
actionId: ActionId;
|
|
1034
|
+
parameters: Record<string, unknown>;
|
|
1035
|
+
tenantId: string;
|
|
1036
|
+
spaceId: string;
|
|
1037
|
+
actorId: string;
|
|
1038
|
+
actorType: ActorType;
|
|
1039
|
+
correlationId?: string;
|
|
1040
|
+
causationId?: string;
|
|
1041
|
+
provenance?: InvocationProvenance;
|
|
1042
|
+
executionReason?: Extract<KnownActionExecutionReason, "initial" | "offline_replay">;
|
|
1043
|
+
/** Stable logical command key. Reusing it returns the original invocation; a pending failed dispatch may retry its stable workflow ID. */
|
|
1044
|
+
idempotencyKey?: string;
|
|
1045
|
+
/** Opaque, non-secret authorization/admission reference persisted with the invocation. */
|
|
1046
|
+
authorizationBindingId?: string;
|
|
1047
|
+
authorizationBinding?: AuthorizationBinding;
|
|
1048
|
+
}
|
|
1049
|
+
export interface SubmitActionResult {
|
|
1050
|
+
actionInvocationId: string;
|
|
1051
|
+
status: ActionStatus;
|
|
1052
|
+
workflowId: string;
|
|
1053
|
+
runId?: string;
|
|
1054
|
+
result?: Record<string, unknown>;
|
|
1055
|
+
error?: string;
|
|
1056
|
+
reconciliation?: AuthorizationReconciliationOutcome;
|
|
1057
|
+
adapterReconciliation?: AdapterReconciliationOutcome;
|
|
1058
|
+
/** Present while the invocation waits for an external system to complete it. */
|
|
1059
|
+
pendingCompletion?: PendingExternalCompletion;
|
|
1060
|
+
/** Mirrors the action's declared consistency so a caller knows whether the result is settled. */
|
|
1061
|
+
consistency?: "authoritative-now" | "provisional-until-reconciled";
|
|
1062
|
+
hitlRoute?: AgentActionRoute;
|
|
1063
|
+
hitlRiskTier?: AgentActionRiskTier;
|
|
1064
|
+
}
|
|
1065
|
+
export interface ExecuteActionResult {
|
|
1066
|
+
actionInvocationId: string;
|
|
1067
|
+
status: ActionStatus;
|
|
1068
|
+
result?: Record<string, unknown>;
|
|
1069
|
+
error?: string;
|
|
1070
|
+
reconciliation?: AuthorizationReconciliationOutcome;
|
|
1071
|
+
adapterReconciliation?: AdapterReconciliationOutcome;
|
|
1072
|
+
/** Present while the invocation waits for an external system to complete it. */
|
|
1073
|
+
pendingCompletion?: PendingExternalCompletion;
|
|
1074
|
+
/** Mirrors the action's declared consistency so a caller knows whether the result is settled. */
|
|
1075
|
+
consistency?: "authoritative-now" | "provisional-until-reconciled";
|
|
1076
|
+
hitlRoute?: AgentActionRoute;
|
|
1077
|
+
hitlRiskTier?: AgentActionRiskTier;
|
|
1078
|
+
}
|
|
1079
|
+
export interface ExecuteInvocationOptions {
|
|
1080
|
+
/** Required when executing a row already protected by a worker or approval-resume lease. */
|
|
1081
|
+
leaseOwner?: string;
|
|
1082
|
+
/** Claim generation paired with leaseOwner; stale generations are rejected. */
|
|
1083
|
+
leaseToken?: number;
|
|
1084
|
+
}
|
|
1085
|
+
export interface PlatformActionWorkerOptions<TDb> {
|
|
1086
|
+
host: GovernedActionHost;
|
|
1087
|
+
store: RecoverablePlatformHostStore<TDb>;
|
|
1088
|
+
workerId: string;
|
|
1089
|
+
batchSize?: number;
|
|
1090
|
+
leaseDurationMs?: number;
|
|
1091
|
+
leaseRenewalIntervalMs?: number;
|
|
1092
|
+
pollIntervalMs?: number;
|
|
1093
|
+
tenantId?: string;
|
|
1094
|
+
spaceId?: string;
|
|
1095
|
+
signal?: AbortSignal;
|
|
1096
|
+
onError?: (error: unknown, invocation?: ActionInvocationRecord) => void;
|
|
1097
|
+
telemetry?: PlatformHostTelemetry;
|
|
1098
|
+
/**
|
|
1099
|
+
* Sweep overdue external handoffs each cycle. Defaults to on. Turn it off
|
|
1100
|
+
* for a store without the governance seam, where the sweep would refuse
|
|
1101
|
+
* on every cycle, and run the sweep elsewhere.
|
|
1102
|
+
*/
|
|
1103
|
+
sweepOverdueCompletions?: boolean;
|
|
1104
|
+
}
|
|
1105
|
+
export interface PlatformActionWorkerCycleResult {
|
|
1106
|
+
claimed: number;
|
|
1107
|
+
completed: number;
|
|
1108
|
+
failed: number;
|
|
1109
|
+
/** Present when claimed agent work was durably parked instead of failing. */
|
|
1110
|
+
waitingForApproval?: number;
|
|
1111
|
+
/**
|
|
1112
|
+
* Present only when > 0: claimed invocations whose execution threw a
|
|
1113
|
+
* RetryableExecutionError (counted by error type, not by where it was thrown).
|
|
1114
|
+
* The row stays leased and a later claim retries it; excluded from failed.
|
|
1115
|
+
*/
|
|
1116
|
+
deferred?: number;
|
|
1037
1117
|
}
|
|
1038
1118
|
/** Origin of error text redacted before Host records or returns it. */
|
|
1039
|
-
interface ErrorTextRedactionContext {
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
}
|
|
1047
|
-
interface PlatformHostOptions<TDb> {
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
hitlEvaluator?: AgentActionPolicyEvaluator;
|
|
1111
|
-
/** Durable evaluator/ruleset version recorded with every HITL decision. */
|
|
1112
|
-
hitlPolicyVersion?: string;
|
|
1113
|
-
/** Optional portable resolver; provider-specific implementations belong in integration packages. */
|
|
1114
|
-
resolveMutationGovernance?: MutationGovernanceResolver;
|
|
1115
|
-
/** Translate policy outcomes into durable, enforceable obligations. */
|
|
1116
|
-
resolvePolicyObligations?: (outcomes: readonly PolicyOutcome[]) => Promise<PolicyObligation[]> | PolicyObligation[];
|
|
1117
|
-
/** Translate a successful adapter result into audit-safe external execution evidence. */
|
|
1118
|
-
extractExecutionAttestation?: (input: {
|
|
1119
|
-
actionInvocationId: string;
|
|
1120
|
-
adapterInvocationId: string;
|
|
1121
|
-
adapterType: string;
|
|
1122
|
-
operation: string;
|
|
1123
|
-
vendor: string;
|
|
1124
|
-
/** Audit-safe adapter input after redactAdapterInput has been applied. */
|
|
1125
|
-
input: Record<string, unknown>;
|
|
1126
|
-
startedAt: Date;
|
|
1127
|
-
completedAt: Date;
|
|
1128
|
-
/** Adapter output after redactAdapterOutput, when configured. */
|
|
1129
|
-
output: Record<string, unknown>;
|
|
1130
|
-
}) => Promise<ExecutionAttestation | undefined> | ExecutionAttestation | undefined;
|
|
1131
|
-
/** Package/provider/ruleset generations persisted with every newly created invocation. */
|
|
1132
|
-
runtimeEvidence?: Partial<GovernanceRuntimeEvidence>;
|
|
1133
|
-
/**
|
|
1134
|
-
* Trusted composition identity attached by the Host configuration, never
|
|
1135
|
-
* accepted directly from submission input. Requires an explicit registry;
|
|
1136
|
-
* its module namespaces and versions are checked against these identities.
|
|
1137
|
-
*/
|
|
1138
|
-
composition?: {
|
|
1139
|
-
assembly: AssemblyLockfile;
|
|
1140
|
-
/**
|
|
1141
|
-
* Receives a fresh object whose action, scope, actor, correlation,
|
|
1142
|
-
* causation, idempotency key, binding id and execution reason are the
|
|
1143
|
-
* ones Host read at submission and persists, whatever the caller
|
|
1144
|
-
* changed on its own object since. For an action without
|
|
1145
|
-
* `admitSubmission`, its `parameters`, `provenance` and
|
|
1146
|
-
* `authorizationBinding` read and assign the caller's input, as when
|
|
1147
|
-
* the callback was handed that input itself; for an action that
|
|
1148
|
-
* declares it, they are fresh copies of Host's snapshot.
|
|
1149
|
-
*/
|
|
1150
|
-
resolveInitiatingReleaseDigest?(input: SubmitActionInput): Promise<string | undefined> | string | undefined;
|
|
1151
|
-
};
|
|
1152
|
-
/** Lease held while an approved invocation resumes; defaults to five minutes. */
|
|
1153
|
-
approvalResumeLeaseDurationMs?: number;
|
|
1154
|
-
/**
|
|
1155
|
-
* Remove forbidden/sensitive fields before durable invocation persistence.
|
|
1156
|
-
* For an action without `admitSubmission`, receives the caller's
|
|
1157
|
-
* parameters object, before provenance normalization and the composition
|
|
1158
|
-
* callback, as before. For an action that declares it, receives Host's
|
|
1159
|
-
* copy, after the check admitted the submission.
|
|
1160
|
-
*/
|
|
1161
|
-
redactActionParameters?: (actionId: ActionId, parameters: Record<string, unknown>) => Record<string, unknown>;
|
|
1162
|
-
/**
|
|
1163
|
-
* The bound on an action's `admitSubmission` check. An answer that
|
|
1164
|
-
* settles this many milliseconds or more after the check was called,
|
|
1165
|
-
* measured on the monotonic clock when its promise settles, is refused as
|
|
1166
|
-
* `timed_out` and the check's signal is aborted. A whole number from 1 to
|
|
1167
|
-
* 2 147 483 647 (the timer maximum), or `createGovernedActionHost` throws;
|
|
1168
|
-
* default 10 000.
|
|
1169
|
-
*/
|
|
1170
|
-
admissionTimeoutMs?: number;
|
|
1171
|
-
resolvePolicies?: (input: ResolvePoliciesInput) => Promise<RuntimePolicyDefinition[]>;
|
|
1172
|
-
extractEvents?: (data: Record<string, unknown>) => PendingAssetEvent[];
|
|
1173
|
-
/** Handler-result fields consumed by extractEvents and omitted from the durable result. */
|
|
1174
|
-
eventResultFields?: readonly string[];
|
|
1175
|
-
redactAdapterInput?: (actionId: ActionId, adapterType: string, operation: string, input: Record<string, unknown>) => Record<string, unknown>;
|
|
1176
|
-
/**
|
|
1177
|
-
* Redact successful adapter output before row/event persistence and attestation extraction.
|
|
1178
|
-
* A throwing hook or a null, array or non-object return withholds output and requires reconciliation.
|
|
1179
|
-
* Class instances and Dates are accepted, matching the adapter output record contract.
|
|
1180
|
-
* Keep redactors deterministic and stable across deploys.
|
|
1181
|
-
* Accepted-operation references are read from the original adapter result.
|
|
1182
|
-
*/
|
|
1183
|
-
redactAdapterOutput?: (actionId: ActionId, adapterType: string, operation: string, output: Record<string, unknown>) => Record<string, unknown>;
|
|
1184
|
-
/**
|
|
1185
|
-
* Redact originating handler, adapter, completion and caught execution error text.
|
|
1186
|
-
* Host-authored fixed text bypasses this hook; circuit and consistency errors use adapter context.
|
|
1187
|
-
* Empty originating text bypasses the hook unchanged. For non-empty input, throwing or returning
|
|
1188
|
-
* a non-string or empty string uses a placeholder on execution paths, but refuses a completion
|
|
1189
|
-
* as redaction_failed before writes. State-machine `transition.error` text uses `source: "handler"`.
|
|
1190
|
-
* Keep redactors deterministic and stable across deploys: changed output can make a repeat
|
|
1191
|
-
* completion look like different evidence.
|
|
1192
|
-
*/
|
|
1193
|
-
redactErrorText?: (context: ErrorTextRedactionContext, message: string) => string;
|
|
1194
|
-
/**
|
|
1195
|
-
* Redact completion results before merging, schema validation, persistence and digesting.
|
|
1196
|
-
* Contradiction detection compares retained values; legacy raw digests also match repeats.
|
|
1197
|
-
* A throwing hook or a null, array or non-object return refuses as redaction_failed before writes.
|
|
1198
|
-
* Class instances and Dates are accepted by the same record predicate as adapter output.
|
|
1199
|
-
* Keep redactors deterministic and stable across deploys: changes can make a repeat look like
|
|
1200
|
-
* different evidence. A matching legacy raw digest is acknowledged before invoking hooks.
|
|
1201
|
-
*/
|
|
1202
|
-
redactExternalCompletionResult?: (actionId: ActionId, provider: string, result: Record<string, unknown>) => Record<string, unknown>;
|
|
1203
|
-
adapterEventSubject?: (actionId: ActionId, parameters: unknown, handlerResult: Record<string, unknown>) => {
|
|
1204
|
-
subjectType: string;
|
|
1205
|
-
subjectId: string;
|
|
1206
|
-
} | undefined;
|
|
1207
|
-
now?: () => Date;
|
|
1208
|
-
/** Vendor-neutral lifecycle and metric sink. Telemetry is best effort. */
|
|
1209
|
-
telemetry?: PlatformHostTelemetry;
|
|
1210
|
-
/**
|
|
1211
|
-
* Epoch-millis deadline delivered to every adapter execution context.
|
|
1212
|
-
* When omitted, no deadline is set and adapters receive no AbortSignal.
|
|
1213
|
-
*/
|
|
1214
|
-
adapterDeadlineMs?: number;
|
|
1215
|
-
}
|
|
1216
|
-
interface GovernedActionHost {
|
|
1217
|
-
submitAction(input: SubmitActionInput): Promise<SubmitActionResult>;
|
|
1218
|
-
executeInvocation(actionInvocationId: string, tenantId: string, spaceId: string, options?: ExecuteInvocationOptions): Promise<ExecuteActionResult>;
|
|
1219
|
-
resumeApprovedInvocation(actionInvocationId: string, tenantId: string, spaceId: string, decision: ActionApprovalDecision): Promise<ExecuteActionResult>;
|
|
1220
|
-
recordExecutionAttestation(actionInvocationId: string, tenantId: string, spaceId: string, attestation: ExecutionAttestation): Promise<void>;
|
|
1221
|
-
recordExternalReconciliation(actionInvocationId: string, tenantId: string, spaceId: string, reconciliation: ExternalReconciliation): Promise<void>;
|
|
1119
|
+
export interface ErrorTextRedactionContext {
|
|
1120
|
+
actionId: ActionId;
|
|
1121
|
+
source: "handler" | "adapter" | "external_completion" | "execution";
|
|
1122
|
+
adapterType?: string;
|
|
1123
|
+
operation?: string;
|
|
1124
|
+
/** Adapter vendor or external completion provider. */
|
|
1125
|
+
provider?: string;
|
|
1126
|
+
}
|
|
1127
|
+
export interface PlatformHostOptions<TDb> {
|
|
1128
|
+
store: PlatformHostStore<TDb>;
|
|
1129
|
+
authorization: PlatformHostAuthorization;
|
|
1130
|
+
/** Preferred explicit catalog assembled from this runtime's Fabric modules. */
|
|
1131
|
+
registry?: Pick<ModuleRegistry<TDb>, "resolveAction" | "resolvePolicy" | "resolveStateMachine"> & Partial<Pick<ModuleRegistry<TDb>, "orderedModules">>;
|
|
1132
|
+
/** Resolve vertical- or runtime-local actions without mutating the process-wide registry. */
|
|
1133
|
+
resolveAction?: (actionId: ActionId) => ActionDefinition<TDb> | undefined;
|
|
1134
|
+
adapters?: readonly AdapterImplementation[];
|
|
1135
|
+
/**
|
|
1136
|
+
* Supplies the circuit breaker for each adapter call. Defaults to a new
|
|
1137
|
+
* `AdapterCircuitBreakerRegistry` per Host instance, which creates one
|
|
1138
|
+
* in-process breaker per `adapterType:operation` from that adapter's own
|
|
1139
|
+
* `circuitBreaker` config, on first use, and none for adapters without one.
|
|
1140
|
+
* Pass a shared registry or a custom provider to share breakers between
|
|
1141
|
+
* Host instances, receive breaker telemetry, or set manual overrides.
|
|
1142
|
+
* The default key shares failures across tenants and vendors in a registry.
|
|
1143
|
+
* Use `new AdapterCircuitBreakerRegistry({ key: scopedAdapterCircuitBreakerKey })`
|
|
1144
|
+
* for tenant/space/vendor isolation. Host passes trusted tenant/space scope
|
|
1145
|
+
* to the provider. The registry keeps the first config seen for a key;
|
|
1146
|
+
* later conflicting configs reuse that breaker without throwing. Breakers
|
|
1147
|
+
* are never evicted, so scoped keys keep one breaker per scope seen.
|
|
1148
|
+
*/
|
|
1149
|
+
adapterCircuitBreakers?: AdapterCircuitBreakerProvider;
|
|
1150
|
+
/**
|
|
1151
|
+
* Positive integer attempt cap for RetryableExecutionError during governance,
|
|
1152
|
+
* before policy-evaluation persistence (default 5). A leased, idempotent action
|
|
1153
|
+
* below the cap is left running for worker reclaim after lease expiry.
|
|
1154
|
+
* Inline execution, approval resume, exhausted attempts, and non-idempotent
|
|
1155
|
+
* actions fail. Policy persistence, obligation listing/resolution/persistence, state-machine checks,
|
|
1156
|
+
* the handler transaction, handlers, adapters, and finalization are excluded;
|
|
1157
|
+
* their failure/reconciliation/recovery semantics apply, subject to recoveryMaxAttempts.
|
|
1158
|
+
*/
|
|
1159
|
+
retryableExecutionMaxAttempts?: number;
|
|
1160
|
+
/**
|
|
1161
|
+
* Positive integer cap on worker claims for resumed leased running invocations
|
|
1162
|
+
* including the first (default max(5, retryableExecutionMaxAttempts); Infinity is rejected).
|
|
1163
|
+
* An explicit value must be at least retryableExecutionMaxAttempts. Claims above
|
|
1164
|
+
* the cap settle reconciliation_required before
|
|
1165
|
+
* handler or adapter execution. Inline/direct execution and approval resume
|
|
1166
|
+
* do not increment this counter. Approval resume is admitted at the cap and settles
|
|
1167
|
+
* reconciliation above it; approval does not reset the count. Parked handoffs are excluded. A worker dying
|
|
1168
|
+
* before the check consumes a claim without executing a provider at that point.
|
|
1169
|
+
*/
|
|
1170
|
+
recoveryMaxAttempts?: number;
|
|
1171
|
+
dispatcher?: PlatformActionDispatcher;
|
|
1172
|
+
services?: FabricRuntimeServices;
|
|
1173
|
+
idempotency?: {
|
|
1174
|
+
conflictMode?: "audit-only" | "enforce";
|
|
1175
|
+
onConflict?(conflict: IdempotencyConflict): void;
|
|
1176
|
+
onLegacyRecord?(invocation: ActionInvocationRecord): void;
|
|
1177
|
+
};
|
|
1178
|
+
provenance?: {
|
|
1179
|
+
auditAttributeAllowlist?: readonly string[];
|
|
1180
|
+
maxAttributes?: number;
|
|
1181
|
+
maxValueLength?: number;
|
|
1182
|
+
redactAuditAttributes?(attributes: NamespacedAttributes): NamespacedAttributes;
|
|
1183
|
+
onTrace?(provenance: InvocationProvenance): void;
|
|
1184
|
+
};
|
|
1185
|
+
/** Requires an outbox-capable store; every canonical event is then appended with delivery state. */
|
|
1186
|
+
outbox?: {
|
|
1187
|
+
producerModuleVersion(actionId: ActionId, actionVersion: number): string;
|
|
1188
|
+
classifyPayload(event: AssetEventEnvelope): EventPayloadClassification;
|
|
1189
|
+
includeProvenance?(event: AssetEventEnvelope, classification: EventPayloadClassification): boolean;
|
|
1222
1190
|
/**
|
|
1223
|
-
*
|
|
1224
|
-
*
|
|
1225
|
-
*
|
|
1191
|
+
* Opt an event's `actorId` and `actorType` into its outbox envelope. Absent, the actor is
|
|
1192
|
+
* excluded for every classification. Only `true` includes it. An included actor reaches every
|
|
1193
|
+
* sink of every relay reading this outbox.
|
|
1226
1194
|
*/
|
|
1227
|
-
|
|
1195
|
+
includeActor?(event: AssetEventEnvelope, classification: EventPayloadClassification): boolean;
|
|
1196
|
+
traceContext?(event: AssetEventEnvelope): Record<string, string> | undefined;
|
|
1197
|
+
/** Host lifecycle events are excluded by default; opt in only after making their payload audit-safe. */
|
|
1198
|
+
shouldPublish?(event: AssetEventEnvelope): boolean;
|
|
1199
|
+
};
|
|
1200
|
+
/** Optional vertical-owned evaluator. When absent, agent behavior is unchanged. */
|
|
1201
|
+
hitlEvaluator?: AgentActionPolicyEvaluator;
|
|
1202
|
+
/** Durable evaluator/ruleset version recorded with every HITL decision. */
|
|
1203
|
+
hitlPolicyVersion?: string;
|
|
1204
|
+
/** Optional portable resolver; provider-specific implementations belong in integration packages. */
|
|
1205
|
+
resolveMutationGovernance?: MutationGovernanceResolver;
|
|
1206
|
+
/** Translate policy outcomes into durable, enforceable obligations. */
|
|
1207
|
+
resolvePolicyObligations?: (outcomes: readonly PolicyOutcome[]) => Promise<PolicyObligation[]> | PolicyObligation[];
|
|
1208
|
+
/** Translate a successful adapter result into audit-safe evidence. Recovery may call this
|
|
1209
|
+
* again with stored input/output; return deterministic evidence for the same input. */
|
|
1210
|
+
extractExecutionAttestation?: (input: {
|
|
1211
|
+
actionInvocationId: string;
|
|
1212
|
+
adapterInvocationId: string;
|
|
1213
|
+
adapterType: string;
|
|
1214
|
+
operation: string;
|
|
1215
|
+
vendor: string;
|
|
1216
|
+
/** Audit-safe adapter input after redactAdapterInput has been applied. */
|
|
1217
|
+
input: Record<string, unknown>;
|
|
1218
|
+
startedAt: Date;
|
|
1219
|
+
completedAt: Date;
|
|
1220
|
+
/** Adapter output after redactAdapterOutput, when configured. */
|
|
1221
|
+
output: Record<string, unknown>;
|
|
1222
|
+
}) => Promise<ExecutionAttestation | undefined> | ExecutionAttestation | undefined;
|
|
1223
|
+
/** Package/provider/ruleset generations persisted with every newly created invocation. */
|
|
1224
|
+
runtimeEvidence?: Partial<GovernanceRuntimeEvidence>;
|
|
1225
|
+
/**
|
|
1226
|
+
* Trusted composition identity attached by the Host configuration, never
|
|
1227
|
+
* accepted directly from submission input. Requires an explicit registry;
|
|
1228
|
+
* its module namespaces and versions are checked against these identities.
|
|
1229
|
+
*/
|
|
1230
|
+
composition?: {
|
|
1231
|
+
assembly: AssemblyLockfile;
|
|
1228
1232
|
/**
|
|
1229
|
-
*
|
|
1230
|
-
*
|
|
1231
|
-
*
|
|
1233
|
+
* Receives a fresh object whose action, scope, actor, correlation,
|
|
1234
|
+
* causation, idempotency key, binding id and execution reason are the
|
|
1235
|
+
* ones Host read at submission and persists, whatever the caller
|
|
1236
|
+
* changed on its own object since. For an action without
|
|
1237
|
+
* `admitSubmission`, its `parameters`, `provenance` and
|
|
1238
|
+
* `authorizationBinding` read and assign the caller's input, as when
|
|
1239
|
+
* the callback was handed that input itself; for an action that
|
|
1240
|
+
* declares it, they are fresh copies of Host's snapshot.
|
|
1232
1241
|
*/
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1242
|
+
resolveInitiatingReleaseDigest?(input: SubmitActionInput): Promise<string | undefined> | string | undefined;
|
|
1243
|
+
};
|
|
1244
|
+
/** Lease held while an approved invocation resumes; defaults to five minutes. */
|
|
1245
|
+
approvalResumeLeaseDurationMs?: number;
|
|
1246
|
+
/**
|
|
1247
|
+
* Remove forbidden/sensitive fields before durable invocation persistence.
|
|
1248
|
+
* For an action without `admitSubmission`, receives the caller's
|
|
1249
|
+
* parameters object, before provenance normalization and the composition
|
|
1250
|
+
* callback, as before. For an action that declares it, receives Host's
|
|
1251
|
+
* copy, after the check admitted the submission.
|
|
1252
|
+
*/
|
|
1253
|
+
redactActionParameters?: (actionId: ActionId, parameters: Record<string, unknown>) => Record<string, unknown>;
|
|
1254
|
+
/**
|
|
1255
|
+
* The bound on an action's `admitSubmission` check. An answer that
|
|
1256
|
+
* settles this many milliseconds or more after the check was called,
|
|
1257
|
+
* measured on the monotonic clock when its promise settles, is refused as
|
|
1258
|
+
* `timed_out` and the check's signal is aborted. A whole number from 1 to
|
|
1259
|
+
* 2 147 483 647 (the timer maximum), or `createGovernedActionHost` throws;
|
|
1260
|
+
* default 10 000.
|
|
1261
|
+
*/
|
|
1262
|
+
admissionTimeoutMs?: number;
|
|
1263
|
+
resolvePolicies?: (input: ResolvePoliciesInput) => Promise<RuntimePolicyDefinition[]>;
|
|
1264
|
+
extractEvents?: (data: Record<string, unknown>) => PendingAssetEvent[];
|
|
1265
|
+
/** Handler-result fields consumed by extractEvents and omitted from the durable result. */
|
|
1266
|
+
eventResultFields?: readonly string[];
|
|
1267
|
+
redactAdapterInput?: (actionId: ActionId, adapterType: string, operation: string, input: Record<string, unknown>) => Record<string, unknown>;
|
|
1268
|
+
/**
|
|
1269
|
+
* Redact successful adapter output before row/event persistence and attestation extraction.
|
|
1270
|
+
* A throwing hook or a null, array or non-object return withholds output and requires reconciliation.
|
|
1271
|
+
* Class instances and Dates are accepted, matching the adapter output record contract.
|
|
1272
|
+
* Keep redactors deterministic and stable across deploys.
|
|
1273
|
+
* Accepted-operation references are read from the original adapter result.
|
|
1274
|
+
*/
|
|
1275
|
+
redactAdapterOutput?: (actionId: ActionId, adapterType: string, operation: string, output: Record<string, unknown>) => Record<string, unknown>;
|
|
1276
|
+
/**
|
|
1277
|
+
* Redact originating handler, adapter, completion and caught execution error text.
|
|
1278
|
+
* Host-authored fixed text bypasses this hook; circuit and consistency errors use adapter context.
|
|
1279
|
+
* Empty originating text bypasses the hook unchanged. For non-empty input, throwing or returning
|
|
1280
|
+
* a non-string or empty string uses a placeholder on execution paths, but refuses a completion
|
|
1281
|
+
* as redaction_failed before writes. State-machine `transition.error` text uses `source: "handler"`.
|
|
1282
|
+
* Keep redactors deterministic and stable across deploys: changed output can make a repeat
|
|
1283
|
+
* completion look like different evidence.
|
|
1284
|
+
*/
|
|
1285
|
+
redactErrorText?: (context: ErrorTextRedactionContext, message: string) => string;
|
|
1286
|
+
/**
|
|
1287
|
+
* Redact completion results before merging, schema validation, persistence and digesting.
|
|
1288
|
+
* Contradiction detection compares retained values; legacy raw digests also match repeats.
|
|
1289
|
+
* A throwing hook or a null, array or non-object return refuses as redaction_failed before writes.
|
|
1290
|
+
* Class instances and Dates are accepted by the same record predicate as adapter output.
|
|
1291
|
+
* Keep redactors deterministic and stable across deploys: changes can make a repeat look like
|
|
1292
|
+
* different evidence. A matching legacy raw digest is acknowledged before invoking hooks.
|
|
1293
|
+
*/
|
|
1294
|
+
redactExternalCompletionResult?: (actionId: ActionId, provider: string, result: Record<string, unknown>) => Record<string, unknown>;
|
|
1295
|
+
adapterEventSubject?: (actionId: ActionId, parameters: unknown, handlerResult: Record<string, unknown>) => {
|
|
1296
|
+
subjectType: string;
|
|
1297
|
+
subjectId: string;
|
|
1298
|
+
} | undefined;
|
|
1299
|
+
now?: () => Date;
|
|
1300
|
+
/** Vendor-neutral lifecycle and metric sink. Telemetry is best effort. */
|
|
1301
|
+
telemetry?: PlatformHostTelemetry;
|
|
1302
|
+
/**
|
|
1303
|
+
* Epoch-millis deadline delivered to every adapter execution context.
|
|
1304
|
+
* When omitted, no deadline is set and adapters receive no AbortSignal.
|
|
1305
|
+
*/
|
|
1306
|
+
adapterDeadlineMs?: number;
|
|
1307
|
+
}
|
|
1308
|
+
export interface GovernedActionHost {
|
|
1309
|
+
submitAction(input: SubmitActionInput): Promise<SubmitActionResult>;
|
|
1310
|
+
executeInvocation(actionInvocationId: string, tenantId: string, spaceId: string, options?: ExecuteInvocationOptions): Promise<ExecuteActionResult>;
|
|
1311
|
+
resumeApprovedInvocation(actionInvocationId: string, tenantId: string, spaceId: string, decision: ActionApprovalDecision): Promise<ExecuteActionResult>;
|
|
1312
|
+
recordExecutionAttestation(actionInvocationId: string, tenantId: string, spaceId: string, attestation: ExecutionAttestation): Promise<void>;
|
|
1313
|
+
recordExternalReconciliation(actionInvocationId: string, tenantId: string, spaceId: string, reconciliation: ExternalReconciliation): Promise<void>;
|
|
1314
|
+
/**
|
|
1315
|
+
* Complete an invocation an adapter handed off, by the reference the
|
|
1316
|
+
* external system was given. Idempotent for a repeated identical
|
|
1317
|
+
* completion; a contradictory one moves the invocation to reconciliation.
|
|
1318
|
+
*/
|
|
1319
|
+
completeExternalInvocation(actionInvocationId: string, tenantId: string, spaceId: string, completion: ExternalCompletion): Promise<ExecuteActionResult>;
|
|
1320
|
+
/**
|
|
1321
|
+
* Move eligible running, unleased overdue handoffs to `reconciliation_required`
|
|
1322
|
+
* and retain the handoff with overdueAt. A callback can settle that verdict
|
|
1323
|
+
* only after parking; callbacks for swept unparked invocations record redacted
|
|
1324
|
+
* evidence without result-schema validation. Parked rows lacking overdueAt
|
|
1325
|
+
* retain the weaker "did not complete by" error-substring fallback.
|
|
1326
|
+
*/
|
|
1327
|
+
reconcileOverdueCompletions(input?: ReconcileOverdueCompletionsInput): Promise<{
|
|
1328
|
+
overdue: string[];
|
|
1329
|
+
}>;
|
|
1236
1330
|
}
|
|
1237
1331
|
/**
|
|
1238
1332
|
* Host operator operations kept outside `GovernedActionHost`, so an existing
|
|
1239
1333
|
* hand-written `GovernedActionHost` still satisfies that interface.
|
|
1240
1334
|
* `createGovernedActionHost()` returns both.
|
|
1241
1335
|
*/
|
|
1242
|
-
interface OutboxRequeueHost {
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
}
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
renewOutboxLease(input: {
|
|
1315
|
-
id: string;
|
|
1316
|
-
workerId: string;
|
|
1317
|
-
leaseToken: number;
|
|
1318
|
-
leaseDurationMs: number;
|
|
1319
|
-
now?: Date;
|
|
1320
|
-
}): Promise<boolean>;
|
|
1321
|
-
listOutbox(input?: {
|
|
1322
|
-
tenantId?: string;
|
|
1323
|
-
spaceId?: string;
|
|
1324
|
-
statuses?: OutboxStatus[];
|
|
1325
|
-
}): Promise<OutboxRecord[]>;
|
|
1326
|
-
getOutboxRecord(id: string, tenantId: string, spaceId: string): Promise<OutboxRecord | undefined>;
|
|
1327
|
-
requeueOutboxDeadLetter(input: RequeueOutboxDeadLetterStoreInput): Promise<RequeueOutboxDeadLetterStoreResult>;
|
|
1328
|
-
listOutboxRequeues(input: {
|
|
1329
|
-
tenantId: string;
|
|
1330
|
-
spaceId: string;
|
|
1331
|
-
outboxId?: string;
|
|
1332
|
-
}): Promise<OutboxRequeueRecord[]>;
|
|
1333
|
-
private requireLeasedOutbox;
|
|
1334
|
-
nextEventSequence(tenantId: string, spaceId: string): Promise<number>;
|
|
1335
|
-
getEntityStateSource(tenantId: string, spaceId: string, entityType: string, entityId: string): Promise<{
|
|
1336
|
-
state: string;
|
|
1337
|
-
actionInvocationId: string;
|
|
1338
|
-
} | undefined>;
|
|
1339
|
-
getEntityState(tenantId: string, spaceId: string, entityType: string, entityId: string): Promise<string | undefined>;
|
|
1340
|
-
listActionInvocations(input?: ListActionInvocationsInput): Promise<ActionInvocationRecord[]>;
|
|
1341
|
-
getHealthCounts(input: PlatformHostHealthQuery): Promise<PlatformHostHealthCounts>;
|
|
1342
|
-
claimActionInvocations(input: ClaimActionInvocationsInput): Promise<ActionInvocationRecord[]>;
|
|
1343
|
-
updateLeasedActionInvocation(input: UpdateLeasedActionInvocationInput): Promise<boolean>;
|
|
1344
|
-
renewActionInvocationLease(input: RenewActionInvocationLeaseInput): Promise<boolean>;
|
|
1345
|
-
listEvents(tenantId: string, spaceId: string): Promise<AssetEventEnvelope[]>;
|
|
1346
|
-
}
|
|
1347
|
-
|
|
1348
|
-
declare function toEnterpriseEventEnvelope(event: AssetEventEnvelope, metadata: OutboxEventMetadata): EnterpriseEventEnvelope;
|
|
1349
|
-
/** The `includeActor` decision a store records with the outbox record it writes from `metadata`. */
|
|
1350
|
-
declare function outboxActorDisclosure(metadata: OutboxEventMetadata): OutboxActorDisclosure;
|
|
1351
|
-
interface EnterpriseEventPublishContext {
|
|
1352
|
-
signal: AbortSignal;
|
|
1353
|
-
/**
|
|
1354
|
-
* Why the envelope does or does not carry `actorId`/`actorType`. `runOutboxRelayCycle()` always
|
|
1355
|
-
* sets it; a caller other than the relay may omit it, which a consumer should treat like `legacy`.
|
|
1356
|
-
*/
|
|
1357
|
-
actorDisclosure?: EnterpriseEventActorDisclosure;
|
|
1358
|
-
}
|
|
1359
|
-
interface EnterpriseEventPublisher {
|
|
1360
|
-
publish(event: EnterpriseEventEnvelope, context?: EnterpriseEventPublishContext): Promise<void>;
|
|
1361
|
-
}
|
|
1362
|
-
interface OutboxRelayOptions<TDb> {
|
|
1363
|
-
store: OutboxPlatformHostStore<TDb>;
|
|
1364
|
-
publisher: EnterpriseEventPublisher;
|
|
1336
|
+
export interface OutboxRequeueHost {
|
|
1337
|
+
/**
|
|
1338
|
+
* Operator replay of a dead-lettered outbox record: authorize the trusted
|
|
1339
|
+
* actor for the tenant and space against the record as read, then move
|
|
1340
|
+
* that same dead letter back to pending with a fresh attempt budget and
|
|
1341
|
+
* append who, when, and why beside the earlier failure. The relay
|
|
1342
|
+
* republishes it under the same `eventId`. Requires an
|
|
1343
|
+
* `OutboxRequeuePlatformHostStore`; refusals are returned, not thrown.
|
|
1344
|
+
*/
|
|
1345
|
+
requeueOutboxDeadLetter(input: RequeueOutboxDeadLetterInput): Promise<RequeueOutboxDeadLetterResult>;
|
|
1346
|
+
}
|
|
1347
|
+
//#endregion
|
|
1348
|
+
//#region src/host.d.ts
|
|
1349
|
+
export declare function createGovernedActionHost<TDb>(options: PlatformHostOptions<TDb>): GovernedActionHost & OutboxRequeueHost;
|
|
1350
|
+
//#endregion
|
|
1351
|
+
//#region src/memory-store.d.ts
|
|
1352
|
+
export interface MemoryPlatformHostTransactionProvider<TDb> {
|
|
1353
|
+
snapshot(db: TDb): TDb;
|
|
1354
|
+
restore(db: TDb, snapshot: TDb): void;
|
|
1355
|
+
}
|
|
1356
|
+
export declare class MemoryPlatformHostStore<TDb> implements RecoverablePlatformHostStore<TDb>, ApprovalPlatformHostStore<TDb>, GovernancePlatformHostStore<TDb>, OutboxPlatformHostStore<TDb>, OutboxRequeuePlatformHostStore<TDb> {
|
|
1357
|
+
readonly db: TDb;
|
|
1358
|
+
readonly transactionalOutbox: boolean;
|
|
1359
|
+
transactionWithEvents?: <TResult>(run: (transaction: PlatformHostMutationTransaction<TDb>) => Promise<TResult>) => Promise<TResult>;
|
|
1360
|
+
private adapterCommit;
|
|
1361
|
+
private transactionTail;
|
|
1362
|
+
readonly invocations: ActionInvocationRecord[];
|
|
1363
|
+
readonly policyEvaluations: PolicyEvaluationRecord[];
|
|
1364
|
+
readonly adapterInvocations: AdapterInvocationRecord[];
|
|
1365
|
+
readonly events: AssetEventEnvelope[];
|
|
1366
|
+
readonly policyObligations: PolicyObligationRecord[];
|
|
1367
|
+
readonly executionAttestations: ExecutionAttestationRecord[];
|
|
1368
|
+
readonly externalReconciliations: ExternalReconciliationRecord[];
|
|
1369
|
+
readonly outbox: OutboxRecord[];
|
|
1370
|
+
/**
|
|
1371
|
+
* Requeue evidence is append-only audit history, so unlike the ledger
|
|
1372
|
+
* arrays above, which tests have always inspected and seeded directly, it
|
|
1373
|
+
* is not public: `listOutboxRequeues` returns copies with their own Dates. TypeScript
|
|
1374
|
+
* `private`, as for the store's other internals, is a compile-time guard.
|
|
1375
|
+
*/
|
|
1376
|
+
private readonly outboxRequeues;
|
|
1377
|
+
constructor(db: TDb, transactionProvider?: MemoryPlatformHostTransactionProvider<TDb>);
|
|
1378
|
+
transaction<TResult>(run: (db: TDb) => Promise<TResult>): Promise<TResult>;
|
|
1379
|
+
private runTransactionWithEvents;
|
|
1380
|
+
createActionInvocation(input: CreateActionInvocationInput): Promise<ActionInvocationRecord>;
|
|
1381
|
+
getActionInvocation(id: string, tenantId: string, spaceId: string): Promise<ActionInvocationRecord | undefined>;
|
|
1382
|
+
updateActionInvocation(id: string, tenantId: string, spaceId: string, patch: ActionInvocationPatch): Promise<void>;
|
|
1383
|
+
recordHitlDecision(actionInvocationId: string, tenantId: string, spaceId: string, decision: HitlDecisionEvidence): Promise<ActionInvocationRecord>;
|
|
1384
|
+
beginApprovalDecision(input: BeginApprovalDecisionInput): Promise<ApprovalDecisionTransitionResult>;
|
|
1385
|
+
appendPolicyEvaluation(record: PolicyEvaluationRecord): Promise<void>;
|
|
1386
|
+
recordMutationGovernance(actionInvocationId: string, tenantId: string, spaceId: string, context: Pick<ActionInvocationRecord, "mutationFootprint" | "executionPrincipal"> & {
|
|
1387
|
+
footprint: NonNullable<ActionInvocationRecord["mutationFootprint"]>;
|
|
1388
|
+
executionPrincipal: NonNullable<ActionInvocationRecord["executionPrincipal"]>;
|
|
1389
|
+
}): Promise<ActionInvocationRecord>;
|
|
1390
|
+
appendPolicyObligations(records: PolicyObligationRecord[]): Promise<void>;
|
|
1391
|
+
listPolicyObligations(actionInvocationId: string, tenantId: string, spaceId: string): Promise<PolicyObligationRecord[]>;
|
|
1392
|
+
updatePolicyObligation(actionInvocationId: string, obligationId: string, status: PolicyObligationRecord["status"], evidenceReferences?: PolicyObligationRecord["evidenceReferences"]): Promise<void>;
|
|
1393
|
+
appendExecutionAttestation(record: ExecutionAttestationRecord): Promise<void>;
|
|
1394
|
+
listExecutionAttestations(actionInvocationId: string, tenantId: string, spaceId: string): Promise<ExecutionAttestationRecord[]>;
|
|
1395
|
+
appendExternalReconciliation(record: ExternalReconciliationRecord): Promise<void>;
|
|
1396
|
+
private adapterWriteMatches;
|
|
1397
|
+
updateSettledActionInvocation(input: UpdateSettledActionInvocationInput): Promise<boolean>;
|
|
1398
|
+
writeAdapterInvocation(input: AdapterInvocationWriteInput): Promise<boolean>;
|
|
1399
|
+
createAdapterInvocation(record: AdapterInvocationRecord): Promise<void>;
|
|
1400
|
+
getAdapterInvocation(id: string, scope?: AdapterInvocationScope): Promise<AdapterInvocationRecord | undefined>;
|
|
1401
|
+
updateAdapterInvocation(id: string, patch: Partial<Pick<AdapterInvocationRecord, "status" | "output" | "error" | "attempt" | "updatedAt" | "reconciliation">>, scope?: AdapterInvocationScope): Promise<void>;
|
|
1402
|
+
appendEvent(event: AssetEventEnvelope): Promise<void>;
|
|
1403
|
+
appendEventWithOutbox(event: AssetEventEnvelope, metadata: OutboxEventMetadata): Promise<void>;
|
|
1404
|
+
claimOutbox(input: ClaimOutboxInput): Promise<OutboxRecord[]>;
|
|
1405
|
+
markOutboxPublished(id: string, workerId: string, publishedAt: Date, leaseToken?: number): Promise<void>;
|
|
1406
|
+
markOutboxFailed(input: {
|
|
1407
|
+
id: string;
|
|
1365
1408
|
workerId: string;
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1409
|
+
leaseToken?: number;
|
|
1410
|
+
error: string;
|
|
1411
|
+
availableAt: Date;
|
|
1412
|
+
deadLetter: boolean;
|
|
1413
|
+
}): Promise<void>;
|
|
1414
|
+
renewOutboxLease(input: {
|
|
1415
|
+
id: string;
|
|
1416
|
+
workerId: string;
|
|
1417
|
+
leaseToken: number;
|
|
1418
|
+
leaseDurationMs: number;
|
|
1419
|
+
now?: Date;
|
|
1420
|
+
}): Promise<boolean>;
|
|
1421
|
+
listOutbox(input?: {
|
|
1422
|
+
tenantId?: string;
|
|
1423
|
+
spaceId?: string;
|
|
1424
|
+
statuses?: OutboxStatus[];
|
|
1425
|
+
}): Promise<OutboxRecord[]>;
|
|
1426
|
+
getOutboxRecord(id: string, tenantId: string, spaceId: string): Promise<OutboxRecord | undefined>;
|
|
1427
|
+
requeueOutboxDeadLetter(input: RequeueOutboxDeadLetterStoreInput): Promise<RequeueOutboxDeadLetterStoreResult>;
|
|
1428
|
+
listOutboxRequeues(input: {
|
|
1429
|
+
tenantId: string;
|
|
1430
|
+
spaceId: string;
|
|
1431
|
+
outboxId?: string;
|
|
1432
|
+
}): Promise<OutboxRequeueRecord[]>;
|
|
1433
|
+
private requireLeasedOutbox;
|
|
1434
|
+
nextEventSequence(tenantId: string, spaceId: string): Promise<number>;
|
|
1435
|
+
getEntityStateSource(tenantId: string, spaceId: string, entityType: string, entityId: string): Promise<{
|
|
1436
|
+
state: string;
|
|
1437
|
+
actionInvocationId: string;
|
|
1438
|
+
} | undefined>;
|
|
1439
|
+
getEntityState(tenantId: string, spaceId: string, entityType: string, entityId: string): Promise<string | undefined>;
|
|
1440
|
+
listActionInvocations(input?: ListActionInvocationsInput): Promise<ActionInvocationRecord[]>;
|
|
1441
|
+
getHealthCounts(input: PlatformHostHealthQuery): Promise<PlatformHostHealthCounts>;
|
|
1442
|
+
claimActionInvocations(input: ClaimActionInvocationsInput): Promise<ActionInvocationRecord[]>;
|
|
1443
|
+
updateLeasedActionInvocation(input: UpdateLeasedActionInvocationInput): Promise<boolean>;
|
|
1444
|
+
renewActionInvocationLease(input: RenewActionInvocationLeaseInput): Promise<boolean>;
|
|
1445
|
+
listEvents(tenantId: string, spaceId: string): Promise<AssetEventEnvelope[]>;
|
|
1446
|
+
}
|
|
1447
|
+
//#endregion
|
|
1448
|
+
//#region src/outbox.d.ts
|
|
1449
|
+
export declare function toEnterpriseEventEnvelope(event: AssetEventEnvelope, metadata: OutboxEventMetadata): EnterpriseEventEnvelope;
|
|
1450
|
+
/** The `includeActor` decision a store records with the outbox record it writes from `metadata`. */
|
|
1451
|
+
export declare function outboxActorDisclosure(metadata: OutboxEventMetadata): OutboxActorDisclosure;
|
|
1452
|
+
export interface EnterpriseEventPublishContext {
|
|
1453
|
+
signal: AbortSignal;
|
|
1454
|
+
/**
|
|
1455
|
+
* Why the envelope does or does not carry `actorId`/`actorType`. `runOutboxRelayCycle()` always
|
|
1456
|
+
* sets it; a caller other than the relay may omit it, which a consumer should treat like `legacy`.
|
|
1457
|
+
*/
|
|
1458
|
+
actorDisclosure?: EnterpriseEventActorDisclosure;
|
|
1459
|
+
}
|
|
1460
|
+
export interface EnterpriseEventPublisher {
|
|
1461
|
+
publish(event: EnterpriseEventEnvelope, context?: EnterpriseEventPublishContext): Promise<void>;
|
|
1462
|
+
}
|
|
1463
|
+
export interface OutboxRelayOptions<TDb> {
|
|
1464
|
+
store: OutboxPlatformHostStore<TDb>;
|
|
1465
|
+
publisher: EnterpriseEventPublisher;
|
|
1466
|
+
workerId: string;
|
|
1467
|
+
leaseDurationMs?: number;
|
|
1468
|
+
leaseRenewalIntervalMs?: number;
|
|
1469
|
+
publishTimeoutMs?: number;
|
|
1470
|
+
batchSize?: number;
|
|
1471
|
+
maxAttempts?: number;
|
|
1472
|
+
retryDelayMs?: (attempt: number) => number;
|
|
1473
|
+
now?: () => Date;
|
|
1474
|
+
telemetry?: PlatformHostTelemetry;
|
|
1475
|
+
}
|
|
1476
|
+
export interface OutboxRelayResult {
|
|
1477
|
+
claimed: number;
|
|
1478
|
+
published: number;
|
|
1479
|
+
failed: number;
|
|
1480
|
+
deadLettered: number;
|
|
1481
|
+
}
|
|
1482
|
+
export declare function runOutboxRelayCycle<TDb>(options: OutboxRelayOptions<TDb>): Promise<OutboxRelayResult>;
|
|
1382
1483
|
/**
|
|
1383
1484
|
* A copy with its own Date fields and trace context. The event payload and
|
|
1384
1485
|
* provenance are shallow: the copy shares them with the record, as before.
|
|
1385
1486
|
*/
|
|
1386
|
-
declare function cloneOutboxRecord(record: OutboxRecord): OutboxRecord;
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1487
|
+
export declare function cloneOutboxRecord(record: OutboxRecord): OutboxRecord;
|
|
1488
|
+
//#endregion
|
|
1489
|
+
//#region src/postgres-store.d.ts
|
|
1490
|
+
export interface PlatformHostSqlResult<Row = Record<string, unknown>> {
|
|
1491
|
+
rows: Row[];
|
|
1390
1492
|
}
|
|
1391
1493
|
/** Structural subset implemented by `pg.Pool` and Lakebase-compatible clients. */
|
|
1392
|
-
interface PlatformHostSqlClient {
|
|
1393
|
-
|
|
1494
|
+
export interface PlatformHostSqlClient {
|
|
1495
|
+
query<Row = Record<string, unknown>>(sql: string, values?: unknown[]): Promise<PlatformHostSqlResult<Row>>;
|
|
1394
1496
|
}
|
|
1395
|
-
interface PostgresPlatformHostTransactionContext<TDb> {
|
|
1396
|
-
|
|
1397
|
-
|
|
1497
|
+
export interface PostgresPlatformHostTransactionContext<TDb> {
|
|
1498
|
+
db: TDb;
|
|
1499
|
+
sql: PlatformHostSqlClient;
|
|
1398
1500
|
}
|
|
1399
1501
|
/**
|
|
1400
1502
|
* Application-owned transaction binder.
|
|
@@ -1403,87 +1505,90 @@ interface PostgresPlatformHostTransactionContext<TDb> {
|
|
|
1403
1505
|
* `pg.PoolClient`. Production applications provide this adapter so domain
|
|
1404
1506
|
* methods and Host ledger writes share one PostgreSQL transaction.
|
|
1405
1507
|
*/
|
|
1406
|
-
interface PostgresPlatformHostTransactionProvider<TDb> {
|
|
1407
|
-
|
|
1508
|
+
export interface PostgresPlatformHostTransactionProvider<TDb> {
|
|
1509
|
+
run<TResult>(run: (context: PostgresPlatformHostTransactionContext<TDb>) => Promise<TResult>): Promise<TResult>;
|
|
1408
1510
|
}
|
|
1409
1511
|
/** Durable mutation-pipeline ledger for Databricks Lakebase or standard Postgres. */
|
|
1410
|
-
declare class PostgresPlatformHostStore<TDb> implements RecoverablePlatformHostStore<TDb>, ApprovalPlatformHostStore<TDb>, GovernancePlatformHostStore<TDb>, OutboxPlatformHostStore<TDb>, OutboxRequeuePlatformHostStore<TDb> {
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1512
|
+
export declare class PostgresPlatformHostStore<TDb> implements RecoverablePlatformHostStore<TDb>, ApprovalPlatformHostStore<TDb>, GovernancePlatformHostStore<TDb>, OutboxPlatformHostStore<TDb>, OutboxRequeuePlatformHostStore<TDb> {
|
|
1513
|
+
readonly db: TDb;
|
|
1514
|
+
private readonly sql;
|
|
1515
|
+
readonly transactionWithEvents?: AtomicMutationPlatformHostStore<TDb>["transactionWithEvents"];
|
|
1516
|
+
readonly transactionalOutbox: boolean;
|
|
1517
|
+
constructor(db: TDb, sql: PlatformHostSqlClient, transactionProvider?: PostgresPlatformHostTransactionProvider<TDb>);
|
|
1518
|
+
ensureSchema(): Promise<void>;
|
|
1519
|
+
transaction<TResult>(run: (db: TDb) => Promise<TResult>): Promise<TResult>;
|
|
1520
|
+
createActionInvocation(input: CreateActionInvocationInput): Promise<ActionInvocationRecord>;
|
|
1521
|
+
getActionInvocation(id: string, tenantId: string, spaceId: string): Promise<ActionInvocationRecord | undefined>;
|
|
1522
|
+
updateActionInvocation(id: string, tenantId: string, spaceId: string, patch: ActionInvocationPatch): Promise<void>;
|
|
1523
|
+
recordHitlDecision(actionInvocationId: string, tenantId: string, spaceId: string, decision: HitlDecisionEvidence): Promise<ActionInvocationRecord>;
|
|
1524
|
+
beginApprovalDecision(input: BeginApprovalDecisionInput): Promise<ApprovalDecisionTransitionResult>;
|
|
1525
|
+
appendPolicyEvaluation(record: PolicyEvaluationRecord): Promise<void>;
|
|
1526
|
+
recordMutationGovernance(actionInvocationId: string, tenantId: string, spaceId: string, context: {
|
|
1527
|
+
footprint: NonNullable<ActionInvocationRecord["mutationFootprint"]>;
|
|
1528
|
+
executionPrincipal: NonNullable<ActionInvocationRecord["executionPrincipal"]>;
|
|
1529
|
+
}): Promise<ActionInvocationRecord>;
|
|
1530
|
+
appendPolicyObligations(records: PolicyObligationRecord[]): Promise<void>;
|
|
1531
|
+
listPolicyObligations(actionInvocationId: string, tenantId: string, spaceId: string): Promise<PolicyObligationRecord[]>;
|
|
1532
|
+
updatePolicyObligation(actionInvocationId: string, obligationId: string, status: PolicyObligationRecord["status"], evidenceReferences?: PolicyObligationRecord["evidenceReferences"]): Promise<void>;
|
|
1533
|
+
appendExecutionAttestation(record: ExecutionAttestationRecord): Promise<void>;
|
|
1534
|
+
listExecutionAttestations(actionInvocationId: string, tenantId: string, spaceId: string): Promise<ExecutionAttestationRecord[]>;
|
|
1535
|
+
appendExternalReconciliation(record: ExternalReconciliationRecord): Promise<void>;
|
|
1536
|
+
updateSettledActionInvocation(input: UpdateSettledActionInvocationInput): Promise<boolean>;
|
|
1537
|
+
writeAdapterInvocation(input: AdapterInvocationWriteInput): Promise<boolean>;
|
|
1538
|
+
createAdapterInvocation(record: AdapterInvocationRecord): Promise<void>;
|
|
1539
|
+
getAdapterInvocation(id: string, scope?: AdapterInvocationScope): Promise<AdapterInvocationRecord | undefined>;
|
|
1540
|
+
updateAdapterInvocation(id: string, patch: Partial<Pick<AdapterInvocationRecord, "status" | "output" | "error" | "attempt" | "updatedAt" | "reconciliation">>, scope?: AdapterInvocationScope): Promise<void>;
|
|
1541
|
+
appendEvent(event: AssetEventEnvelope): Promise<void>;
|
|
1542
|
+
appendEventWithOutbox(event: AssetEventEnvelope, metadata: OutboxEventMetadata): Promise<void>;
|
|
1543
|
+
claimOutbox(input: ClaimOutboxInput): Promise<OutboxRecord[]>;
|
|
1544
|
+
markOutboxPublished(id: string, workerId: string, publishedAt: Date, leaseToken?: number): Promise<void>;
|
|
1545
|
+
markOutboxFailed(input: {
|
|
1546
|
+
id: string;
|
|
1547
|
+
workerId: string;
|
|
1548
|
+
leaseToken?: number;
|
|
1549
|
+
error: string;
|
|
1550
|
+
availableAt: Date;
|
|
1551
|
+
deadLetter: boolean;
|
|
1552
|
+
}): Promise<void>;
|
|
1553
|
+
renewOutboxLease(input: {
|
|
1554
|
+
id: string;
|
|
1555
|
+
workerId: string;
|
|
1556
|
+
leaseToken: number;
|
|
1557
|
+
leaseDurationMs: number;
|
|
1558
|
+
now?: Date;
|
|
1559
|
+
}): Promise<boolean>;
|
|
1560
|
+
listOutbox(input?: {
|
|
1561
|
+
tenantId?: string;
|
|
1562
|
+
spaceId?: string;
|
|
1563
|
+
statuses?: OutboxStatus[];
|
|
1564
|
+
}): Promise<OutboxRecord[]>;
|
|
1565
|
+
getOutboxRecord(id: string, tenantId: string, spaceId: string): Promise<OutboxRecord | undefined>;
|
|
1566
|
+
requeueOutboxDeadLetter(input: RequeueOutboxDeadLetterStoreInput): Promise<RequeueOutboxDeadLetterStoreResult>;
|
|
1567
|
+
listOutboxRequeues(input: {
|
|
1568
|
+
tenantId: string;
|
|
1569
|
+
spaceId: string;
|
|
1570
|
+
outboxId?: string;
|
|
1571
|
+
}): Promise<OutboxRequeueRecord[]>;
|
|
1572
|
+
nextEventSequence(tenantId: string, spaceId: string): Promise<number>;
|
|
1573
|
+
getEntityStateSource(tenantId: string, spaceId: string, entityType: string, entityId: string): Promise<{
|
|
1574
|
+
state: string;
|
|
1575
|
+
actionInvocationId: string;
|
|
1576
|
+
} | undefined>;
|
|
1577
|
+
getEntityState(tenantId: string, spaceId: string, entityType: string, entityId: string): Promise<string | undefined>;
|
|
1578
|
+
listActionInvocations(input?: ListActionInvocationsInput): Promise<ActionInvocationRecord[]>;
|
|
1579
|
+
getHealthCounts(input: PlatformHostHealthQuery): Promise<PlatformHostHealthCounts>;
|
|
1580
|
+
claimActionInvocations(input: ClaimActionInvocationsInput): Promise<ActionInvocationRecord[]>;
|
|
1581
|
+
updateLeasedActionInvocation(input: UpdateLeasedActionInvocationInput): Promise<boolean>;
|
|
1582
|
+
renewActionInvocationLease(input: RenewActionInvocationLeaseInput): Promise<boolean>;
|
|
1583
|
+
listEvents(tenantId: string, spaceId: string): Promise<AssetEventEnvelope[]>;
|
|
1584
|
+
getEvent(id: string, tenantId: string, spaceId: string): Promise<AssetEventEnvelope | undefined>;
|
|
1585
|
+
}
|
|
1586
|
+
//#endregion
|
|
1587
|
+
//#region src/postgres-migrations.d.ts
|
|
1588
|
+
export interface PostgresMigration {
|
|
1589
|
+
version: number;
|
|
1590
|
+
name: string;
|
|
1591
|
+
sql: string;
|
|
1487
1592
|
}
|
|
1488
1593
|
/**
|
|
1489
1594
|
* Applies an immutable, ordered migration set in one PostgreSQL transaction.
|
|
@@ -1491,74 +1596,76 @@ interface PostgresMigration {
|
|
|
1491
1596
|
* The transaction-scoped advisory lock serializes migrators. A previously
|
|
1492
1597
|
* applied version may be presented again only when its checksum is unchanged.
|
|
1493
1598
|
*/
|
|
1494
|
-
declare function applyPostgresMigrations(client: PlatformHostSqlClient, migrations: readonly PostgresMigration[]): Promise<void>;
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
declare function digestParameters(parameters: unknown): string;
|
|
1499
|
-
|
|
1599
|
+
export declare function applyPostgresMigrations(client: PlatformHostSqlClient, migrations: readonly PostgresMigration[]): Promise<void>;
|
|
1600
|
+
//#endregion
|
|
1601
|
+
//#region src/command-identity.d.ts
|
|
1602
|
+
export declare const PARAMETER_DIGEST_ALGORITHM: "fabric-canonical-json-sha256-v1";
|
|
1603
|
+
export declare function digestParameters(parameters: unknown): string;
|
|
1604
|
+
//#endregion
|
|
1605
|
+
//#region src/worker.d.ts
|
|
1500
1606
|
/**
|
|
1501
1607
|
* Durable store-backed dispatch: the pending invocation row is the queue item.
|
|
1502
1608
|
* Repeated dispatches are safe because the workflow id is stable per invocation.
|
|
1503
1609
|
*/
|
|
1504
|
-
declare function createStoreBackedActionDispatcher(): PlatformActionDispatcher;
|
|
1610
|
+
export declare function createStoreBackedActionDispatcher(): PlatformActionDispatcher;
|
|
1505
1611
|
/** Claim and execute one bounded batch. Safe to run concurrently across workers. */
|
|
1506
|
-
declare function runPlatformActionWorkerCycle<TDb>(options: PlatformActionWorkerOptions<TDb>): Promise<PlatformActionWorkerCycleResult>;
|
|
1612
|
+
export declare function runPlatformActionWorkerCycle<TDb>(options: PlatformActionWorkerOptions<TDb>): Promise<PlatformActionWorkerCycleResult>;
|
|
1507
1613
|
/** Poll until aborted. Each iteration is bounded and waits without busy-spinning. */
|
|
1508
|
-
declare function runPlatformActionWorker<TDb>(options: PlatformActionWorkerOptions<TDb>): Promise<void>;
|
|
1509
|
-
|
|
1614
|
+
export declare function runPlatformActionWorker<TDb>(options: PlatformActionWorkerOptions<TDb>): Promise<void>;
|
|
1615
|
+
//#endregion
|
|
1616
|
+
//#region src/saga-parent-lifecycle.d.ts
|
|
1510
1617
|
interface HostSagaParentLifecycleIdentity {
|
|
1511
|
-
|
|
1512
|
-
|
|
1618
|
+
/** Stable identity shared by every retry of the same lifecycle transition. */
|
|
1619
|
+
lifecycleId?: string;
|
|
1513
1620
|
}
|
|
1514
1621
|
/**
|
|
1515
1622
|
* Durable record of a single step completing within a saga parent.
|
|
1516
1623
|
* Structurally compatible with {@link import("@fabricorg/platform-temporal").SagaParentProgressRecord}.
|
|
1517
1624
|
*/
|
|
1518
|
-
interface HostSagaParentProgressRecord {
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
}
|
|
1524
|
-
interface HostSagaParentProgressInput extends HostSagaParentLifecycleIdentity {
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
}
|
|
1530
|
-
interface HostSagaParentApprovalInput extends HostSagaParentLifecycleIdentity {
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
}
|
|
1538
|
-
interface HostSagaParentCancellationInput extends HostSagaParentLifecycleIdentity {
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
}
|
|
1545
|
-
interface HostSagaParentCompletionInput extends HostSagaParentLifecycleIdentity {
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
}
|
|
1551
|
-
interface HostSagaParentFailureInput extends HostSagaParentLifecycleIdentity {
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
}
|
|
1558
|
-
interface HostCompensationRecord {
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1625
|
+
export interface HostSagaParentProgressRecord {
|
|
1626
|
+
stepId: string;
|
|
1627
|
+
index: number;
|
|
1628
|
+
total: number;
|
|
1629
|
+
completedAt: string;
|
|
1630
|
+
}
|
|
1631
|
+
export interface HostSagaParentProgressInput extends HostSagaParentLifecycleIdentity {
|
|
1632
|
+
parentInvocationId: string;
|
|
1633
|
+
tenantId: string;
|
|
1634
|
+
spaceId: string;
|
|
1635
|
+
progress: HostSagaParentProgressRecord;
|
|
1636
|
+
}
|
|
1637
|
+
export interface HostSagaParentApprovalInput extends HostSagaParentLifecycleIdentity {
|
|
1638
|
+
parentInvocationId: string;
|
|
1639
|
+
tenantId: string;
|
|
1640
|
+
spaceId: string;
|
|
1641
|
+
stepId: string;
|
|
1642
|
+
approvalId: string;
|
|
1643
|
+
reason: string;
|
|
1644
|
+
}
|
|
1645
|
+
export interface HostSagaParentCancellationInput extends HostSagaParentLifecycleIdentity {
|
|
1646
|
+
parentInvocationId: string;
|
|
1647
|
+
tenantId: string;
|
|
1648
|
+
spaceId: string;
|
|
1649
|
+
reason: string;
|
|
1650
|
+
actorId: string;
|
|
1651
|
+
}
|
|
1652
|
+
export interface HostSagaParentCompletionInput extends HostSagaParentLifecycleIdentity {
|
|
1653
|
+
parentInvocationId: string;
|
|
1654
|
+
tenantId: string;
|
|
1655
|
+
spaceId: string;
|
|
1656
|
+
result: Record<string, unknown>;
|
|
1657
|
+
}
|
|
1658
|
+
export interface HostSagaParentFailureInput extends HostSagaParentLifecycleIdentity {
|
|
1659
|
+
parentInvocationId: string;
|
|
1660
|
+
tenantId: string;
|
|
1661
|
+
spaceId: string;
|
|
1662
|
+
error: string;
|
|
1663
|
+
compensation: HostCompensationRecord[];
|
|
1664
|
+
}
|
|
1665
|
+
export interface HostCompensationRecord {
|
|
1666
|
+
stepId: string;
|
|
1667
|
+
actionId: string;
|
|
1668
|
+
error?: string;
|
|
1562
1669
|
}
|
|
1563
1670
|
/**
|
|
1564
1671
|
* Durable saga parent lifecycle contract backed by a Platform Host store.
|
|
@@ -1573,17 +1680,17 @@ interface HostCompensationRecord {
|
|
|
1573
1680
|
* the persisted progress, approval park, cancellation, completion, or failure
|
|
1574
1681
|
* without in-memory state.
|
|
1575
1682
|
*/
|
|
1576
|
-
interface HostSagaParentLifecycle {
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
}
|
|
1583
|
-
interface CreateDurableSagaParentLifecycleOptions<TDb> {
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1683
|
+
export interface HostSagaParentLifecycle {
|
|
1684
|
+
recordProgress(input: HostSagaParentProgressInput): Promise<void>;
|
|
1685
|
+
parkApproval(input: HostSagaParentApprovalInput): Promise<void>;
|
|
1686
|
+
cancel(input: HostSagaParentCancellationInput): Promise<void>;
|
|
1687
|
+
complete(input: HostSagaParentCompletionInput): Promise<void>;
|
|
1688
|
+
fail(input: HostSagaParentFailureInput): Promise<void>;
|
|
1689
|
+
}
|
|
1690
|
+
export interface CreateDurableSagaParentLifecycleOptions<TDb> {
|
|
1691
|
+
store: PlatformHostStore<TDb>;
|
|
1692
|
+
/** Optional clock for deterministic tests. */
|
|
1693
|
+
now?: () => Date;
|
|
1587
1694
|
}
|
|
1588
1695
|
/**
|
|
1589
1696
|
* Create a {@link HostSagaParentLifecycle} backed by a Platform Host store.
|
|
@@ -1593,55 +1700,56 @@ interface CreateDurableSagaParentLifecycleOptions<TDb> {
|
|
|
1593
1700
|
* lifecycle event and transitions the parent invocation to the appropriate
|
|
1594
1701
|
* status so a fresh worker can observe the persisted state after a rollover.
|
|
1595
1702
|
*/
|
|
1596
|
-
declare function createDurableSagaParentLifecycle<TDb>(options: CreateDurableSagaParentLifecycleOptions<TDb>): HostSagaParentLifecycle;
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
}
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1703
|
+
export declare function createDurableSagaParentLifecycle<TDb>(options: CreateDurableSagaParentLifecycleOptions<TDb>): HostSagaParentLifecycle;
|
|
1704
|
+
//#endregion
|
|
1705
|
+
//#region src/tenant-isolation.d.ts
|
|
1706
|
+
export interface TenantIsolationScope {
|
|
1707
|
+
tenantId: string;
|
|
1708
|
+
spaceId: string;
|
|
1709
|
+
actorId: string;
|
|
1710
|
+
actorType: ActorType;
|
|
1711
|
+
}
|
|
1712
|
+
export interface TenantIsolationSubject<TDb = unknown> {
|
|
1713
|
+
host: GovernedActionHost;
|
|
1714
|
+
store: RecoverablePlatformHostStore<TDb>;
|
|
1715
|
+
/** A governed action registered on the host, and parameters it accepts. */
|
|
1716
|
+
actionId: ActionId;
|
|
1717
|
+
parameters?: Record<string, unknown>;
|
|
1718
|
+
/** Two scopes in different tenants. */
|
|
1719
|
+
ours: TenantIsolationScope;
|
|
1720
|
+
theirs: TenantIsolationScope;
|
|
1721
|
+
/**
|
|
1722
|
+
* Optional: a governed read the subject exposes, scoped as the projection
|
|
1723
|
+
* host scopes it. Returns what a viewer in `scope` sees for the view. Every
|
|
1724
|
+
* row must carry the `tenantId` it belongs to, so the check can tell a row
|
|
1725
|
+
* of ours from a row of theirs that merely looks the same; two tenants may
|
|
1726
|
+
* legitimately hold equal-looking rows.
|
|
1727
|
+
*/
|
|
1728
|
+
read?(scope: TenantIsolationScope): Promise<{
|
|
1729
|
+
allowed: boolean;
|
|
1730
|
+
rows: readonly {
|
|
1731
|
+
tenantId: string;
|
|
1732
|
+
}[];
|
|
1733
|
+
}>;
|
|
1734
|
+
/**
|
|
1735
|
+
* Optional: put the host and store back to a known state before a check.
|
|
1736
|
+
* The checks tolerate accumulated state, and each retires any row it
|
|
1737
|
+
* creates directly, so this exists for subjects whose store is shared.
|
|
1738
|
+
*/
|
|
1739
|
+
reset?(): Promise<void> | void;
|
|
1740
|
+
}
|
|
1741
|
+
export interface TenantIsolationCheck {
|
|
1742
|
+
id: "fabric.tenancy.invocation-scoped-read.v1" | "fabric.tenancy.idempotency-key-scoped.v1" | "fabric.tenancy.events-scoped.v1" | "fabric.tenancy.worker-claim-scoped.v1" | "fabric.tenancy.completion-scoped.v1" | "fabric.tenancy.projection-scoped.v1" | "fabric.tenancy.adapter-invocation-read-scoped.v1" | "fabric.tenancy.adapter-invocation-write-scoped.v1";
|
|
1743
|
+
run(subject: TenantIsolationSubject): Promise<string[]>;
|
|
1744
|
+
}
|
|
1745
|
+
export interface TenantIsolationResult {
|
|
1746
|
+
passed: boolean;
|
|
1747
|
+
checks: Array<{
|
|
1748
|
+
id: TenantIsolationCheck["id"];
|
|
1749
|
+
status: "passed" | "failed" | "skipped";
|
|
1750
|
+
evidence: string[];
|
|
1751
|
+
error?: string;
|
|
1752
|
+
}>;
|
|
1645
1753
|
}
|
|
1646
1754
|
/**
|
|
1647
1755
|
* The suite any deployment of the host must pass before it claims isolation.
|
|
@@ -1654,8 +1762,8 @@ interface TenantIsolationResult {
|
|
|
1654
1762
|
* space, or owning invocation; and, when the subject lends a read, a viewer in
|
|
1655
1763
|
* the other tenant sees nothing of ours.
|
|
1656
1764
|
*/
|
|
1657
|
-
declare function tenantIsolationChecks(): readonly TenantIsolationCheck[];
|
|
1765
|
+
export declare function tenantIsolationChecks(): readonly TenantIsolationCheck[];
|
|
1658
1766
|
/** Run every check, returning each result rather than throwing on the first. */
|
|
1659
|
-
declare function runTenantIsolationChecks(subject: TenantIsolationSubject): Promise<TenantIsolationResult>;
|
|
1660
|
-
|
|
1661
|
-
export {
|
|
1767
|
+
export declare function runTenantIsolationChecks(subject: TenantIsolationSubject): Promise<TenantIsolationResult>;
|
|
1768
|
+
//#endregion
|
|
1769
|
+
export { canonicalJson };
|