@fabricorg/platform-host 1.0.0 → 2.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 CHANGED
@@ -1,5 +1,26 @@
1
1
  # @fabricorg/platform-host
2
2
 
3
+ ## 2.0.0
4
+
5
+ ### Minor Changes
6
+
7
+ - Add the optional durable event outbox, PostgreSQL and memory adapters, and at-least-once relay.
8
+ - Add manifest v2 typed entity contracts, v1 reader normalization, optional action result schemas, and
9
+ Host enforcement of result validation before events and adapters.
10
+
11
+ ### Patch Changes
12
+
13
+ - Updated dependencies
14
+ - Updated dependencies
15
+ - @fabricorg/platform@0.11.0
16
+
17
+ ## Unreleased
18
+
19
+ - Validate optional action result schemas immediately after handler execution and before events or
20
+ adapters. Invalid results roll back the handler transaction and persist a sanitized failure.
21
+ - Add optional memory and PostgreSQL outbox capabilities with atomic canonical-event records,
22
+ lease-based at-least-once relay, retry, replay, and dead-letter state.
23
+
3
24
  ## 1.0.0
4
25
 
5
26
  ### Minor Changes
package/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  The canonical host for the `@fabricorg/platform` mutation pipeline.
4
4
 
5
5
  ```bash
6
- pnpm add @fabricorg/platform@^0.9.0 @fabricorg/platform-host@^0.7.0
6
+ pnpm add @fabricorg/platform@^0.10.0 @fabricorg/platform-host@^1.0.0
7
7
  ```
8
8
 
9
9
  ## AI agent integration boundary
@@ -15,7 +15,7 @@ registration, and submit stable idempotent commands. The gateway derives tenant
15
15
  calls `submitAction()`; an agent must never call handlers, adapters, workflow internals, or database
16
16
  writes directly.
17
17
 
18
- See the [Platform Host 0.7 agent integration
18
+ See the [Platform Host 1.0 agent integration
19
19
  guide](https://platform.fabric.pro/docs/platform/reference/platform-host) for application wiring,
20
20
  execution-time authorization, the PostgreSQL transaction binder, recovery semantics, and the external
21
21
  gateway contract.
@@ -100,6 +100,12 @@ application knows how its `TDb` is rebound to the transaction's SQL client.
100
100
  Stores without this additive capability retain the legacy boundary for compatibility and must not
101
101
  claim atomic domain-write/event persistence.
102
102
 
103
+ Actions can optionally declare `resultSchema`. The Host validates public handler result data after
104
+ the handler and before canonical event append or adapter execution. Invalid results roll back the
105
+ handler transaction, emit no domain/completion event, invoke no adapter, and persist only a sanitized
106
+ validation failure. This validates the handler result contract; it does not observe arbitrary writes
107
+ through an application-owned `TDb`.
108
+
103
109
  ## Agent HITL
104
110
 
105
111
  Hosts can inject a vertical-owned `hitlEvaluator`. It runs only for `actorType: "agent"`, after schema
@@ -171,7 +177,7 @@ explain which contract and provider adapter governed a mutation after dependenci
171
177
  const host = createGovernedActionHost({
172
178
  // ...
173
179
  runtimeEvidence: {
174
- hostPackageVersion: "0.7.0",
180
+ hostPackageVersion: "1.0.0",
175
181
  policyRulesetVersion: "gtm-rules.v8",
176
182
  providerBridge: { name: "@fabric-harness/databricks", version: "1" },
177
183
  },
@@ -181,3 +187,12 @@ const host = createGovernedActionHost({
181
187
  `MemoryPlatformHostStore` is for tests and local demos. Production control planes use
182
188
  `PostgresPlatformHostStore` with Databricks Lakebase (or standard Postgres), call
183
189
  `ensureSchema()` at startup, and hydrate projections from `listEvents()`.
190
+
191
+ ## Durable outbox egress
192
+
193
+ Configure `outbox` on `createGovernedActionHost()` only with an `OutboxPlatformHostStore`.
194
+ The Host then uses `appendEventWithOutbox` so the canonical event and delivery record share
195
+ the proven event transaction. `runOutboxRelayCycle()` leases and publishes records with retry
196
+ and dead-letter handling. Delivery is at least once: consumers deduplicate on immutable
197
+ `eventId`. Payload classification is metadata, not a redaction mechanism; event payloads must
198
+ already be audit-safe.
package/dist/index.cjs CHANGED
@@ -16,6 +16,12 @@ var RecoverableFinalizationError = class extends Error {
16
16
  name = "RecoverableFinalizationError";
17
17
  };
18
18
  function createGovernedActionHost(options) {
19
+ if (options.outbox) {
20
+ const outboxStore = asOutboxStore(options.store);
21
+ if (!outboxStore || !asAtomicMutationStore(options.store) || outboxStore.transactionalOutbox !== true) {
22
+ throw new Error("Outbox egress requires a store with transactionalOutbox and transactionWithEvents capabilities.");
23
+ }
24
+ }
19
25
  const adapters = new platform.AdapterRegistry();
20
26
  for (const adapter of options.adapters ?? []) adapters.register(adapter);
21
27
  const now = options.now ?? (() => /* @__PURE__ */ new Date());
@@ -340,6 +346,13 @@ function createGovernedActionHost(options) {
340
346
  throw new Error(handlerResult.error ?? "Action handler failed");
341
347
  }
342
348
  const handlerData = handlerResult.data ?? {};
349
+ if (action.resultSchema) {
350
+ const publicResult = withoutPrivateHostFields(handlerData, eventResultFields);
351
+ const parsedResult = action.resultSchema.safeParse(publicResult);
352
+ if (!parsedResult.success) {
353
+ throw new Error(`Action result validation failed at ${parsedResult.error.issues.map((issue) => issue.path.map(String).join(".") || "result").join(", ")}`);
354
+ }
355
+ }
343
356
  const events = extractEvents(handlerData);
344
357
  const undeclaredEvent = events.find(
345
358
  (event) => !action.emitsEvents.includes(event.eventType)
@@ -680,7 +693,24 @@ function createGovernedActionHost(options) {
680
693
  correlationId: invocation.correlationId,
681
694
  ...invocation.causationId ? { causationId: invocation.causationId } : {}
682
695
  };
683
- await (transaction ?? options.store).appendEvent(envelope);
696
+ if (options.outbox) {
697
+ const traceContext = options.outbox.traceContext?.(envelope);
698
+ const metadata = {
699
+ producerModuleVersion: options.outbox.producerModuleVersion(invocation.actionId, invocation.actionVersion),
700
+ payloadClassification: options.outbox.classifyPayload(envelope),
701
+ ...traceContext ? { traceContext } : {}
702
+ };
703
+ if (transaction) {
704
+ if (!transaction.appendEventWithOutbox) throw new Error("Outbox egress requires an atomic transaction with appendEventWithOutbox.");
705
+ await transaction.appendEventWithOutbox(envelope, metadata);
706
+ } else {
707
+ const outboxStore = asOutboxStore(options.store);
708
+ if (!outboxStore) throw new Error("Outbox egress requires an outbox-capable Platform Host store.");
709
+ await outboxStore.appendEventWithOutbox(envelope, metadata);
710
+ }
711
+ } else {
712
+ await (transaction ?? options.store).appendEvent(envelope);
713
+ }
684
714
  }
685
715
  async function fail(invocation, status, error) {
686
716
  await options.store.updateActionInvocation(
@@ -717,6 +747,10 @@ function asAtomicMutationStore(store) {
717
747
  const candidate = store;
718
748
  return typeof candidate.transactionWithEvents === "function" ? store : void 0;
719
749
  }
750
+ function asOutboxStore(store) {
751
+ const candidate = store;
752
+ return typeof candidate.appendEventWithOutbox === "function" && typeof candidate.claimOutbox === "function" ? store : void 0;
753
+ }
720
754
  function asGovernanceStore(store) {
721
755
  const candidate = store;
722
756
  return typeof candidate.recordMutationGovernance === "function" && typeof candidate.appendPolicyObligations === "function" && typeof candidate.appendExecutionAttestation === "function" ? store : void 0;
@@ -773,6 +807,73 @@ function lifecycleId(prefix, invocationId, key) {
773
807
  return `${prefix}_${invocationId}_${safeKey}`;
774
808
  }
775
809
 
810
+ // src/outbox.ts
811
+ function toEnterpriseEventEnvelope(event, metadata) {
812
+ return {
813
+ eventId: event.id,
814
+ eventType: event.eventType,
815
+ eventSchemaVersion: event.eventSchemaVersion,
816
+ tenantId: event.tenantId,
817
+ spaceId: event.spaceId,
818
+ subjectType: event.subjectType,
819
+ subjectId: event.subjectId,
820
+ sequence: event.sequence,
821
+ ...event.actionInvocationId ? { actionInvocationId: event.actionInvocationId } : {},
822
+ correlationId: event.correlationId,
823
+ ...event.causationId ? { causationId: event.causationId } : {},
824
+ occurredAt: event.occurredAt,
825
+ recordedAt: event.recordedAt,
826
+ producerModuleVersion: metadata.producerModuleVersion,
827
+ payloadClassification: metadata.payloadClassification,
828
+ ...metadata.traceContext ? { traceContext: { ...metadata.traceContext } } : {},
829
+ payload: event.payload
830
+ };
831
+ }
832
+ async function runOutboxRelayCycle(options) {
833
+ const now = options.now ?? (() => /* @__PURE__ */ new Date());
834
+ const maxAttempts = options.maxAttempts ?? 10;
835
+ const records = await options.store.claimOutbox({
836
+ workerId: options.workerId,
837
+ leaseDurationMs: options.leaseDurationMs ?? 3e4,
838
+ limit: options.batchSize ?? 100,
839
+ now: now()
840
+ });
841
+ const result = { claimed: records.length, published: 0, failed: 0, deadLettered: 0 };
842
+ for (const record of records) {
843
+ try {
844
+ await options.publisher.publish(record.event);
845
+ try {
846
+ await options.store.markOutboxPublished(record.id, options.workerId, now());
847
+ } catch {
848
+ result.failed += 1;
849
+ continue;
850
+ }
851
+ result.published += 1;
852
+ } catch (error) {
853
+ const deadLetter = record.attemptCount >= maxAttempts;
854
+ try {
855
+ await options.store.markOutboxFailed({
856
+ id: record.id,
857
+ workerId: options.workerId,
858
+ error: error instanceof Error ? error.message : String(error),
859
+ availableAt: new Date(now().getTime() + (options.retryDelayMs?.(record.attemptCount) ?? 1e3)),
860
+ deadLetter
861
+ });
862
+ } catch {
863
+ }
864
+ result.failed += 1;
865
+ if (deadLetter) result.deadLettered += 1;
866
+ }
867
+ }
868
+ return result;
869
+ }
870
+ function cloneOutboxRecord(record) {
871
+ return {
872
+ ...record,
873
+ event: { ...record.event, ...record.event.traceContext ? { traceContext: { ...record.event.traceContext } } : {} }
874
+ };
875
+ }
876
+
776
877
  // src/memory-store.ts
777
878
  var MemoryPlatformHostStore = class {
778
879
  constructor(db) {
@@ -786,6 +887,7 @@ var MemoryPlatformHostStore = class {
786
887
  policyObligations = [];
787
888
  executionAttestations = [];
788
889
  externalReconciliations = [];
890
+ outbox = [];
789
891
  async transaction(run) {
790
892
  return run(this.db);
791
893
  }
@@ -904,6 +1006,53 @@ var MemoryPlatformHostStore = class {
904
1006
  if (this.events.some((candidate) => candidate.id === event.id)) return;
905
1007
  this.events.push(event);
906
1008
  }
1009
+ async appendEventWithOutbox(event, metadata) {
1010
+ if (this.events.some((candidate) => candidate.id === event.id)) return;
1011
+ const createdAt = new Date(event.recordedAt);
1012
+ this.events.push(event);
1013
+ this.outbox.push({
1014
+ id: event.id,
1015
+ tenantId: event.tenantId,
1016
+ spaceId: event.spaceId,
1017
+ event: toEnterpriseEventEnvelope(event, metadata),
1018
+ status: "pending",
1019
+ attemptCount: 0,
1020
+ availableAt: createdAt,
1021
+ createdAt
1022
+ });
1023
+ }
1024
+ async claimOutbox(input) {
1025
+ const current = input.now ?? /* @__PURE__ */ new Date();
1026
+ return this.outbox.filter((record) => record.status === "pending" && record.availableAt <= current && (!record.leaseExpiresAt || record.leaseExpiresAt <= current) && (!input.tenantId || record.tenantId === input.tenantId) && (!input.spaceId || record.spaceId === input.spaceId)).sort((left, right) => left.createdAt.getTime() - right.createdAt.getTime() || left.id.localeCompare(right.id)).slice(0, Math.max(1, Math.min(input.limit ?? 100, 1e3))).map((record) => {
1027
+ record.leaseOwner = input.workerId;
1028
+ record.leaseExpiresAt = new Date(current.getTime() + input.leaseDurationMs);
1029
+ record.attemptCount += 1;
1030
+ return cloneOutboxRecord(record);
1031
+ });
1032
+ }
1033
+ async markOutboxPublished(id, workerId, publishedAt) {
1034
+ const record = this.requireLeasedOutbox(id, workerId);
1035
+ record.status = "published";
1036
+ record.publishedAt = publishedAt;
1037
+ delete record.leaseOwner;
1038
+ delete record.leaseExpiresAt;
1039
+ }
1040
+ async markOutboxFailed(input) {
1041
+ const record = this.requireLeasedOutbox(input.id, input.workerId);
1042
+ record.status = input.deadLetter ? "dead_letter" : "pending";
1043
+ record.lastError = input.error;
1044
+ record.availableAt = input.availableAt;
1045
+ delete record.leaseOwner;
1046
+ delete record.leaseExpiresAt;
1047
+ }
1048
+ async listOutbox(input = {}) {
1049
+ return this.outbox.filter((record) => (!input.tenantId || record.tenantId === input.tenantId) && (!input.spaceId || record.spaceId === input.spaceId) && (!input.statuses?.length || input.statuses.includes(record.status))).map(cloneOutboxRecord);
1050
+ }
1051
+ requireLeasedOutbox(id, workerId) {
1052
+ const record = this.outbox.find((candidate) => candidate.id === id);
1053
+ if (!record || record.leaseOwner !== workerId) throw new Error(`Outbox record ${id} is not leased by ${workerId}.`);
1054
+ return record;
1055
+ }
907
1056
  async nextEventSequence(tenantId, spaceId) {
908
1057
  return this.events.filter((event) => event.tenantId === tenantId && event.spaceId === spaceId).length + 1;
909
1058
  }
@@ -947,12 +1096,14 @@ var PostgresPlatformHostStore = class _PostgresPlatformHostStore {
947
1096
  constructor(db, sql, transactionProvider) {
948
1097
  this.db = db;
949
1098
  this.sql = sql;
1099
+ this.transactionalOutbox = transactionProvider !== void 0;
950
1100
  if (transactionProvider) {
951
1101
  this.transactionWithEvents = async (run) => transactionProvider.run(async ({ db: db2, sql: sql2 }) => {
952
1102
  const scoped = new _PostgresPlatformHostStore(db2, sql2);
953
1103
  return run({
954
1104
  db: db2,
955
1105
  appendEvent: (event) => scoped.appendEvent(event),
1106
+ appendEventWithOutbox: (event, metadata) => scoped.appendEventWithOutbox(event, metadata),
956
1107
  nextEventSequence: (tenantId, spaceId) => scoped.nextEventSequence(tenantId, spaceId),
957
1108
  listEvents: (tenantId, spaceId) => scoped.listEvents(tenantId, spaceId),
958
1109
  updateActionInvocation: (id, tenantId, spaceId, patch) => scoped.updateActionInvocation(id, tenantId, spaceId, patch)
@@ -963,6 +1114,7 @@ var PostgresPlatformHostStore = class _PostgresPlatformHostStore {
963
1114
  db;
964
1115
  sql;
965
1116
  transactionWithEvents;
1117
+ transactionalOutbox;
966
1118
  async ensureSchema() {
967
1119
  await this.sql.query(`
968
1120
  CREATE SCHEMA IF NOT EXISTS fabric_platform;
@@ -1046,6 +1198,15 @@ var PostgresPlatformHostStore = class _PostgresPlatformHostStore {
1046
1198
  CREATE INDEX IF NOT EXISTS asset_events_subject_idx
1047
1199
  ON fabric_platform.asset_events
1048
1200
  (tenant_id, space_id, subject_type, subject_id, sequence);
1201
+ CREATE TABLE IF NOT EXISTS fabric_platform.event_outbox (
1202
+ id text PRIMARY KEY, tenant_id text NOT NULL, space_id text NOT NULL,
1203
+ event jsonb NOT NULL, status text NOT NULL DEFAULT 'pending',
1204
+ attempt_count integer NOT NULL DEFAULT 0, available_at timestamptz NOT NULL,
1205
+ lease_owner text, lease_expires_at timestamptz, last_error text,
1206
+ created_at timestamptz NOT NULL, published_at timestamptz
1207
+ );
1208
+ CREATE INDEX IF NOT EXISTS event_outbox_claim_idx
1209
+ ON fabric_platform.event_outbox (status, available_at, lease_expires_at, created_at);
1049
1210
  `);
1050
1211
  }
1051
1212
  async transaction(run) {
@@ -1328,6 +1489,86 @@ var PostgresPlatformHostStore = class _PostgresPlatformHostStore {
1328
1489
  ]
1329
1490
  );
1330
1491
  }
1492
+ async appendEventWithOutbox(event, metadata) {
1493
+ const envelope = toEnterpriseEventEnvelope(event, metadata);
1494
+ await this.sql.query(
1495
+ `WITH inserted_event AS (
1496
+ INSERT INTO fabric_platform.asset_events
1497
+ (id,tenant_id,space_id,event_type,event_schema_version,subject_type,subject_id,
1498
+ actor_id,actor_type,action_invocation_id,payload,sequence,occurred_at,recorded_at,
1499
+ correlation_id,causation_id)
1500
+ VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11::jsonb,$12,$13,$14,$15,$16)
1501
+ ON CONFLICT (id) DO NOTHING RETURNING id
1502
+ )
1503
+ INSERT INTO fabric_platform.event_outbox
1504
+ (id,tenant_id,space_id,event,status,attempt_count,available_at,created_at)
1505
+ SELECT $1,$2,$3,$17::jsonb,'pending',0,$14,$14 FROM inserted_event
1506
+ ON CONFLICT (id) DO NOTHING`,
1507
+ [
1508
+ event.id,
1509
+ event.tenantId,
1510
+ event.spaceId,
1511
+ event.eventType,
1512
+ event.eventSchemaVersion,
1513
+ event.subjectType,
1514
+ event.subjectId,
1515
+ event.actorId,
1516
+ event.actorType,
1517
+ event.actionInvocationId ?? null,
1518
+ JSON.stringify(event.payload),
1519
+ event.sequence,
1520
+ event.occurredAt,
1521
+ event.recordedAt,
1522
+ event.correlationId,
1523
+ event.causationId ?? null,
1524
+ JSON.stringify(envelope)
1525
+ ]
1526
+ );
1527
+ }
1528
+ async claimOutbox(input) {
1529
+ const current = input.now ?? /* @__PURE__ */ new Date();
1530
+ const leaseExpiresAt = new Date(current.getTime() + input.leaseDurationMs);
1531
+ const result = await this.sql.query(
1532
+ `WITH claimable AS (
1533
+ SELECT id FROM fabric_platform.event_outbox
1534
+ WHERE status='pending' AND available_at <= $1
1535
+ AND (lease_expires_at IS NULL OR lease_expires_at <= $1)
1536
+ AND ($2::text IS NULL OR tenant_id=$2)
1537
+ AND ($3::text IS NULL OR space_id=$3)
1538
+ ORDER BY created_at,id FOR UPDATE SKIP LOCKED LIMIT $4
1539
+ )
1540
+ UPDATE fabric_platform.event_outbox AS item
1541
+ SET lease_owner=$5, lease_expires_at=$6, attempt_count=attempt_count+1
1542
+ FROM claimable WHERE item.id=claimable.id RETURNING item.*`,
1543
+ [current, input.tenantId ?? null, input.spaceId ?? null, Math.max(1, Math.min(input.limit ?? 100, 1e3)), input.workerId, leaseExpiresAt]
1544
+ );
1545
+ return result.rows.map(toOutboxRecord);
1546
+ }
1547
+ async markOutboxPublished(id, workerId, publishedAt) {
1548
+ const result = await this.sql.query(
1549
+ `UPDATE fabric_platform.event_outbox SET status='published',published_at=$3,
1550
+ lease_owner=NULL,lease_expires_at=NULL WHERE id=$1 AND lease_owner=$2 RETURNING id`,
1551
+ [id, workerId, publishedAt]
1552
+ );
1553
+ if (result.rows.length === 0) throw new Error(`Outbox record ${id} is not leased by ${workerId}.`);
1554
+ }
1555
+ async markOutboxFailed(input) {
1556
+ const result = await this.sql.query(
1557
+ `UPDATE fabric_platform.event_outbox SET status=$3,last_error=$4,available_at=$5,
1558
+ lease_owner=NULL,lease_expires_at=NULL WHERE id=$1 AND lease_owner=$2 RETURNING id`,
1559
+ [input.id, input.workerId, input.deadLetter ? "dead_letter" : "pending", input.error, input.availableAt]
1560
+ );
1561
+ if (result.rows.length === 0) throw new Error(`Outbox record ${input.id} is not leased by ${input.workerId}.`);
1562
+ }
1563
+ async listOutbox(input = {}) {
1564
+ const result = await this.sql.query(
1565
+ `SELECT * FROM fabric_platform.event_outbox
1566
+ WHERE ($1::text IS NULL OR tenant_id=$1) AND ($2::text IS NULL OR space_id=$2)
1567
+ AND ($3::text[] IS NULL OR status=ANY($3::text[])) ORDER BY created_at,id`,
1568
+ [input.tenantId ?? null, input.spaceId ?? null, input.statuses?.length ? input.statuses : null]
1569
+ );
1570
+ return result.rows.map(toOutboxRecord);
1571
+ }
1331
1572
  async nextEventSequence(tenantId, spaceId) {
1332
1573
  const result = await this.sql.query(
1333
1574
  `INSERT INTO fabric_platform.event_sequences (tenant_id,space_id,next_sequence)
@@ -1516,6 +1757,41 @@ function toEventRecord(row) {
1516
1757
  ...row.causation_id ? { causationId: String(row.causation_id) } : {}
1517
1758
  };
1518
1759
  }
1760
+ function toOutboxRecord(row) {
1761
+ const event = row.event;
1762
+ return {
1763
+ id: String(row.id),
1764
+ tenantId: String(row.tenant_id),
1765
+ spaceId: String(row.space_id),
1766
+ event: {
1767
+ eventId: String(event.eventId),
1768
+ eventType: String(event.eventType),
1769
+ eventSchemaVersion: Number(event.eventSchemaVersion),
1770
+ tenantId: String(event.tenantId),
1771
+ spaceId: String(event.spaceId),
1772
+ subjectType: String(event.subjectType),
1773
+ subjectId: String(event.subjectId),
1774
+ sequence: Number(event.sequence),
1775
+ ...event.actionInvocationId ? { actionInvocationId: String(event.actionInvocationId) } : {},
1776
+ correlationId: String(event.correlationId),
1777
+ ...event.causationId ? { causationId: String(event.causationId) } : {},
1778
+ occurredAt: new Date(event.occurredAt),
1779
+ recordedAt: new Date(event.recordedAt),
1780
+ producerModuleVersion: String(event.producerModuleVersion),
1781
+ payloadClassification: String(event.payloadClassification),
1782
+ ...event.traceContext ? { traceContext: event.traceContext } : {},
1783
+ payload: event.payload
1784
+ },
1785
+ status: String(row.status),
1786
+ attemptCount: Number(row.attempt_count),
1787
+ availableAt: new Date(row.available_at),
1788
+ ...row.lease_owner ? { leaseOwner: String(row.lease_owner) } : {},
1789
+ ...row.lease_expires_at ? { leaseExpiresAt: new Date(row.lease_expires_at) } : {},
1790
+ ...row.last_error ? { lastError: String(row.last_error) } : {},
1791
+ createdAt: new Date(row.created_at),
1792
+ ...row.published_at ? { publishedAt: new Date(row.published_at) } : {}
1793
+ };
1794
+ }
1519
1795
 
1520
1796
  // src/worker.ts
1521
1797
  var DEFAULT_BATCH_SIZE = 10;
@@ -1588,9 +1864,12 @@ async function abortableDelay(milliseconds, signal) {
1588
1864
  exports.MemoryPlatformHostStore = MemoryPlatformHostStore;
1589
1865
  exports.PLATFORM_HOST_CONTRACT_VERSION = PLATFORM_HOST_CONTRACT_VERSION;
1590
1866
  exports.PostgresPlatformHostStore = PostgresPlatformHostStore;
1867
+ exports.cloneOutboxRecord = cloneOutboxRecord;
1591
1868
  exports.createGovernedActionHost = createGovernedActionHost;
1592
1869
  exports.createStoreBackedActionDispatcher = createStoreBackedActionDispatcher;
1870
+ exports.runOutboxRelayCycle = runOutboxRelayCycle;
1593
1871
  exports.runPlatformActionWorker = runPlatformActionWorker;
1594
1872
  exports.runPlatformActionWorkerCycle = runPlatformActionWorkerCycle;
1873
+ exports.toEnterpriseEventEnvelope = toEnterpriseEventEnvelope;
1595
1874
  //# sourceMappingURL=index.cjs.map
1596
1875
  //# sourceMappingURL=index.cjs.map