@fabricorg/platform-host 8.6.0 → 8.7.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/dist/index.d.cts CHANGED
@@ -275,6 +275,8 @@ export interface FinalizationCheckpoint {
275
275
  export interface StagedInvocationOrigin {
276
276
  parentInvocationId: string;
277
277
  stageKey: string;
278
+ /** Host-registered principal name captured in the durable staged intent. */
279
+ principal?: string;
278
280
  }
279
281
  export interface AgentProposal {
280
282
  confidence?: number;
@@ -757,6 +759,8 @@ export interface StagedInvocationRecord {
757
759
  parentActionId: ActionId;
758
760
  key: string;
759
761
  actionId: ActionId;
762
+ /** Host-registered principal name selected by the parent action declaration. */
763
+ principal?: string;
760
764
  expectedActionVersion: number;
761
765
  parameters: Record<string, unknown>;
762
766
  parameterDigest: string;
@@ -1498,6 +1502,11 @@ export interface PlatformHostOptions<TDb> {
1498
1502
  registry?: Pick<ModuleRegistry<TDb>, "resolveAction" | "resolvePolicy" | "resolveStateMachine"> & Partial<Pick<ModuleRegistry<TDb>, "orderedModules">>;
1499
1503
  /** Resolve vertical- or runtime-local actions without mutating the process-wide registry. */
1500
1504
  resolveAction?: (actionId: ActionId) => ActionDefinition<TDb> | undefined;
1505
+ /** Host-owned identities available to parent action declarations for staged dispatch. */
1506
+ stagedInvocationPrincipals?: Readonly<Record<string, {
1507
+ actorId: string;
1508
+ actorType: ActorType;
1509
+ }>>;
1501
1510
  adapters?: readonly AdapterImplementation[];
1502
1511
  /**
1503
1512
  * Supplies the circuit breaker for each adapter call. Defaults to a new
@@ -2233,11 +2242,13 @@ export declare const MAX_STAGED_INVOCATION_KEY_LENGTH = 128;
2233
2242
  export declare const MAX_STAGED_INVOCATION_BYTES: number;
2234
2243
  export declare const MAX_STAGED_INVOCATION_BATCH_BYTES: number;
2235
2244
  export declare const STAGED_INVOCATION_KEY_PATTERN: RegExp;
2245
+ export declare const STAGED_INVOCATION_PRINCIPAL_PATTERN: RegExp;
2236
2246
  interface PrepareStagedInvocationBatchInput<TDb> {
2237
2247
  parent: Pick<ActionInvocationRecord, "id" | "tenantId" | "spaceId" | "actionId">;
2238
2248
  parentAction: ActionDefinition<TDb>;
2239
2249
  requests: readonly StagedInvocationRequest[];
2240
2250
  resolveAction(actionId: ActionId): ActionDefinition<TDb> | undefined;
2251
+ stagedInvocationPrincipals?: Readonly<Record<string, unknown>>;
2241
2252
  redactParameters?(actionId: ActionId, parameters: Record<string, unknown>): Record<string, unknown>;
2242
2253
  /** Keys whose parameters already passed the redactor into a durable checkpoint. */
2243
2254
  redactedKeys?: readonly string[];
package/dist/index.d.ts CHANGED
@@ -275,6 +275,8 @@ export interface FinalizationCheckpoint {
275
275
  export interface StagedInvocationOrigin {
276
276
  parentInvocationId: string;
277
277
  stageKey: string;
278
+ /** Host-registered principal name captured in the durable staged intent. */
279
+ principal?: string;
278
280
  }
279
281
  export interface AgentProposal {
280
282
  confidence?: number;
@@ -757,6 +759,8 @@ export interface StagedInvocationRecord {
757
759
  parentActionId: ActionId;
758
760
  key: string;
759
761
  actionId: ActionId;
762
+ /** Host-registered principal name selected by the parent action declaration. */
763
+ principal?: string;
760
764
  expectedActionVersion: number;
761
765
  parameters: Record<string, unknown>;
762
766
  parameterDigest: string;
@@ -1498,6 +1502,11 @@ export interface PlatformHostOptions<TDb> {
1498
1502
  registry?: Pick<ModuleRegistry<TDb>, "resolveAction" | "resolvePolicy" | "resolveStateMachine"> & Partial<Pick<ModuleRegistry<TDb>, "orderedModules">>;
1499
1503
  /** Resolve vertical- or runtime-local actions without mutating the process-wide registry. */
1500
1504
  resolveAction?: (actionId: ActionId) => ActionDefinition<TDb> | undefined;
1505
+ /** Host-owned identities available to parent action declarations for staged dispatch. */
1506
+ stagedInvocationPrincipals?: Readonly<Record<string, {
1507
+ actorId: string;
1508
+ actorType: ActorType;
1509
+ }>>;
1501
1510
  adapters?: readonly AdapterImplementation[];
1502
1511
  /**
1503
1512
  * Supplies the circuit breaker for each adapter call. Defaults to a new
@@ -2233,11 +2242,13 @@ export declare const MAX_STAGED_INVOCATION_KEY_LENGTH = 128;
2233
2242
  export declare const MAX_STAGED_INVOCATION_BYTES: number;
2234
2243
  export declare const MAX_STAGED_INVOCATION_BATCH_BYTES: number;
2235
2244
  export declare const STAGED_INVOCATION_KEY_PATTERN: RegExp;
2245
+ export declare const STAGED_INVOCATION_PRINCIPAL_PATTERN: RegExp;
2236
2246
  interface PrepareStagedInvocationBatchInput<TDb> {
2237
2247
  parent: Pick<ActionInvocationRecord, "id" | "tenantId" | "spaceId" | "actionId">;
2238
2248
  parentAction: ActionDefinition<TDb>;
2239
2249
  requests: readonly StagedInvocationRequest[];
2240
2250
  resolveAction(actionId: ActionId): ActionDefinition<TDb> | undefined;
2251
+ stagedInvocationPrincipals?: Readonly<Record<string, unknown>>;
2241
2252
  redactParameters?(actionId: ActionId, parameters: Record<string, unknown>): Record<string, unknown>;
2242
2253
  /** Keys whose parameters already passed the redactor into a durable checkpoint. */
2243
2254
  redactedKeys?: readonly string[];
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { types } from "util";
2
- import { AdapterCircuitBreakerRegistry, AdapterRegistry, FABRIC_GOVERNANCE_CONTRACT_VERSION, ReconciliationRequiredError, aggregatePolicyOutcomes, assertActionFinalization, assertAdapterCircuitBreakerConfig, assertAdapterOutcomeConsistency, assertAdapterStepDeadlines, assertGovernanceRuntimeEvidence, assertMutationGovernanceContext, canonicalJson, createFabricId, evaluatePolicyDefinitions, evaluateStateMachineTransition, executeWithAdapterRetry, isAdapterCircuitOpenError, isReconciliationRequiredError, isRetryableExecutionError } from "@fabricorg/platform";
2
+ import { AdapterCircuitBreakerRegistry, AdapterRegistry, FABRIC_GOVERNANCE_CONTRACT_VERSION, ReconciliationRequiredError, aggregatePolicyOutcomes, assertActionFinalization, assertAdapterCircuitBreakerConfig, assertAdapterOutcomeConsistency, assertAdapterStepDeadlines, assertGovernanceRuntimeEvidence, assertMutationGovernanceContext, canonicalJson, createFabricId, evaluatePolicyDefinitions, evaluateStateMachineTransition, executeWithAdapterRetry, isActorType, isAdapterCircuitOpenError, isReconciliationRequiredError, isRetryableExecutionError } from "@fabricorg/platform";
3
3
  import { performance } from "perf_hooks";
4
4
  import { assertAssemblyRuntimeCompatible } from "@fabricorg/assembly";
5
5
  import { createHash } from "crypto";
@@ -1374,6 +1374,7 @@ const MAX_STAGED_INVOCATION_KEY_LENGTH = 128;
1374
1374
  const MAX_STAGED_INVOCATION_BYTES = 65536;
1375
1375
  const MAX_STAGED_INVOCATION_BATCH_BYTES = 262144;
1376
1376
  const STAGED_INVOCATION_KEY_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._:-]*$/;
1377
+ const STAGED_INVOCATION_PRINCIPAL_PATTERN = /^[a-z][a-z0-9._:-]{0,127}$/;
1377
1378
  /** Validate and normalize one immutable batch before its parent transaction commits. */
1378
1379
  function prepareStagedInvocationBatch(input) {
1379
1380
  if (!Array.isArray(input.requests)) throw new Error("stagedInvocations must be an array.");
@@ -1393,6 +1394,8 @@ function prepareStagedInvocationBatch(input) {
1393
1394
  if (!(input.parentAction.stagesInvocations ?? []).includes(request.actionId)) throw new Error(`Action "${input.parentAction.actionId}" may not stage "${String(request.actionId)}".`);
1394
1395
  const child = input.resolveAction(request.actionId);
1395
1396
  if (!child) throw new Error(`Staged action "${String(request.actionId)}" is not registered.`);
1397
+ const principal = input.parentAction.stagedInvocationPrincipals?.[child.actionId];
1398
+ if (principal !== void 0 && !Object.hasOwn(input.stagedInvocationPrincipals ?? {}, principal)) throw new Error(`Staged invocation principal "${principal}" is not registered with this Platform Host.`);
1396
1399
  const parameters = finalizationJson(request.parameters);
1397
1400
  if (!parameters || typeof parameters !== "object" || Array.isArray(parameters)) throw new Error(`stagedInvocations[${index}] parameters must be a JSON object.`);
1398
1401
  if (!child.schema.safeParse(parameters).success) throw new Error(`stagedInvocations[${index}] parameters do not match action "${child.actionId}".`);
@@ -1407,24 +1410,27 @@ function prepareStagedInvocationBatch(input) {
1407
1410
  if (byteLength(canonicalJson({
1408
1411
  key: request.key,
1409
1412
  actionId: child.actionId,
1410
- parameters: durableParameters
1413
+ parameters: durableParameters,
1414
+ ...principal !== void 0 ? { principal } : {}
1411
1415
  })) > 65536) throw new Error(`stagedInvocations[${index}] exceeds ${MAX_STAGED_INVOCATION_BYTES} bytes.`);
1412
1416
  return {
1413
1417
  key: request.key,
1414
1418
  actionId: child.actionId,
1415
1419
  expectedActionVersion: child.version,
1416
1420
  parameters: durableParameters,
1417
- parameterDigest: digestParameters(durableParameters)
1421
+ parameterDigest: digestParameters(durableParameters),
1422
+ ...principal !== void 0 ? { principal } : {}
1418
1423
  };
1419
1424
  });
1420
1425
  for (const [index, request] of normalized.entries()) if (normalized.findIndex((candidate) => candidate.key === request.key) !== index) throw new Error(`stagedInvocations contains duplicate key "${request.key}".`);
1421
1426
  normalized.sort((left, right) => compareText(left.key, right.key) || compareText(left.actionId, right.actionId));
1422
- const batchIdentity = normalized.map(({ key, actionId, expectedActionVersion, parameters, parameterDigest }) => ({
1427
+ const batchIdentity = normalized.map(({ key, actionId, expectedActionVersion, parameters, parameterDigest, principal }) => ({
1423
1428
  key,
1424
1429
  actionId,
1425
1430
  expectedActionVersion,
1426
1431
  parameters,
1427
- parameterDigest
1432
+ parameterDigest,
1433
+ ...principal !== void 0 ? { principal } : {}
1428
1434
  }));
1429
1435
  if (byteLength(canonicalJson(batchIdentity)) > 262144) throw new Error(`stagedInvocations batch exceeds ${MAX_STAGED_INVOCATION_BATCH_BYTES} bytes.`);
1430
1436
  const batchDigest = digestParameters({
@@ -1459,7 +1465,8 @@ function stagedInvocationRequestIdentity(record) {
1459
1465
  expectedActionVersion: record.expectedActionVersion,
1460
1466
  parameters: record.parameters,
1461
1467
  parameterDigest: record.parameterDigest,
1462
- batchDigest: record.batchDigest
1468
+ batchDigest: record.batchDigest,
1469
+ ...record.principal !== void 0 ? { principal: record.principal } : {}
1463
1470
  });
1464
1471
  }
1465
1472
  function cloneStagedInvocationRecord(record) {
@@ -1526,6 +1533,20 @@ const STAGED_ERROR = Object.freeze({
1526
1533
  lookup: "Staged child lookup failed."
1527
1534
  });
1528
1535
  function createGovernedActionHost(options) {
1536
+ const configuredStagedPrincipals = options.stagedInvocationPrincipals;
1537
+ if (configuredStagedPrincipals !== void 0 && (!configuredStagedPrincipals || typeof configuredStagedPrincipals !== "object" || Array.isArray(configuredStagedPrincipals))) throw new Error("stagedInvocationPrincipals must be an object.");
1538
+ const stagedInvocationPrincipals = Object.freeze(Object.fromEntries(Object.entries(configuredStagedPrincipals ?? {}).map(([name, candidate]) => {
1539
+ if (!STAGED_INVOCATION_PRINCIPAL_PATTERN.test(name)) throw new Error(`Invalid staged invocation principal name: ${name}`);
1540
+ if (!candidate || typeof candidate !== "object" || Array.isArray(candidate)) throw new Error(`Staged invocation principal "${name}" must be an object.`);
1541
+ const actorId = candidate.actorId;
1542
+ const actorType = candidate.actorType;
1543
+ if (typeof actorId !== "string" || actorId.length === 0) throw new Error(`Staged invocation principal "${name}" actorId must be a non-empty string.`);
1544
+ if (typeof actorType !== "string" || !isActorType(actorType)) throw new Error(`Staged invocation principal "${name}" has invalid actorType.`);
1545
+ return [name, Object.freeze({
1546
+ actorId,
1547
+ actorType
1548
+ })];
1549
+ })));
1529
1550
  if (options.approvalDefaultTtlMs !== void 0 && (!Number.isSafeInteger(options.approvalDefaultTtlMs) || options.approvalDefaultTtlMs <= 0)) throw new Error("approvalDefaultTtlMs must be a positive safe integer in milliseconds.");
1530
1551
  if (options.approvalLifecycleEvents) {
1531
1552
  const approvalStore = asApprovalStore(options.store);
@@ -1559,6 +1580,9 @@ function createGovernedActionHost(options) {
1559
1580
  const configuredActionResolver = options.resolveAction ?? options.registry?.resolveAction;
1560
1581
  if (!configuredActionResolver) throw new Error("Platform Host requires an explicit module registry or resolveAction function.");
1561
1582
  const actionResolver = configuredActionResolver;
1583
+ if (options.registry?.orderedModules) {
1584
+ for (const module of options.registry.orderedModules) for (const action of module.actions ?? []) for (const principal of Object.values(action.stagedInvocationPrincipals ?? {})) if (!Object.hasOwn(stagedInvocationPrincipals, principal)) throw new Error(`Staged invocation principal "${principal}" referenced by action "${action.actionId}" is not registered with this Platform Host.`);
1585
+ }
1562
1586
  const stagedStore = asStagedInvocationStore(options.store);
1563
1587
  const declaresStaging = options.registry?.orderedModules?.some((module) => (module.actions ?? []).some((action) => (action.stagesInvocations?.length ?? 0) > 0)) ?? false;
1564
1588
  if (declaresStaging && (!stagedStore || !asAtomicMutationStore(options.store))) throw new Error("Staged descendant invocations require a store with transactionalStagedInvocations and transactionWithEvents capabilities.");
@@ -2702,6 +2726,7 @@ function createGovernedActionHost(options) {
2702
2726
  parentAction: action,
2703
2727
  requests: rawStagedInvocations,
2704
2728
  resolveAction: actionResolver,
2729
+ stagedInvocationPrincipals,
2705
2730
  redactParameters: options.redactActionParameters,
2706
2731
  now: now()
2707
2732
  });
@@ -3573,6 +3598,7 @@ function createGovernedActionHost(options) {
3573
3598
  parentAction: action,
3574
3599
  requests: stagedRequests,
3575
3600
  resolveAction: actionResolver,
3601
+ stagedInvocationPrincipals,
3576
3602
  redactParameters: options.redactActionParameters,
3577
3603
  redactedKeys: handlerStagedInvocations.map((request) => request.key),
3578
3604
  now: now()
@@ -4143,6 +4169,8 @@ function createGovernedActionHost(options) {
4143
4169
  if (!parent || parent.status !== "completed") throw new Error("Staged parent is not completed.");
4144
4170
  const child = actionResolver(record.actionId);
4145
4171
  if (!child) throw new StagedDispatchRejectionError("Staged action is no longer registered.");
4172
+ const principal = record.principal !== void 0 && Object.hasOwn(stagedInvocationPrincipals, record.principal) ? stagedInvocationPrincipals[record.principal] : void 0;
4173
+ if (record.principal !== void 0 && !principal) throw new StagedDispatchRejectionError("Staged invocation principal is no longer registered.");
4146
4174
  if (child.execution?.authorityMoment === "capture") throw new StagedDispatchRejectionError("Staged action now requires capture-time authority.");
4147
4175
  if (!child.schema.safeParse(structuredClone(record.parameters)).success) throw new StagedDispatchRejectionError("Staged parameters no longer match the registered action.");
4148
4176
  return submitActionInternal({
@@ -4150,8 +4178,8 @@ function createGovernedActionHost(options) {
4150
4178
  parameters: structuredClone(record.parameters),
4151
4179
  tenantId: parent.tenantId,
4152
4180
  spaceId: parent.spaceId,
4153
- actorId: parent.actorId,
4154
- actorType: parent.actorType,
4181
+ actorId: principal?.actorId ?? parent.actorId,
4182
+ actorType: principal?.actorType ?? parent.actorType,
4155
4183
  correlationId: parent.correlationId,
4156
4184
  causationId: parent.id,
4157
4185
  provenance: {
@@ -4165,7 +4193,8 @@ function createGovernedActionHost(options) {
4165
4193
  id: record.id,
4166
4194
  origin: {
4167
4195
  parentInvocationId: parent.id,
4168
- stageKey: record.key
4196
+ stageKey: record.key,
4197
+ ...record.principal !== void 0 ? { principal: record.principal } : {}
4169
4198
  },
4170
4199
  workerId: lease.workerId,
4171
4200
  leaseToken: lease.leaseToken,
@@ -4835,7 +4864,7 @@ var MemoryPlatformHostStore = class {
4835
4864
  kind: "existing",
4836
4865
  invocation: existing
4837
4866
  };
4838
- if (!this.stagedInvocations.find((record) => record.id === input.stageId && record.tenantId === invocation.tenantId && record.spaceId === invocation.spaceId && record.parentInvocationId === invocation.stagedOrigin.parentInvocationId && record.key === invocation.stagedOrigin.stageKey && record.actionId === invocation.actionId && record.status === "pending" && record.leaseOwner === input.workerId && record.leaseToken === input.leaseToken && record.leaseExpiresAt !== void 0 && record.leaseExpiresAt > now)) return { kind: "lease_lost" };
4867
+ if (!this.stagedInvocations.find((record) => record.id === input.stageId && record.tenantId === invocation.tenantId && record.spaceId === invocation.spaceId && record.parentInvocationId === invocation.stagedOrigin.parentInvocationId && record.key === invocation.stagedOrigin.stageKey && record.actionId === invocation.actionId && record.principal === invocation.stagedOrigin.principal && record.status === "pending" && record.leaseOwner === input.workerId && record.leaseToken === input.leaseToken && record.leaseExpiresAt !== void 0 && record.leaseExpiresAt > now)) return { kind: "lease_lost" };
4839
4868
  const createdAt = /* @__PURE__ */ new Date();
4840
4869
  const record = {
4841
4870
  ...invocation,
@@ -5683,6 +5712,16 @@ var PostgresPlatformHostStore = class PostgresPlatformHostStore {
5683
5712
  version: 13,
5684
5713
  name: "agent_proposal",
5685
5714
  sql: `ALTER TABLE fabric_platform.action_invocations ADD COLUMN IF NOT EXISTS agent_proposal jsonb;`
5715
+ },
5716
+ {
5717
+ version: 14,
5718
+ name: "staged_invocation_principals",
5719
+ sql: `
5720
+ ALTER TABLE fabric_platform.staged_invocations
5721
+ ADD COLUMN IF NOT EXISTS principal text;
5722
+ ALTER TABLE fabric_platform.action_invocations
5723
+ ADD COLUMN IF NOT EXISTS staged_origin_principal text;
5724
+ `
5686
5725
  }
5687
5726
  ]);
5688
5727
  }
@@ -5747,9 +5786,9 @@ var PostgresPlatformHostStore = class PostgresPlatformHostStore {
5747
5786
  const current = input.now ?? /* @__PURE__ */ new Date();
5748
5787
  const admitted = invocation.admittedAt !== void 0;
5749
5788
  const admittedColumn = admitted ? ",admitted_at" : "";
5750
- const admittedValue = admitted ? ",$30" : "";
5789
+ const admittedValue = admitted ? ",$31" : "";
5751
5790
  const proposalColumn = invocation.agentProposal !== void 0 ? ",agent_proposal" : "";
5752
- const proposalValue = invocation.agentProposal !== void 0 ? `,$${admitted ? 31 : 30}::jsonb` : "";
5791
+ const proposalValue = invocation.agentProposal !== void 0 ? `,$${admitted ? 32 : 31}::jsonb` : "";
5753
5792
  const values = [
5754
5793
  invocation.id,
5755
5794
  invocation.tenantId,
@@ -5776,6 +5815,7 @@ var PostgresPlatformHostStore = class PostgresPlatformHostStore {
5776
5815
  invocation.runtimeEvidence ? JSON.stringify(invocation.runtimeEvidence) : null,
5777
5816
  invocation.stagedOrigin.parentInvocationId,
5778
5817
  invocation.stagedOrigin.stageKey,
5818
+ invocation.stagedOrigin.principal ?? null,
5779
5819
  input.stageId,
5780
5820
  input.workerId,
5781
5821
  input.leaseToken,
@@ -5788,10 +5828,11 @@ var PostgresPlatformHostStore = class PostgresPlatformHostStore {
5788
5828
  result = await this.sql.query(`WITH fence AS (
5789
5829
  SELECT stage.id
5790
5830
  FROM fabric_platform.staged_invocations AS stage
5791
- WHERE stage.id=$26 AND stage.tenant_id=$2 AND stage.space_id=$3
5831
+ WHERE stage.id=$27 AND stage.tenant_id=$2 AND stage.space_id=$3
5792
5832
  AND stage.parent_invocation_id=$24 AND stage.stage_key=$25 AND stage.action_id=$4
5793
- AND stage.status='pending' AND stage.lease_owner=$27 AND stage.lease_token=$28
5794
- AND stage.lease_expires_at IS NOT NULL AND stage.lease_expires_at > $29
5833
+ AND stage.principal IS NOT DISTINCT FROM $26
5834
+ AND stage.status='pending' AND stage.lease_owner=$28 AND stage.lease_token=$29
5835
+ AND stage.lease_expires_at IS NOT NULL AND stage.lease_expires_at > $30
5795
5836
  FOR SHARE
5796
5837
  )
5797
5838
  INSERT INTO fabric_platform.action_invocations
@@ -5799,17 +5840,19 @@ var PostgresPlatformHostStore = class PostgresPlatformHostStore {
5799
5840
  parameters,result,correlation_id,causation_id,idempotency_key,parameter_digest,
5800
5841
  parameter_digest_algorithm,idempotency_actor_id,idempotency_authorization_binding_id,
5801
5842
  invocation_provenance,authorization_binding,execution_reason,authorization_binding_id,error,
5802
- runtime_evidence,staged_parent_invocation_id,staged_stage_key${admittedColumn}${proposalColumn},created_at,updated_at)
5843
+ runtime_evidence,staged_parent_invocation_id,staged_stage_key,staged_origin_principal${admittedColumn}${proposalColumn},created_at,updated_at)
5803
5844
  SELECT $1,$2,$3,$4,$5,$6,$7,$8,$9::jsonb,$10::jsonb,$11,$12,$13,$14,$15,$16,$17,
5804
- $18::jsonb,$19::jsonb,$20,$21,$22,$23::jsonb,$24,$25${admittedValue}${proposalValue},$29,$29
5845
+ $18::jsonb,$19::jsonb,$20,$21,$22,$23::jsonb,$24,$25,$26${admittedValue}${proposalValue},$30,$30
5805
5846
  FROM fence
5806
5847
  ON CONFLICT (tenant_id,space_id,staged_parent_invocation_id,staged_stage_key)
5807
5848
  WHERE staged_parent_invocation_id IS NOT NULL AND staged_stage_key IS NOT NULL
5808
5849
  DO UPDATE SET id=fabric_platform.action_invocations.id
5809
5850
  RETURNING *`, values);
5810
5851
  } catch (error) {
5811
- if (invocation.agentProposal !== void 0 && error?.code === "42703") throw new Error("Agent proposals require PostgreSQL migration 13 (agent_proposal); run ensureSchema().", { cause: error });
5812
- if (error?.code === "42703" || error?.code === "42P01") throw new Error("A staged child needs PostgreSQL migration 11 (staged_descendant_invocations); run ensureSchema() before dispatching staged invocations.", { cause: error });
5852
+ const databaseError = error;
5853
+ if (invocation.agentProposal !== void 0 && databaseError?.code === "42703" && typeof databaseError.message === "string" && /\bagent_proposal\b/.test(databaseError.message)) throw new Error("Agent proposals require PostgreSQL migration 13 (agent_proposal); run ensureSchema().", { cause: error });
5854
+ if (databaseError?.code === "42703") throw new Error("A staged child needs PostgreSQL migration 14 (staged_invocation_principals); run ensureSchema() before dispatching staged invocations.", { cause: error });
5855
+ if (databaseError?.code === "42P01") throw new Error("A staged child needs PostgreSQL migration 11 (staged_descendant_invocations); run ensureSchema() before dispatching staged invocations.", { cause: error });
5813
5856
  throw error;
5814
5857
  }
5815
5858
  if (result.rows[0]) {
@@ -5851,33 +5894,39 @@ var PostgresPlatformHostStore = class PostgresPlatformHostStore {
5851
5894
  }
5852
5895
  for (const record of records) {
5853
5896
  if (record.tenantId !== first.tenantId || record.spaceId !== first.spaceId || record.parentInvocationId !== first.parentInvocationId || record.batchDigest !== first.batchDigest) throw new Error(`Invalid staged invocation batch for parent ${first.parentInvocationId}.`);
5854
- await this.sql.query(`INSERT INTO fabric_platform.staged_invocations
5855
- (id,tenant_id,space_id,parent_invocation_id,parent_action_id,stage_key,action_id,
5897
+ try {
5898
+ await this.sql.query(`INSERT INTO fabric_platform.staged_invocations
5899
+ (id,tenant_id,space_id,parent_invocation_id,parent_action_id,stage_key,action_id,principal,
5856
5900
  expected_action_version,parameters,parameter_digest,batch_digest,status,child_invocation_id,
5857
5901
  attempt_count,available_at,lease_owner,lease_expires_at,lease_token,last_error,created_at,updated_at)
5858
- VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9::jsonb,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21)`, [
5859
- record.id,
5860
- record.tenantId,
5861
- record.spaceId,
5862
- record.parentInvocationId,
5863
- record.parentActionId,
5864
- record.key,
5865
- record.actionId,
5866
- record.expectedActionVersion,
5867
- JSON.stringify(record.parameters),
5868
- record.parameterDigest,
5869
- record.batchDigest,
5870
- record.status,
5871
- record.childInvocationId ?? null,
5872
- record.attemptCount,
5873
- record.availableAt,
5874
- record.leaseOwner ?? null,
5875
- record.leaseExpiresAt ?? null,
5876
- record.leaseToken,
5877
- record.lastError ?? null,
5878
- record.createdAt,
5879
- record.updatedAt
5880
- ]);
5902
+ VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10::jsonb,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21,$22)`, [
5903
+ record.id,
5904
+ record.tenantId,
5905
+ record.spaceId,
5906
+ record.parentInvocationId,
5907
+ record.parentActionId,
5908
+ record.key,
5909
+ record.actionId,
5910
+ record.principal ?? null,
5911
+ record.expectedActionVersion,
5912
+ JSON.stringify(record.parameters),
5913
+ record.parameterDigest,
5914
+ record.batchDigest,
5915
+ record.status,
5916
+ record.childInvocationId ?? null,
5917
+ record.attemptCount,
5918
+ record.availableAt,
5919
+ record.leaseOwner ?? null,
5920
+ record.leaseExpiresAt ?? null,
5921
+ record.leaseToken,
5922
+ record.lastError ?? null,
5923
+ record.createdAt,
5924
+ record.updatedAt
5925
+ ]);
5926
+ } catch (error) {
5927
+ if (error?.code === "42703") throw new Error("Staging an invocation needs PostgreSQL migration 14 (staged_invocation_principals); run ensureSchema() before staging invocations.", { cause: error });
5928
+ throw error;
5929
+ }
5881
5930
  }
5882
5931
  }
5883
5932
  async getActionInvocation(id, tenantId, spaceId) {
@@ -6898,7 +6947,8 @@ function toActionRecord(row) {
6898
6947
  ...row.idempotency_authorization_binding_id ? { idempotencyAuthorizationBindingId: String(row.idempotency_authorization_binding_id) } : {},
6899
6948
  ...row.staged_parent_invocation_id && row.staged_stage_key ? { stagedOrigin: {
6900
6949
  parentInvocationId: String(row.staged_parent_invocation_id),
6901
- stageKey: String(row.staged_stage_key)
6950
+ stageKey: String(row.staged_stage_key),
6951
+ ...row.staged_origin_principal ? { principal: String(row.staged_origin_principal) } : {}
6902
6952
  } } : {},
6903
6953
  ...row.invocation_provenance ? { provenance: row.invocation_provenance } : {},
6904
6954
  ...row.authorization_binding ? { authorizationBinding: row.authorization_binding } : {},
@@ -6944,6 +6994,7 @@ function toStagedInvocationRecord(row) {
6944
6994
  parentActionId: String(row.parent_action_id),
6945
6995
  key: String(row.stage_key),
6946
6996
  actionId: String(row.action_id),
6997
+ ...row.principal ? { principal: String(row.principal) } : {},
6947
6998
  expectedActionVersion: Number(row.expected_action_version),
6948
6999
  parameters: row.parameters,
6949
7000
  parameterDigest: String(row.parameter_digest),
@@ -8425,6 +8476,6 @@ async function runEventAppendChecks(subject) {
8425
8476
  };
8426
8477
  }
8427
8478
  //#endregion
8428
- export { APPROVAL_DECIDED_EVENT, APPROVAL_EXPIRED_EVENT, APPROVAL_REQUESTED_EVENT, ActionAdmissionError, ExternalCompletionError, IdempotencyConflictError, MAX_APPROVAL_EVIDENCE_BYTES, MAX_STAGED_INVOCATIONS, MAX_STAGED_INVOCATION_BATCH_BYTES, MAX_STAGED_INVOCATION_BYTES, MAX_STAGED_INVOCATION_KEY_LENGTH, MemoryPlatformHostStore, PARAMETER_DIGEST_ALGORITHM, PLATFORM_HOST_CONTRACT_VERSION, PLATFORM_HOST_HEALTH_CONTRACT_VERSION, PLATFORM_HOST_METRIC_NAMES, PostgresPlatformHostStore, STAGED_INVOCATION_KEY_PATTERN, SubmissionRefusalError, applyPostgresMigrations, asStagedInvocationStore, canonicalJson, cloneOutboxRecord, cloneStagedInvocationRecord, createDurableSagaParentLifecycle, createGovernedActionHost, createStoreBackedActionDispatcher, digestParameters, emitPlatformHostTelemetry, eventAppendChecks, getPlatformHostHealthSnapshot, outboxActorDisclosure, prepareStagedInvocationBatch, runEventAppendChecks, runOutboxRelayCycle, runPlatformActionWorker, runPlatformActionWorkerCycle, runTenantIsolationChecks, stagedInvocationRequestIdentity, tenantIsolationChecks, toEnterpriseEventEnvelope };
8479
+ export { APPROVAL_DECIDED_EVENT, APPROVAL_EXPIRED_EVENT, APPROVAL_REQUESTED_EVENT, ActionAdmissionError, ExternalCompletionError, IdempotencyConflictError, MAX_APPROVAL_EVIDENCE_BYTES, MAX_STAGED_INVOCATIONS, MAX_STAGED_INVOCATION_BATCH_BYTES, MAX_STAGED_INVOCATION_BYTES, MAX_STAGED_INVOCATION_KEY_LENGTH, MemoryPlatformHostStore, PARAMETER_DIGEST_ALGORITHM, PLATFORM_HOST_CONTRACT_VERSION, PLATFORM_HOST_HEALTH_CONTRACT_VERSION, PLATFORM_HOST_METRIC_NAMES, PostgresPlatformHostStore, STAGED_INVOCATION_KEY_PATTERN, STAGED_INVOCATION_PRINCIPAL_PATTERN, SubmissionRefusalError, applyPostgresMigrations, asStagedInvocationStore, canonicalJson, cloneOutboxRecord, cloneStagedInvocationRecord, createDurableSagaParentLifecycle, createGovernedActionHost, createStoreBackedActionDispatcher, digestParameters, emitPlatformHostTelemetry, eventAppendChecks, getPlatformHostHealthSnapshot, outboxActorDisclosure, prepareStagedInvocationBatch, runEventAppendChecks, runOutboxRelayCycle, runPlatformActionWorker, runPlatformActionWorkerCycle, runTenantIsolationChecks, stagedInvocationRequestIdentity, tenantIsolationChecks, toEnterpriseEventEnvelope };
8429
8480
 
8430
8481
  //# sourceMappingURL=index.js.map