@fabricorg/platform-host 2.0.0 → 2.0.1
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 +20 -8
- package/README.md +16 -7
- package/dist/index.cjs +60 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +12 -2
- package/dist/index.d.ts +12 -2
- package/dist/index.js +60 -3
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.d.cts
CHANGED
|
@@ -382,6 +382,8 @@ interface PlatformHostOptions<TDb> {
|
|
|
382
382
|
producerModuleVersion(actionId: ActionId, actionVersion: number): string;
|
|
383
383
|
classifyPayload(event: AssetEventEnvelope): EventPayloadClassification;
|
|
384
384
|
traceContext?(event: AssetEventEnvelope): Record<string, string> | undefined;
|
|
385
|
+
/** Host lifecycle events are excluded by default; opt in only after making their payload audit-safe. */
|
|
386
|
+
shouldPublish?(event: AssetEventEnvelope): boolean;
|
|
385
387
|
};
|
|
386
388
|
/** Optional vertical-owned evaluator. When absent, agent behavior is unchanged. */
|
|
387
389
|
hitlEvaluator?: AgentActionPolicyEvaluator;
|
|
@@ -433,8 +435,15 @@ interface GovernedActionHost {
|
|
|
433
435
|
|
|
434
436
|
declare function createGovernedActionHost<TDb>(options: PlatformHostOptions<TDb>): GovernedActionHost;
|
|
435
437
|
|
|
438
|
+
interface MemoryPlatformHostTransactionProvider<TDb> {
|
|
439
|
+
snapshot(db: TDb): TDb;
|
|
440
|
+
restore(db: TDb, snapshot: TDb): void;
|
|
441
|
+
}
|
|
436
442
|
declare class MemoryPlatformHostStore<TDb> implements RecoverablePlatformHostStore<TDb>, ApprovalPlatformHostStore<TDb>, GovernancePlatformHostStore<TDb>, OutboxPlatformHostStore<TDb> {
|
|
437
443
|
readonly db: TDb;
|
|
444
|
+
readonly transactionalOutbox: boolean;
|
|
445
|
+
transactionWithEvents?: <TResult>(run: (transaction: PlatformHostMutationTransaction<TDb>) => Promise<TResult>) => Promise<TResult>;
|
|
446
|
+
private transactionTail;
|
|
438
447
|
readonly invocations: ActionInvocationRecord[];
|
|
439
448
|
readonly policyEvaluations: PolicyEvaluationRecord[];
|
|
440
449
|
readonly adapterInvocations: AdapterInvocationRecord[];
|
|
@@ -443,8 +452,9 @@ declare class MemoryPlatformHostStore<TDb> implements RecoverablePlatformHostSto
|
|
|
443
452
|
readonly executionAttestations: ExecutionAttestationRecord[];
|
|
444
453
|
readonly externalReconciliations: ExternalReconciliationRecord[];
|
|
445
454
|
readonly outbox: OutboxRecord[];
|
|
446
|
-
constructor(db: TDb);
|
|
455
|
+
constructor(db: TDb, transactionProvider?: MemoryPlatformHostTransactionProvider<TDb>);
|
|
447
456
|
transaction<TResult>(run: (db: TDb) => Promise<TResult>): Promise<TResult>;
|
|
457
|
+
private runTransactionWithEvents;
|
|
448
458
|
createActionInvocation(input: CreateActionInvocationInput): Promise<ActionInvocationRecord>;
|
|
449
459
|
getActionInvocation(id: string, tenantId: string, spaceId: string): Promise<ActionInvocationRecord | undefined>;
|
|
450
460
|
updateActionInvocation(id: string, tenantId: string, spaceId: string, patch: Partial<Pick<ActionInvocationRecord, "status" | "result" | "error">>): Promise<void>;
|
|
@@ -593,4 +603,4 @@ declare function runPlatformActionWorkerCycle<TDb>(options: PlatformActionWorker
|
|
|
593
603
|
/** Poll until aborted. Each iteration is bounded and waits without busy-spinning. */
|
|
594
604
|
declare function runPlatformActionWorker<TDb>(options: PlatformActionWorkerOptions<TDb>): Promise<void>;
|
|
595
605
|
|
|
596
|
-
export { type ActionApprovalDecision, type ActionAuthorizationInput, type ActionExecutionAuthorizationInput, type ActionExecutionReason, type ActionInvocationRecord, type AdapterInvocationRecord, type AdapterInvocationStatus, type ApprovalDecisionTransitionResult, type ApprovalPlatformHostStore, type AtomicMutationPlatformHostStore, type BeginApprovalDecisionInput, type ClaimActionInvocationsInput, type ClaimOutboxInput, type CreateActionInvocationInput, type DispatchActionInput, type DispatchActionResult, type EnterpriseEventEnvelope, type EnterpriseEventPublisher, type EventPayloadClassification, type ExecuteActionResult, type ExecuteInvocationOptions, type ExecutionAttestationRecord, type ExternalReconciliationRecord, type GovernancePlatformHostStore, type GovernedActionHost, type HitlDecisionEvidence, type ListActionInvocationsInput, MemoryPlatformHostStore, type OutboxEventMetadata, type OutboxPlatformHostStore, type OutboxRecord, type OutboxRelayOptions, type OutboxRelayResult, type OutboxStatus, PLATFORM_HOST_CONTRACT_VERSION, type PendingAssetEvent, type PersistedActionApprovalDecision, type PlatformActionDispatcher, type PlatformActionWorkerCycleResult, type PlatformActionWorkerOptions, type PlatformHostAuthorization, type PlatformHostMutationTransaction, type PlatformHostOptions, type PlatformHostSqlClient, type PlatformHostSqlResult, type PlatformHostStore, type PolicyEvaluationRecord, type PolicyObligationRecord, PostgresPlatformHostStore, type PostgresPlatformHostTransactionContext, type PostgresPlatformHostTransactionProvider, type RecoverablePlatformHostStore, type SubmitActionInput, type SubmitActionResult, cloneOutboxRecord, createGovernedActionHost, createStoreBackedActionDispatcher, runOutboxRelayCycle, runPlatformActionWorker, runPlatformActionWorkerCycle, toEnterpriseEventEnvelope };
|
|
606
|
+
export { type ActionApprovalDecision, type ActionAuthorizationInput, type ActionExecutionAuthorizationInput, type ActionExecutionReason, type ActionInvocationRecord, type AdapterInvocationRecord, type AdapterInvocationStatus, type ApprovalDecisionTransitionResult, type ApprovalPlatformHostStore, type AtomicMutationPlatformHostStore, type BeginApprovalDecisionInput, type ClaimActionInvocationsInput, type ClaimOutboxInput, type CreateActionInvocationInput, type DispatchActionInput, type DispatchActionResult, type EnterpriseEventEnvelope, type EnterpriseEventPublisher, type EventPayloadClassification, type ExecuteActionResult, type ExecuteInvocationOptions, type ExecutionAttestationRecord, type ExternalReconciliationRecord, type GovernancePlatformHostStore, type GovernedActionHost, type HitlDecisionEvidence, type ListActionInvocationsInput, MemoryPlatformHostStore, type MemoryPlatformHostTransactionProvider, type OutboxEventMetadata, type OutboxPlatformHostStore, type OutboxRecord, type OutboxRelayOptions, type OutboxRelayResult, type OutboxStatus, PLATFORM_HOST_CONTRACT_VERSION, type PendingAssetEvent, type PersistedActionApprovalDecision, type PlatformActionDispatcher, type PlatformActionWorkerCycleResult, type PlatformActionWorkerOptions, type PlatformHostAuthorization, type PlatformHostMutationTransaction, type PlatformHostOptions, type PlatformHostSqlClient, type PlatformHostSqlResult, type PlatformHostStore, type PolicyEvaluationRecord, type PolicyObligationRecord, PostgresPlatformHostStore, type PostgresPlatformHostTransactionContext, type PostgresPlatformHostTransactionProvider, type RecoverablePlatformHostStore, type SubmitActionInput, type SubmitActionResult, cloneOutboxRecord, createGovernedActionHost, createStoreBackedActionDispatcher, runOutboxRelayCycle, runPlatformActionWorker, runPlatformActionWorkerCycle, toEnterpriseEventEnvelope };
|
package/dist/index.d.ts
CHANGED
|
@@ -382,6 +382,8 @@ interface PlatformHostOptions<TDb> {
|
|
|
382
382
|
producerModuleVersion(actionId: ActionId, actionVersion: number): string;
|
|
383
383
|
classifyPayload(event: AssetEventEnvelope): EventPayloadClassification;
|
|
384
384
|
traceContext?(event: AssetEventEnvelope): Record<string, string> | undefined;
|
|
385
|
+
/** Host lifecycle events are excluded by default; opt in only after making their payload audit-safe. */
|
|
386
|
+
shouldPublish?(event: AssetEventEnvelope): boolean;
|
|
385
387
|
};
|
|
386
388
|
/** Optional vertical-owned evaluator. When absent, agent behavior is unchanged. */
|
|
387
389
|
hitlEvaluator?: AgentActionPolicyEvaluator;
|
|
@@ -433,8 +435,15 @@ interface GovernedActionHost {
|
|
|
433
435
|
|
|
434
436
|
declare function createGovernedActionHost<TDb>(options: PlatformHostOptions<TDb>): GovernedActionHost;
|
|
435
437
|
|
|
438
|
+
interface MemoryPlatformHostTransactionProvider<TDb> {
|
|
439
|
+
snapshot(db: TDb): TDb;
|
|
440
|
+
restore(db: TDb, snapshot: TDb): void;
|
|
441
|
+
}
|
|
436
442
|
declare class MemoryPlatformHostStore<TDb> implements RecoverablePlatformHostStore<TDb>, ApprovalPlatformHostStore<TDb>, GovernancePlatformHostStore<TDb>, OutboxPlatformHostStore<TDb> {
|
|
437
443
|
readonly db: TDb;
|
|
444
|
+
readonly transactionalOutbox: boolean;
|
|
445
|
+
transactionWithEvents?: <TResult>(run: (transaction: PlatformHostMutationTransaction<TDb>) => Promise<TResult>) => Promise<TResult>;
|
|
446
|
+
private transactionTail;
|
|
438
447
|
readonly invocations: ActionInvocationRecord[];
|
|
439
448
|
readonly policyEvaluations: PolicyEvaluationRecord[];
|
|
440
449
|
readonly adapterInvocations: AdapterInvocationRecord[];
|
|
@@ -443,8 +452,9 @@ declare class MemoryPlatformHostStore<TDb> implements RecoverablePlatformHostSto
|
|
|
443
452
|
readonly executionAttestations: ExecutionAttestationRecord[];
|
|
444
453
|
readonly externalReconciliations: ExternalReconciliationRecord[];
|
|
445
454
|
readonly outbox: OutboxRecord[];
|
|
446
|
-
constructor(db: TDb);
|
|
455
|
+
constructor(db: TDb, transactionProvider?: MemoryPlatformHostTransactionProvider<TDb>);
|
|
447
456
|
transaction<TResult>(run: (db: TDb) => Promise<TResult>): Promise<TResult>;
|
|
457
|
+
private runTransactionWithEvents;
|
|
448
458
|
createActionInvocation(input: CreateActionInvocationInput): Promise<ActionInvocationRecord>;
|
|
449
459
|
getActionInvocation(id: string, tenantId: string, spaceId: string): Promise<ActionInvocationRecord | undefined>;
|
|
450
460
|
updateActionInvocation(id: string, tenantId: string, spaceId: string, patch: Partial<Pick<ActionInvocationRecord, "status" | "result" | "error">>): Promise<void>;
|
|
@@ -593,4 +603,4 @@ declare function runPlatformActionWorkerCycle<TDb>(options: PlatformActionWorker
|
|
|
593
603
|
/** Poll until aborted. Each iteration is bounded and waits without busy-spinning. */
|
|
594
604
|
declare function runPlatformActionWorker<TDb>(options: PlatformActionWorkerOptions<TDb>): Promise<void>;
|
|
595
605
|
|
|
596
|
-
export { type ActionApprovalDecision, type ActionAuthorizationInput, type ActionExecutionAuthorizationInput, type ActionExecutionReason, type ActionInvocationRecord, type AdapterInvocationRecord, type AdapterInvocationStatus, type ApprovalDecisionTransitionResult, type ApprovalPlatformHostStore, type AtomicMutationPlatformHostStore, type BeginApprovalDecisionInput, type ClaimActionInvocationsInput, type ClaimOutboxInput, type CreateActionInvocationInput, type DispatchActionInput, type DispatchActionResult, type EnterpriseEventEnvelope, type EnterpriseEventPublisher, type EventPayloadClassification, type ExecuteActionResult, type ExecuteInvocationOptions, type ExecutionAttestationRecord, type ExternalReconciliationRecord, type GovernancePlatformHostStore, type GovernedActionHost, type HitlDecisionEvidence, type ListActionInvocationsInput, MemoryPlatformHostStore, type OutboxEventMetadata, type OutboxPlatformHostStore, type OutboxRecord, type OutboxRelayOptions, type OutboxRelayResult, type OutboxStatus, PLATFORM_HOST_CONTRACT_VERSION, type PendingAssetEvent, type PersistedActionApprovalDecision, type PlatformActionDispatcher, type PlatformActionWorkerCycleResult, type PlatformActionWorkerOptions, type PlatformHostAuthorization, type PlatformHostMutationTransaction, type PlatformHostOptions, type PlatformHostSqlClient, type PlatformHostSqlResult, type PlatformHostStore, type PolicyEvaluationRecord, type PolicyObligationRecord, PostgresPlatformHostStore, type PostgresPlatformHostTransactionContext, type PostgresPlatformHostTransactionProvider, type RecoverablePlatformHostStore, type SubmitActionInput, type SubmitActionResult, cloneOutboxRecord, createGovernedActionHost, createStoreBackedActionDispatcher, runOutboxRelayCycle, runPlatformActionWorker, runPlatformActionWorkerCycle, toEnterpriseEventEnvelope };
|
|
606
|
+
export { type ActionApprovalDecision, type ActionAuthorizationInput, type ActionExecutionAuthorizationInput, type ActionExecutionReason, type ActionInvocationRecord, type AdapterInvocationRecord, type AdapterInvocationStatus, type ApprovalDecisionTransitionResult, type ApprovalPlatformHostStore, type AtomicMutationPlatformHostStore, type BeginApprovalDecisionInput, type ClaimActionInvocationsInput, type ClaimOutboxInput, type CreateActionInvocationInput, type DispatchActionInput, type DispatchActionResult, type EnterpriseEventEnvelope, type EnterpriseEventPublisher, type EventPayloadClassification, type ExecuteActionResult, type ExecuteInvocationOptions, type ExecutionAttestationRecord, type ExternalReconciliationRecord, type GovernancePlatformHostStore, type GovernedActionHost, type HitlDecisionEvidence, type ListActionInvocationsInput, MemoryPlatformHostStore, type MemoryPlatformHostTransactionProvider, type OutboxEventMetadata, type OutboxPlatformHostStore, type OutboxRecord, type OutboxRelayOptions, type OutboxRelayResult, type OutboxStatus, PLATFORM_HOST_CONTRACT_VERSION, type PendingAssetEvent, type PersistedActionApprovalDecision, type PlatformActionDispatcher, type PlatformActionWorkerCycleResult, type PlatformActionWorkerOptions, type PlatformHostAuthorization, type PlatformHostMutationTransaction, type PlatformHostOptions, type PlatformHostSqlClient, type PlatformHostSqlResult, type PlatformHostStore, type PolicyEvaluationRecord, type PolicyObligationRecord, PostgresPlatformHostStore, type PostgresPlatformHostTransactionContext, type PostgresPlatformHostTransactionProvider, type RecoverablePlatformHostStore, type SubmitActionInput, type SubmitActionResult, cloneOutboxRecord, createGovernedActionHost, createStoreBackedActionDispatcher, runOutboxRelayCycle, runPlatformActionWorker, runPlatformActionWorkerCycle, toEnterpriseEventEnvelope };
|
package/dist/index.js
CHANGED
|
@@ -326,6 +326,9 @@ function createGovernedActionHost(options) {
|
|
|
326
326
|
let domainEvents = [];
|
|
327
327
|
try {
|
|
328
328
|
const runHandler = async (db, transaction) => {
|
|
329
|
+
if (options.outbox && !transaction?.appendEventWithOutbox) {
|
|
330
|
+
throw new Error("Outbox egress requires transactionWithEvents to provide appendEventWithOutbox before handler execution.");
|
|
331
|
+
}
|
|
329
332
|
const handlerResult = action.handler ? await action.handler(
|
|
330
333
|
{
|
|
331
334
|
actionInvocationId,
|
|
@@ -692,6 +695,12 @@ function createGovernedActionHost(options) {
|
|
|
692
695
|
...invocation.causationId ? { causationId: invocation.causationId } : {}
|
|
693
696
|
};
|
|
694
697
|
if (options.outbox) {
|
|
698
|
+
const hostLifecycleEvent = (/* @__PURE__ */ new Set(["AdapterInvocationStarted", "AdapterInvocationSucceeded", "AdapterInvocationFailed", "ComplianceBlocked"])).has(envelope.eventType);
|
|
699
|
+
const shouldPublish = options.outbox.shouldPublish?.(envelope) ?? !hostLifecycleEvent;
|
|
700
|
+
if (!shouldPublish) {
|
|
701
|
+
await (transaction ?? options.store).appendEvent(envelope);
|
|
702
|
+
return;
|
|
703
|
+
}
|
|
695
704
|
const traceContext = options.outbox.traceContext?.(envelope);
|
|
696
705
|
const metadata = {
|
|
697
706
|
producerModuleVersion: options.outbox.producerModuleVersion(invocation.actionId, invocation.actionVersion),
|
|
@@ -847,13 +856,13 @@ async function runOutboxRelayCycle(options) {
|
|
|
847
856
|
continue;
|
|
848
857
|
}
|
|
849
858
|
result.published += 1;
|
|
850
|
-
} catch
|
|
859
|
+
} catch {
|
|
851
860
|
const deadLetter = record.attemptCount >= maxAttempts;
|
|
852
861
|
try {
|
|
853
862
|
await options.store.markOutboxFailed({
|
|
854
863
|
id: record.id,
|
|
855
864
|
workerId: options.workerId,
|
|
856
|
-
error:
|
|
865
|
+
error: "Event publisher failed",
|
|
857
866
|
availableAt: new Date(now().getTime() + (options.retryDelayMs?.(record.attemptCount) ?? 1e3)),
|
|
858
867
|
deadLetter
|
|
859
868
|
});
|
|
@@ -874,10 +883,14 @@ function cloneOutboxRecord(record) {
|
|
|
874
883
|
|
|
875
884
|
// src/memory-store.ts
|
|
876
885
|
var MemoryPlatformHostStore = class {
|
|
877
|
-
constructor(db) {
|
|
886
|
+
constructor(db, transactionProvider) {
|
|
878
887
|
this.db = db;
|
|
888
|
+
this.transactionalOutbox = transactionProvider !== void 0;
|
|
889
|
+
if (transactionProvider) this.transactionWithEvents = (run) => this.runTransactionWithEvents(run, transactionProvider);
|
|
879
890
|
}
|
|
880
891
|
db;
|
|
892
|
+
transactionalOutbox;
|
|
893
|
+
transactionTail = Promise.resolve();
|
|
881
894
|
invocations = [];
|
|
882
895
|
policyEvaluations = [];
|
|
883
896
|
adapterInvocations = [];
|
|
@@ -889,6 +902,50 @@ var MemoryPlatformHostStore = class {
|
|
|
889
902
|
async transaction(run) {
|
|
890
903
|
return run(this.db);
|
|
891
904
|
}
|
|
905
|
+
async runTransactionWithEvents(run, transactionProvider) {
|
|
906
|
+
let release;
|
|
907
|
+
const previous = this.transactionTail;
|
|
908
|
+
this.transactionTail = new Promise((resolve) => {
|
|
909
|
+
release = resolve;
|
|
910
|
+
});
|
|
911
|
+
await previous;
|
|
912
|
+
let domainSnapshot;
|
|
913
|
+
let snapshotCreated = false;
|
|
914
|
+
try {
|
|
915
|
+
domainSnapshot = transactionProvider.snapshot(this.db);
|
|
916
|
+
snapshotCreated = true;
|
|
917
|
+
const pendingEvents = [];
|
|
918
|
+
const pendingUpdates = [];
|
|
919
|
+
const appendPending = async (event, metadata) => {
|
|
920
|
+
if (this.events.some((candidate) => candidate.id === event.id) || pendingEvents.some((candidate) => candidate.event.id === event.id)) return;
|
|
921
|
+
pendingEvents.push({ event, ...metadata ? { metadata } : {} });
|
|
922
|
+
};
|
|
923
|
+
const result = await run({
|
|
924
|
+
db: this.db,
|
|
925
|
+
appendEvent: (event) => appendPending(event),
|
|
926
|
+
appendEventWithOutbox: (event, metadata) => appendPending(event, metadata),
|
|
927
|
+
nextEventSequence: async (tenantId, spaceId) => (await this.listEvents(tenantId, spaceId)).length + pendingEvents.filter((candidate) => candidate.event.tenantId === tenantId && candidate.event.spaceId === spaceId).length + 1,
|
|
928
|
+
listEvents: async (tenantId, spaceId) => [...await this.listEvents(tenantId, spaceId), ...pendingEvents.map((candidate) => candidate.event).filter((event) => event.tenantId === tenantId && event.spaceId === spaceId)],
|
|
929
|
+
updateActionInvocation: async (id, tenantId, spaceId, patch) => {
|
|
930
|
+
pendingUpdates.push({ id, tenantId, spaceId, patch });
|
|
931
|
+
}
|
|
932
|
+
});
|
|
933
|
+
for (const update of pendingUpdates) {
|
|
934
|
+
if (!await this.getActionInvocation(update.id, update.tenantId, update.spaceId)) throw new Error(`ActionInvocation not found: ${update.id}`);
|
|
935
|
+
}
|
|
936
|
+
for (const pending of pendingEvents) {
|
|
937
|
+
if (pending.metadata) await this.appendEventWithOutbox(pending.event, pending.metadata);
|
|
938
|
+
else await this.appendEvent(pending.event);
|
|
939
|
+
}
|
|
940
|
+
for (const update of pendingUpdates) await this.updateActionInvocation(update.id, update.tenantId, update.spaceId, update.patch);
|
|
941
|
+
return result;
|
|
942
|
+
} catch (error) {
|
|
943
|
+
if (snapshotCreated) transactionProvider.restore(this.db, domainSnapshot);
|
|
944
|
+
throw error;
|
|
945
|
+
} finally {
|
|
946
|
+
release();
|
|
947
|
+
}
|
|
948
|
+
}
|
|
892
949
|
async createActionInvocation(input) {
|
|
893
950
|
if (input.idempotencyKey) {
|
|
894
951
|
const existing = this.invocations.find(
|