@voltro/workflow 0.86.0 → 0.88.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.
Files changed (99) hide show
  1. package/CHANGELOG.md +5484 -0
  2. package/THIRD-PARTY-NOTICES.md +3 -227
  3. package/dist/admission.js +1 -2
  4. package/dist/admissionDrainer.js +5 -3
  5. package/dist/admissionGate.js +1 -2
  6. package/dist/admissionStore.js +1 -2
  7. package/dist/admissionSubmission.js +1 -2
  8. package/dist/admissionTables.js +4 -4
  9. package/dist/admissionTransaction.js +1 -2
  10. package/dist/awaitEvent.js +1 -2
  11. package/dist/budgetHold.js +1 -2
  12. package/dist/cancelOnPlan.js +1 -2
  13. package/dist/cancelOnSweep.js +1 -2
  14. package/dist/cancelPendingStart.js +1 -2
  15. package/dist/cluster.d.ts +111 -27
  16. package/dist/cluster.js +12 -8
  17. package/dist/clusterCron.js +18 -11
  18. package/dist/clusterDiagnostics.js +1 -2
  19. package/dist/clusterDiagnosticsSql.js +1 -2
  20. package/dist/clusterLayer.js +105 -71
  21. package/dist/clusterMigrationGate.js +1 -2
  22. package/dist/clusterRunnerLayer.js +27 -18
  23. package/dist/clusterShardGroups.js +32 -0
  24. package/dist/clusterTestSuite.d.ts +45 -2
  25. package/dist/clusterTestSuite.js +225 -197
  26. package/dist/controlMonitor.js +1 -2
  27. package/dist/controlRequest.js +1 -2
  28. package/dist/executionRefusal.js +1 -2
  29. package/dist/failureHandoff.js +1 -2
  30. package/dist/failureMessage.js +1 -2
  31. package/dist/failureRecovery.js +1 -2
  32. package/dist/failureReportStore.js +1 -2
  33. package/dist/flowControl.js +1 -2
  34. package/dist/forwardStartReceipts.js +1 -2
  35. package/dist/inMemoryLayer.js +1 -2
  36. package/dist/inMemoryRecorder.js +1 -2
  37. package/dist/index.d.ts +50 -23
  38. package/dist/index.js +24 -23
  39. package/dist/inspectWorkflow.js +2 -3
  40. package/dist/journalEncryption.js +1 -2
  41. package/dist/journalRoutingGuard.js +49 -0
  42. package/dist/journalRoutingLayout.js +46 -0
  43. package/dist/journalRoutingLock.js +38 -0
  44. package/dist/journalRoutingMaintenance.js +23 -0
  45. package/dist/journalRoutingMessageStorage.js +31 -0
  46. package/dist/journalRoutingNamespace.js +22 -0
  47. package/dist/journalRoutingRuntime.js +32 -0
  48. package/dist/journalRoutingSharding.js +27 -0
  49. package/dist/journalRoutingState.js +92 -0
  50. package/dist/journalRoutingTable.js +10 -0
  51. package/dist/journalRoutingTransaction.js +15 -0
  52. package/dist/messages.js +1 -2
  53. package/dist/nondeterminism.js +1 -2
  54. package/dist/parentClosure.js +1 -2
  55. package/dist/parentClosureRecovery.js +1 -2
  56. package/dist/pendingSubmission.js +1 -2
  57. package/dist/prepareSubmissionDispatch.js +1 -2
  58. package/dist/preparedExecution.js +1 -2
  59. package/dist/primitives.js +1 -2
  60. package/dist/queuedCancellationRequest.js +1 -2
  61. package/dist/queuedControl.js +1 -2
  62. package/dist/recorder.js +1 -2
  63. package/dist/residentExecutionEvidence.js +1 -2
  64. package/dist/retryPolicy.js +1 -2
  65. package/dist/runEventsTable.js +1 -2
  66. package/dist/runGeneration.js +1 -2
  67. package/dist/runRecording.js +1 -2
  68. package/dist/runStepsTable.js +1 -2
  69. package/dist/runnerStorageGuard.js +1 -2
  70. package/dist/runsTable.js +1 -2
  71. package/dist/scheduleDeclaration.js +1 -2
  72. package/dist/signalHint.js +1 -2
  73. package/dist/signals.js +1 -2
  74. package/dist/signalsSuspending.js +1 -2
  75. package/dist/sqliteWorkflowOwnership.js +1 -2
  76. package/dist/stalenessSweep.js +1 -2
  77. package/dist/startContextsTable.js +1 -2
  78. package/dist/startReceipt.js +1 -2
  79. package/dist/submissionRecovery.js +1 -2
  80. package/dist/submissionRejection.js +1 -2
  81. package/dist/submissionRetry.js +1 -2
  82. package/dist/suspensionUnavailable.js +1 -2
  83. package/dist/updates.js +1 -2
  84. package/dist/watermarkTable.js +1 -2
  85. package/dist/webCrypto.js +4 -17
  86. package/dist/workflowDelivery.js +1 -2
  87. package/dist/workflowExecutorRouting.js +32 -0
  88. package/dist/workflowJournal.js +1 -2
  89. package/dist/workflowJournalReset.js +1 -2
  90. package/dist/workflowReadSelections.js +1 -2
  91. package/dist/workflowRestartDispatch.js +30 -25
  92. package/dist/workflowRestartObservation.js +1 -2
  93. package/dist/workflowRestartPreparation.js +1 -2
  94. package/dist/workflowRestartReservation.js +158 -157
  95. package/dist/workflowResumeDispatch.js +18 -18
  96. package/dist/workflowRuntimeReadiness.js +11 -0
  97. package/dist/workflowShardRelocation.js +57 -0
  98. package/dist/workflowShardRelocationSql.js +71 -0
  99. package/package.json +5 -11
@@ -0,0 +1,38 @@
1
+ import { Effect as e } from "effect";
2
+ import { SqlClient as t } from "effect/sql";
3
+ import { fnv1a64 as n } from "@voltro/database/sql";
4
+ // src/journalRoutingLock.ts
5
+ var r = (r) => e.gen(function* () {
6
+ let i = r.namespace, a = r.mode, o = r.timeoutMs ?? 3e4;
7
+ if (!i || i.length > 256 || !["shared", "exclusive"].includes(a) || !Number.isSafeInteger(o) || o < 1 || o > 3e5) return yield* e.fail(/* @__PURE__ */ Error("Invalid journal routing lock options"));
8
+ let s = yield* t.SqlClient, c = s.onDialectOrElse({
9
+ pg: () => "pg",
10
+ mssql: () => "mssql",
11
+ orElse: () => "unsupported"
12
+ });
13
+ if (c === "unsupported") return yield* e.fail(/* @__PURE__ */ Error("Journal routing locks require PostgreSQL or SQL Server"));
14
+ let l = (n("voltro:journal-routing:" + i) & 9223372036854775807n).toString(), u = "voltro-journal-routing-" + l, d = yield* s.reserve, f = a === "shared" ? "_shared" : "", p = c === "pg" ? `SELECT pg_try_advisory_lock${f}(${l}::bigint)` : `DECLARE @res int; EXEC @res = sp_getapplock @Resource = '${u}', @LockMode = '${a === "shared" ? "Shared" : "Exclusive"}', @LockOwner = 'Session', @LockTimeout = 0; SELECT @res`, m = c === "pg" ? `SELECT pg_advisory_unlock${f}(${l}::bigint)` : `DECLARE @res int; EXEC @res = sp_releaseapplock @Resource = '${u}', @LockOwner = 'Session'; SELECT @res`, h = performance.now(), g = e.gen(function* () {
15
+ for (;;) {
16
+ let t = (yield* d.executeValues(p, []))[0]?.[0];
17
+ if (c === "pg" ? t === !0 || t === "t" || t === 1 : typeof t == "number" && t >= 0) return;
18
+ if (c === "mssql" && t !== -1) return yield* e.fail(/* @__PURE__ */ Error("Journal routing application lock failed"));
19
+ let n = o - (performance.now() - h);
20
+ if (n <= 0) return yield* e.fail(/* @__PURE__ */ Error("Journal routing lock acquisition timed out"));
21
+ yield* e.sleep(Math.min(n, 100));
22
+ }
23
+ });
24
+ yield* e.acquireRelease(g, () => d.executeValues(m, []).pipe(e.flatMap((t) => {
25
+ let n = t[0]?.[0];
26
+ return (c === "pg" ? n === !0 || n === "t" || n === 1 : typeof n == "number" && n >= 0) ? e.void : e.die(/* @__PURE__ */ Error("Journal routing lock was lost before release"));
27
+ }), e.orDie));
28
+ let _ = c === "pg" ? `SELECT EXISTS (SELECT 1 FROM pg_locks WHERE locktype = 'advisory' AND pid = pg_backend_pid() AND granted AND classid = (${l}::bigint >> 32)::oid AND objid = (${l}::bigint & 4294967295)::oid AND objsubid = 1 AND mode = '${a === "shared" ? "ShareLock" : "ExclusiveLock"}')` : `SELECT APPLOCK_MODE('public', '${u}', 'Session')`;
29
+ return {
30
+ connection: d,
31
+ dialect: c,
32
+ verify: d.executeValues(_, []).pipe(e.flatMap((t) => {
33
+ let n = t[0]?.[0];
34
+ return (c === "pg" ? n === !0 || n === "t" || n === 1 : n === (a === "shared" ? "Shared" : "Exclusive")) ? e.void : e.fail(/* @__PURE__ */ Error("Journal routing lock ownership was lost"));
35
+ }))
36
+ };
37
+ });
38
+ export { r as acquireJournalRoutingLock };
@@ -0,0 +1,23 @@
1
+ import { withJournalRoutingTransaction as e } from "./journalRoutingTransaction.js";
2
+ import { acquireJournalRoutingLock as t } from "./journalRoutingLock.js";
3
+ import { JournalRoutingMaintenance as n } from "./workflowShardRelocationSql.js";
4
+ import { Effect as r, Option as i } from "effect";
5
+ import { SqlClient as a } from "effect/sql";
6
+ // src/journalRoutingMaintenance.ts
7
+ var o = (o, s = 3e4) => r.gen(function* () {
8
+ let c = yield* a.SqlClient;
9
+ return c.onDialectOrElse({
10
+ pg: () => !0,
11
+ orElse: () => !1
12
+ }) ? n.of({ exclusive: (n) => r.scoped(r.gen(function* () {
13
+ let a = yield* r.serviceOption(c.transactionService);
14
+ if (i.isSome(a)) return yield* r.fail(/* @__PURE__ */ Error("Journal maintenance cannot enter an ambient transaction"));
15
+ let { connection: l } = yield* t({
16
+ namespace: o,
17
+ mode: "exclusive",
18
+ timeoutMs: s
19
+ });
20
+ return yield* e(c, l, n);
21
+ })).pipe(r.provideService(a.SqlClient, c)) }) : yield* r.fail(/* @__PURE__ */ Error("Pinned journal maintenance currently requires PostgreSQL"));
22
+ });
23
+ export { o as makePostgresJournalRoutingMaintenance };
@@ -0,0 +1,31 @@
1
+ import { protectJournalRoutingEffect as e } from "./journalRoutingGuard.js";
2
+ import { Effect as t } from "effect";
3
+ import { MessageStorage as n } from "effect/cluster";
4
+ import { PersistenceError as r } from "effect/cluster/ClusterError";
5
+ // src/journalRoutingMessageStorage.ts
6
+ var i = (i, a) => {
7
+ let o = (e) => t.gen(function* () {
8
+ return yield* yield* a.run(t.exit(e)).pipe(t.mapError((e) => new r({ cause: e })));
9
+ });
10
+ return n.MessageStorage.of({
11
+ saveRequest: (e) => o(t.suspend(() => i.saveRequest(e))),
12
+ saveEnvelope: (e) => o(t.suspend(() => i.saveEnvelope(e))),
13
+ saveReply: (e) => o(t.suspend(() => i.saveReply(e))),
14
+ clearReplies: (e) => o(t.suspend(() => i.clearReplies(e))),
15
+ repliesFor: (e) => o(t.suspend(() => i.repliesFor(e))),
16
+ repliesForUnfiltered: (e) => o(t.suspend(() => i.repliesForUnfiltered(e))),
17
+ requestIdForPrimaryKey: (e) => o(t.suspend(() => i.requestIdForPrimaryKey(e))),
18
+ unprocessedMessages: (e) => o(t.suspend(() => i.unprocessedMessages(e))),
19
+ unprocessedMessagesById: (e) => o(t.suspend(() => i.unprocessedMessagesById(e))),
20
+ resetShards: (e) => o(t.suspend(() => i.resetShards(e))),
21
+ resetRequests: (e) => o(t.suspend(() => i.resetRequests(e))),
22
+ resetAddresses: (e) => o(t.suspend(() => i.resetAddresses(e))),
23
+ withTransaction: (t) => e(a, i.withTransaction(t)),
24
+ resetAddress: (e) => o(t.suspend(() => i.resetAddress(e))),
25
+ clearAddress: (e) => o(t.suspend(() => i.clearAddress(e))),
26
+ registerReplyHandler: (e) => i.registerReplyHandler(e),
27
+ unregisterReplyHandler: (e) => i.unregisterReplyHandler(e),
28
+ unregisterShardReplyHandlers: (e) => i.unregisterShardReplyHandlers(e)
29
+ });
30
+ };
31
+ export { i as guardJournalMessageStorage };
@@ -0,0 +1,22 @@
1
+ import { workflowJournalRoutingTable as e } from "./journalRoutingTable.js";
2
+ import { Effect as t } from "effect";
3
+ import { SqlClient as n } from "effect/sql";
4
+ // src/journalRoutingNamespace.ts
5
+ var r = t.gen(function* () {
6
+ let r = (yield* n.SqlClient).withoutTransforms();
7
+ if (!r.onDialectOrElse({
8
+ pg: () => !0,
9
+ orElse: () => !1
10
+ })) return yield* t.fail(/* @__PURE__ */ Error("Journal namespace resolution requires PostgreSQL"));
11
+ let i = yield* r`
12
+ SELECT n.nspname AS schema_name, current_schema() AS active_schema, c.relkind AS kind,
13
+ format('%I.%I', n.nspname, ${e.tableName}::text) AS routing_table
14
+ FROM pg_class c JOIN pg_namespace n ON n.oid = c.relnamespace
15
+ WHERE c.oid = to_regclass('cluster_messages')`, a = i[0];
16
+ return i.length !== 1 || !a || a.kind !== "r" || a.schema_name !== a.active_schema ? yield* t.fail(/* @__PURE__ */ Error("Journal table must exist in the active PostgreSQL schema without search-path fallback")) : Object.freeze({
17
+ namespace: `pg:${a.schema_name}:cluster_messages`,
18
+ schema: a.schema_name,
19
+ routingTable: r.literal(a.routing_table)
20
+ });
21
+ }), i = r.pipe(t.map((e) => e.namespace));
22
+ export { r as resolvePostgresJournalLocation, i as resolvePostgresJournalNamespace };
@@ -0,0 +1,32 @@
1
+ import { journalRoutingLayout as e, journalWorkflowGroup as t } from "./journalRoutingLayout.js";
2
+ import { Context as n } from "effect";
3
+ import { ClusterSchema as r } from "effect/cluster";
4
+ // src/journalRoutingRuntime.ts
5
+ var i = class extends n.Service()("@voltro/workflow/JournalRoutingLayout") {}, a = (e, i) => {
6
+ let a = n.add(e.annotations, r.ShardGroup, () => t(i, e._tag));
7
+ return new Proxy(e, { get(e, t, n) {
8
+ return t === "annotations" ? a : Reflect.get(e, t, n);
9
+ } });
10
+ }, o = (t, n) => (e(n), {
11
+ ...t,
12
+ register: (e, r) => t.register(a(e, n), r),
13
+ execute: (e, r) => t.execute(a(e, n), r),
14
+ poll: (e, r) => t.poll(a(e, n), r),
15
+ interrupt: (e, r) => t.interrupt(a(e, n), r),
16
+ resume: (e, r) => t.resume(a(e, n), r),
17
+ scheduleClock: (e, r) => t.scheduleClock(a(e, n), r)
18
+ }), s = (n, i) => {
19
+ let a = e(i), o = (e) => e.startsWith("Workflow/") && !e.startsWith("Workflow/-/") ? t(i, e.slice(9)) : e.startsWith("ClusterCron/") ? a.cronGroup : void 0;
20
+ return {
21
+ ...n,
22
+ makeClient: (e) => {
23
+ let t = o(e.type);
24
+ return n.makeClient(t === void 0 ? e : e.annotate(r.ShardGroup, () => t));
25
+ },
26
+ registerEntity: (e, t, i) => {
27
+ let a = o(e.type);
28
+ return n.registerEntity(a === void 0 ? e : e.annotate(r.ShardGroup, () => a), t, i);
29
+ }
30
+ };
31
+ };
32
+ export { i as JournalRoutingLayout, a as routeJournalWorkflow, s as withJournalEntityRouting, o as withJournalWorkflowRouting };
@@ -0,0 +1,27 @@
1
+ import { protectJournalRoutingEffect as e } from "./journalRoutingGuard.js";
2
+ import { Effect as t, Stream as n } from "effect";
3
+ import { Rpc as r, RpcSchema as i } from "effect/rpc";
4
+ // src/journalRoutingSharding.ts
5
+ var a = (a, o) => {
6
+ let s = (i) => {
7
+ if (typeof i == "object" && i && r.isWrapper(i)) return {
8
+ ...i,
9
+ value: s(i.value)
10
+ };
11
+ if (t.isEffect(i)) return e(o, i);
12
+ if (n.isStream(i)) {
13
+ let r = i;
14
+ return n.unwrap(t.map(e(o, n.toPull(r)), (r) => n.fromPull(t.succeed(e(o, r)))));
15
+ }
16
+ throw Error("Cluster handler must return an Effect, Stream or RPC wrapper");
17
+ };
18
+ return {
19
+ ...a,
20
+ registerEntity: (r, c, l) => e(o, t.suspend(() => a.registerEntity(r, c.pipe(t.map((e) => new Proxy(e, { get(e, a, c) {
21
+ let l = Reflect.get(e, a, c), u = typeof a == "string" ? r.protocol.requests.get(a) : void 0;
22
+ return !u || typeof l != "function" ? l : (...r) => o.isClosed() ? i.isStreamSchema(u.successSchema) ? n.fromEffect(t.interrupt) : t.interrupt : s(Reflect.apply(l, e, r));
23
+ } }))), l))),
24
+ registerSingleton: (n, r, i) => e(o, t.suspend(() => a.registerSingleton(n, e(o, r), i)))
25
+ };
26
+ };
27
+ export { a as withJournalRoutingGuard };
@@ -0,0 +1,92 @@
1
+ import { makeJournalRoutingGuard as e } from "./journalRoutingGuard.js";
2
+ import { workflowJournalRoutingRowId as t, workflowJournalRoutingTable as n } from "./journalRoutingTable.js";
3
+ import { journalRoutingLayout as r, journalRoutingTransitions as i } from "./journalRoutingLayout.js";
4
+ import { withJournalRoutingTransaction as a } from "./journalRoutingTransaction.js";
5
+ import { resolvePostgresJournalLocation as o, resolvePostgresJournalNamespace as s } from "./journalRoutingNamespace.js";
6
+ import { acquireJournalRoutingLock as c } from "./journalRoutingLock.js";
7
+ import { JournalRoutingMaintenance as l, relocateWorkflowJournal as u } from "./workflowShardRelocationSql.js";
8
+ import { makePostgresJournalRoutingMaintenance as d } from "./journalRoutingMaintenance.js";
9
+ import { Effect as f, Option as p } from "effect";
10
+ import { SqlClient as m } from "effect/sql";
11
+ // src/journalRoutingState.ts
12
+ var h = (e, t) => f.gen(function* () {
13
+ let r = yield* e`SELECT c.relkind AS kind
14
+ FROM pg_class c JOIN pg_namespace n ON n.oid = c.relnamespace
15
+ WHERE n.nspname = ${t} AND c.relname = ${n.tableName}`;
16
+ return r.length === 0 ? !1 : r.length !== 1 || r[0]?.kind !== "r" ? yield* f.fail(/* @__PURE__ */ Error("Journal routing metadata must be a table in the journal schema")) : !0;
17
+ }), g = (e) => {
18
+ if (!Number.isSafeInteger(e.generation) || e.generation < 0 || e.generation >= 2 ** 53 - 1 || !/^[a-z][a-z0-9._-]{0,63}$/.test(e.layout)) throw Error("Invalid journal routing state");
19
+ return r(e.layout), Object.freeze({
20
+ generation: e.generation,
21
+ layout: e.layout
22
+ });
23
+ }, _ = (e) => f.gen(function* () {
24
+ let n = yield* f.sync(() => g(e.expected)), r = yield* f.sync(() => g({
25
+ generation: n.generation + 1,
26
+ layout: e.nextLayout
27
+ })), a = yield* f.sync(() => i(n.layout, r.layout)), c = yield* m.SqlClient, p = c.withoutTransforms(), _ = yield* s, v = yield* d(_), y = l.of({ exclusive: (e) => v.exclusive(f.gen(function* () {
28
+ let i = yield* o;
29
+ if (i.namespace !== _) return yield* f.fail(/* @__PURE__ */ Error("Journal namespace changed during maintenance acquisition"));
30
+ if (yield* p`SELECT pg_advisory_xact_lock(6322741009312602::bigint)`, !(yield* h(p, i.schema))) return yield* f.fail(/* @__PURE__ */ Error("Workflow journal routing table is missing; apply the app schema first"));
31
+ yield* p`INSERT INTO ${i.routingTable} (id, namespace, generation, layout, relocation)
32
+ VALUES (${t(_)}, ${_}, 0, 'default', '[]') ON CONFLICT (namespace) DO NOTHING`;
33
+ let [s] = yield* p`
34
+ SELECT generation, layout FROM ${i.routingTable} WHERE namespace = ${_} FOR UPDATE`;
35
+ if (!s || String(s.generation) !== String(n.generation) || s.layout !== n.layout) return yield* f.fail(/* @__PURE__ */ Error("Journal routing generation changed; transition refused"));
36
+ let c = yield* e;
37
+ return yield* p`UPDATE ${i.routingTable} SET generation = ${r.generation}, layout = ${r.layout},
38
+ relocation = ${JSON.stringify(a)} WHERE namespace = ${_}`, c;
39
+ }).pipe(f.provideService(m.SqlClient, c))) });
40
+ return {
41
+ ...yield* u(a).pipe(f.provideService(l, y)),
42
+ state: r
43
+ };
44
+ }), v = () => f.gen(function* () {
45
+ let e = yield* m.SqlClient;
46
+ if (p.isSome(yield* f.serviceOption(e.transactionService))) return yield* f.fail(/* @__PURE__ */ Error("Journal routing admission cannot enter an ambient transaction"));
47
+ if (!e.onDialectOrElse({
48
+ pg: () => !0,
49
+ orElse: () => !1
50
+ })) return yield* f.fail(/* @__PURE__ */ Error("Journal routing generation admission currently requires PostgreSQL"));
51
+ let t = yield* s, n = yield* c({
52
+ namespace: t,
53
+ mode: "shared"
54
+ }), r = yield* a(e, n.connection, f.gen(function* () {
55
+ let n = yield* o;
56
+ if (n.namespace !== t) return yield* f.fail(/* @__PURE__ */ Error("Journal namespace changed during runtime admission"));
57
+ if (!(yield* h(e, n.schema))) return {
58
+ generation: 0,
59
+ layout: "default"
60
+ };
61
+ let r = yield* e`
62
+ SELECT generation, layout FROM ${n.routingTable} WHERE namespace = ${t}`;
63
+ return r.length === 0 ? {
64
+ generation: 0,
65
+ layout: "default"
66
+ } : r.length === 1 ? yield* f.sync(() => g({
67
+ generation: Number(r[0]?.generation),
68
+ layout: String(r[0]?.layout)
69
+ })) : yield* f.fail(/* @__PURE__ */ Error("Journal routing metadata has duplicate namespace rows"));
70
+ }));
71
+ return {
72
+ ...n,
73
+ state: r,
74
+ namespace: t
75
+ };
76
+ }), y = f.gen(function* () {
77
+ let e = yield* v();
78
+ return {
79
+ namespace: e.namespace,
80
+ state: e.state
81
+ };
82
+ }), b = (e) => f.gen(function* () {
83
+ let t = yield* f.sync(() => g(e)), n = yield* v();
84
+ return n.state.generation !== t.generation || n.state.layout !== t.layout ? yield* f.fail(/* @__PURE__ */ Error("Journal routing generation does not match this runtime")) : n;
85
+ }), x = (t) => f.gen(function* () {
86
+ let n = yield* b(t), r = yield* e({ verify: n.verify });
87
+ return {
88
+ ...n,
89
+ ...r
90
+ };
91
+ });
92
+ export { x as acquireGuardedPostgresJournalRoutingAdmission, b as acquirePostgresJournalRoutingAdmission, g as captureJournalRoutingState, y as readPostgresJournalRoutingState, _ as transitionPostgresJournalRouting };
@@ -0,0 +1,10 @@
1
+ import { bigint as e, derivedRowId as t, id as n, table as r, text as i } from "@voltro/database";
2
+ // src/journalRoutingTable.ts
3
+ var a = r("_voltro_workflow_journal_routing", {
4
+ id: n({ prefix: "wfjr" }),
5
+ namespace: i(),
6
+ generation: e(),
7
+ layout: i(),
8
+ relocation: i()
9
+ }).unique(["namespace"]).nonReactive(), o = (e) => t("wfjr", e);
10
+ export { o as workflowJournalRoutingRowId, a as workflowJournalRoutingTable };
@@ -0,0 +1,15 @@
1
+ import { Effect as e } from "effect";
2
+ import { SqlClient as t } from "effect/sql";
3
+ // src/journalRoutingTransaction.ts
4
+ var n = (n, r, i) => t.makeWithTransaction({
5
+ transactionService: n.transactionService,
6
+ spanAttributes: [],
7
+ acquireConnection: () => e.succeed(r),
8
+ begin: (t) => t.executeUnprepared("BEGIN", [], void 0).pipe(e.asVoid),
9
+ commit: (t) => t.executeUnprepared("COMMIT", [], void 0).pipe(e.asVoid),
10
+ rollback: (t) => t.executeUnprepared("ROLLBACK", [], void 0).pipe(e.asVoid),
11
+ savepoint: (t, n) => t.executeUnprepared(`SAVEPOINT voltro_routing_${n}`, [], void 0).pipe(e.asVoid),
12
+ rollbackSavepoint: (t, n) => t.executeUnprepared(`ROLLBACK TO SAVEPOINT voltro_routing_${n}`, [], void 0).pipe(e.asVoid),
13
+ releaseSavepoint: (t, n) => t.executeUnprepared(`RELEASE SAVEPOINT voltro_routing_${n}`, [], void 0).pipe(e.asVoid)
14
+ })(i);
15
+ export { n as withJournalRoutingTransaction };
package/dist/messages.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { openEventPayload as e } from "./journalEncryption.js";
2
2
  import { eq as t } from "@voltro/database";
3
- //#region src/messages.ts
3
+ // src/messages.ts
4
4
  var n = (e) => new Promise((t) => setTimeout(t, e)), r = () => {
5
5
  let e = globalThis.crypto;
6
6
  return typeof e?.randomUUID == "function" ? e.randomUUID() : `${Date.now().toString(36)}${Math.random().toString(36).slice(2)}`;
@@ -88,5 +88,4 @@ var n = (e) => new Promise((t) => setTimeout(t, e)), r = () => {
88
88
  await n(f);
89
89
  }
90
90
  };
91
- //#endregion
92
91
  export { o as WorkflowMessageNotRecorded, i as makeWorkflowUpdateId, a as resolveWorkflowMessageRun, s as sendWorkflowSignal, c as sendWorkflowUpdate };
@@ -1,6 +1,6 @@
1
1
  import { CurrentWorkflowRunId as e, WorkflowRunRecorder as t } from "./recorder.js";
2
2
  import { Context as n, Effect as r } from "effect";
3
- //#region src/nondeterminism.ts
3
+ // src/nondeterminism.ts
4
4
  var i = (e) => {
5
5
  let t = /* @__PURE__ */ new Map();
6
6
  for (let n of e) t.set(n.stepName, (t.get(n.stepName) ?? 0) + 1);
@@ -47,5 +47,4 @@ var i = (e) => {
47
47
  payload: o(e)
48
48
  }).then(() => void 0).catch(() => void 0));
49
49
  });
50
- //#endregion
51
50
  export { a as CurrentWorkflowReplayShape, i as makeReplayShapeTracker, o as nondeterminismEventPayload, s as reportNondeterminism };
@@ -2,7 +2,7 @@ import { acceptWorkflowControlInTransaction as e, hasUnsettledParentClosureContr
2
2
  import { cancelSuspendedWorkflowRunInTransaction as r } from "./runGeneration.js";
3
3
  import { Schema as i } from "effect";
4
4
  import { and as a, derivedRowId as o, eq as s, gt as c } from "@voltro/database";
5
- //#region src/parentClosure.ts
5
+ // src/parentClosure.ts
6
6
  var l = "_voltro_workflow_parent_closures", u = i.NonEmptyString, d = i.Struct({
7
7
  id: u,
8
8
  runId: u,
@@ -137,5 +137,4 @@ var l = "_voltro_workflow_parent_closures", u = i.NonEmptyString, d = i.Struct({
137
137
  wrapped: y
138
138
  };
139
139
  };
140
- //#endregion
141
140
  export { p as stageParentClosureAtChildEntry, m as stageWorkflowParentClosureInTransaction };
@@ -1,6 +1,6 @@
1
1
  import { stageWorkflowParentClosureInTransaction as e } from "./parentClosure.js";
2
2
  import { and as t, eq as n, gt as r, isNull as i } from "@voltro/database";
3
- //#region src/parentClosureRecovery.ts
3
+ // src/parentClosureRecovery.ts
4
4
  var a = "_voltro_workflow_parent_closures", o = /* @__PURE__ */ new WeakMap(), s = async (s, c, l) => {
5
5
  let u = o.get(s), d = await s.store.query({
6
6
  table: a,
@@ -50,5 +50,4 @@ var a = "_voltro_workflow_parent_closures", o = /* @__PURE__ */ new WeakMap(), s
50
50
  examined: d.length > 0
51
51
  });
52
52
  };
53
- //#endregion
54
53
  export { s as recoverWorkflowParentClosures };
@@ -3,7 +3,7 @@ import { persistReservedSubmission as t, readAdmissionSubmission as n, reserveAd
3
3
  import { bindWorkflowStartReceipts as i } from "./startReceipt.js";
4
4
  import { PENDING_TABLE as a, toPendingIntent as o } from "./admissionStore.js";
5
5
  import { eq as s } from "@voltro/database";
6
- //#region src/pendingSubmission.ts
6
+ // src/pendingSubmission.ts
7
7
  var c = async (e, r) => {
8
8
  if (new Set(r.intentIds).size !== r.intentIds.length) throw Error("Admitted transfer requires distinct pending identities");
9
9
  let c = await n(e, r.id);
@@ -81,5 +81,4 @@ var c = async (e, r) => {
81
81
  }
82
82
  };
83
83
  };
84
- //#endregion
85
84
  export { c as takeAdmittedSubmissionInTransaction, l as takePendingAdmissionSubmission, u as takePendingAdmissionSubmissionInTransaction };
@@ -1,5 +1,5 @@
1
1
  import { prepareAdmissionSubmissionExecutionInTransaction as e, readAdmissionSubmission as t } from "./admissionSubmission.js";
2
- //#region src/prepareSubmissionDispatch.ts
2
+ // src/prepareSubmissionDispatch.ts
3
3
  var n = async (n, r, i) => {
4
4
  let a = await n.transaction((e) => t(e, r.id));
5
5
  if (a === void 0 || a.workflowName !== r.workflowName || a.tenantId !== r.tenantId || a.ledgerId !== r.ledgerId) throw Error("Submission dispatch lost its resident owner");
@@ -13,5 +13,4 @@ var n = async (n, r, i) => {
13
13
  if (s.preparedExecutionId === null) throw Error("Submission preparation returned no execution identity");
14
14
  return s.preparedExecutionId;
15
15
  };
16
- //#endregion
17
16
  export { n as prepareSubmissionDispatch };
@@ -1,5 +1,5 @@
1
1
  import { Effect as e } from "effect";
2
- //#region src/preparedExecution.ts
2
+ // src/preparedExecution.ts
3
3
  var t = Symbol.for("@voltro/workflow/PreparedExecution"), n = (e, n) => {
4
4
  Object.defineProperty(e, t, {
5
5
  value: n,
@@ -10,5 +10,4 @@ var t = Symbol.for("@voltro/workflow/PreparedExecution"), n = (e, n) => {
10
10
  let o = n[t];
11
11
  return typeof o == "function" ? o(r, i, a?.discard ?? !0) : e.die(/* @__PURE__ */ Error("Workflow definition has no prepared-execution capability"));
12
12
  });
13
- //#endregion
14
13
  export { n as attachPreparedWorkflowExecution, i as executePreparedWorkflow, r as hasPreparedWorkflowExecution };
@@ -10,7 +10,7 @@ import { Activity as A, Activity as j, DurableClock as M, DurableClock as N, Dur
10
10
  import { RateLimiter as L } from "effect/persistence";
11
11
  import { Cause as R, Duration as z, Effect as B, Effectable as V, Schema as H } from "effect";
12
12
  import { attachWorkflowAccess as U, resolveWorkflowAccess as W } from "@voltro/protocol";
13
- //#region src/primitives.ts
13
+ // src/primitives.ts
14
14
  var G = Symbol.for("voltro.workflow.workerLayer"), K = Symbol.for("voltro.workflow.version"), q = "__voltroWorkflowMessages", J = "__voltroWorkflowFlowControl", Y = (e) => typeof e == "object" && !!e && e[G] === !0, X = (e) => (typeof e == "object" || typeof e == "function") && e !== null, re = (e) => X(e) && e[K] !== void 0 ? e[K] : {
15
15
  version: "1",
16
16
  compatibleWith: ["1"],
@@ -221,5 +221,4 @@ var G = Symbol.for("voltro.workflow.workerLayer"), K = Symbol.for("voltro.workfl
221
221
  execute: i.pipe(B.catchDefect((e) => B.die(s(e, c))))
222
222
  }));
223
223
  }, me = (e) => B.map(g, (t) => t.includes(e)), he = F.withCompensation, ge = A.idempotencyKey;
224
- //#endregion
225
224
  export { T as CurrentWorkflowReplayShape, x as DEFAULT_WORKFLOW_SCHEDULE_MAX_RUNTIME_MS, u as DEFERRING_CONTROLS, J as WorkflowFlowControlProperty, q as WorkflowMessagesProperty, S as WorkflowScheduleProperty, K as WorkflowVersionTypeId, G as WorkflowWorkerLayerTypeId, d as assertConsistentPools, f as deferringControlsOf, N as durableClock, oe as durableQueue, te as durableQueueModule, ae as getWorkflowFlowControl, C as getWorkflowSchedule, re as getWorkflowVersionMetadata, p as hasCancelOn, m as hasFlowControl, X as isCarrier, Y as isWorkflowWorkerLayer, E as makeReplayShapeTracker, D as nondeterminismEventPayload, me as patch, se as processQueue, Q as queueWorker, ce as rateLimit, O as reportNondeterminism, $ as sleep, le as sleepUntil, pe as step, ge as stepIdempotencyKey, j as stepModule, h as validateFlowControl, w as validateWorkflowSchedule, he as withCompensation, ie as workflow, ne as workflowModule };
@@ -7,7 +7,7 @@ import { cancelSuspendedWorkflowRunInTransaction as c } from "./runGeneration.js
7
7
  import { Schema as l } from "effect";
8
8
  import { WorkflowQueuedCancellationResultSchema as u } from "@voltro/protocol";
9
9
  import { and as d, derivedRowId as f, eq as p, gt as m, id as h, json as g, table as _, text as v, timestamp as y } from "@voltro/database";
10
- //#region src/queuedCancellationRequest.ts
10
+ // src/queuedCancellationRequest.ts
11
11
  var b = _("_voltro_workflow_queued_cancellations", {
12
12
  id: h({ prefix: "wfqc" }),
13
13
  receiptId: v(),
@@ -360,5 +360,4 @@ var b = _("_voltro_workflow_queued_cancellations", {
360
360
  if (e.length < 100) return a;
361
361
  }
362
362
  };
363
- //#endregion
364
363
  export { k as acceptQueuedCancellationInTransaction, A as bindQueuedCancellationRunInTransaction, D as observeQueuedCancellationInTransaction, b as queuedCancellationRequestsTable, O as queuedCancellationResult, w as readQueuedCancellationRequestInTransaction, j as stageQueuedCancellationsAtRunEntry };
@@ -1,6 +1,6 @@
1
1
  import { acceptQueuedCancellationInTransaction as e, observeQueuedCancellationInTransaction as t, queuedCancellationResult as n } from "./queuedCancellationRequest.js";
2
2
  import { Schema as r } from "effect";
3
- //#region src/queuedControl.ts
3
+ // src/queuedControl.ts
4
4
  var i = r.Struct({
5
5
  requestId: r.NonEmptyString,
6
6
  receiptId: r.NonEmptyString,
@@ -17,5 +17,4 @@ var i = r.Struct({
17
17
  let o = r.decodeUnknownSync(i)(a);
18
18
  return n(o, await t(e, o));
19
19
  };
20
- //#endregion
21
20
  export { a as cancelQueuedWorkflowStartInTransaction, o as readQueuedWorkflowCancellationInTransaction };
package/dist/recorder.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { Context as e, Effect as t } from "effect";
2
- //#region src/recorder.ts
2
+ // src/recorder.ts
3
3
  var n = class extends e.Service()("@voltro/WorkflowRunRecorder") {}, r = e.Reference("@voltro/workflow/CurrentWorkflowRunId", { defaultValue: () => void 0 }), i = e.Reference("@voltro/workflow/CurrentWorkflowExecutionId", { defaultValue: () => void 0 }), a = e.Reference("@voltro/workflow/CurrentWorkflowStep", { defaultValue: () => void 0 }), o = t.gen(function* () {
4
4
  let e = yield* i, t = yield* a;
5
5
  return e === void 0 || t === void 0 ? void 0 : {
@@ -7,5 +7,4 @@ var n = class extends e.Service()("@voltro/WorkflowRunRecorder") {}, r = e.Refer
7
7
  step: t
8
8
  };
9
9
  }), s = e.Reference("@voltro/workflow/CurrentWorkflowGeneration", { defaultValue: () => void 0 }), c = e.Reference("@voltro/workflow/CurrentWorkflowWakeTenant", { defaultValue: () => void 0 }), l = e.Reference("@voltro/workflow/CurrentWorkflowPatches", { defaultValue: () => [] }), u = () => r, d = () => i, f = class extends e.Service()("@voltro/WorkflowStepInterceptor") {};
10
- //#endregion
11
10
  export { i as CurrentWorkflowExecutionId, s as CurrentWorkflowGeneration, l as CurrentWorkflowPatches, r as CurrentWorkflowRunId, a as CurrentWorkflowStep, c as CurrentWorkflowWakeTenant, n as WorkflowRunRecorder, f as WorkflowStepInterceptorTag, o as currentWorkflowStep, d as getCurrentWorkflowExecutionId, u as getCurrentWorkflowRunId };
@@ -1,6 +1,6 @@
1
1
  import { Schema as e } from "effect";
2
2
  import { eq as t } from "@voltro/database";
3
- //#region src/residentExecutionEvidence.ts
3
+ // src/residentExecutionEvidence.ts
4
4
  var n = e.Struct({
5
5
  runId: e.NonEmptyString,
6
6
  workflowName: e.NonEmptyString,
@@ -60,5 +60,4 @@ var n = e.Struct({
60
60
  completedAt: c.closedAt
61
61
  };
62
62
  };
63
- //#endregion
64
63
  export { r as readResidentExecutionEvidence };
@@ -1,5 +1,5 @@
1
1
  import { Cause as e, Duration as t, Effect as n, Exit as r, Option as i, Schedule as a } from "effect";
2
- //#region src/retryPolicy.ts
2
+ // src/retryPolicy.ts
3
3
  var o = (e) => {
4
4
  if (typeof e != "object" || !e) return;
5
5
  let n = e.retryAfterMillis;
@@ -53,5 +53,4 @@ var o = (e) => {
53
53
  while: i
54
54
  });
55
55
  };
56
- //#endregion
57
56
  export { m as applyRetryPolicy, l as retryPolicyIsActive };
@@ -1,6 +1,6 @@
1
1
  import { _voltroWorkflowRunsTable as e } from "./runsTable.js";
2
2
  import { id as t, integer as n, json as r, reference as i, table as a, text as o, timestamp as s } from "@voltro/database";
3
- //#region src/runEventsTable.ts
3
+ // src/runEventsTable.ts
4
4
  var c = a("_voltro_workflow_run_events", {
5
5
  id: t({ prefix: "wfev" }),
6
6
  runId: i(() => e, {
@@ -13,5 +13,4 @@ var c = a("_voltro_workflow_run_events", {
13
13
  stepName: o().nullable(),
14
14
  attempt: n().nullable()
15
15
  }).index(["runId", "occurredAt"]).index(["eventType"]);
16
- //#endregion
17
16
  export { c as _voltroWorkflowRunEventsTable };
@@ -10,7 +10,7 @@ import { stageQueuedCancellationsAtRunEntry as g } from "./queuedCancellationReq
10
10
  import { Schema as _ } from "effect";
11
11
  import { derivedRowId as v, eq as y } from "@voltro/database";
12
12
  import { createHash as b } from "node:crypto";
13
- //#region src/runGeneration.ts
13
+ // src/runGeneration.ts
14
14
  var x = "_voltro_workflow_runs", S = _.NullOr(_.Struct({
15
15
  requestId: _.NonEmptyString,
16
16
  restartToken: _.NullOr(_.NonEmptyString)
@@ -341,5 +341,4 @@ var x = "_voltro_workflow_runs", S = _.NullOr(_.Struct({
341
341
  terminalEvent: w
342
342
  };
343
343
  }, A = (e, t) => k(e, t, "running");
344
- //#endregion
345
344
  export { D as cancelSuspendedWorkflowRunInTransaction, A as completeWorkflowRunGenerationInTransaction, w as enterWorkflowRestartGenerationInTransaction, T as enterWorkflowRunGenerationInTransaction, O as suspendWorkflowRunGenerationInTransaction };
@@ -10,7 +10,7 @@ import { Cause as v, Effect as y, Exit as b, Fiber as x } from "effect";
10
10
  import { publishServerError as S } from "@voltro/protocol";
11
11
  import { eq as C } from "@voltro/database";
12
12
  import { WorkflowInstance as w } from "effect/workflow/WorkflowEngine";
13
- //#region src/runRecording.ts
13
+ // src/runRecording.ts
14
14
  var T = 8192, E = 3, D = 2e3, O = () => {
15
15
  let e = (e) => {
16
16
  if (e === void 0) return;
@@ -611,5 +611,4 @@ var T = 8192, E = 3, D = 2e3, O = () => {
611
611
  }))), Q;
612
612
  }));
613
613
  };
614
- //#endregion
615
614
  export { E as DEFAULT_MAX_RUN_RECLAIMS, D as DEFAULT_REPLAY_SHAPE_LIMIT, F as makeWorkflowRunRecorder, k as normaliseWorkflowPatches, O as resolveRunGuardTuning, P as serialiseWorkflowRowForWire, M as truncateWorkflowValue, I as wrapWorkflowExecuteWithRunRecording };
@@ -1,6 +1,6 @@
1
1
  import { _voltroWorkflowRunsTable as e } from "./runsTable.js";
2
2
  import { id as t, integer as n, json as r, reference as i, table as a, text as o, timestamp as s } from "@voltro/database";
3
- //#region src/runStepsTable.ts
3
+ // src/runStepsTable.ts
4
4
  var c = a("_voltro_workflow_run_steps", {
5
5
  id: t({ prefix: "wfstep" }),
6
6
  runId: i(() => e, {
@@ -24,5 +24,4 @@ var c = a("_voltro_workflow_run_steps", {
24
24
  completedAt: s().nullable(),
25
25
  durationMs: n().nullable()
26
26
  }).index(["runId", "stepName"]).index(["startedAt"]);
27
- //#endregion
28
27
  export { c as _voltroWorkflowRunStepsTable };
@@ -1,7 +1,7 @@
1
1
  import { Duration as e, Effect as t, Schedule as n } from "effect";
2
2
  import { RunnerStorage as r } from "effect/cluster";
3
3
  import { PersistenceError as i } from "effect/cluster/ClusterError";
4
- //#region src/runnerStorageGuard.ts
4
+ // src/runnerStorageGuard.ts
5
5
  var a = (a, o) => t.gen(function* () {
6
6
  let s = e.fromInputUnsafe(o.interval), c = e.toMillis(o.giveUpAfter), l, u, d = !1, f = !1;
7
7
  yield* o.probe.pipe(t.timeout(s), t.isSuccess, t.flatMap((e) => t.sync(() => {
@@ -25,5 +25,4 @@ var a = (a, o) => t.gen(function* () {
25
25
  })
26
26
  });
27
27
  });
28
- //#endregion
29
28
  export { a as guardRunnerStorage };
package/dist/runsTable.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { boolean as e, id as t, integer as n, json as r, table as i, text as a, timestamp as o } from "@voltro/database";
2
- //#region src/runsTable.ts
2
+ // src/runsTable.ts
3
3
  var s = i("_voltro_workflow_runs", {
4
4
  id: t({ prefix: "wfrun" }),
5
5
  tag: a(),
@@ -38,5 +38,4 @@ var s = i("_voltro_workflow_runs", {
38
38
  "abandon"
39
39
  ]).nullable()
40
40
  }).index(["tag"]).index(["status"]).index(["source"]).index(["startedAt"]).index(["parentExecutionId"]).index(["parentClosePolicy"]);
41
- //#endregion
42
41
  export { s as _voltroWorkflowRunsTable };
@@ -1,5 +1,5 @@
1
1
  import { Cron as e, Duration as t, Result as n } from "effect";
2
- //#region src/scheduleDeclaration.ts
2
+ // src/scheduleDeclaration.ts
3
3
  var r = 864e5, i = /* @__PURE__ */ new Set([
4
4
  "skip",
5
5
  "buffer",
@@ -40,5 +40,4 @@ var r = 864e5, i = /* @__PURE__ */ new Set([
40
40
  let t = e[c];
41
41
  return t === void 0 ? void 0 : t;
42
42
  };
43
- //#endregion
44
43
  export { r as DEFAULT_WORKFLOW_SCHEDULE_MAX_RUNTIME_MS, c as WorkflowScheduleProperty, l as getWorkflowSchedule, o as validateWorkflowSchedule };
@@ -1,4 +1,4 @@
1
- //#region src/signalHint.ts
1
+ // src/signalHint.ts
2
2
  var e = 3e5, t, n = (e) => {
3
3
  t = e !== void 0 && Number.isFinite(e) && e > 0 ? e : void 0;
4
4
  }, r = () => {
@@ -19,5 +19,4 @@ var e = 3e5, t, n = (e) => {
19
19
  let a = e.workflowName === void 0 ? "" : ` in workflow '${e.workflowName}'`;
20
20
  return (e.warn ?? ((e) => console.warn(e)))(`awaitSignal('${e.signalName}')${a} declares a ${Math.round(e.timeoutMs / 1e3)}s timeout — a wait that long holds a worker fiber for its whole duration. For human-approval-length waits, awaitSignalSuspending (same call shape, from @voltro/workflow) SUSPENDS the run and frees the slot until the signal arrives. This is a hint, not a behaviour change; it is logged once per workflow. Threshold: workflows.suspendSignalHintMs in app.config.ts, or VOLTRO_WORKFLOW_SUSPEND_HINT_MS.`), !0;
21
21
  };
22
- //#endregion
23
22
  export { e as DEFAULT_SUSPEND_HINT_MS, o as maybeHintSuspendingSignal, a as resetSuspendHintsForTest, r as resolveSuspendHintMs, n as setSuspendSignalHintMs };
package/dist/signals.js CHANGED
@@ -4,7 +4,7 @@ import { maybeHintSuspendingSignal as i } from "./signalHint.js";
4
4
  import { Effect as a, Schema as o } from "effect";
5
5
  import { and as s, eq as c } from "@voltro/database";
6
6
  import { WorkflowInstance as l } from "effect/workflow/WorkflowEngine";
7
- //#region src/signals.ts
7
+ // src/signals.ts
8
8
  var u = async (e, t) => {
9
9
  if (e) try {
10
10
  await e.recordEvent(t);
@@ -66,5 +66,4 @@ var u = async (e, t) => {
66
66
  execute: p
67
67
  });
68
68
  };
69
- //#endregion
70
69
  export { d as awaitSignal };