@fabricorg/platform-host 8.6.0 → 8.8.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
  });
@@ -3122,6 +3147,7 @@ function createGovernedActionHost(options) {
3122
3147
  ...invocation.causationId ? { causationId: invocation.causationId } : {},
3123
3148
  attempt,
3124
3149
  maxAttempts,
3150
+ ...executionLease ? { lease: executionLease } : {},
3125
3151
  ...deadlineMs ? { deadlineMs } : {},
3126
3152
  ...adapterController ? { signal: adapterController.signal } : {}
3127
3153
  });
@@ -3573,6 +3599,7 @@ function createGovernedActionHost(options) {
3573
3599
  parentAction: action,
3574
3600
  requests: stagedRequests,
3575
3601
  resolveAction: actionResolver,
3602
+ stagedInvocationPrincipals,
3576
3603
  redactParameters: options.redactActionParameters,
3577
3604
  redactedKeys: handlerStagedInvocations.map((request) => request.key),
3578
3605
  now: now()
@@ -4143,6 +4170,8 @@ function createGovernedActionHost(options) {
4143
4170
  if (!parent || parent.status !== "completed") throw new Error("Staged parent is not completed.");
4144
4171
  const child = actionResolver(record.actionId);
4145
4172
  if (!child) throw new StagedDispatchRejectionError("Staged action is no longer registered.");
4173
+ const principal = record.principal !== void 0 && Object.hasOwn(stagedInvocationPrincipals, record.principal) ? stagedInvocationPrincipals[record.principal] : void 0;
4174
+ if (record.principal !== void 0 && !principal) throw new StagedDispatchRejectionError("Staged invocation principal is no longer registered.");
4146
4175
  if (child.execution?.authorityMoment === "capture") throw new StagedDispatchRejectionError("Staged action now requires capture-time authority.");
4147
4176
  if (!child.schema.safeParse(structuredClone(record.parameters)).success) throw new StagedDispatchRejectionError("Staged parameters no longer match the registered action.");
4148
4177
  return submitActionInternal({
@@ -4150,8 +4179,8 @@ function createGovernedActionHost(options) {
4150
4179
  parameters: structuredClone(record.parameters),
4151
4180
  tenantId: parent.tenantId,
4152
4181
  spaceId: parent.spaceId,
4153
- actorId: parent.actorId,
4154
- actorType: parent.actorType,
4182
+ actorId: principal?.actorId ?? parent.actorId,
4183
+ actorType: principal?.actorType ?? parent.actorType,
4155
4184
  correlationId: parent.correlationId,
4156
4185
  causationId: parent.id,
4157
4186
  provenance: {
@@ -4165,7 +4194,8 @@ function createGovernedActionHost(options) {
4165
4194
  id: record.id,
4166
4195
  origin: {
4167
4196
  parentInvocationId: parent.id,
4168
- stageKey: record.key
4197
+ stageKey: record.key,
4198
+ ...record.principal !== void 0 ? { principal: record.principal } : {}
4169
4199
  },
4170
4200
  workerId: lease.workerId,
4171
4201
  leaseToken: lease.leaseToken,
@@ -4835,7 +4865,7 @@ var MemoryPlatformHostStore = class {
4835
4865
  kind: "existing",
4836
4866
  invocation: existing
4837
4867
  };
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" };
4868
+ 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
4869
  const createdAt = /* @__PURE__ */ new Date();
4840
4870
  const record = {
4841
4871
  ...invocation,
@@ -5683,6 +5713,16 @@ var PostgresPlatformHostStore = class PostgresPlatformHostStore {
5683
5713
  version: 13,
5684
5714
  name: "agent_proposal",
5685
5715
  sql: `ALTER TABLE fabric_platform.action_invocations ADD COLUMN IF NOT EXISTS agent_proposal jsonb;`
5716
+ },
5717
+ {
5718
+ version: 14,
5719
+ name: "staged_invocation_principals",
5720
+ sql: `
5721
+ ALTER TABLE fabric_platform.staged_invocations
5722
+ ADD COLUMN IF NOT EXISTS principal text;
5723
+ ALTER TABLE fabric_platform.action_invocations
5724
+ ADD COLUMN IF NOT EXISTS staged_origin_principal text;
5725
+ `
5686
5726
  }
5687
5727
  ]);
5688
5728
  }
@@ -5747,9 +5787,9 @@ var PostgresPlatformHostStore = class PostgresPlatformHostStore {
5747
5787
  const current = input.now ?? /* @__PURE__ */ new Date();
5748
5788
  const admitted = invocation.admittedAt !== void 0;
5749
5789
  const admittedColumn = admitted ? ",admitted_at" : "";
5750
- const admittedValue = admitted ? ",$30" : "";
5790
+ const admittedValue = admitted ? ",$31" : "";
5751
5791
  const proposalColumn = invocation.agentProposal !== void 0 ? ",agent_proposal" : "";
5752
- const proposalValue = invocation.agentProposal !== void 0 ? `,$${admitted ? 31 : 30}::jsonb` : "";
5792
+ const proposalValue = invocation.agentProposal !== void 0 ? `,$${admitted ? 32 : 31}::jsonb` : "";
5753
5793
  const values = [
5754
5794
  invocation.id,
5755
5795
  invocation.tenantId,
@@ -5776,6 +5816,7 @@ var PostgresPlatformHostStore = class PostgresPlatformHostStore {
5776
5816
  invocation.runtimeEvidence ? JSON.stringify(invocation.runtimeEvidence) : null,
5777
5817
  invocation.stagedOrigin.parentInvocationId,
5778
5818
  invocation.stagedOrigin.stageKey,
5819
+ invocation.stagedOrigin.principal ?? null,
5779
5820
  input.stageId,
5780
5821
  input.workerId,
5781
5822
  input.leaseToken,
@@ -5788,10 +5829,11 @@ var PostgresPlatformHostStore = class PostgresPlatformHostStore {
5788
5829
  result = await this.sql.query(`WITH fence AS (
5789
5830
  SELECT stage.id
5790
5831
  FROM fabric_platform.staged_invocations AS stage
5791
- WHERE stage.id=$26 AND stage.tenant_id=$2 AND stage.space_id=$3
5832
+ WHERE stage.id=$27 AND stage.tenant_id=$2 AND stage.space_id=$3
5792
5833
  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
5834
+ AND stage.principal IS NOT DISTINCT FROM $26
5835
+ AND stage.status='pending' AND stage.lease_owner=$28 AND stage.lease_token=$29
5836
+ AND stage.lease_expires_at IS NOT NULL AND stage.lease_expires_at > $30
5795
5837
  FOR SHARE
5796
5838
  )
5797
5839
  INSERT INTO fabric_platform.action_invocations
@@ -5799,17 +5841,19 @@ var PostgresPlatformHostStore = class PostgresPlatformHostStore {
5799
5841
  parameters,result,correlation_id,causation_id,idempotency_key,parameter_digest,
5800
5842
  parameter_digest_algorithm,idempotency_actor_id,idempotency_authorization_binding_id,
5801
5843
  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)
5844
+ runtime_evidence,staged_parent_invocation_id,staged_stage_key,staged_origin_principal${admittedColumn}${proposalColumn},created_at,updated_at)
5803
5845
  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
5846
+ $18::jsonb,$19::jsonb,$20,$21,$22,$23::jsonb,$24,$25,$26${admittedValue}${proposalValue},$30,$30
5805
5847
  FROM fence
5806
5848
  ON CONFLICT (tenant_id,space_id,staged_parent_invocation_id,staged_stage_key)
5807
5849
  WHERE staged_parent_invocation_id IS NOT NULL AND staged_stage_key IS NOT NULL
5808
5850
  DO UPDATE SET id=fabric_platform.action_invocations.id
5809
5851
  RETURNING *`, values);
5810
5852
  } 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 });
5853
+ const databaseError = error;
5854
+ 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 });
5855
+ 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 });
5856
+ 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
5857
  throw error;
5814
5858
  }
5815
5859
  if (result.rows[0]) {
@@ -5851,33 +5895,39 @@ var PostgresPlatformHostStore = class PostgresPlatformHostStore {
5851
5895
  }
5852
5896
  for (const record of records) {
5853
5897
  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,
5898
+ try {
5899
+ await this.sql.query(`INSERT INTO fabric_platform.staged_invocations
5900
+ (id,tenant_id,space_id,parent_invocation_id,parent_action_id,stage_key,action_id,principal,
5856
5901
  expected_action_version,parameters,parameter_digest,batch_digest,status,child_invocation_id,
5857
5902
  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
- ]);
5903
+ VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10::jsonb,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21,$22)`, [
5904
+ record.id,
5905
+ record.tenantId,
5906
+ record.spaceId,
5907
+ record.parentInvocationId,
5908
+ record.parentActionId,
5909
+ record.key,
5910
+ record.actionId,
5911
+ record.principal ?? null,
5912
+ record.expectedActionVersion,
5913
+ JSON.stringify(record.parameters),
5914
+ record.parameterDigest,
5915
+ record.batchDigest,
5916
+ record.status,
5917
+ record.childInvocationId ?? null,
5918
+ record.attemptCount,
5919
+ record.availableAt,
5920
+ record.leaseOwner ?? null,
5921
+ record.leaseExpiresAt ?? null,
5922
+ record.leaseToken,
5923
+ record.lastError ?? null,
5924
+ record.createdAt,
5925
+ record.updatedAt
5926
+ ]);
5927
+ } catch (error) {
5928
+ if (error?.code === "42703") throw new Error("Staging an invocation needs PostgreSQL migration 14 (staged_invocation_principals); run ensureSchema() before staging invocations.", { cause: error });
5929
+ throw error;
5930
+ }
5881
5931
  }
5882
5932
  }
5883
5933
  async getActionInvocation(id, tenantId, spaceId) {
@@ -6898,7 +6948,8 @@ function toActionRecord(row) {
6898
6948
  ...row.idempotency_authorization_binding_id ? { idempotencyAuthorizationBindingId: String(row.idempotency_authorization_binding_id) } : {},
6899
6949
  ...row.staged_parent_invocation_id && row.staged_stage_key ? { stagedOrigin: {
6900
6950
  parentInvocationId: String(row.staged_parent_invocation_id),
6901
- stageKey: String(row.staged_stage_key)
6951
+ stageKey: String(row.staged_stage_key),
6952
+ ...row.staged_origin_principal ? { principal: String(row.staged_origin_principal) } : {}
6902
6953
  } } : {},
6903
6954
  ...row.invocation_provenance ? { provenance: row.invocation_provenance } : {},
6904
6955
  ...row.authorization_binding ? { authorizationBinding: row.authorization_binding } : {},
@@ -6944,6 +6995,7 @@ function toStagedInvocationRecord(row) {
6944
6995
  parentActionId: String(row.parent_action_id),
6945
6996
  key: String(row.stage_key),
6946
6997
  actionId: String(row.action_id),
6998
+ ...row.principal ? { principal: String(row.principal) } : {},
6947
6999
  expectedActionVersion: Number(row.expected_action_version),
6948
7000
  parameters: row.parameters,
6949
7001
  parameterDigest: String(row.parameter_digest),
@@ -8425,6 +8477,6 @@ async function runEventAppendChecks(subject) {
8425
8477
  };
8426
8478
  }
8427
8479
  //#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 };
8480
+ 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
8481
 
8430
8482
  //# sourceMappingURL=index.js.map