@fabricorg/platform-host 8.1.2 → 8.3.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 +79 -0
- package/README.md +288 -18
- package/dist/index.cjs +1640 -173
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +387 -18
- package/dist/index.d.ts +387 -18
- package/dist/index.js +1632 -175
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
package/dist/index.d.cts
CHANGED
|
@@ -1,4 +1,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";
|
|
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, StagedInvocationRequest, canonicalJson } from "@fabricorg/platform";
|
|
2
2
|
import { AssemblyLockfile } from "@fabricorg/assembly";
|
|
3
3
|
//#region src/observability.d.ts
|
|
4
4
|
/** Version of the vendor-neutral health/readiness contract. */
|
|
@@ -218,6 +218,14 @@ export declare class ActionAdmissionError extends Error {
|
|
|
218
218
|
/** The check's own code, present only for `refused`. */
|
|
219
219
|
refusalCode?: string | undefined);
|
|
220
220
|
}
|
|
221
|
+
export type SubmissionRefusal = "entitlement" | "authorization";
|
|
222
|
+
/** A definitive authorization-boundary refusal before an invocation is created. */
|
|
223
|
+
export declare class SubmissionRefusalError extends Error {
|
|
224
|
+
readonly actionId: string;
|
|
225
|
+
readonly refusal: SubmissionRefusal;
|
|
226
|
+
readonly code: "ACTION_SUBMISSION_REFUSED";
|
|
227
|
+
constructor(actionId: string, refusal: SubmissionRefusal, message: string);
|
|
228
|
+
}
|
|
221
229
|
export type ExternalCompletionRefusal = "still_executing" | "not_found" | "not_awaiting" | "immediate_contract" | "reference_mismatch" | "provider_mismatch" | "invalid_completion" | "result_invalid" | "redaction_failed";
|
|
222
230
|
/**
|
|
223
231
|
* Why a completion was not applied, typed so a webhook handler can answer
|
|
@@ -241,6 +249,31 @@ export interface PendingAssetEvent {
|
|
|
241
249
|
payload: unknown;
|
|
242
250
|
eventSchemaVersion?: number;
|
|
243
251
|
}
|
|
252
|
+
/** JSON preparation committed with the handler before adapter execution. */
|
|
253
|
+
export interface FinalizationCheckpoint {
|
|
254
|
+
protocol: "atomic-after-adapters-v1";
|
|
255
|
+
actionVersion: number;
|
|
256
|
+
steps: {
|
|
257
|
+
adapterType: string;
|
|
258
|
+
operation: string;
|
|
259
|
+
}[];
|
|
260
|
+
params: import("@fabricorg/platform").FinalizationJson;
|
|
261
|
+
handlerData: import("@fabricorg/platform").FinalizationRecord;
|
|
262
|
+
handlerEvents: (Omit<PendingAssetEvent, "payload"> & {
|
|
263
|
+
payload: import("@fabricorg/platform").FinalizationJson;
|
|
264
|
+
})[];
|
|
265
|
+
result: import("@fabricorg/platform").FinalizationRecord;
|
|
266
|
+
stateTransition?: Omit<PendingAssetEvent, "payload"> & {
|
|
267
|
+
payload: import("@fabricorg/platform").FinalizationJson;
|
|
268
|
+
};
|
|
269
|
+
skipped: number[];
|
|
270
|
+
/** Handler requests retained so finalization replay stages the identical batch. */
|
|
271
|
+
stagedInvocations?: readonly import("@fabricorg/platform").StagedInvocationRequest[];
|
|
272
|
+
}
|
|
273
|
+
export interface StagedInvocationOrigin {
|
|
274
|
+
parentInvocationId: string;
|
|
275
|
+
stageKey: string;
|
|
276
|
+
}
|
|
244
277
|
export interface ActionInvocationRecord {
|
|
245
278
|
id: string;
|
|
246
279
|
tenantId: string;
|
|
@@ -259,12 +292,16 @@ export interface ActionInvocationRecord {
|
|
|
259
292
|
parameterDigestAlgorithm?: "fabric-canonical-json-sha256-v1";
|
|
260
293
|
idempotencyActorId?: string;
|
|
261
294
|
idempotencyAuthorizationBindingId?: string;
|
|
295
|
+
/** Host-only identity for a staged child; public submissions cannot set it. */
|
|
296
|
+
stagedOrigin?: StagedInvocationOrigin;
|
|
262
297
|
provenance?: Omit<InvocationProvenance, "traceAttributes">;
|
|
263
298
|
authorizationBinding?: AuthorizationBinding;
|
|
264
299
|
executionReason?: ActionExecutionReason;
|
|
265
300
|
authorizationReconciliation?: AuthorizationReconciliationOutcome;
|
|
266
301
|
/** Durable evidence when an adapter returned an ambiguous outcome requiring reconciliation. */
|
|
267
302
|
adapterReconciliation?: AdapterReconciliationOutcome;
|
|
303
|
+
/** Durable normalized preparation; absent for invocations prepared by older Hosts. */
|
|
304
|
+
finalizationCheckpoint?: FinalizationCheckpoint;
|
|
268
305
|
/**
|
|
269
306
|
* Transition Host validated for an idempotent after_adapters action, saved
|
|
270
307
|
* after handler/result/event validation inside a mutation transaction, or before
|
|
@@ -289,6 +326,8 @@ export interface ActionInvocationRecord {
|
|
|
289
326
|
authorizationBindingId?: string;
|
|
290
327
|
/** Worker claims including the first; approval acceptance sets a minimum of 1. */
|
|
291
328
|
attemptCount: number;
|
|
329
|
+
/** Latest claim durably deferred in pre-effect governance; permits only the immediately next claim. */
|
|
330
|
+
deferredBeforeEffectAttempt?: number;
|
|
292
331
|
leaseOwner?: string;
|
|
293
332
|
leaseExpiresAt?: Date;
|
|
294
333
|
/** Monotonic claim generation used to reject writes from expired workers. */
|
|
@@ -456,7 +495,7 @@ export interface AdapterInvocationRecord {
|
|
|
456
495
|
createdAt: Date;
|
|
457
496
|
updatedAt: Date;
|
|
458
497
|
}
|
|
459
|
-
export interface CreateActionInvocationInput extends Omit<ActionInvocationRecord, "createdAt" | "updatedAt" | "attemptCount" | "leaseOwner" | "leaseExpiresAt" | "leaseToken"> {}
|
|
498
|
+
export interface CreateActionInvocationInput extends Omit<ActionInvocationRecord, "createdAt" | "updatedAt" | "attemptCount" | "leaseOwner" | "leaseExpiresAt" | "leaseToken" | "stagedOrigin"> {}
|
|
460
499
|
/** Scope of an adapter checkpoint within its owning action invocation. */
|
|
461
500
|
export interface AdapterInvocationScope {
|
|
462
501
|
tenantId: string;
|
|
@@ -514,6 +553,8 @@ export interface PlatformHostStore<TDb> {
|
|
|
514
553
|
transaction<TResult>(run: (db: TDb) => Promise<TResult>): Promise<TResult>;
|
|
515
554
|
createActionInvocation(input: CreateActionInvocationInput): Promise<ActionInvocationRecord>;
|
|
516
555
|
getActionInvocation(id: string, tenantId: string, spaceId: string): Promise<ActionInvocationRecord | undefined>;
|
|
556
|
+
/** Resolve Host-owned staged identity within one tenant and space. */
|
|
557
|
+
getActionInvocationByStagedOrigin?(tenantId: string, spaceId: string, origin: StagedInvocationOrigin): Promise<ActionInvocationRecord | undefined>;
|
|
517
558
|
updateActionInvocation(id: string, tenantId: string, spaceId: string, patch: ActionInvocationPatch): Promise<void>;
|
|
518
559
|
appendPolicyEvaluation(record: PolicyEvaluationRecord): Promise<void>;
|
|
519
560
|
createAdapterInvocation(record: AdapterInvocationRecord): Promise<void>;
|
|
@@ -645,6 +686,135 @@ export interface PlatformHostMutationTransaction<TDb> {
|
|
|
645
686
|
* governance evidence cannot share the event/verdict transaction.
|
|
646
687
|
*/
|
|
647
688
|
appendExternalReconciliation?: GovernancePlatformHostStore<TDb>["appendExternalReconciliation"];
|
|
689
|
+
/** Atomically retain an immutable staged batch with the parent mutation. */
|
|
690
|
+
stageInvocations?(records: readonly StagedInvocationRecord[]): Promise<void>;
|
|
691
|
+
}
|
|
692
|
+
export type StagedInvocationStatus = "pending" | "dispatched" | "rejected" | "dead_lettered" | "cancelled";
|
|
693
|
+
export interface StagedInvocationRecord {
|
|
694
|
+
id: string;
|
|
695
|
+
tenantId: string;
|
|
696
|
+
spaceId: string;
|
|
697
|
+
parentInvocationId: string;
|
|
698
|
+
parentActionId: ActionId;
|
|
699
|
+
key: string;
|
|
700
|
+
actionId: ActionId;
|
|
701
|
+
expectedActionVersion: number;
|
|
702
|
+
parameters: Record<string, unknown>;
|
|
703
|
+
parameterDigest: string;
|
|
704
|
+
batchDigest: string;
|
|
705
|
+
status: StagedInvocationStatus;
|
|
706
|
+
/**
|
|
707
|
+
* The child's id, recorded by the first settlement whose attempt knew it.
|
|
708
|
+
* A settlement without an id leaves an earlier one in place. After a crash
|
|
709
|
+
* between child creation and settlement it stays absent until a later
|
|
710
|
+
* attempt finds the child by its staged origin.
|
|
711
|
+
*/
|
|
712
|
+
childInvocationId?: string;
|
|
713
|
+
attemptCount: number;
|
|
714
|
+
availableAt: Date;
|
|
715
|
+
leaseOwner?: string;
|
|
716
|
+
leaseExpiresAt?: Date;
|
|
717
|
+
leaseToken: number;
|
|
718
|
+
lastError?: string;
|
|
719
|
+
createdAt: Date;
|
|
720
|
+
updatedAt: Date;
|
|
721
|
+
}
|
|
722
|
+
export interface ClaimStagedInvocationsInput {
|
|
723
|
+
workerId: string;
|
|
724
|
+
leaseDurationMs: number;
|
|
725
|
+
limit?: number;
|
|
726
|
+
tenantId?: string;
|
|
727
|
+
spaceId?: string;
|
|
728
|
+
now?: Date;
|
|
729
|
+
}
|
|
730
|
+
export interface CreateStagedActionInvocationInput {
|
|
731
|
+
stageId: string;
|
|
732
|
+
workerId: string;
|
|
733
|
+
leaseToken: number;
|
|
734
|
+
now?: Date;
|
|
735
|
+
invocation: CreateActionInvocationInput & {
|
|
736
|
+
stagedOrigin: StagedInvocationOrigin;
|
|
737
|
+
};
|
|
738
|
+
}
|
|
739
|
+
export type CreateStagedActionInvocationResult = {
|
|
740
|
+
kind: "created" | "existing";
|
|
741
|
+
invocation: ActionInvocationRecord;
|
|
742
|
+
} | {
|
|
743
|
+
kind: "lease_lost";
|
|
744
|
+
};
|
|
745
|
+
/** Optional durable capability for transactional staging and post-completion dispatch. */
|
|
746
|
+
export interface StagedInvocationPlatformHostStore<TDb> extends PlatformHostStore<TDb> {
|
|
747
|
+
readonly transactionalStagedInvocations?: boolean;
|
|
748
|
+
getActionInvocationByStagedOrigin(tenantId: string, spaceId: string, origin: StagedInvocationOrigin): Promise<ActionInvocationRecord | undefined>;
|
|
749
|
+
/** Return the existing origin or create it only while this exact stage lease is live. */
|
|
750
|
+
createActionInvocationForStagedLease(input: CreateStagedActionInvocationInput): Promise<CreateStagedActionInvocationResult>;
|
|
751
|
+
claimStagedInvocations(input: ClaimStagedInvocationsInput): Promise<StagedInvocationRecord[]>;
|
|
752
|
+
/**
|
|
753
|
+
* The settlements below are each one compare-and-set on a pending row's
|
|
754
|
+
* lease owner and token, and release the lease. A settlement that carries
|
|
755
|
+
* `childInvocationId` records it; one without leaves a recorded id in place.
|
|
756
|
+
*/
|
|
757
|
+
markStagedInvocationDispatched(input: {
|
|
758
|
+
id: string;
|
|
759
|
+
workerId: string;
|
|
760
|
+
leaseToken: number;
|
|
761
|
+
childInvocationId: string;
|
|
762
|
+
now?: Date;
|
|
763
|
+
}): Promise<boolean>;
|
|
764
|
+
markStagedInvocationRejected(input: {
|
|
765
|
+
id: string;
|
|
766
|
+
workerId: string;
|
|
767
|
+
leaseToken: number;
|
|
768
|
+
error: string;
|
|
769
|
+
now?: Date;
|
|
770
|
+
}): Promise<boolean>;
|
|
771
|
+
markStagedInvocationFailed(input: {
|
|
772
|
+
id: string;
|
|
773
|
+
workerId: string;
|
|
774
|
+
leaseToken: number;
|
|
775
|
+
error: string;
|
|
776
|
+
availableAt: Date;
|
|
777
|
+
deadLetter: boolean;
|
|
778
|
+
childInvocationId?: string;
|
|
779
|
+
now?: Date;
|
|
780
|
+
}): Promise<boolean>;
|
|
781
|
+
renewStagedInvocationLease(input: {
|
|
782
|
+
id: string;
|
|
783
|
+
workerId: string;
|
|
784
|
+
leaseToken: number;
|
|
785
|
+
leaseDurationMs: number;
|
|
786
|
+
now?: Date;
|
|
787
|
+
}): Promise<boolean>;
|
|
788
|
+
/**
|
|
789
|
+
* Replace the lease token of a pending row this worker leases with a larger
|
|
790
|
+
* one and extend the lease, in one compare-and-set on owner, token and an
|
|
791
|
+
* unexpired lease. Returns the new token, or `undefined` when the lease no
|
|
792
|
+
* longer matches. Tokens only grow, as with claims, so a later claim never
|
|
793
|
+
* hands an old token out again. Afterwards the old token fails the
|
|
794
|
+
* child-creation fence, renewal and every settlement. A store must order
|
|
795
|
+
* the rotation after any child creation the fence already admitted under
|
|
796
|
+
* the old token (PostgreSQL: the fence's `FOR SHARE` row lock makes the
|
|
797
|
+
* rotation wait). Host rotates before the lookup that decides a stage
|
|
798
|
+
* whose attempt holds no child id.
|
|
799
|
+
*/
|
|
800
|
+
rotateStagedInvocationLease(input: {
|
|
801
|
+
id: string;
|
|
802
|
+
workerId: string;
|
|
803
|
+
leaseToken: number;
|
|
804
|
+
leaseDurationMs: number;
|
|
805
|
+
now?: Date;
|
|
806
|
+
}): Promise<number | undefined>;
|
|
807
|
+
cancelStagedInvocationsForFailedParents(input?: {
|
|
808
|
+
tenantId?: string;
|
|
809
|
+
spaceId?: string;
|
|
810
|
+
now?: Date;
|
|
811
|
+
}): Promise<number>;
|
|
812
|
+
listStagedInvocations(input: {
|
|
813
|
+
tenantId: string;
|
|
814
|
+
spaceId: string;
|
|
815
|
+
parentInvocationId?: string;
|
|
816
|
+
statuses?: readonly StagedInvocationStatus[];
|
|
817
|
+
}): Promise<StagedInvocationRecord[]>;
|
|
648
818
|
}
|
|
649
819
|
export type OutboxStatus = "pending" | "published" | "dead_letter";
|
|
650
820
|
export type EventPayloadClassification = "public" | "internal" | "confidential" | "restricted";
|
|
@@ -954,7 +1124,7 @@ export interface ClaimActionInvocationsInput {
|
|
|
954
1124
|
* - `claimActionInvocations` must never claim a running invocation without a
|
|
955
1125
|
* lease, which is what a parked invocation is.
|
|
956
1126
|
*/
|
|
957
|
-
export type ActionInvocationPatch = Partial<Pick<ActionInvocationRecord, "status" | "result" | "error" | "authorizationReconciliation" | "adapterReconciliation" | "pendingStateTransition" | "pendingCompletion" | "externalCompletion">>;
|
|
1127
|
+
export type ActionInvocationPatch = Partial<Pick<ActionInvocationRecord, "finalizationCheckpoint" | "deferredBeforeEffectAttempt" | "status" | "result" | "error" | "authorizationReconciliation" | "adapterReconciliation" | "pendingStateTransition" | "pendingCompletion" | "externalCompletion">>;
|
|
958
1128
|
export interface UpdateLeasedActionInvocationInput {
|
|
959
1129
|
id: string;
|
|
960
1130
|
tenantId: string;
|
|
@@ -990,7 +1160,7 @@ export interface ActionAuthorizationInput {
|
|
|
990
1160
|
actorId: string;
|
|
991
1161
|
actorType: ActorType;
|
|
992
1162
|
}
|
|
993
|
-
export type KnownActionExecutionReason = "initial" | "approval_resume" | "recovery" | "offline_replay";
|
|
1163
|
+
export type KnownActionExecutionReason = "initial" | "approval_resume" | "recovery" | "offline_replay" | "staged_dispatch";
|
|
994
1164
|
export type ActionExecutionReason = KnownActionExecutionReason | (string & {});
|
|
995
1165
|
/**
|
|
996
1166
|
* Trusted execution-boundary authorization input.
|
|
@@ -1131,6 +1301,14 @@ export interface PlatformActionWorkerOptions<TDb> {
|
|
|
1131
1301
|
* on every cycle, and run the sweep elsewhere.
|
|
1132
1302
|
*/
|
|
1133
1303
|
sweepOverdueCompletions?: boolean;
|
|
1304
|
+
/** Dispatch staged descendants each cycle. Defaults to on when a registered action declares them. */
|
|
1305
|
+
dispatchStagedInvocations?: boolean;
|
|
1306
|
+
stagedInvocationBatchSize?: number;
|
|
1307
|
+
stagedInvocationLeaseDurationMs?: number;
|
|
1308
|
+
stagedInvocationLeaseRenewalIntervalMs?: number;
|
|
1309
|
+
stagedInvocationSubmissionTimeoutMs?: number;
|
|
1310
|
+
stagedInvocationMaxAttempts?: number;
|
|
1311
|
+
stagedInvocationRetryDelayMs?: (attempt: number) => number;
|
|
1134
1312
|
}
|
|
1135
1313
|
export interface PlatformActionWorkerCycleResult {
|
|
1136
1314
|
claimed: number;
|
|
@@ -1144,6 +1322,38 @@ export interface PlatformActionWorkerCycleResult {
|
|
|
1144
1322
|
* The row stays leased and a later claim retries it; excluded from failed.
|
|
1145
1323
|
*/
|
|
1146
1324
|
deferred?: number;
|
|
1325
|
+
staged?: StagedInvocationDispatchResult;
|
|
1326
|
+
}
|
|
1327
|
+
export interface StagedInvocationDispatchInput {
|
|
1328
|
+
workerId: string;
|
|
1329
|
+
limit?: number;
|
|
1330
|
+
leaseDurationMs?: number;
|
|
1331
|
+
leaseRenewalIntervalMs?: number;
|
|
1332
|
+
submissionTimeoutMs?: number;
|
|
1333
|
+
maxAttempts?: number;
|
|
1334
|
+
retryDelayMs?: (attempt: number) => number;
|
|
1335
|
+
tenantId?: string;
|
|
1336
|
+
spaceId?: string;
|
|
1337
|
+
/**
|
|
1338
|
+
* Receives a failed staged-origin lookup and any error that ends one claimed
|
|
1339
|
+
* row's processing early (a store error from renewal, rotation or
|
|
1340
|
+
* settlement). The sweep counts that row as failed and continues.
|
|
1341
|
+
*/
|
|
1342
|
+
onError?: (error: unknown) => void;
|
|
1343
|
+
}
|
|
1344
|
+
/**
|
|
1345
|
+
* Counters for one sweep. Each claimed row is counted once, as dispatched,
|
|
1346
|
+
* rejected or failed. `failed` includes rows settled for retry, rows whose
|
|
1347
|
+
* lease was lost before settlement, and rows whose processing threw;
|
|
1348
|
+
* `deadLettered` counts the subset of `failed` settled as `dead_lettered`.
|
|
1349
|
+
*/
|
|
1350
|
+
export interface StagedInvocationDispatchResult {
|
|
1351
|
+
claimed: number;
|
|
1352
|
+
dispatched: number;
|
|
1353
|
+
rejected: number;
|
|
1354
|
+
failed: number;
|
|
1355
|
+
deadLettered: number;
|
|
1356
|
+
cancelled: number;
|
|
1147
1357
|
}
|
|
1148
1358
|
/** Origin of error text redacted before Host records or returns it. */
|
|
1149
1359
|
export interface ErrorTextRedactionContext {
|
|
@@ -1179,10 +1389,12 @@ export interface PlatformHostOptions<TDb> {
|
|
|
1179
1389
|
adapterCircuitBreakers?: AdapterCircuitBreakerProvider;
|
|
1180
1390
|
/**
|
|
1181
1391
|
* Positive integer attempt cap for RetryableExecutionError during governance,
|
|
1182
|
-
* before policy-evaluation persistence (default 5). A leased
|
|
1183
|
-
*
|
|
1184
|
-
*
|
|
1185
|
-
*
|
|
1392
|
+
* before policy-evaluation persistence (default 5). A leased action below the cap
|
|
1393
|
+
* is left running for worker reclaim after lease expiry. Non-idempotent actions
|
|
1394
|
+
* require a lease-fenced pre-effect deferral marker for the current claim; only
|
|
1395
|
+
* the immediately next claim may proceed using that marker. Inline execution,
|
|
1396
|
+
* approval resume, exhausted attempts, and marker-write failures are not retried.
|
|
1397
|
+
* Policy persistence, obligation listing/resolution/persistence, state-machine checks,
|
|
1186
1398
|
* the handler transaction, handlers, adapters, and finalization are excluded;
|
|
1187
1399
|
* their failure/reconciliation/recovery semantics apply, subject to recoveryMaxAttempts.
|
|
1188
1400
|
*/
|
|
@@ -1294,6 +1506,12 @@ export interface PlatformHostOptions<TDb> {
|
|
|
1294
1506
|
extractEvents?: (data: Record<string, unknown>) => PendingAssetEvent[];
|
|
1295
1507
|
/** Handler-result fields consumed by extractEvents and omitted from the durable result. */
|
|
1296
1508
|
eventResultFields?: readonly string[];
|
|
1509
|
+
/**
|
|
1510
|
+
* Optional name registry for hook-returned events from action.finalize.
|
|
1511
|
+
* Checks eventType and subjectType membership; it does not validate handler events,
|
|
1512
|
+
* eventSchemaVersion compatibility, or payload schemas.
|
|
1513
|
+
*/
|
|
1514
|
+
eventContracts?: import("@fabricorg/platform").EventContractRegistry;
|
|
1297
1515
|
redactAdapterInput?: (actionId: ActionId, adapterType: string, operation: string, input: Record<string, unknown>) => Record<string, unknown>;
|
|
1298
1516
|
/**
|
|
1299
1517
|
* Redact successful adapter output before row/event persistence and attestation extraction.
|
|
@@ -1330,13 +1548,18 @@ export interface PlatformHostOptions<TDb> {
|
|
|
1330
1548
|
/** Vendor-neutral lifecycle and metric sink. Telemetry is best effort. */
|
|
1331
1549
|
telemetry?: PlatformHostTelemetry;
|
|
1332
1550
|
/**
|
|
1333
|
-
*
|
|
1334
|
-
*
|
|
1551
|
+
* Duration in milliseconds, measured before the step enters adapter retry execution.
|
|
1552
|
+
* A step deadlineMs overrides this duration. When this is omitted or zero and
|
|
1553
|
+
* the step has no deadlineMs, no deadline or AbortSignal is delivered.
|
|
1335
1554
|
*/
|
|
1336
1555
|
adapterDeadlineMs?: number;
|
|
1337
1556
|
}
|
|
1338
1557
|
export interface GovernedActionHost {
|
|
1339
1558
|
submitAction(input: SubmitActionInput): Promise<SubmitActionResult>;
|
|
1559
|
+
/** Whether this Host's registry contains an action with a non-empty staged-descendant allowlist. */
|
|
1560
|
+
readonly hasStagedInvocationActions?: boolean;
|
|
1561
|
+
/** One bounded lease-fenced sweep of completed parents' staged descendants. */
|
|
1562
|
+
dispatchStagedInvocations?(input: StagedInvocationDispatchInput): Promise<StagedInvocationDispatchResult>;
|
|
1340
1563
|
executeInvocation(actionInvocationId: string, tenantId: string, spaceId: string, options?: ExecuteInvocationOptions): Promise<ExecuteActionResult>;
|
|
1341
1564
|
resumeApprovedInvocation(actionInvocationId: string, tenantId: string, spaceId: string, decision: ActionApprovalDecision): Promise<ExecuteActionResult>;
|
|
1342
1565
|
recordExecutionAttestation(actionInvocationId: string, tenantId: string, spaceId: string, attestation: ExecutionAttestation): Promise<void>;
|
|
@@ -1383,9 +1606,10 @@ export interface MemoryPlatformHostTransactionProvider<TDb> {
|
|
|
1383
1606
|
snapshot(db: TDb): TDb;
|
|
1384
1607
|
restore(db: TDb, snapshot: TDb): void;
|
|
1385
1608
|
}
|
|
1386
|
-
export declare class MemoryPlatformHostStore<TDb> implements RecoverablePlatformHostStore<TDb>, ApprovalPlatformHostStore<TDb>, GovernancePlatformHostStore<TDb>, OutboxPlatformHostStore<TDb>, OutboxRequeuePlatformHostStore<TDb> {
|
|
1609
|
+
export declare class MemoryPlatformHostStore<TDb> implements RecoverablePlatformHostStore<TDb>, ApprovalPlatformHostStore<TDb>, GovernancePlatformHostStore<TDb>, OutboxPlatformHostStore<TDb>, OutboxRequeuePlatformHostStore<TDb>, StagedInvocationPlatformHostStore<TDb> {
|
|
1387
1610
|
readonly db: TDb;
|
|
1388
1611
|
readonly transactionalOutbox: boolean;
|
|
1612
|
+
readonly transactionalStagedInvocations: boolean;
|
|
1389
1613
|
transactionWithEvents?: <TResult>(run: (transaction: PlatformHostMutationTransaction<TDb>) => Promise<TResult>) => Promise<TResult>;
|
|
1390
1614
|
private adapterCommit;
|
|
1391
1615
|
private transactionTail;
|
|
@@ -1397,6 +1621,7 @@ export declare class MemoryPlatformHostStore<TDb> implements RecoverablePlatform
|
|
|
1397
1621
|
readonly executionAttestations: ExecutionAttestationRecord[];
|
|
1398
1622
|
readonly externalReconciliations: ExternalReconciliationRecord[];
|
|
1399
1623
|
readonly outbox: OutboxRecord[];
|
|
1624
|
+
readonly stagedInvocations: StagedInvocationRecord[];
|
|
1400
1625
|
/**
|
|
1401
1626
|
* Requeue evidence is append-only audit history, so unlike the ledger
|
|
1402
1627
|
* arrays above, which tests have always inspected and seeded directly, it
|
|
@@ -1408,7 +1633,10 @@ export declare class MemoryPlatformHostStore<TDb> implements RecoverablePlatform
|
|
|
1408
1633
|
transaction<TResult>(run: (db: TDb) => Promise<TResult>): Promise<TResult>;
|
|
1409
1634
|
private runTransactionWithEvents;
|
|
1410
1635
|
createActionInvocation(input: CreateActionInvocationInput): Promise<ActionInvocationRecord>;
|
|
1636
|
+
createActionInvocationForStagedLease(input: CreateStagedActionInvocationInput): Promise<CreateStagedActionInvocationResult>;
|
|
1637
|
+
private applyStagedBatch;
|
|
1411
1638
|
getActionInvocation(id: string, tenantId: string, spaceId: string): Promise<ActionInvocationRecord | undefined>;
|
|
1639
|
+
getActionInvocationByStagedOrigin(tenantId: string, spaceId: string, origin: StagedInvocationOrigin): Promise<ActionInvocationRecord | undefined>;
|
|
1412
1640
|
updateActionInvocation(id: string, tenantId: string, spaceId: string, patch: ActionInvocationPatch): Promise<void>;
|
|
1413
1641
|
recordHitlDecision(actionInvocationId: string, tenantId: string, spaceId: string, decision: HitlDecisionEvidence): Promise<ActionInvocationRecord>;
|
|
1414
1642
|
beginApprovalDecision(input: BeginApprovalDecisionInput): Promise<ApprovalDecisionTransitionResult>;
|
|
@@ -1472,6 +1700,60 @@ export declare class MemoryPlatformHostStore<TDb> implements RecoverablePlatform
|
|
|
1472
1700
|
claimActionInvocations(input: ClaimActionInvocationsInput): Promise<ActionInvocationRecord[]>;
|
|
1473
1701
|
updateLeasedActionInvocation(input: UpdateLeasedActionInvocationInput): Promise<boolean>;
|
|
1474
1702
|
renewActionInvocationLease(input: RenewActionInvocationLeaseInput): Promise<boolean>;
|
|
1703
|
+
claimStagedInvocations(input: ClaimStagedInvocationsInput): Promise<StagedInvocationRecord[]>;
|
|
1704
|
+
markStagedInvocationDispatched(input: {
|
|
1705
|
+
id: string;
|
|
1706
|
+
workerId: string;
|
|
1707
|
+
leaseToken: number;
|
|
1708
|
+
childInvocationId: string;
|
|
1709
|
+
now?: Date;
|
|
1710
|
+
}): Promise<boolean>;
|
|
1711
|
+
markStagedInvocationRejected(input: {
|
|
1712
|
+
id: string;
|
|
1713
|
+
workerId: string;
|
|
1714
|
+
leaseToken: number;
|
|
1715
|
+
error: string;
|
|
1716
|
+
now?: Date;
|
|
1717
|
+
}): Promise<boolean>;
|
|
1718
|
+
markStagedInvocationFailed(input: {
|
|
1719
|
+
id: string;
|
|
1720
|
+
workerId: string;
|
|
1721
|
+
leaseToken: number;
|
|
1722
|
+
error: string;
|
|
1723
|
+
availableAt: Date;
|
|
1724
|
+
deadLetter: boolean;
|
|
1725
|
+
childInvocationId?: string;
|
|
1726
|
+
now?: Date;
|
|
1727
|
+
}): Promise<boolean>;
|
|
1728
|
+
renewStagedInvocationLease(input: {
|
|
1729
|
+
id: string;
|
|
1730
|
+
workerId: string;
|
|
1731
|
+
leaseToken: number;
|
|
1732
|
+
leaseDurationMs: number;
|
|
1733
|
+
now?: Date;
|
|
1734
|
+
}): Promise<boolean>;
|
|
1735
|
+
/** Await-free, like the fenced create above, so a create runs wholly before or after it. */
|
|
1736
|
+
rotateStagedInvocationLease(input: {
|
|
1737
|
+
id: string;
|
|
1738
|
+
workerId: string;
|
|
1739
|
+
leaseToken: number;
|
|
1740
|
+
leaseDurationMs: number;
|
|
1741
|
+
now?: Date;
|
|
1742
|
+
}): Promise<number | undefined>;
|
|
1743
|
+
cancelStagedInvocationsForFailedParents(input?: {
|
|
1744
|
+
tenantId?: string;
|
|
1745
|
+
spaceId?: string;
|
|
1746
|
+
now?: Date;
|
|
1747
|
+
}): Promise<number>;
|
|
1748
|
+
listStagedInvocations(input: {
|
|
1749
|
+
tenantId: string;
|
|
1750
|
+
spaceId: string;
|
|
1751
|
+
parentInvocationId?: string;
|
|
1752
|
+
statuses?: readonly StagedInvocationStatus[];
|
|
1753
|
+
}): Promise<StagedInvocationRecord[]>;
|
|
1754
|
+
private leasedStagedInvocation;
|
|
1755
|
+
/** Mirrors PostgreSQL: a missing child id keeps the recorded one; `lastError` is replaced. */
|
|
1756
|
+
private settleStagedInvocation;
|
|
1475
1757
|
listEvents(tenantId: string, spaceId: string): Promise<AssetEventEnvelope[]>;
|
|
1476
1758
|
}
|
|
1477
1759
|
//#endregion
|
|
@@ -1539,16 +1821,20 @@ export interface PostgresPlatformHostTransactionProvider<TDb> {
|
|
|
1539
1821
|
run<TResult>(run: (context: PostgresPlatformHostTransactionContext<TDb>) => Promise<TResult>): Promise<TResult>;
|
|
1540
1822
|
}
|
|
1541
1823
|
/** Durable mutation-pipeline ledger for Databricks Lakebase or standard Postgres. */
|
|
1542
|
-
export declare class PostgresPlatformHostStore<TDb> implements RecoverablePlatformHostStore<TDb>, ApprovalPlatformHostStore<TDb>, GovernancePlatformHostStore<TDb>, OutboxPlatformHostStore<TDb>, OutboxRequeuePlatformHostStore<TDb> {
|
|
1824
|
+
export declare class PostgresPlatformHostStore<TDb> implements RecoverablePlatformHostStore<TDb>, ApprovalPlatformHostStore<TDb>, GovernancePlatformHostStore<TDb>, OutboxPlatformHostStore<TDb>, OutboxRequeuePlatformHostStore<TDb>, StagedInvocationPlatformHostStore<TDb> {
|
|
1543
1825
|
readonly db: TDb;
|
|
1544
1826
|
private readonly sql;
|
|
1545
1827
|
readonly transactionWithEvents?: AtomicMutationPlatformHostStore<TDb>["transactionWithEvents"];
|
|
1546
1828
|
readonly transactionalOutbox: boolean;
|
|
1829
|
+
readonly transactionalStagedInvocations: boolean;
|
|
1547
1830
|
constructor(db: TDb, sql: PlatformHostSqlClient, transactionProvider?: PostgresPlatformHostTransactionProvider<TDb>);
|
|
1548
1831
|
ensureSchema(): Promise<void>;
|
|
1549
1832
|
transaction<TResult>(run: (db: TDb) => Promise<TResult>): Promise<TResult>;
|
|
1550
1833
|
createActionInvocation(input: CreateActionInvocationInput): Promise<ActionInvocationRecord>;
|
|
1834
|
+
createActionInvocationForStagedLease(input: CreateStagedActionInvocationInput): Promise<CreateStagedActionInvocationResult>;
|
|
1835
|
+
stageInvocations(records: readonly StagedInvocationRecord[]): Promise<void>;
|
|
1551
1836
|
getActionInvocation(id: string, tenantId: string, spaceId: string): Promise<ActionInvocationRecord | undefined>;
|
|
1837
|
+
getActionInvocationByStagedOrigin(tenantId: string, spaceId: string, origin: StagedInvocationOrigin): Promise<ActionInvocationRecord | undefined>;
|
|
1552
1838
|
updateActionInvocation(id: string, tenantId: string, spaceId: string, patch: ActionInvocationPatch): Promise<void>;
|
|
1553
1839
|
recordHitlDecision(actionInvocationId: string, tenantId: string, spaceId: string, decision: HitlDecisionEvidence): Promise<ActionInvocationRecord>;
|
|
1554
1840
|
beginApprovalDecision(input: BeginApprovalDecisionInput): Promise<ApprovalDecisionTransitionResult>;
|
|
@@ -1599,6 +1885,66 @@ export declare class PostgresPlatformHostStore<TDb> implements RecoverablePlatfo
|
|
|
1599
1885
|
spaceId: string;
|
|
1600
1886
|
outboxId?: string;
|
|
1601
1887
|
}): Promise<OutboxRequeueRecord[]>;
|
|
1888
|
+
claimStagedInvocations(input: ClaimStagedInvocationsInput): Promise<StagedInvocationRecord[]>;
|
|
1889
|
+
markStagedInvocationDispatched(input: {
|
|
1890
|
+
id: string;
|
|
1891
|
+
workerId: string;
|
|
1892
|
+
leaseToken: number;
|
|
1893
|
+
childInvocationId: string;
|
|
1894
|
+
now?: Date;
|
|
1895
|
+
}): Promise<boolean>;
|
|
1896
|
+
markStagedInvocationRejected(input: {
|
|
1897
|
+
id: string;
|
|
1898
|
+
workerId: string;
|
|
1899
|
+
leaseToken: number;
|
|
1900
|
+
error: string;
|
|
1901
|
+
now?: Date;
|
|
1902
|
+
}): Promise<boolean>;
|
|
1903
|
+
markStagedInvocationFailed(input: {
|
|
1904
|
+
id: string;
|
|
1905
|
+
workerId: string;
|
|
1906
|
+
leaseToken: number;
|
|
1907
|
+
error: string;
|
|
1908
|
+
availableAt: Date;
|
|
1909
|
+
deadLetter: boolean;
|
|
1910
|
+
childInvocationId?: string;
|
|
1911
|
+
now?: Date;
|
|
1912
|
+
}): Promise<boolean>;
|
|
1913
|
+
renewStagedInvocationLease(input: {
|
|
1914
|
+
id: string;
|
|
1915
|
+
workerId: string;
|
|
1916
|
+
leaseToken: number;
|
|
1917
|
+
leaseDurationMs: number;
|
|
1918
|
+
now?: Date;
|
|
1919
|
+
}): Promise<boolean>;
|
|
1920
|
+
/**
|
|
1921
|
+
* The UPDATE needs a row lock that conflicts with the `FOR SHARE` lock the
|
|
1922
|
+
* fenced child insert takes on this row, so it waits for an in-flight
|
|
1923
|
+
* insert to commit. A fenced insert under the old token that reaches the
|
|
1924
|
+
* row while this rotation is uncommitted waits for it, rechecks the new row
|
|
1925
|
+
* version and inserts nothing (live tests "orders a token rotation after an
|
|
1926
|
+
* in-flight fenced create ..." and "refuses a fenced create under the old
|
|
1927
|
+
* token once a token rotation is ordered before it").
|
|
1928
|
+
*/
|
|
1929
|
+
rotateStagedInvocationLease(input: {
|
|
1930
|
+
id: string;
|
|
1931
|
+
workerId: string;
|
|
1932
|
+
leaseToken: number;
|
|
1933
|
+
leaseDurationMs: number;
|
|
1934
|
+
now?: Date;
|
|
1935
|
+
}): Promise<number | undefined>;
|
|
1936
|
+
cancelStagedInvocationsForFailedParents(input?: {
|
|
1937
|
+
tenantId?: string;
|
|
1938
|
+
spaceId?: string;
|
|
1939
|
+
now?: Date;
|
|
1940
|
+
}): Promise<number>;
|
|
1941
|
+
listStagedInvocations(input: {
|
|
1942
|
+
tenantId: string;
|
|
1943
|
+
spaceId: string;
|
|
1944
|
+
parentInvocationId?: string;
|
|
1945
|
+
statuses?: readonly StagedInvocationStatus[];
|
|
1946
|
+
}): Promise<StagedInvocationRecord[]>;
|
|
1947
|
+
private settleStagedInvocation;
|
|
1602
1948
|
nextEventSequence(tenantId: string, spaceId: string): Promise<number>;
|
|
1603
1949
|
getEntityStateSource(tenantId: string, spaceId: string, entityType: string, entityId: string): Promise<{
|
|
1604
1950
|
state: string;
|
|
@@ -1732,6 +2078,28 @@ export interface CreateDurableSagaParentLifecycleOptions<TDb> {
|
|
|
1732
2078
|
*/
|
|
1733
2079
|
export declare function createDurableSagaParentLifecycle<TDb>(options: CreateDurableSagaParentLifecycleOptions<TDb>): HostSagaParentLifecycle;
|
|
1734
2080
|
//#endregion
|
|
2081
|
+
//#region src/staged-invocations.d.ts
|
|
2082
|
+
export declare const MAX_STAGED_INVOCATIONS = 32;
|
|
2083
|
+
export declare const MAX_STAGED_INVOCATION_KEY_LENGTH = 128;
|
|
2084
|
+
export declare const MAX_STAGED_INVOCATION_BYTES: number;
|
|
2085
|
+
export declare const MAX_STAGED_INVOCATION_BATCH_BYTES: number;
|
|
2086
|
+
export declare const STAGED_INVOCATION_KEY_PATTERN: RegExp;
|
|
2087
|
+
interface PrepareStagedInvocationBatchInput<TDb> {
|
|
2088
|
+
parent: Pick<ActionInvocationRecord, "id" | "tenantId" | "spaceId" | "actionId">;
|
|
2089
|
+
parentAction: ActionDefinition<TDb>;
|
|
2090
|
+
requests: readonly StagedInvocationRequest[];
|
|
2091
|
+
resolveAction(actionId: ActionId): ActionDefinition<TDb> | undefined;
|
|
2092
|
+
redactParameters?(actionId: ActionId, parameters: Record<string, unknown>): Record<string, unknown>;
|
|
2093
|
+
/** Keys whose parameters already passed the redactor into a durable checkpoint. */
|
|
2094
|
+
redactedKeys?: readonly string[];
|
|
2095
|
+
now: Date;
|
|
2096
|
+
}
|
|
2097
|
+
/** Validate and normalize one immutable batch before its parent transaction commits. */
|
|
2098
|
+
export declare function prepareStagedInvocationBatch<TDb>(input: PrepareStagedInvocationBatchInput<TDb>): StagedInvocationRecord[];
|
|
2099
|
+
export declare function stagedInvocationRequestIdentity(record: StagedInvocationRecord): string;
|
|
2100
|
+
export declare function cloneStagedInvocationRecord(record: StagedInvocationRecord): StagedInvocationRecord;
|
|
2101
|
+
export declare function asStagedInvocationStore<TDb>(store: PlatformHostStore<TDb>): StagedInvocationPlatformHostStore<TDb> | undefined;
|
|
2102
|
+
//#endregion
|
|
1735
2103
|
//#region src/tenant-isolation.d.ts
|
|
1736
2104
|
export interface TenantIsolationScope {
|
|
1737
2105
|
tenantId: string;
|
|
@@ -1769,7 +2137,7 @@ export interface TenantIsolationSubject<TDb = unknown> {
|
|
|
1769
2137
|
reset?(): Promise<void> | void;
|
|
1770
2138
|
}
|
|
1771
2139
|
export interface TenantIsolationCheck {
|
|
1772
|
-
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";
|
|
2140
|
+
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.staged-invocation-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";
|
|
1773
2141
|
run(subject: TenantIsolationSubject): Promise<string[]>;
|
|
1774
2142
|
}
|
|
1775
2143
|
export interface TenantIsolationResult {
|
|
@@ -1782,15 +2150,16 @@ export interface TenantIsolationResult {
|
|
|
1782
2150
|
}>;
|
|
1783
2151
|
}
|
|
1784
2152
|
/**
|
|
1785
|
-
* The suite
|
|
2153
|
+
* The suite a deployment of the host must pass before it claims isolation.
|
|
1786
2154
|
*
|
|
1787
|
-
*
|
|
2155
|
+
* Nine checks: an invocation cannot be read, executed, or completed under
|
|
1788
2156
|
* another tenant's scope; an idempotency key is a tenant's own, so the same
|
|
1789
2157
|
* key in two tenants is two invocations; a tenant's event stream carries no
|
|
1790
2158
|
* other tenant's events; a worker scoped to one tenant does not claim another's
|
|
1791
|
-
* work;
|
|
1792
|
-
*
|
|
1793
|
-
* the
|
|
2159
|
+
* work; staged listing and claiming retain tenant and space scope; an adapter
|
|
2160
|
+
* checkpoint cannot be read or written under another tenant, space, or owning
|
|
2161
|
+
* invocation; and, when the subject lends a read, a viewer in the other tenant
|
|
2162
|
+
* sees nothing of ours.
|
|
1794
2163
|
*/
|
|
1795
2164
|
export declare function tenantIsolationChecks(): readonly TenantIsolationCheck[];
|
|
1796
2165
|
/** Run every check, returning each result rather than throwing on the first. */
|