@fabricorg/platform-host 7.5.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 +220 -0
- package/MIGRATION-8.md +247 -0
- package/README.md +455 -45
- package/dist/index.cjs +5407 -4251
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1513 -1380
- package/dist/index.d.ts +1513 -1380
- package/dist/index.js +5400 -4246
- package/dist/index.js.map +1 -1
- package/package.json +9 -7
package/dist/index.d.ts
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,147 +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
|
-
|
|
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;
|
|
371
387
|
}
|
|
372
388
|
/**
|
|
373
389
|
* What an external system reports when it finishes work the host accepted.
|
|
@@ -377,109 +393,180 @@ interface PendingExternalCompletion {
|
|
|
377
393
|
* refused, because completing the wrong invocation is worse than dropping a
|
|
378
394
|
* callback.
|
|
379
395
|
*/
|
|
380
|
-
interface ExternalCompletion {
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
}
|
|
390
|
-
interface RecordedExternalCompletion extends ExternalCompletion {
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
}
|
|
401
|
-
interface ReconcileOverdueCompletionsInput {
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
}
|
|
407
|
-
type AdapterInvocationStatus = "running" | "succeeded" | "failed" | "ambiguous";
|
|
408
|
-
interface AdapterReconciliationOutcome {
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
}
|
|
419
|
-
interface AdapterInvocationRecord {
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
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;
|
|
436
458
|
}
|
|
459
|
+
export interface CreateActionInvocationInput extends Omit<ActionInvocationRecord, "createdAt" | "updatedAt" | "attemptCount" | "leaseOwner" | "leaseExpiresAt" | "leaseToken"> {}
|
|
437
460
|
/** Scope of an adapter checkpoint within its owning action invocation. */
|
|
438
|
-
interface AdapterInvocationScope {
|
|
439
|
-
|
|
440
|
-
|
|
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;
|
|
441
567
|
actionInvocationId: string;
|
|
442
|
-
}
|
|
443
|
-
|
|
444
|
-
readonly db: TDb;
|
|
445
|
-
/**
|
|
446
|
-
* Run against the store's domain handle. This base seam does not promise a
|
|
447
|
-
* database transaction. Use `transactionWithEvents` when domain writes,
|
|
448
|
-
* canonical events, and invocation state must commit atomically.
|
|
449
|
-
*/
|
|
450
|
-
transaction<TResult>(run: (db: TDb) => Promise<TResult>): Promise<TResult>;
|
|
451
|
-
createActionInvocation(input: CreateActionInvocationInput): Promise<ActionInvocationRecord>;
|
|
452
|
-
getActionInvocation(id: string, tenantId: string, spaceId: string): Promise<ActionInvocationRecord | undefined>;
|
|
453
|
-
updateActionInvocation(id: string, tenantId: string, spaceId: string, patch: ActionInvocationPatch): Promise<void>;
|
|
454
|
-
appendPolicyEvaluation(record: PolicyEvaluationRecord): Promise<void>;
|
|
455
|
-
createAdapterInvocation(record: AdapterInvocationRecord): Promise<void>;
|
|
456
|
-
/**
|
|
457
|
-
* Host supplies scope from its store-loaded invocation at adapter call sites.
|
|
458
|
-
* When supplied, stores must match tenant, space, and action invocation:
|
|
459
|
-
* an out-of-scope record returns undefined. Optional for compatibility with
|
|
460
|
-
* existing custom stores and direct callers; tenantIsolationChecks tests
|
|
461
|
-
* scoped read and write conformance.
|
|
462
|
-
*/
|
|
463
|
-
getAdapterInvocation(id: string, scope?: AdapterInvocationScope): Promise<AdapterInvocationRecord | undefined>;
|
|
464
|
-
/**
|
|
465
|
-
* Match all three scope fields when supplied, changing nothing outside it
|
|
466
|
-
* (a not-found error is permitted). Host supplies scope as described above;
|
|
467
|
-
* optional only for compatibility with existing stores and direct callers.
|
|
468
|
-
*/
|
|
469
|
-
updateAdapterInvocation(id: string, patch: Partial<Pick<AdapterInvocationRecord, "status" | "output" | "error" | "attempt" | "updatedAt">>, scope?: AdapterInvocationScope): Promise<void>;
|
|
470
|
-
appendEvent(event: AssetEventEnvelope): Promise<void>;
|
|
471
|
-
nextEventSequence(tenantId: string, spaceId: string): Promise<number>;
|
|
472
|
-
/**
|
|
473
|
-
* Return the state and invocation writer of the same event selected by
|
|
474
|
-
* getEntityState, scoped to this subject and tenant/space. Return undefined
|
|
475
|
-
* when that event or its invocation provenance is unavailable. Transaction
|
|
476
|
-
* implementations include pending events visible to getEntityState.
|
|
477
|
-
*/
|
|
478
|
-
getEntityStateSource?(tenantId: string, spaceId: string, entityType: string, entityId: string): Promise<{
|
|
479
|
-
state: string;
|
|
480
|
-
actionInvocationId: string;
|
|
481
|
-
} | undefined>;
|
|
482
|
-
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>;
|
|
483
570
|
}
|
|
484
571
|
/**
|
|
485
572
|
* Transaction-scoped Host operations used to commit domain writes and their
|
|
@@ -489,141 +576,159 @@ interface PlatformHostStore<TDb> {
|
|
|
489
576
|
* lifecycle method on this object. Implementations must roll the whole unit
|
|
490
577
|
* back when `run` throws.
|
|
491
578
|
*/
|
|
492
|
-
interface PlatformHostMutationTransaction<TDb> {
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
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
|
-
|
|
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;
|
|
534
639
|
}
|
|
535
640
|
/**
|
|
536
641
|
* Whether Host put actor identity on an outbox record's envelope, decided by `includeActor` when
|
|
537
642
|
* the record was written. A record has no value when it predates the decision (`legacy`).
|
|
538
643
|
*/
|
|
539
|
-
type OutboxActorDisclosure = "included" | "suppressed";
|
|
644
|
+
export type OutboxActorDisclosure = "included" | "suppressed";
|
|
540
645
|
/**
|
|
541
646
|
* What the relay tells a publisher about an envelope's actor identity: the record's
|
|
542
647
|
* `OutboxActorDisclosure`, or `legacy` for a record with none. The memory and PostgreSQL stores
|
|
543
648
|
* hydrate actor identity only for `included` records, so their legacy and suppressed envelopes carry
|
|
544
649
|
* none; a consumer that needs it reads the canonical event.
|
|
545
650
|
*/
|
|
546
|
-
type EnterpriseEventActorDisclosure = OutboxActorDisclosure | "legacy";
|
|
547
|
-
interface EnterpriseEventEnvelope {
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
}
|
|
576
|
-
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: {
|
|
577
713
|
id: string;
|
|
578
|
-
|
|
579
|
-
spaceId: string;
|
|
580
|
-
event: EnterpriseEventEnvelope;
|
|
581
|
-
/** Absent for a record written before Host recorded the `includeActor` decision. */
|
|
582
|
-
actorDisclosure?: OutboxActorDisclosure;
|
|
583
|
-
status: OutboxStatus;
|
|
584
|
-
attemptCount: number;
|
|
585
|
-
availableAt: Date;
|
|
586
|
-
leaseOwner?: string;
|
|
587
|
-
leaseExpiresAt?: Date;
|
|
714
|
+
workerId: string;
|
|
588
715
|
leaseToken?: number;
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
}
|
|
593
|
-
|
|
716
|
+
error: string;
|
|
717
|
+
availableAt: Date;
|
|
718
|
+
deadLetter: boolean;
|
|
719
|
+
}): Promise<void>;
|
|
720
|
+
renewOutboxLease(input: {
|
|
721
|
+
id: string;
|
|
594
722
|
workerId: string;
|
|
723
|
+
leaseToken: number;
|
|
595
724
|
leaseDurationMs: number;
|
|
596
|
-
|
|
725
|
+
now?: Date;
|
|
726
|
+
}): Promise<boolean>;
|
|
727
|
+
listOutbox(input?: {
|
|
597
728
|
tenantId?: string;
|
|
598
729
|
spaceId?: string;
|
|
599
|
-
|
|
600
|
-
}
|
|
601
|
-
interface OutboxPlatformHostStore<TDb> extends PlatformHostStore<TDb> {
|
|
602
|
-
/** True only when transactionWithEvents supplies appendEventWithOutbox in the same unit of work. */
|
|
603
|
-
readonly transactionalOutbox?: boolean;
|
|
604
|
-
appendEventWithOutbox(event: AssetEventEnvelope, metadata: OutboxEventMetadata): Promise<void>;
|
|
605
|
-
claimOutbox(input: ClaimOutboxInput): Promise<OutboxRecord[]>;
|
|
606
|
-
markOutboxPublished(id: string, workerId: string, publishedAt: Date, leaseToken?: number): Promise<void>;
|
|
607
|
-
markOutboxFailed(input: {
|
|
608
|
-
id: string;
|
|
609
|
-
workerId: string;
|
|
610
|
-
leaseToken?: number;
|
|
611
|
-
error: string;
|
|
612
|
-
availableAt: Date;
|
|
613
|
-
deadLetter: boolean;
|
|
614
|
-
}): Promise<void>;
|
|
615
|
-
renewOutboxLease(input: {
|
|
616
|
-
id: string;
|
|
617
|
-
workerId: string;
|
|
618
|
-
leaseToken: number;
|
|
619
|
-
leaseDurationMs: number;
|
|
620
|
-
now?: Date;
|
|
621
|
-
}): Promise<boolean>;
|
|
622
|
-
listOutbox(input?: {
|
|
623
|
-
tenantId?: string;
|
|
624
|
-
spaceId?: string;
|
|
625
|
-
statuses?: OutboxStatus[];
|
|
626
|
-
}): Promise<OutboxRecord[]>;
|
|
730
|
+
statuses?: OutboxStatus[];
|
|
731
|
+
}): Promise<OutboxRecord[]>;
|
|
627
732
|
}
|
|
628
733
|
/**
|
|
629
734
|
* Append-only evidence of one operator requeue of a dead-lettered outbox
|
|
@@ -631,42 +736,42 @@ interface OutboxPlatformHostStore<TDb> extends PlatformHostStore<TDb> {
|
|
|
631
736
|
* so the failure that exhausted the record stays readable after its attempt
|
|
632
737
|
* budget is reset.
|
|
633
738
|
*/
|
|
634
|
-
interface OutboxRequeueRecord {
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
}
|
|
652
|
-
interface RequeueOutboxDeadLetterStoreInput {
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
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;
|
|
670
775
|
}
|
|
671
776
|
/**
|
|
672
777
|
* `not_found`: no record with this id in the tenant and space, including a
|
|
@@ -675,74 +780,74 @@ interface RequeueOutboxDeadLetterStoreInput {
|
|
|
675
780
|
* requeue won the compare-and-set. `stale`: the record is a dead letter
|
|
676
781
|
* again, but not the one the caller observed; read and authorize it afresh.
|
|
677
782
|
*/
|
|
678
|
-
type OutboxRequeueRefusal = "not_found" | "not_dead_letter" | "stale";
|
|
679
|
-
type RequeueOutboxDeadLetterStoreResult = {
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
783
|
+
export type OutboxRequeueRefusal = "not_found" | "not_dead_letter" | "stale";
|
|
784
|
+
export type RequeueOutboxDeadLetterStoreResult = {
|
|
785
|
+
applied: true;
|
|
786
|
+
record: OutboxRecord;
|
|
787
|
+
requeue: OutboxRequeueRecord;
|
|
683
788
|
} | {
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
789
|
+
applied: false;
|
|
790
|
+
refusal: OutboxRequeueRefusal;
|
|
791
|
+
currentStatus?: OutboxStatus;
|
|
687
792
|
};
|
|
688
793
|
/**
|
|
689
794
|
* Optional outbox capability that moves a dead-lettered record back to
|
|
690
795
|
* pending. Kept apart from `OutboxPlatformHostStore` so a custom outbox store
|
|
691
796
|
* that predates it still satisfies that interface.
|
|
692
797
|
*/
|
|
693
|
-
interface OutboxRequeuePlatformHostStore<TDb> extends OutboxPlatformHostStore<TDb> {
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
tenantId: string;
|
|
709
|
-
spaceId: string;
|
|
710
|
-
outboxId?: string;
|
|
711
|
-
}): Promise<OutboxRequeueRecord[]>;
|
|
712
|
-
}
|
|
713
|
-
interface RequeueOutboxDeadLetterInput {
|
|
714
|
-
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: {
|
|
715
813
|
tenantId: string;
|
|
716
814
|
spaceId: string;
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
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;
|
|
730
835
|
} | {
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
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;
|
|
736
841
|
};
|
|
737
842
|
/** Facts given to `authorizeOutboxRequeue`. `record` is absent when no record with this id exists in the scope. */
|
|
738
|
-
interface OutboxRequeueAuthorizationInput {
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
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">;
|
|
746
851
|
}
|
|
747
852
|
/**
|
|
748
853
|
* Optional production capability for atomic domain/event persistence.
|
|
@@ -751,60 +856,60 @@ interface OutboxRequeueAuthorizationInput {
|
|
|
751
856
|
* not implement it retain the legacy transaction boundary for compatibility,
|
|
752
857
|
* but cannot claim atomic domain-write/event persistence.
|
|
753
858
|
*/
|
|
754
|
-
interface AtomicMutationPlatformHostStore<TDb> extends PlatformHostStore<TDb> {
|
|
755
|
-
|
|
756
|
-
}
|
|
757
|
-
interface BeginApprovalDecisionInput {
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
}
|
|
766
|
-
interface ApprovalDecisionTransitionResult {
|
|
767
|
-
|
|
768
|
-
|
|
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;
|
|
769
874
|
}
|
|
770
875
|
/** Optional store capability required only when agent HITL or approval resume is used. */
|
|
771
|
-
interface ApprovalPlatformHostStore<TDb> extends PlatformHostStore<TDb> {
|
|
772
|
-
|
|
773
|
-
|
|
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>;
|
|
774
879
|
}
|
|
775
880
|
/** Optional durable capabilities used when external-governance enrichment is configured. */
|
|
776
|
-
interface GovernancePlatformHostStore<TDb> extends PlatformHostStore<TDb> {
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
}
|
|
788
|
-
interface ListActionInvocationsInput {
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
}
|
|
801
|
-
interface ClaimActionInvocationsInput {
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
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;
|
|
808
913
|
}
|
|
809
914
|
/**
|
|
810
915
|
* What the host writes back to an invocation.
|
|
@@ -819,55 +924,55 @@ interface ClaimActionInvocationsInput {
|
|
|
819
924
|
* - `claimActionInvocations` must never claim a running invocation without a
|
|
820
925
|
* lease, which is what a parked invocation is.
|
|
821
926
|
*/
|
|
822
|
-
type ActionInvocationPatch = Partial<Pick<ActionInvocationRecord, "status" | "result" | "error" | "authorizationReconciliation" | "adapterReconciliation" | "pendingCompletion" | "externalCompletion">>;
|
|
823
|
-
interface UpdateLeasedActionInvocationInput {
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
}
|
|
831
|
-
interface RenewActionInvocationLeaseInput {
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
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;
|
|
839
944
|
}
|
|
840
945
|
/** Store capabilities required by the durable polling worker and operator tooling. */
|
|
841
|
-
interface RecoverablePlatformHostStore<TDb> extends PlatformHostStore<TDb> {
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
}
|
|
848
|
-
interface ActionAuthorizationInput {
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
}
|
|
858
|
-
type KnownActionExecutionReason = "initial" | "approval_resume" | "recovery" | "offline_replay";
|
|
859
|
-
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 & {});
|
|
860
965
|
/**
|
|
861
966
|
* Trusted execution-boundary authorization input.
|
|
862
967
|
*
|
|
863
968
|
* Parameters are the schema-parsed durable parameters, never caller-supplied
|
|
864
969
|
* transient values. `invocation` is the canonical record that will execute.
|
|
865
970
|
*/
|
|
866
|
-
interface ActionExecutionAuthorizationInput extends ActionAuthorizationInput {
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
971
|
+
export interface ActionExecutionAuthorizationInput extends ActionAuthorizationInput {
|
|
972
|
+
actionInvocationId: string;
|
|
973
|
+
parameters: unknown;
|
|
974
|
+
invocation: Readonly<ActionInvocationRecord>;
|
|
975
|
+
executionReason: ActionExecutionReason;
|
|
871
976
|
}
|
|
872
977
|
/**
|
|
873
978
|
* Input to `resolvePolicies`. Carries the invocation identity and the
|
|
@@ -876,41 +981,41 @@ interface ActionExecutionAuthorizationInput extends ActionAuthorizationInput {
|
|
|
876
981
|
* persisted evaluation per invocation and policy, so return the same snapshot
|
|
877
982
|
* for an `actionInvocationId` on every attempt.
|
|
878
983
|
*/
|
|
879
|
-
interface ResolvePoliciesInput extends ActionExecutionAuthorizationInput {
|
|
880
|
-
|
|
881
|
-
}
|
|
882
|
-
interface PlatformHostAuthorization {
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
}
|
|
901
|
-
interface DispatchActionInput {
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
}
|
|
908
|
-
interface DispatchActionResult {
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
}
|
|
912
|
-
interface PlatformActionDispatcher {
|
|
913
|
-
|
|
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>;
|
|
914
1019
|
}
|
|
915
1020
|
/**
|
|
916
1021
|
* One submission. `submitAction` reads the scalar fields (`actionId`, scope,
|
|
@@ -924,452 +1029,474 @@ interface PlatformActionDispatcher {
|
|
|
924
1029
|
* as the caller's objects, read where and as often as before (README,
|
|
925
1030
|
* "Submission snapshot").
|
|
926
1031
|
*/
|
|
927
|
-
interface SubmitActionInput {
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
}
|
|
944
|
-
interface SubmitActionResult {
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
}
|
|
960
|
-
interface ExecuteActionResult {
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
}
|
|
974
|
-
interface ExecuteInvocationOptions {
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
}
|
|
980
|
-
interface PlatformActionWorkerOptions<TDb> {
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
}
|
|
1000
|
-
interface PlatformActionWorkerCycleResult {
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
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;
|
|
1012
1117
|
}
|
|
1013
1118
|
/** Origin of error text redacted before Host records or returns it. */
|
|
1014
|
-
interface ErrorTextRedactionContext {
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
}
|
|
1022
|
-
interface PlatformHostOptions<TDb> {
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
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
|
-
hitlEvaluator?: AgentActionPolicyEvaluator;
|
|
1086
|
-
/** Durable evaluator/ruleset version recorded with every HITL decision. */
|
|
1087
|
-
hitlPolicyVersion?: string;
|
|
1088
|
-
/** Optional portable resolver; provider-specific implementations belong in integration packages. */
|
|
1089
|
-
resolveMutationGovernance?: MutationGovernanceResolver;
|
|
1090
|
-
/** Translate policy outcomes into durable, enforceable obligations. */
|
|
1091
|
-
resolvePolicyObligations?: (outcomes: readonly PolicyOutcome[]) => Promise<PolicyObligation[]> | PolicyObligation[];
|
|
1092
|
-
/** Translate a successful adapter result into audit-safe external execution evidence. */
|
|
1093
|
-
extractExecutionAttestation?: (input: {
|
|
1094
|
-
actionInvocationId: string;
|
|
1095
|
-
adapterInvocationId: string;
|
|
1096
|
-
adapterType: string;
|
|
1097
|
-
operation: string;
|
|
1098
|
-
vendor: string;
|
|
1099
|
-
/** Audit-safe adapter input after redactAdapterInput has been applied. */
|
|
1100
|
-
input: Record<string, unknown>;
|
|
1101
|
-
startedAt: Date;
|
|
1102
|
-
completedAt: Date;
|
|
1103
|
-
/** Adapter output after redactAdapterOutput, when configured. */
|
|
1104
|
-
output: Record<string, unknown>;
|
|
1105
|
-
}) => Promise<ExecutionAttestation | undefined> | ExecutionAttestation | undefined;
|
|
1106
|
-
/** Package/provider/ruleset generations persisted with every newly created invocation. */
|
|
1107
|
-
runtimeEvidence?: Partial<GovernanceRuntimeEvidence>;
|
|
1108
|
-
/**
|
|
1109
|
-
* Trusted composition identity attached by the Host configuration, never
|
|
1110
|
-
* accepted directly from submission input. Requires an explicit registry;
|
|
1111
|
-
* its module namespaces and versions are checked against these identities.
|
|
1112
|
-
*/
|
|
1113
|
-
composition?: {
|
|
1114
|
-
assembly: AssemblyLockfile;
|
|
1115
|
-
/**
|
|
1116
|
-
* Receives a fresh object whose action, scope, actor, correlation,
|
|
1117
|
-
* causation, idempotency key, binding id and execution reason are the
|
|
1118
|
-
* ones Host read at submission and persists, whatever the caller
|
|
1119
|
-
* changed on its own object since. For an action without
|
|
1120
|
-
* `admitSubmission`, its `parameters`, `provenance` and
|
|
1121
|
-
* `authorizationBinding` read and assign the caller's input, as when
|
|
1122
|
-
* the callback was handed that input itself; for an action that
|
|
1123
|
-
* declares it, they are fresh copies of Host's snapshot.
|
|
1124
|
-
*/
|
|
1125
|
-
resolveInitiatingReleaseDigest?(input: SubmitActionInput): Promise<string | undefined> | string | undefined;
|
|
1126
|
-
};
|
|
1127
|
-
/** Lease held while an approved invocation resumes; defaults to five minutes. */
|
|
1128
|
-
approvalResumeLeaseDurationMs?: number;
|
|
1129
|
-
/**
|
|
1130
|
-
* Remove forbidden/sensitive fields before durable invocation persistence.
|
|
1131
|
-
* For an action without `admitSubmission`, receives the caller's
|
|
1132
|
-
* parameters object, before provenance normalization and the composition
|
|
1133
|
-
* callback, as before. For an action that declares it, receives Host's
|
|
1134
|
-
* copy, after the check admitted the submission.
|
|
1135
|
-
*/
|
|
1136
|
-
redactActionParameters?: (actionId: ActionId, parameters: Record<string, unknown>) => Record<string, unknown>;
|
|
1137
|
-
/**
|
|
1138
|
-
* The bound on an action's `admitSubmission` check. An answer that
|
|
1139
|
-
* settles this many milliseconds or more after the check was called,
|
|
1140
|
-
* measured on the monotonic clock when its promise settles, is refused as
|
|
1141
|
-
* `timed_out` and the check's signal is aborted. A whole number from 1 to
|
|
1142
|
-
* 2 147 483 647 (the timer maximum), or `createGovernedActionHost` throws;
|
|
1143
|
-
* default 10 000.
|
|
1144
|
-
*/
|
|
1145
|
-
admissionTimeoutMs?: number;
|
|
1146
|
-
resolvePolicies?: (input: ResolvePoliciesInput) => Promise<RuntimePolicyDefinition[]>;
|
|
1147
|
-
extractEvents?: (data: Record<string, unknown>) => PendingAssetEvent[];
|
|
1148
|
-
/** Handler-result fields consumed by extractEvents and omitted from the durable result. */
|
|
1149
|
-
eventResultFields?: readonly string[];
|
|
1150
|
-
redactAdapterInput?: (actionId: ActionId, adapterType: string, operation: string, input: Record<string, unknown>) => Record<string, unknown>;
|
|
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;
|
|
1151
1190
|
/**
|
|
1152
|
-
*
|
|
1153
|
-
*
|
|
1154
|
-
*
|
|
1155
|
-
* Keep redactors deterministic and stable across deploys.
|
|
1156
|
-
* Accepted-operation references are read from the original adapter result.
|
|
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.
|
|
1157
1194
|
*/
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
/**
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
recordExecutionAttestation(actionInvocationId: string, tenantId: string, spaceId: string, attestation: ExecutionAttestation): Promise<void>;
|
|
1196
|
-
recordExternalReconciliation(actionInvocationId: string, tenantId: string, spaceId: string, reconciliation: ExternalReconciliation): Promise<void>;
|
|
1197
|
-
/**
|
|
1198
|
-
* Complete an invocation an adapter handed off, by the reference the
|
|
1199
|
-
* external system was given. Idempotent for a repeated identical
|
|
1200
|
-
* completion; a contradictory one moves the invocation to reconciliation.
|
|
1201
|
-
*/
|
|
1202
|
-
completeExternalInvocation(actionInvocationId: string, tenantId: string, spaceId: string, completion: ExternalCompletion): Promise<ExecuteActionResult>;
|
|
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;
|
|
1203
1232
|
/**
|
|
1204
|
-
*
|
|
1205
|
-
*
|
|
1206
|
-
*
|
|
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.
|
|
1207
1241
|
*/
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
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
|
+
}>;
|
|
1211
1330
|
}
|
|
1212
1331
|
/**
|
|
1213
1332
|
* Host operator operations kept outside `GovernedActionHost`, so an existing
|
|
1214
1333
|
* hand-written `GovernedActionHost` still satisfies that interface.
|
|
1215
1334
|
* `createGovernedActionHost()` returns both.
|
|
1216
1335
|
*/
|
|
1217
|
-
interface OutboxRequeueHost {
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
}
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
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
|
-
tenantId?: string;
|
|
1298
|
-
spaceId?: string;
|
|
1299
|
-
statuses?: OutboxStatus[];
|
|
1300
|
-
}): Promise<OutboxRecord[]>;
|
|
1301
|
-
getOutboxRecord(id: string, tenantId: string, spaceId: string): Promise<OutboxRecord | undefined>;
|
|
1302
|
-
requeueOutboxDeadLetter(input: RequeueOutboxDeadLetterStoreInput): Promise<RequeueOutboxDeadLetterStoreResult>;
|
|
1303
|
-
listOutboxRequeues(input: {
|
|
1304
|
-
tenantId: string;
|
|
1305
|
-
spaceId: string;
|
|
1306
|
-
outboxId?: string;
|
|
1307
|
-
}): Promise<OutboxRequeueRecord[]>;
|
|
1308
|
-
private requireLeasedOutbox;
|
|
1309
|
-
nextEventSequence(tenantId: string, spaceId: string): Promise<number>;
|
|
1310
|
-
getEntityStateSource(tenantId: string, spaceId: string, entityType: string, entityId: string): Promise<{
|
|
1311
|
-
state: string;
|
|
1312
|
-
actionInvocationId: string;
|
|
1313
|
-
} | undefined>;
|
|
1314
|
-
getEntityState(tenantId: string, spaceId: string, entityType: string, entityId: string): Promise<string | undefined>;
|
|
1315
|
-
listActionInvocations(input?: ListActionInvocationsInput): Promise<ActionInvocationRecord[]>;
|
|
1316
|
-
getHealthCounts(input: PlatformHostHealthQuery): Promise<PlatformHostHealthCounts>;
|
|
1317
|
-
claimActionInvocations(input: ClaimActionInvocationsInput): Promise<ActionInvocationRecord[]>;
|
|
1318
|
-
updateLeasedActionInvocation(input: UpdateLeasedActionInvocationInput): Promise<boolean>;
|
|
1319
|
-
renewActionInvocationLease(input: RenewActionInvocationLeaseInput): Promise<boolean>;
|
|
1320
|
-
listEvents(tenantId: string, spaceId: string): Promise<AssetEventEnvelope[]>;
|
|
1321
|
-
}
|
|
1322
|
-
|
|
1323
|
-
declare function toEnterpriseEventEnvelope(event: AssetEventEnvelope, metadata: OutboxEventMetadata): EnterpriseEventEnvelope;
|
|
1324
|
-
/** The `includeActor` decision a store records with the outbox record it writes from `metadata`. */
|
|
1325
|
-
declare function outboxActorDisclosure(metadata: OutboxEventMetadata): OutboxActorDisclosure;
|
|
1326
|
-
interface EnterpriseEventPublishContext {
|
|
1327
|
-
signal: AbortSignal;
|
|
1328
|
-
/**
|
|
1329
|
-
* Why the envelope does or does not carry `actorId`/`actorType`. `runOutboxRelayCycle()` always
|
|
1330
|
-
* sets it; a caller other than the relay may omit it, which a consumer should treat like `legacy`.
|
|
1331
|
-
*/
|
|
1332
|
-
actorDisclosure?: EnterpriseEventActorDisclosure;
|
|
1333
|
-
}
|
|
1334
|
-
interface EnterpriseEventPublisher {
|
|
1335
|
-
publish(event: EnterpriseEventEnvelope, context?: EnterpriseEventPublishContext): Promise<void>;
|
|
1336
|
-
}
|
|
1337
|
-
interface OutboxRelayOptions<TDb> {
|
|
1338
|
-
store: OutboxPlatformHostStore<TDb>;
|
|
1339
|
-
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;
|
|
1408
|
+
workerId: string;
|
|
1409
|
+
leaseToken?: number;
|
|
1410
|
+
error: string;
|
|
1411
|
+
availableAt: Date;
|
|
1412
|
+
deadLetter: boolean;
|
|
1413
|
+
}): Promise<void>;
|
|
1414
|
+
renewOutboxLease(input: {
|
|
1415
|
+
id: string;
|
|
1340
1416
|
workerId: string;
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
}
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
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>;
|
|
1357
1483
|
/**
|
|
1358
1484
|
* A copy with its own Date fields and trace context. The event payload and
|
|
1359
1485
|
* provenance are shallow: the copy shares them with the record, as before.
|
|
1360
1486
|
*/
|
|
1361
|
-
declare function cloneOutboxRecord(record: OutboxRecord): OutboxRecord;
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
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[];
|
|
1365
1492
|
}
|
|
1366
1493
|
/** Structural subset implemented by `pg.Pool` and Lakebase-compatible clients. */
|
|
1367
|
-
interface PlatformHostSqlClient {
|
|
1368
|
-
|
|
1494
|
+
export interface PlatformHostSqlClient {
|
|
1495
|
+
query<Row = Record<string, unknown>>(sql: string, values?: unknown[]): Promise<PlatformHostSqlResult<Row>>;
|
|
1369
1496
|
}
|
|
1370
|
-
interface PostgresPlatformHostTransactionContext<TDb> {
|
|
1371
|
-
|
|
1372
|
-
|
|
1497
|
+
export interface PostgresPlatformHostTransactionContext<TDb> {
|
|
1498
|
+
db: TDb;
|
|
1499
|
+
sql: PlatformHostSqlClient;
|
|
1373
1500
|
}
|
|
1374
1501
|
/**
|
|
1375
1502
|
* Application-owned transaction binder.
|
|
@@ -1378,87 +1505,90 @@ interface PostgresPlatformHostTransactionContext<TDb> {
|
|
|
1378
1505
|
* `pg.PoolClient`. Production applications provide this adapter so domain
|
|
1379
1506
|
* methods and Host ledger writes share one PostgreSQL transaction.
|
|
1380
1507
|
*/
|
|
1381
|
-
interface PostgresPlatformHostTransactionProvider<TDb> {
|
|
1382
|
-
|
|
1508
|
+
export interface PostgresPlatformHostTransactionProvider<TDb> {
|
|
1509
|
+
run<TResult>(run: (context: PostgresPlatformHostTransactionContext<TDb>) => Promise<TResult>): Promise<TResult>;
|
|
1383
1510
|
}
|
|
1384
1511
|
/** Durable mutation-pipeline ledger for Databricks Lakebase or standard Postgres. */
|
|
1385
|
-
declare class PostgresPlatformHostStore<TDb> implements RecoverablePlatformHostStore<TDb>, ApprovalPlatformHostStore<TDb>, GovernancePlatformHostStore<TDb>, OutboxPlatformHostStore<TDb>, OutboxRequeuePlatformHostStore<TDb> {
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
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
|
-
|
|
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;
|
|
1462
1592
|
}
|
|
1463
1593
|
/**
|
|
1464
1594
|
* Applies an immutable, ordered migration set in one PostgreSQL transaction.
|
|
@@ -1466,74 +1596,76 @@ interface PostgresMigration {
|
|
|
1466
1596
|
* The transaction-scoped advisory lock serializes migrators. A previously
|
|
1467
1597
|
* applied version may be presented again only when its checksum is unchanged.
|
|
1468
1598
|
*/
|
|
1469
|
-
declare function applyPostgresMigrations(client: PlatformHostSqlClient, migrations: readonly PostgresMigration[]): Promise<void>;
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
declare function digestParameters(parameters: unknown): string;
|
|
1474
|
-
|
|
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
|
|
1475
1606
|
/**
|
|
1476
1607
|
* Durable store-backed dispatch: the pending invocation row is the queue item.
|
|
1477
1608
|
* Repeated dispatches are safe because the workflow id is stable per invocation.
|
|
1478
1609
|
*/
|
|
1479
|
-
declare function createStoreBackedActionDispatcher(): PlatformActionDispatcher;
|
|
1610
|
+
export declare function createStoreBackedActionDispatcher(): PlatformActionDispatcher;
|
|
1480
1611
|
/** Claim and execute one bounded batch. Safe to run concurrently across workers. */
|
|
1481
|
-
declare function runPlatformActionWorkerCycle<TDb>(options: PlatformActionWorkerOptions<TDb>): Promise<PlatformActionWorkerCycleResult>;
|
|
1612
|
+
export declare function runPlatformActionWorkerCycle<TDb>(options: PlatformActionWorkerOptions<TDb>): Promise<PlatformActionWorkerCycleResult>;
|
|
1482
1613
|
/** Poll until aborted. Each iteration is bounded and waits without busy-spinning. */
|
|
1483
|
-
declare function runPlatformActionWorker<TDb>(options: PlatformActionWorkerOptions<TDb>): Promise<void>;
|
|
1484
|
-
|
|
1614
|
+
export declare function runPlatformActionWorker<TDb>(options: PlatformActionWorkerOptions<TDb>): Promise<void>;
|
|
1615
|
+
//#endregion
|
|
1616
|
+
//#region src/saga-parent-lifecycle.d.ts
|
|
1485
1617
|
interface HostSagaParentLifecycleIdentity {
|
|
1486
|
-
|
|
1487
|
-
|
|
1618
|
+
/** Stable identity shared by every retry of the same lifecycle transition. */
|
|
1619
|
+
lifecycleId?: string;
|
|
1488
1620
|
}
|
|
1489
1621
|
/**
|
|
1490
1622
|
* Durable record of a single step completing within a saga parent.
|
|
1491
1623
|
* Structurally compatible with {@link import("@fabricorg/platform-temporal").SagaParentProgressRecord}.
|
|
1492
1624
|
*/
|
|
1493
|
-
interface HostSagaParentProgressRecord {
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
}
|
|
1499
|
-
interface HostSagaParentProgressInput extends HostSagaParentLifecycleIdentity {
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
}
|
|
1505
|
-
interface HostSagaParentApprovalInput extends HostSagaParentLifecycleIdentity {
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
}
|
|
1513
|
-
interface HostSagaParentCancellationInput extends HostSagaParentLifecycleIdentity {
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
}
|
|
1520
|
-
interface HostSagaParentCompletionInput extends HostSagaParentLifecycleIdentity {
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
}
|
|
1526
|
-
interface HostSagaParentFailureInput extends HostSagaParentLifecycleIdentity {
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
}
|
|
1533
|
-
interface HostCompensationRecord {
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
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;
|
|
1537
1669
|
}
|
|
1538
1670
|
/**
|
|
1539
1671
|
* Durable saga parent lifecycle contract backed by a Platform Host store.
|
|
@@ -1548,17 +1680,17 @@ interface HostCompensationRecord {
|
|
|
1548
1680
|
* the persisted progress, approval park, cancellation, completion, or failure
|
|
1549
1681
|
* without in-memory state.
|
|
1550
1682
|
*/
|
|
1551
|
-
interface HostSagaParentLifecycle {
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
}
|
|
1558
|
-
interface CreateDurableSagaParentLifecycleOptions<TDb> {
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
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;
|
|
1562
1694
|
}
|
|
1563
1695
|
/**
|
|
1564
1696
|
* Create a {@link HostSagaParentLifecycle} backed by a Platform Host store.
|
|
@@ -1568,55 +1700,56 @@ interface CreateDurableSagaParentLifecycleOptions<TDb> {
|
|
|
1568
1700
|
* lifecycle event and transitions the parent invocation to the appropriate
|
|
1569
1701
|
* status so a fresh worker can observe the persisted state after a rollover.
|
|
1570
1702
|
*/
|
|
1571
|
-
declare function createDurableSagaParentLifecycle<TDb>(options: CreateDurableSagaParentLifecycleOptions<TDb>): HostSagaParentLifecycle;
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
}
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
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
|
+
}>;
|
|
1620
1753
|
}
|
|
1621
1754
|
/**
|
|
1622
1755
|
* The suite any deployment of the host must pass before it claims isolation.
|
|
@@ -1629,8 +1762,8 @@ interface TenantIsolationResult {
|
|
|
1629
1762
|
* space, or owning invocation; and, when the subject lends a read, a viewer in
|
|
1630
1763
|
* the other tenant sees nothing of ours.
|
|
1631
1764
|
*/
|
|
1632
|
-
declare function tenantIsolationChecks(): readonly TenantIsolationCheck[];
|
|
1765
|
+
export declare function tenantIsolationChecks(): readonly TenantIsolationCheck[];
|
|
1633
1766
|
/** Run every check, returning each result rather than throwing on the first. */
|
|
1634
|
-
declare function runTenantIsolationChecks(subject: TenantIsolationSubject): Promise<TenantIsolationResult>;
|
|
1635
|
-
|
|
1636
|
-
export {
|
|
1767
|
+
export declare function runTenantIsolationChecks(subject: TenantIsolationSubject): Promise<TenantIsolationResult>;
|
|
1768
|
+
//#endregion
|
|
1769
|
+
export { canonicalJson };
|