@fabricorg/platform-host 3.0.0 → 5.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 +41 -0
- package/README.md +5 -4
- package/dist/index.cjs +52 -28
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +10 -2
- package/dist/index.d.ts +10 -2
- package/dist/index.js +53 -29
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.d.cts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { ActorType, ActionId, ActionStatus, AgentActionRoute, AgentActionRiskTier, MutationFootprint, ExecutionPrincipal, GovernanceRuntimeEvidence, PolicyOutcome, AssetEventEnvelope, ExecutionAttestation, ExternalReconciliation, PolicyObligation, PolicyObligationStatus, ActionDefinition, AdapterImplementation, FabricRuntimeServices, AgentActionPolicyEvaluator, MutationGovernanceResolver, RuntimePolicyDefinition } from '@fabricorg/platform';
|
|
1
|
+
import { ActorType, ActionId, ActionStatus, AgentActionRoute, AgentActionRiskTier, MutationFootprint, ExecutionPrincipal, GovernanceRuntimeEvidence, PolicyOutcome, AssetEventEnvelope, ExecutionAttestation, ExternalReconciliation, PolicyObligation, PolicyObligationStatus, ModuleRegistry, ActionDefinition, AdapterImplementation, FabricRuntimeServices, AgentActionPolicyEvaluator, MutationGovernanceResolver, RuntimePolicyDefinition } from '@fabricorg/platform';
|
|
2
2
|
|
|
3
3
|
/** Durable Host lifecycle generation, independent from the npm package version. */
|
|
4
4
|
declare const PLATFORM_HOST_CONTRACT_VERSION: 2;
|
|
5
|
-
type InvocationSource = "
|
|
5
|
+
type InvocationSource = "ui" | "api" | "agent" | "worker" | "system" | (string & {});
|
|
6
6
|
type NamespacedAttributes = Record<string, string>;
|
|
7
7
|
interface InvocationProvenance {
|
|
8
8
|
source: InvocationSource;
|
|
@@ -213,6 +213,8 @@ interface EnterpriseEventEnvelope {
|
|
|
213
213
|
source: InvocationSource;
|
|
214
214
|
auditAttributes?: NamespacedAttributes;
|
|
215
215
|
};
|
|
216
|
+
/** Present only for events an action declaring provisional consistency emitted. */
|
|
217
|
+
consistency?: "authoritative-now" | "provisional-until-reconciled";
|
|
216
218
|
payload: unknown;
|
|
217
219
|
}
|
|
218
220
|
interface OutboxRecord {
|
|
@@ -393,6 +395,8 @@ interface SubmitActionResult {
|
|
|
393
395
|
result?: Record<string, unknown>;
|
|
394
396
|
error?: string;
|
|
395
397
|
reconciliation?: AuthorizationReconciliationOutcome;
|
|
398
|
+
/** Mirrors the action's declared consistency so a caller knows whether the result is settled. */
|
|
399
|
+
consistency?: "authoritative-now" | "provisional-until-reconciled";
|
|
396
400
|
hitlRoute?: AgentActionRoute;
|
|
397
401
|
hitlRiskTier?: AgentActionRiskTier;
|
|
398
402
|
}
|
|
@@ -402,6 +406,8 @@ interface ExecuteActionResult {
|
|
|
402
406
|
result?: Record<string, unknown>;
|
|
403
407
|
error?: string;
|
|
404
408
|
reconciliation?: AuthorizationReconciliationOutcome;
|
|
409
|
+
/** Mirrors the action's declared consistency so a caller knows whether the result is settled. */
|
|
410
|
+
consistency?: "authoritative-now" | "provisional-until-reconciled";
|
|
405
411
|
hitlRoute?: AgentActionRoute;
|
|
406
412
|
hitlRiskTier?: AgentActionRiskTier;
|
|
407
413
|
}
|
|
@@ -431,6 +437,8 @@ interface PlatformActionWorkerCycleResult {
|
|
|
431
437
|
interface PlatformHostOptions<TDb> {
|
|
432
438
|
store: PlatformHostStore<TDb>;
|
|
433
439
|
authorization: PlatformHostAuthorization;
|
|
440
|
+
/** Preferred explicit catalog assembled from this runtime's Fabric modules. */
|
|
441
|
+
registry?: Pick<ModuleRegistry<TDb>, "resolveAction" | "resolvePolicy" | "resolveStateMachine">;
|
|
434
442
|
/** Resolve vertical- or runtime-local actions without mutating the process-wide registry. */
|
|
435
443
|
resolveAction?: (actionId: ActionId) => ActionDefinition<TDb> | undefined;
|
|
436
444
|
adapters?: readonly AdapterImplementation[];
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { ActorType, ActionId, ActionStatus, AgentActionRoute, AgentActionRiskTier, MutationFootprint, ExecutionPrincipal, GovernanceRuntimeEvidence, PolicyOutcome, AssetEventEnvelope, ExecutionAttestation, ExternalReconciliation, PolicyObligation, PolicyObligationStatus, ActionDefinition, AdapterImplementation, FabricRuntimeServices, AgentActionPolicyEvaluator, MutationGovernanceResolver, RuntimePolicyDefinition } from '@fabricorg/platform';
|
|
1
|
+
import { ActorType, ActionId, ActionStatus, AgentActionRoute, AgentActionRiskTier, MutationFootprint, ExecutionPrincipal, GovernanceRuntimeEvidence, PolicyOutcome, AssetEventEnvelope, ExecutionAttestation, ExternalReconciliation, PolicyObligation, PolicyObligationStatus, ModuleRegistry, ActionDefinition, AdapterImplementation, FabricRuntimeServices, AgentActionPolicyEvaluator, MutationGovernanceResolver, RuntimePolicyDefinition } from '@fabricorg/platform';
|
|
2
2
|
|
|
3
3
|
/** Durable Host lifecycle generation, independent from the npm package version. */
|
|
4
4
|
declare const PLATFORM_HOST_CONTRACT_VERSION: 2;
|
|
5
|
-
type InvocationSource = "
|
|
5
|
+
type InvocationSource = "ui" | "api" | "agent" | "worker" | "system" | (string & {});
|
|
6
6
|
type NamespacedAttributes = Record<string, string>;
|
|
7
7
|
interface InvocationProvenance {
|
|
8
8
|
source: InvocationSource;
|
|
@@ -213,6 +213,8 @@ interface EnterpriseEventEnvelope {
|
|
|
213
213
|
source: InvocationSource;
|
|
214
214
|
auditAttributes?: NamespacedAttributes;
|
|
215
215
|
};
|
|
216
|
+
/** Present only for events an action declaring provisional consistency emitted. */
|
|
217
|
+
consistency?: "authoritative-now" | "provisional-until-reconciled";
|
|
216
218
|
payload: unknown;
|
|
217
219
|
}
|
|
218
220
|
interface OutboxRecord {
|
|
@@ -393,6 +395,8 @@ interface SubmitActionResult {
|
|
|
393
395
|
result?: Record<string, unknown>;
|
|
394
396
|
error?: string;
|
|
395
397
|
reconciliation?: AuthorizationReconciliationOutcome;
|
|
398
|
+
/** Mirrors the action's declared consistency so a caller knows whether the result is settled. */
|
|
399
|
+
consistency?: "authoritative-now" | "provisional-until-reconciled";
|
|
396
400
|
hitlRoute?: AgentActionRoute;
|
|
397
401
|
hitlRiskTier?: AgentActionRiskTier;
|
|
398
402
|
}
|
|
@@ -402,6 +406,8 @@ interface ExecuteActionResult {
|
|
|
402
406
|
result?: Record<string, unknown>;
|
|
403
407
|
error?: string;
|
|
404
408
|
reconciliation?: AuthorizationReconciliationOutcome;
|
|
409
|
+
/** Mirrors the action's declared consistency so a caller knows whether the result is settled. */
|
|
410
|
+
consistency?: "authoritative-now" | "provisional-until-reconciled";
|
|
405
411
|
hitlRoute?: AgentActionRoute;
|
|
406
412
|
hitlRiskTier?: AgentActionRiskTier;
|
|
407
413
|
}
|
|
@@ -431,6 +437,8 @@ interface PlatformActionWorkerCycleResult {
|
|
|
431
437
|
interface PlatformHostOptions<TDb> {
|
|
432
438
|
store: PlatformHostStore<TDb>;
|
|
433
439
|
authorization: PlatformHostAuthorization;
|
|
440
|
+
/** Preferred explicit catalog assembled from this runtime's Fabric modules. */
|
|
441
|
+
registry?: Pick<ModuleRegistry<TDb>, "resolveAction" | "resolvePolicy" | "resolveStateMachine">;
|
|
434
442
|
/** Resolve vertical- or runtime-local actions without mutating the process-wide registry. */
|
|
435
443
|
resolveAction?: (actionId: ActionId) => ActionDefinition<TDb> | undefined;
|
|
436
444
|
adapters?: readonly AdapterImplementation[];
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AdapterRegistry,
|
|
1
|
+
import { AdapterRegistry, createFabricId, assertGovernanceRuntimeEvidence, FABRIC_GOVERNANCE_CONTRACT_VERSION, assertMutationGovernanceContext, evaluatePolicyDefinitions, aggregatePolicyOutcomes, validateStateMachineTransition, executeWithAdapterRetry } from '@fabricorg/platform';
|
|
2
2
|
import { createHash } from 'crypto';
|
|
3
3
|
|
|
4
4
|
// src/host.ts
|
|
@@ -29,10 +29,10 @@ function digestParameters(parameters) {
|
|
|
29
29
|
return createHash("sha256").update(canonicalJson(parameters)).digest("hex");
|
|
30
30
|
}
|
|
31
31
|
var ATTRIBUTE_NAME = /^[a-z][a-z0-9-]*(?:\.[A-Za-z][A-Za-z0-9_-]*)+$/;
|
|
32
|
-
var
|
|
32
|
+
var INVOCATION_SOURCE = /^(?:ui|sdui|api|agent|worker|system|[a-z][a-z0-9-]*(?:\.[a-z][a-z0-9-]*)+)$/;
|
|
33
33
|
function normalizeProvenance(input, options) {
|
|
34
34
|
if (!input) return void 0;
|
|
35
|
-
if (!
|
|
35
|
+
if (!INVOCATION_SOURCE.test(input.source)) throw new Error(`Invalid invocation provenance source: ${input.source}`);
|
|
36
36
|
const maxAttributes = options?.maxAttributes ?? 16;
|
|
37
37
|
const maxValueLength = options?.maxValueLength ?? 256;
|
|
38
38
|
const allowlist = new Set(options?.auditAttributeAllowlist ?? []);
|
|
@@ -81,7 +81,10 @@ function createGovernedActionHost(options) {
|
|
|
81
81
|
for (const adapter of options.adapters ?? []) adapters.register(adapter);
|
|
82
82
|
const now = options.now ?? (() => /* @__PURE__ */ new Date());
|
|
83
83
|
const extractEvents = options.extractEvents ?? DEFAULT_EXTRACT_EVENTS;
|
|
84
|
-
const
|
|
84
|
+
const configuredActionResolver = options.resolveAction ?? options.registry?.resolveAction;
|
|
85
|
+
if (!configuredActionResolver) throw new Error("Platform Host requires an explicit module registry or resolveAction function.");
|
|
86
|
+
const actionResolver = configuredActionResolver;
|
|
87
|
+
const stateMachineResolver = options.registry?.resolveStateMachine ?? (() => void 0);
|
|
85
88
|
const eventResultFields = options.eventResultFields ?? ["_events"];
|
|
86
89
|
async function submitAction(input) {
|
|
87
90
|
if (input.executionReason && !["initial", "offline_replay"].includes(input.executionReason)) {
|
|
@@ -89,6 +92,12 @@ function createGovernedActionHost(options) {
|
|
|
89
92
|
}
|
|
90
93
|
const action = actionResolver(input.actionId);
|
|
91
94
|
if (!action) throw new Error(`Unknown action: ${input.actionId}`);
|
|
95
|
+
if (action.execution?.connectivity === "online-required" && input.executionReason === "offline_replay") {
|
|
96
|
+
throw new Error(`Action ${input.actionId} is online-required and cannot be submitted as an offline replay.`);
|
|
97
|
+
}
|
|
98
|
+
if (action.execution?.sensitivity === "restricted" && Object.keys(input.provenance?.auditAttributes ?? {}).length > 0) {
|
|
99
|
+
throw new Error(`Action ${input.actionId} declares restricted sensitivity; provenance audit attributes must not be durably recorded.`);
|
|
100
|
+
}
|
|
92
101
|
const authorizationInput = toAuthorizationInput(action, input);
|
|
93
102
|
if (!await options.authorization.checkEntitlement(authorizationInput)) {
|
|
94
103
|
throw new Error(`Module "${action.namespace}" is not enabled for tenant ${input.tenantId}`);
|
|
@@ -161,7 +170,7 @@ function createGovernedActionHost(options) {
|
|
|
161
170
|
}
|
|
162
171
|
const durableWorkflowId = `action-invocation-${durableInvocation.id}`;
|
|
163
172
|
if (durableInvocation.id !== actionInvocationId) {
|
|
164
|
-
return {
|
|
173
|
+
return withConsistency({
|
|
165
174
|
actionInvocationId: durableInvocation.id,
|
|
166
175
|
status: durableInvocation.status,
|
|
167
176
|
workflowId: durableWorkflowId,
|
|
@@ -170,7 +179,7 @@ function createGovernedActionHost(options) {
|
|
|
170
179
|
...durableInvocation.hitlRoute ? { hitlRoute: durableInvocation.hitlRoute } : {},
|
|
171
180
|
...durableInvocation.hitlRiskTier ? { hitlRiskTier: durableInvocation.hitlRiskTier } : {},
|
|
172
181
|
...durableInvocation.authorizationReconciliation ? { reconciliation: durableInvocation.authorizationReconciliation } : {}
|
|
173
|
-
};
|
|
182
|
+
}, input.actionId);
|
|
174
183
|
}
|
|
175
184
|
if (options.dispatcher) {
|
|
176
185
|
try {
|
|
@@ -180,14 +189,14 @@ function createGovernedActionHost(options) {
|
|
|
180
189
|
spaceId: input.spaceId,
|
|
181
190
|
workflowId: durableWorkflowId
|
|
182
191
|
});
|
|
183
|
-
return {
|
|
192
|
+
return withConsistency({
|
|
184
193
|
actionInvocationId: durableInvocation.id,
|
|
185
194
|
status: durableInvocation.status,
|
|
186
195
|
workflowId: dispatched.workflowId,
|
|
187
196
|
...dispatched.runId ? { runId: dispatched.runId } : {},
|
|
188
197
|
...durableInvocation.hitlRoute ? { hitlRoute: durableInvocation.hitlRoute } : {},
|
|
189
198
|
...durableInvocation.hitlRiskTier ? { hitlRiskTier: durableInvocation.hitlRiskTier } : {}
|
|
190
|
-
};
|
|
199
|
+
}, input.actionId);
|
|
191
200
|
} catch (error) {
|
|
192
201
|
const message = errorMessage(error);
|
|
193
202
|
await options.store.updateActionInvocation(
|
|
@@ -204,7 +213,7 @@ function createGovernedActionHost(options) {
|
|
|
204
213
|
input.tenantId,
|
|
205
214
|
input.spaceId
|
|
206
215
|
);
|
|
207
|
-
return { ...executed, workflowId: durableWorkflowId };
|
|
216
|
+
return { ...withConsistency(executed, input.actionId), workflowId: durableWorkflowId };
|
|
208
217
|
}
|
|
209
218
|
async function executeInvocation(actionInvocationId, tenantId, spaceId, executionOptions = {}, executionReasonOverride) {
|
|
210
219
|
const loadedInvocation = await options.store.getActionInvocation(
|
|
@@ -218,7 +227,7 @@ function createGovernedActionHost(options) {
|
|
|
218
227
|
const resumingRunningInvocation = loadedInvocation.status === "running";
|
|
219
228
|
let invocation = loadedInvocation;
|
|
220
229
|
if (isTerminal(invocation.status) || invocation.status === "waiting_for_approval") {
|
|
221
|
-
return actionResult(invocation);
|
|
230
|
+
return withConsistency(actionResult(invocation), invocation.actionId);
|
|
222
231
|
}
|
|
223
232
|
if (invocation.status === "running" && invocation.leaseOwner && executionOptions.leaseOwner !== invocation.leaseOwner) {
|
|
224
233
|
return {
|
|
@@ -335,7 +344,7 @@ function createGovernedActionHost(options) {
|
|
|
335
344
|
message: `Action ${action.actionId} requires durable capture-time authorization evidence`
|
|
336
345
|
};
|
|
337
346
|
await options.store.updateActionInvocation(actionInvocationId, tenantId, spaceId, { status: "reconciliation_required", error: reconciliation.message, authorizationReconciliation: reconciliation });
|
|
338
|
-
return { actionInvocationId, status: "reconciliation_required", error: reconciliation.message, reconciliation };
|
|
347
|
+
return withConsistency({ actionInvocationId, status: "reconciliation_required", error: reconciliation.message, reconciliation }, action.actionId);
|
|
339
348
|
}
|
|
340
349
|
const bindingExpired = authorityMoment !== "capture" && invocation.authorizationBinding?.expiresAt !== void 0 && Date.parse(invocation.authorizationBinding.expiresAt) <= now().getTime();
|
|
341
350
|
if (bindingExpired) {
|
|
@@ -348,7 +357,7 @@ function createGovernedActionHost(options) {
|
|
|
348
357
|
message: `Authorization binding for action ${action.actionId} expired before execution`
|
|
349
358
|
};
|
|
350
359
|
await options.store.updateActionInvocation(actionInvocationId, tenantId, spaceId, { status: "reconciliation_required", error: reconciliation.message, authorizationReconciliation: reconciliation });
|
|
351
|
-
return { actionInvocationId, status: "reconciliation_required", error: reconciliation.message, reconciliation };
|
|
360
|
+
return withConsistency({ actionInvocationId, status: "reconciliation_required", error: reconciliation.message, reconciliation }, action.actionId);
|
|
352
361
|
}
|
|
353
362
|
const executionAuthorized = authorityMoment === "capture" ? invocation.authorizationBinding !== void 0 : options.authorization.authorizeExecution ? await options.authorization.authorizeExecution({
|
|
354
363
|
...authorizationInput,
|
|
@@ -370,7 +379,7 @@ function createGovernedActionHost(options) {
|
|
|
370
379
|
message: `Actor ${invocation.actorId} is not authorized to execute action ${action.actionId}`
|
|
371
380
|
};
|
|
372
381
|
await options.store.updateActionInvocation(actionInvocationId, tenantId, spaceId, { status: "reconciliation_required", error: reconciliation.message, authorizationReconciliation: reconciliation });
|
|
373
|
-
return { actionInvocationId, status: "reconciliation_required", error: reconciliation.message, reconciliation };
|
|
382
|
+
return withConsistency({ actionInvocationId, status: "reconciliation_required", error: reconciliation.message, reconciliation }, action.actionId);
|
|
374
383
|
}
|
|
375
384
|
const definitions = options.resolvePolicies ? await options.resolvePolicies({
|
|
376
385
|
...authorizationInput,
|
|
@@ -386,6 +395,7 @@ function createGovernedActionHost(options) {
|
|
|
386
395
|
parameters: parsed.data,
|
|
387
396
|
db: options.store.db,
|
|
388
397
|
services: options.services,
|
|
398
|
+
resolveCodePolicy: options.registry?.resolvePolicy,
|
|
389
399
|
mode: "execute",
|
|
390
400
|
now: now()
|
|
391
401
|
});
|
|
@@ -438,10 +448,11 @@ function createGovernedActionHost(options) {
|
|
|
438
448
|
spaceId,
|
|
439
449
|
binding.entityType,
|
|
440
450
|
entityId
|
|
441
|
-
) ?? initialState(binding.entityType) : initialState(binding.entityType);
|
|
451
|
+
) ?? initialState(stateMachineResolver(binding.entityType)) : initialState(stateMachineResolver(binding.entityType));
|
|
442
452
|
const targetState = typeof binding.targetState === "function" ? binding.targetState(parsed.data) : binding.targetState;
|
|
443
453
|
if (targetState !== "") {
|
|
444
|
-
const transition =
|
|
454
|
+
const transition = validateStateMachineTransition(
|
|
455
|
+
stateMachineResolver(binding.entityType),
|
|
445
456
|
binding.entityType,
|
|
446
457
|
currentState,
|
|
447
458
|
targetState,
|
|
@@ -710,7 +721,7 @@ function createGovernedActionHost(options) {
|
|
|
710
721
|
spaceId
|
|
711
722
|
);
|
|
712
723
|
if (!invocation) throw new Error(`ActionInvocation not found: ${actionInvocationId}`);
|
|
713
|
-
if (isTerminal(invocation.status)) return actionResult(invocation);
|
|
724
|
+
if (isTerminal(invocation.status)) return withConsistency(actionResult(invocation), invocation.actionId);
|
|
714
725
|
if (invocation.status !== "waiting_for_approval") {
|
|
715
726
|
return {
|
|
716
727
|
...actionResult(invocation),
|
|
@@ -760,9 +771,9 @@ function createGovernedActionHost(options) {
|
|
|
760
771
|
const transitioned = transition.invocation ?? await options.store.getActionInvocation(actionInvocationId, tenantId, spaceId);
|
|
761
772
|
if (!transition.applied || !transitioned) {
|
|
762
773
|
if (!transitioned) throw new Error(`ActionInvocation not found: ${actionInvocationId}`);
|
|
763
|
-
return actionResult(transitioned);
|
|
774
|
+
return withConsistency(actionResult(transitioned), transitioned.actionId);
|
|
764
775
|
}
|
|
765
|
-
if (!decision.approved) return actionResult(transitioned);
|
|
776
|
+
if (!decision.approved) return withConsistency(actionResult(transitioned), transitioned.actionId);
|
|
766
777
|
return executeInvocation(
|
|
767
778
|
actionInvocationId,
|
|
768
779
|
tenantId,
|
|
@@ -803,6 +814,13 @@ function createGovernedActionHost(options) {
|
|
|
803
814
|
spaceId
|
|
804
815
|
});
|
|
805
816
|
}
|
|
817
|
+
function declaredConsistency(actionId) {
|
|
818
|
+
return actionResolver(actionId)?.execution?.consistency;
|
|
819
|
+
}
|
|
820
|
+
function withConsistency(result, actionId) {
|
|
821
|
+
const consistency = declaredConsistency(actionId);
|
|
822
|
+
return consistency ? { ...result, consistency } : result;
|
|
823
|
+
}
|
|
806
824
|
async function appendEvent(invocation, event, deduplicationKey, defaultEventSchemaVersion = 1, transaction) {
|
|
807
825
|
const timestamp = now();
|
|
808
826
|
const envelope = {
|
|
@@ -825,7 +843,8 @@ function createGovernedActionHost(options) {
|
|
|
825
843
|
recordedAt: timestamp,
|
|
826
844
|
correlationId: invocation.correlationId,
|
|
827
845
|
...invocation.causationId ? { causationId: invocation.causationId } : {},
|
|
828
|
-
...invocation.provenance ? { provenance: { source: invocation.provenance.source, ...invocation.provenance.auditAttributes ? { auditAttributes: invocation.provenance.auditAttributes } : {} } } : {}
|
|
846
|
+
...invocation.provenance ? { provenance: { source: invocation.provenance.source, ...invocation.provenance.auditAttributes ? { auditAttributes: invocation.provenance.auditAttributes } : {} } } : {},
|
|
847
|
+
...declaredConsistency(invocation.actionId) === "provisional-until-reconciled" ? { consistency: "provisional-until-reconciled" } : {}
|
|
829
848
|
};
|
|
830
849
|
if (options.outbox) {
|
|
831
850
|
const hostLifecycleEvent = (/* @__PURE__ */ new Set(["AdapterInvocationStarted", "AdapterInvocationSucceeded", "AdapterInvocationFailed", "ComplianceBlocked"])).has(envelope.eventType);
|
|
@@ -927,8 +946,7 @@ function declaredPolicies(policyIds) {
|
|
|
927
946
|
codeEvaluatorPolicyId: policyId
|
|
928
947
|
}));
|
|
929
948
|
}
|
|
930
|
-
function initialState(
|
|
931
|
-
const machine = resolveStateMachine(entityType);
|
|
949
|
+
function initialState(machine) {
|
|
932
950
|
return Object.values(machine?.states ?? {}).find((state) => state.stateClass === "initial")?.id ?? "none";
|
|
933
951
|
}
|
|
934
952
|
function isTerminal(status) {
|
|
@@ -994,6 +1012,8 @@ function toEnterpriseEventEnvelope(event, metadata) {
|
|
|
994
1012
|
payloadClassification: metadata.payloadClassification,
|
|
995
1013
|
...metadata.traceContext ? { traceContext: { ...metadata.traceContext } } : {},
|
|
996
1014
|
...metadata.includeProvenance && event.provenance ? { provenance: event.provenance } : {},
|
|
1015
|
+
// A provisional fact must stay marked as provisional once it leaves the platform.
|
|
1016
|
+
...event.consistency ? { consistency: event.consistency } : {},
|
|
997
1017
|
payload: event.payload
|
|
998
1018
|
};
|
|
999
1019
|
}
|
|
@@ -1425,10 +1445,11 @@ var PostgresPlatformHostStore = class _PostgresPlatformHostStore {
|
|
|
1425
1445
|
actor_id text NOT NULL, actor_type text NOT NULL, action_invocation_id text,
|
|
1426
1446
|
payload jsonb NOT NULL, sequence bigint NOT NULL,
|
|
1427
1447
|
occurred_at timestamptz NOT NULL, recorded_at timestamptz NOT NULL,
|
|
1428
|
-
correlation_id text NOT NULL, causation_id text, provenance jsonb,
|
|
1448
|
+
correlation_id text NOT NULL, causation_id text, provenance jsonb, consistency text,
|
|
1429
1449
|
UNIQUE (tenant_id, space_id, sequence)
|
|
1430
1450
|
);
|
|
1431
1451
|
ALTER TABLE fabric_platform.asset_events ADD COLUMN IF NOT EXISTS provenance jsonb;
|
|
1452
|
+
ALTER TABLE fabric_platform.asset_events ADD COLUMN IF NOT EXISTS consistency text;
|
|
1432
1453
|
CREATE INDEX IF NOT EXISTS asset_events_subject_idx
|
|
1433
1454
|
ON fabric_platform.asset_events
|
|
1434
1455
|
(tenant_id, space_id, subject_type, subject_id, sequence);
|
|
@@ -1712,8 +1733,8 @@ var PostgresPlatformHostStore = class _PostgresPlatformHostStore {
|
|
|
1712
1733
|
`INSERT INTO fabric_platform.asset_events
|
|
1713
1734
|
(id,tenant_id,space_id,event_type,event_schema_version,subject_type,subject_id,
|
|
1714
1735
|
actor_id,actor_type,action_invocation_id,payload,sequence,occurred_at,recorded_at,
|
|
1715
|
-
correlation_id,causation_id,provenance)
|
|
1716
|
-
VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11::jsonb,$12,$13,$14,$15,$16,$17::jsonb)
|
|
1736
|
+
correlation_id,causation_id,provenance,consistency)
|
|
1737
|
+
VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11::jsonb,$12,$13,$14,$15,$16,$17::jsonb,$18)
|
|
1717
1738
|
ON CONFLICT (id) DO NOTHING`,
|
|
1718
1739
|
[
|
|
1719
1740
|
event.id,
|
|
@@ -1732,7 +1753,8 @@ var PostgresPlatformHostStore = class _PostgresPlatformHostStore {
|
|
|
1732
1753
|
event.recordedAt,
|
|
1733
1754
|
event.correlationId,
|
|
1734
1755
|
event.causationId ?? null,
|
|
1735
|
-
event.provenance ? JSON.stringify(event.provenance) : null
|
|
1756
|
+
event.provenance ? JSON.stringify(event.provenance) : null,
|
|
1757
|
+
event.consistency ?? null
|
|
1736
1758
|
]
|
|
1737
1759
|
);
|
|
1738
1760
|
}
|
|
@@ -1743,8 +1765,8 @@ var PostgresPlatformHostStore = class _PostgresPlatformHostStore {
|
|
|
1743
1765
|
INSERT INTO fabric_platform.asset_events
|
|
1744
1766
|
(id,tenant_id,space_id,event_type,event_schema_version,subject_type,subject_id,
|
|
1745
1767
|
actor_id,actor_type,action_invocation_id,payload,sequence,occurred_at,recorded_at,
|
|
1746
|
-
correlation_id,causation_id,provenance)
|
|
1747
|
-
VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11::jsonb,$12,$13,$14,$15,$16,$17::jsonb)
|
|
1768
|
+
correlation_id,causation_id,provenance,consistency)
|
|
1769
|
+
VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11::jsonb,$12,$13,$14,$15,$16,$17::jsonb,$19)
|
|
1748
1770
|
ON CONFLICT (id) DO NOTHING RETURNING id
|
|
1749
1771
|
)
|
|
1750
1772
|
INSERT INTO fabric_platform.event_outbox
|
|
@@ -1769,7 +1791,8 @@ var PostgresPlatformHostStore = class _PostgresPlatformHostStore {
|
|
|
1769
1791
|
event.correlationId,
|
|
1770
1792
|
event.causationId ?? null,
|
|
1771
1793
|
event.provenance ? JSON.stringify(event.provenance) : null,
|
|
1772
|
-
JSON.stringify(envelope)
|
|
1794
|
+
JSON.stringify(envelope),
|
|
1795
|
+
event.consistency ?? null
|
|
1773
1796
|
]
|
|
1774
1797
|
);
|
|
1775
1798
|
}
|
|
@@ -2011,7 +2034,8 @@ function toEventRecord(row) {
|
|
|
2011
2034
|
recordedAt: new Date(row.recorded_at),
|
|
2012
2035
|
correlationId: String(row.correlation_id),
|
|
2013
2036
|
...row.causation_id ? { causationId: String(row.causation_id) } : {},
|
|
2014
|
-
...row.provenance ? { provenance: row.provenance } : {}
|
|
2037
|
+
...row.provenance ? { provenance: row.provenance } : {},
|
|
2038
|
+
...row.consistency ? { consistency: row.consistency } : {}
|
|
2015
2039
|
};
|
|
2016
2040
|
}
|
|
2017
2041
|
function toOutboxRecord(row) {
|