@nwire/forge 0.7.1 → 0.8.17

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 (85) hide show
  1. package/README.md +169 -79
  2. package/dist/__tests__/action-hooks.test.d.ts +8 -0
  3. package/dist/__tests__/action-hooks.test.d.ts.map +1 -0
  4. package/dist/__tests__/action-hooks.test.js +95 -0
  5. package/dist/__tests__/action-hooks.test.js.map +1 -0
  6. package/dist/__tests__/actor-workflow-hooks.test.d.ts +8 -0
  7. package/dist/__tests__/actor-workflow-hooks.test.d.ts.map +1 -0
  8. package/dist/__tests__/actor-workflow-hooks.test.js +106 -0
  9. package/dist/__tests__/actor-workflow-hooks.test.js.map +1 -0
  10. package/dist/__tests__/lifecycle-logging.test.js +4 -2
  11. package/dist/__tests__/lifecycle-logging.test.js.map +1 -1
  12. package/dist/__tests__/plugin-app-narrow.test.d.ts +12 -0
  13. package/dist/__tests__/plugin-app-narrow.test.d.ts.map +1 -0
  14. package/dist/__tests__/plugin-app-narrow.test.js +77 -0
  15. package/dist/__tests__/plugin-app-narrow.test.js.map +1 -0
  16. package/dist/__tests__/plugin-stress.test.d.ts +21 -0
  17. package/dist/__tests__/plugin-stress.test.d.ts.map +1 -0
  18. package/dist/__tests__/plugin-stress.test.js +203 -0
  19. package/dist/__tests__/plugin-stress.test.js.map +1 -0
  20. package/dist/__tests__/public-marker.test.js +7 -3
  21. package/dist/__tests__/public-marker.test.js.map +1 -1
  22. package/dist/actor-store.d.ts +24 -0
  23. package/dist/actor-store.d.ts.map +1 -1
  24. package/dist/actor-store.js +29 -0
  25. package/dist/actor-store.js.map +1 -1
  26. package/dist/create-app.d.ts +16 -1
  27. package/dist/create-app.d.ts.map +1 -1
  28. package/dist/create-app.js +126 -19
  29. package/dist/create-app.js.map +1 -1
  30. package/dist/define-action.d.ts +75 -9
  31. package/dist/define-action.d.ts.map +1 -1
  32. package/dist/define-action.js +103 -26
  33. package/dist/define-action.js.map +1 -1
  34. package/dist/define-actor.d.ts +3 -1
  35. package/dist/define-actor.d.ts.map +1 -1
  36. package/dist/define-actor.js +11 -4
  37. package/dist/define-actor.js.map +1 -1
  38. package/dist/define-handler.d.ts +39 -3
  39. package/dist/define-handler.d.ts.map +1 -1
  40. package/dist/define-handler.js +10 -1
  41. package/dist/define-handler.js.map +1 -1
  42. package/dist/define-module.d.ts +3 -0
  43. package/dist/define-module.d.ts.map +1 -1
  44. package/dist/define-module.js +3 -0
  45. package/dist/define-module.js.map +1 -1
  46. package/dist/define-plugin.d.ts +25 -1
  47. package/dist/define-plugin.d.ts.map +1 -1
  48. package/dist/define-plugin.js +100 -14
  49. package/dist/define-plugin.js.map +1 -1
  50. package/dist/define-projection.d.ts +3 -1
  51. package/dist/define-projection.d.ts.map +1 -1
  52. package/dist/define-projection.js +3 -0
  53. package/dist/define-projection.js.map +1 -1
  54. package/dist/define-query.d.ts +69 -13
  55. package/dist/define-query.d.ts.map +1 -1
  56. package/dist/define-query.js +48 -17
  57. package/dist/define-query.js.map +1 -1
  58. package/dist/define-workflow.d.ts +19 -1
  59. package/dist/define-workflow.d.ts.map +1 -1
  60. package/dist/define-workflow.js +4 -0
  61. package/dist/define-workflow.js.map +1 -1
  62. package/dist/dev-logger.d.ts.map +1 -1
  63. package/dist/dev-logger.js +22 -1
  64. package/dist/dev-logger.js.map +1 -1
  65. package/dist/event-message.d.ts +9 -2
  66. package/dist/event-message.d.ts.map +1 -1
  67. package/dist/event-message.js +10 -3
  68. package/dist/event-message.js.map +1 -1
  69. package/dist/framework-events.d.ts +1 -64
  70. package/dist/framework-events.d.ts.map +1 -1
  71. package/dist/framework-events.js +3 -0
  72. package/dist/framework-events.js.map +1 -1
  73. package/dist/idempotency-store.d.ts +35 -0
  74. package/dist/idempotency-store.d.ts.map +1 -0
  75. package/dist/idempotency-store.js +32 -0
  76. package/dist/idempotency-store.js.map +1 -0
  77. package/dist/index.d.ts +3 -1
  78. package/dist/index.d.ts.map +1 -1
  79. package/dist/index.js +2 -1
  80. package/dist/index.js.map +1 -1
  81. package/dist/runtime.d.ts +205 -5
  82. package/dist/runtime.d.ts.map +1 -1
  83. package/dist/runtime.js +518 -48
  84. package/dist/runtime.js.map +1 -1
  85. package/package.json +11 -10
@@ -0,0 +1,77 @@
1
+ /**
2
+ * createApp accepts the narrow `@nwire/app` plugin shape as well as the
3
+ * rich forge `definePlugin`. Verifies the adaptation at the boundary:
4
+ *
5
+ * - `provide(name, lifecycle)` produces a container binding whose value
6
+ * comes from `lifecycle.boot()`.
7
+ * - `boot(fn)` fires during app start.
8
+ * - `shutdown(fn)` fires during app stop.
9
+ * - `lifecycle.shutdown(value)` fires for materialized bindings.
10
+ */
11
+ import { describe, it, expect } from "vitest";
12
+ import { z } from "zod";
13
+ import { definePlugin as defineAppPlugin } from "@nwire/app";
14
+ import { createApp, defineAction, defineHandler, defineModule } from "../foundation.js";
15
+ const Ping = defineAction({
16
+ name: "test/ping",
17
+ schema: z.object({ n: z.number() }),
18
+ });
19
+ const handler = defineHandler(Ping, async () => undefined);
20
+ const mod = defineModule("test", { actions: [Ping], handlers: [handler] });
21
+ describe("createApp + narrow @nwire/app plugin", () => {
22
+ it("adapts the narrow shape: provide + boot + shutdown all fire", async () => {
23
+ class Conn {
24
+ url;
25
+ constructor(url) {
26
+ this.url = url;
27
+ }
28
+ closed = false;
29
+ }
30
+ const calls = [];
31
+ const plugin = defineAppPlugin("db", ({ provide, boot, shutdown }) => {
32
+ provide("db", {
33
+ boot: () => new Conn("postgres://x"),
34
+ shutdown: (c) => {
35
+ c.closed = true;
36
+ calls.push("binding.shutdown");
37
+ },
38
+ });
39
+ boot(() => {
40
+ calls.push("plugin.boot");
41
+ });
42
+ shutdown(() => {
43
+ calls.push("plugin.shutdown");
44
+ });
45
+ });
46
+ const app = createApp({ modules: [mod], plugins: [plugin] });
47
+ await app.start();
48
+ // Force resolution so the binding's shutdown is reached at stop().
49
+ const conn = app.container.resolve("db");
50
+ expect(conn).toBeInstanceOf(Conn);
51
+ expect(conn.url).toBe("postgres://x");
52
+ expect(calls).toContain("plugin.boot");
53
+ await app.stop();
54
+ expect(conn.closed).toBe(true);
55
+ // Plugin shutdown runs BEFORE binding shutdown (matches app-plugin
56
+ // contract: "flush owned work before underlying resources go away").
57
+ expect(calls).toEqual(["plugin.boot", "plugin.shutdown", "binding.shutdown"]);
58
+ });
59
+ it("rich + narrow plugins coexist in the same plugins list", async () => {
60
+ const fired = [];
61
+ const richBoot = (await import("../define-plugin.js")).definePlugin("rich", ({ boot }) => {
62
+ boot(() => {
63
+ fired.push("rich.boot");
64
+ });
65
+ });
66
+ const narrowBoot = defineAppPlugin("narrow", ({ boot }) => {
67
+ boot(() => {
68
+ fired.push("narrow.boot");
69
+ });
70
+ });
71
+ const app = createApp({ modules: [mod], plugins: [richBoot, narrowBoot] });
72
+ await app.start();
73
+ await app.stop();
74
+ expect(fired).toEqual(["rich.boot", "narrow.boot"]);
75
+ });
76
+ });
77
+ //# sourceMappingURL=plugin-app-narrow.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin-app-narrow.test.js","sourceRoot":"","sources":["../../src/__tests__/plugin-app-narrow.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Plugin + module lifecycle stress test.
3
+ *
4
+ * Covers the failure modes that aren't exercised by `plugin.test.ts` /
5
+ * `plugin-closure.test.ts` / `lifecycle-logging.test.ts`:
6
+ *
7
+ * 1. Cross-plugin DI — plugin B reads plugin A's binding in its boot.
8
+ * 2. Slow boot timing — PluginBooted carries a real `durationMs`.
9
+ * 3. Boot failure recovery — A boots, B throws, stop() still cleans A.
10
+ * 4. Shutdown isolation — first plugin's shutdown throws but second still runs;
11
+ * the error surfaces from app.stop().
12
+ * 5. Ordering at scale — 10 plugins boot in registration order, shutdown reverse.
13
+ * 6. Module + plugin mixed — PluginRegistered fires with `kind:"module"` for
14
+ * modules first (topo order) then `kind:"plugin"` for plugins.
15
+ *
16
+ * Style follows `lifecycle-logging.test.ts` — real `createApp`, real
17
+ * `app.start()/stop()`, observe via the runtime's framework event bus
18
+ * (`runtime.frameworkEvents.onFire(...)`) and per-event subscriptions.
19
+ */
20
+ export {};
21
+ //# sourceMappingURL=plugin-stress.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin-stress.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/plugin-stress.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG"}
@@ -0,0 +1,203 @@
1
+ /**
2
+ * Plugin + module lifecycle stress test.
3
+ *
4
+ * Covers the failure modes that aren't exercised by `plugin.test.ts` /
5
+ * `plugin-closure.test.ts` / `lifecycle-logging.test.ts`:
6
+ *
7
+ * 1. Cross-plugin DI — plugin B reads plugin A's binding in its boot.
8
+ * 2. Slow boot timing — PluginBooted carries a real `durationMs`.
9
+ * 3. Boot failure recovery — A boots, B throws, stop() still cleans A.
10
+ * 4. Shutdown isolation — first plugin's shutdown throws but second still runs;
11
+ * the error surfaces from app.stop().
12
+ * 5. Ordering at scale — 10 plugins boot in registration order, shutdown reverse.
13
+ * 6. Module + plugin mixed — PluginRegistered fires with `kind:"module"` for
14
+ * modules first (topo order) then `kind:"plugin"` for plugins.
15
+ *
16
+ * Style follows `lifecycle-logging.test.ts` — real `createApp`, real
17
+ * `app.start()/stop()`, observe via the runtime's framework event bus
18
+ * (`runtime.frameworkEvents.onFire(...)`) and per-event subscriptions.
19
+ */
20
+ import { describe, it, expect } from "vitest";
21
+ import { createApp, defineModule, definePlugin } from "../foundation.js";
22
+ import { PluginRegistered, PluginBooted } from "../framework-events.js";
23
+ import { InMemoryContainer } from "@nwire/container";
24
+ describe("plugin + module lifecycle stress", () => {
25
+ it("cross-plugin DI: plugin B's boot resolves a binding plugin A provided", async () => {
26
+ const pluginA = definePlugin("provider", ({ bind }) => {
27
+ bind("config-service", () => ({ name: "from-A" }));
28
+ });
29
+ const seen = [];
30
+ const pluginB = definePlugin("consumer", {
31
+ boot: (container) => {
32
+ seen.push(container.resolve("config-service"));
33
+ },
34
+ });
35
+ const app = createApp({
36
+ container: new InMemoryContainer(),
37
+ modules: [],
38
+ plugins: [pluginA, pluginB],
39
+ devLogs: false,
40
+ });
41
+ await app.start();
42
+ await app.stop();
43
+ expect(seen).toHaveLength(1);
44
+ expect(seen[0]).toEqual({ name: "from-A" });
45
+ });
46
+ it("slow boot timing: PluginBooted carries a durationMs >= the sleep", async () => {
47
+ const SLEEP_MS = 150;
48
+ const TOLERANCE_MS = 120;
49
+ const slow = definePlugin("slow-boot", {
50
+ boot: async () => {
51
+ await new Promise((resolve) => setTimeout(resolve, SLEEP_MS));
52
+ },
53
+ });
54
+ const app = createApp({
55
+ container: new InMemoryContainer(),
56
+ modules: [],
57
+ plugins: [slow],
58
+ devLogs: false,
59
+ });
60
+ const observed = [];
61
+ app.runtime.frameworkEvents.on(PluginBooted, (payload) => {
62
+ observed.push({ name: payload.pluginName, durationMs: payload.durationMs });
63
+ });
64
+ await app.start();
65
+ await app.stop();
66
+ const slowRecord = observed.find((r) => r.name === "slow-boot");
67
+ expect(slowRecord).toBeDefined();
68
+ expect(slowRecord.durationMs).toBeGreaterThanOrEqual(TOLERANCE_MS);
69
+ });
70
+ it("boot failure recovery: B throws, A booted, stop() still cleans up A", async () => {
71
+ const bootErr = new Error("plugin B boot exploded");
72
+ const pluginA = definePlugin("a", {
73
+ boot: () => {
74
+ /* succeeds */
75
+ },
76
+ });
77
+ const pluginB = definePlugin("b", {
78
+ boot: () => {
79
+ throw bootErr;
80
+ },
81
+ });
82
+ const pluginC = definePlugin("c", {
83
+ boot: () => {
84
+ /* should never run — B's failure aborts boot */
85
+ },
86
+ });
87
+ const app = createApp({
88
+ container: new InMemoryContainer(),
89
+ modules: [],
90
+ plugins: [pluginA, pluginB, pluginC],
91
+ devLogs: false,
92
+ });
93
+ const bootedNames = [];
94
+ app.runtime.frameworkEvents.on(PluginBooted, (payload) => {
95
+ bootedNames.push(payload.pluginName);
96
+ });
97
+ const shutdownNames = [];
98
+ // Use the catch-all observer the dev logger / Studio use, so we see
99
+ // every firing regardless of subscriber count.
100
+ app.runtime.frameworkEvents.onFire((rec) => {
101
+ if (rec.eventName === "nwire.plugin.shutdown") {
102
+ const p = rec.payload;
103
+ shutdownNames.push(p.pluginName);
104
+ }
105
+ });
106
+ await expect(app.start()).rejects.toBe(bootErr);
107
+ // A booted before B threw. C should NOT have booted.
108
+ expect(bootedNames).toContain("a");
109
+ expect(bootedNames).not.toContain("c");
110
+ // Now tear the app down — shutdown should still emit PluginShutdown
111
+ // events in reverse declaration order so observers see a clean close.
112
+ await app.stop();
113
+ // A must appear in the shutdown sweep regardless of B's boot failure.
114
+ expect(shutdownNames).toContain("a");
115
+ // Reverse order: C is iterated first, then B, then A. (Their
116
+ // shutdown callbacks are no-ops because none was registered, but
117
+ // the framework still fires the lifecycle events.)
118
+ const aIdx = shutdownNames.indexOf("a");
119
+ const cIdx = shutdownNames.indexOf("c");
120
+ if (cIdx >= 0) {
121
+ // When C appears (framework also fires shutdown events for plugins
122
+ // that never booted), it must come BEFORE A.
123
+ expect(cIdx).toBeLessThan(aIdx);
124
+ }
125
+ });
126
+ it("shutdown isolation: first plugin's shutdown throws, second still runs, error surfaces from stop()", async () => {
127
+ const shutErr = new Error("plugin A shutdown failed");
128
+ const cleanupRan = [];
129
+ const pluginA = definePlugin("a", {
130
+ shutdown: () => {
131
+ cleanupRan.push("a-attempted");
132
+ throw shutErr;
133
+ },
134
+ });
135
+ const pluginB = definePlugin("b", {
136
+ shutdown: () => {
137
+ cleanupRan.push("b-ran");
138
+ },
139
+ });
140
+ const app = createApp({
141
+ container: new InMemoryContainer(),
142
+ modules: [],
143
+ plugins: [pluginA, pluginB],
144
+ devLogs: false,
145
+ });
146
+ await app.start();
147
+ // Shutdown order is reverse: B first, then A. B should run cleanly;
148
+ // then A throws. The framework must surface A's error but only AFTER
149
+ // every other shutdown step has run.
150
+ await expect(app.stop()).rejects.toBe(shutErr);
151
+ expect(cleanupRan).toEqual(["b-ran", "a-attempted"]);
152
+ });
153
+ it("ordering at scale: 10 plugins boot in registration order, shutdown reverse", async () => {
154
+ const boots = [];
155
+ const shutdowns = [];
156
+ const plugins = Array.from({ length: 10 }, (_, i) => {
157
+ const name = `p${i}`;
158
+ return definePlugin(name, {
159
+ boot: () => {
160
+ boots.push(name);
161
+ },
162
+ shutdown: () => {
163
+ shutdowns.push(name);
164
+ },
165
+ });
166
+ });
167
+ const app = createApp({
168
+ container: new InMemoryContainer(),
169
+ modules: [],
170
+ plugins,
171
+ devLogs: false,
172
+ });
173
+ await app.start();
174
+ await app.stop();
175
+ expect(boots).toEqual(["p0", "p1", "p2", "p3", "p4", "p5", "p6", "p7", "p8", "p9"]);
176
+ expect(shutdowns).toEqual(["p9", "p8", "p7", "p6", "p5", "p4", "p3", "p2", "p1", "p0"]);
177
+ });
178
+ it("module + plugin mixed: PluginRegistered fires for modules first (topo) then plugins, with correct kind", async () => {
179
+ const moduleA = defineModule("mod-a", {});
180
+ const moduleB = defineModule("mod-b", {});
181
+ const pluginX = definePlugin("plug-x", {});
182
+ const pluginY = definePlugin("plug-y", {});
183
+ const app = createApp({
184
+ container: new InMemoryContainer(),
185
+ modules: [moduleA, moduleB],
186
+ plugins: [pluginX, pluginY],
187
+ devLogs: false,
188
+ });
189
+ const registrations = [];
190
+ app.runtime.frameworkEvents.on(PluginRegistered, (payload) => {
191
+ registrations.push({ pluginName: payload.pluginName, kind: payload.kind });
192
+ });
193
+ await app.start();
194
+ await app.stop();
195
+ expect(registrations).toEqual([
196
+ { pluginName: "mod-a", kind: "module" },
197
+ { pluginName: "mod-b", kind: "module" },
198
+ { pluginName: "plug-x", kind: "plugin" },
199
+ { pluginName: "plug-y", kind: "plugin" },
200
+ ]);
201
+ });
202
+ });
203
+ //# sourceMappingURL=plugin-stress.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin-stress.test.js","sourceRoot":"","sources":["../../src/__tests__/plugin-stress.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AACtE,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAkB,MAAM,qBAAqB,CAAC;AACrF,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAErD,QAAQ,CAAC,kCAAkC,EAAE,GAAG,EAAE;IAChD,EAAE,CAAC,uEAAuE,EAAE,KAAK,IAAI,EAAE;QAKrF,MAAM,OAAO,GAAG,YAAY,CAAC,UAAU,EAAE,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE;YACpD,IAAI,CAAgB,gBAAgB,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC;QACpE,CAAC,CAAC,CAAC;QAEH,MAAM,IAAI,GAAqC,EAAE,CAAC;QAClD,MAAM,OAAO,GAAG,YAAY,CAAC,UAAU,EAAE;YACvC,IAAI,EAAE,CAAC,SAAS,EAAE,EAAE;gBAClB,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAgB,gBAAgB,CAAC,CAAC,CAAC;YAChE,CAAC;SACF,CAAC,CAAC;QAEH,MAAM,GAAG,GAAG,SAAS,CAAC;YACpB,SAAS,EAAE,IAAI,iBAAiB,EAAE;YAClC,OAAO,EAAE,EAAE;YACX,OAAO,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC;YAC3B,OAAO,EAAE,KAAK;SACf,CAAC,CAAC;QAEH,MAAM,GAAG,CAAC,KAAK,EAAE,CAAC;QAClB,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;QAEjB,MAAM,CAAC,IAAI,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QAC7B,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kEAAkE,EAAE,KAAK,IAAI,EAAE;QAChF,MAAM,QAAQ,GAAG,GAAG,CAAC;QACrB,MAAM,YAAY,GAAG,GAAG,CAAC;QAEzB,MAAM,IAAI,GAAG,YAAY,CAAC,WAAW,EAAE;YACrC,IAAI,EAAE,KAAK,IAAI,EAAE;gBACf,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC;YACtE,CAAC;SACF,CAAC,CAAC;QAEH,MAAM,GAAG,GAAG,SAAS,CAAC;YACpB,SAAS,EAAE,IAAI,iBAAiB,EAAE;YAClC,OAAO,EAAE,EAAE;YACX,OAAO,EAAE,CAAC,IAAI,CAAC;YACf,OAAO,EAAE,KAAK;SACf,CAAC,CAAC;QAEH,MAAM,QAAQ,GAAgD,EAAE,CAAC;QACjE,GAAG,CAAC,OAAO,CAAC,eAAe,CAAC,EAAE,CAAC,YAAY,EAAE,CAAC,OAAO,EAAE,EAAE;YACvD,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,UAAU,EAAE,UAAU,EAAE,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC;QAC9E,CAAC,CAAC,CAAC;QAEH,MAAM,GAAG,CAAC,KAAK,EAAE,CAAC;QAClB,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;QAEjB,MAAM,UAAU,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,WAAW,CAAC,CAAC;QAChE,MAAM,CAAC,UAAU,CAAC,CAAC,WAAW,EAAE,CAAC;QACjC,MAAM,CAAC,UAAW,CAAC,UAAU,CAAC,CAAC,sBAAsB,CAAC,YAAY,CAAC,CAAC;IACtE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qEAAqE,EAAE,KAAK,IAAI,EAAE;QACnF,MAAM,OAAO,GAAG,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;QAEpD,MAAM,OAAO,GAAG,YAAY,CAAC,GAAG,EAAE;YAChC,IAAI,EAAE,GAAG,EAAE;gBACT,cAAc;YAChB,CAAC;SACF,CAAC,CAAC;QACH,MAAM,OAAO,GAAG,YAAY,CAAC,GAAG,EAAE;YAChC,IAAI,EAAE,GAAG,EAAE;gBACT,MAAM,OAAO,CAAC;YAChB,CAAC;SACF,CAAC,CAAC;QACH,MAAM,OAAO,GAAG,YAAY,CAAC,GAAG,EAAE;YAChC,IAAI,EAAE,GAAG,EAAE;gBACT,gDAAgD;YAClD,CAAC;SACF,CAAC,CAAC;QAEH,MAAM,GAAG,GAAG,SAAS,CAAC;YACpB,SAAS,EAAE,IAAI,iBAAiB,EAAE;YAClC,OAAO,EAAE,EAAE;YACX,OAAO,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC;YACpC,OAAO,EAAE,KAAK;SACf,CAAC,CAAC;QAEH,MAAM,WAAW,GAAa,EAAE,CAAC;QACjC,GAAG,CAAC,OAAO,CAAC,eAAe,CAAC,EAAE,CAAC,YAAY,EAAE,CAAC,OAAO,EAAE,EAAE;YACvD,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;QACvC,CAAC,CAAC,CAAC;QAEH,MAAM,aAAa,GAAa,EAAE,CAAC;QACnC,oEAAoE;QACpE,+CAA+C;QAC/C,GAAG,CAAC,OAAO,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE;YACzC,IAAI,GAAG,CAAC,SAAS,KAAK,uBAAuB,EAAE,CAAC;gBAC9C,MAAM,CAAC,GAAG,GAAG,CAAC,OAAiC,CAAC;gBAChD,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;YACnC,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,MAAM,MAAM,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAEhD,qDAAqD;QACrD,MAAM,CAAC,WAAW,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;QACnC,MAAM,CAAC,WAAW,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;QAEvC,oEAAoE;QACpE,sEAAsE;QACtE,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;QAEjB,sEAAsE;QACtE,MAAM,CAAC,aAAa,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;QACrC,6DAA6D;QAC7D,iEAAiE;QACjE,mDAAmD;QACnD,MAAM,IAAI,GAAG,aAAa,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACxC,MAAM,IAAI,GAAG,aAAa,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACxC,IAAI,IAAI,IAAI,CAAC,EAAE,CAAC;YACd,mEAAmE;YACnE,6CAA6C;YAC7C,MAAM,CAAC,IAAI,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;QAClC,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mGAAmG,EAAE,KAAK,IAAI,EAAE;QACjH,MAAM,OAAO,GAAG,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC;QACtD,MAAM,UAAU,GAAa,EAAE,CAAC;QAEhC,MAAM,OAAO,GAAG,YAAY,CAAC,GAAG,EAAE;YAChC,QAAQ,EAAE,GAAG,EAAE;gBACb,UAAU,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;gBAC/B,MAAM,OAAO,CAAC;YAChB,CAAC;SACF,CAAC,CAAC;QACH,MAAM,OAAO,GAAG,YAAY,CAAC,GAAG,EAAE;YAChC,QAAQ,EAAE,GAAG,EAAE;gBACb,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAC3B,CAAC;SACF,CAAC,CAAC;QAEH,MAAM,GAAG,GAAG,SAAS,CAAC;YACpB,SAAS,EAAE,IAAI,iBAAiB,EAAE;YAClC,OAAO,EAAE,EAAE;YACX,OAAO,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC;YAC3B,OAAO,EAAE,KAAK;SACf,CAAC,CAAC;QAEH,MAAM,GAAG,CAAC,KAAK,EAAE,CAAC;QAElB,oEAAoE;QACpE,qEAAqE;QACrE,qCAAqC;QACrC,MAAM,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAE/C,MAAM,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC,CAAC;IACvD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4EAA4E,EAAE,KAAK,IAAI,EAAE;QAC1F,MAAM,KAAK,GAAa,EAAE,CAAC;QAC3B,MAAM,SAAS,GAAa,EAAE,CAAC;QAE/B,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;YAClD,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC;YACrB,OAAO,YAAY,CAAC,IAAI,EAAE;gBACxB,IAAI,EAAE,GAAG,EAAE;oBACT,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBACnB,CAAC;gBACD,QAAQ,EAAE,GAAG,EAAE;oBACb,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBACvB,CAAC;aACF,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;QAEH,MAAM,GAAG,GAAG,SAAS,CAAC;YACpB,SAAS,EAAE,IAAI,iBAAiB,EAAE;YAClC,OAAO,EAAE,EAAE;YACX,OAAO;YACP,OAAO,EAAE,KAAK;SACf,CAAC,CAAC;QAEH,MAAM,GAAG,CAAC,KAAK,EAAE,CAAC;QAClB,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;QAEjB,MAAM,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;QACpF,MAAM,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;IAC1F,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wGAAwG,EAAE,KAAK,IAAI,EAAE;QAGtH,MAAM,OAAO,GAAG,YAAY,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QAC1C,MAAM,OAAO,GAAG,YAAY,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QAC1C,MAAM,OAAO,GAAG,YAAY,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;QAC3C,MAAM,OAAO,GAAG,YAAY,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;QAE3C,MAAM,GAAG,GAAG,SAAS,CAAC;YACpB,SAAS,EAAE,IAAI,iBAAiB,EAAE;YAClC,OAAO,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC;YAC3B,OAAO,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC;YAC3B,OAAO,EAAE,KAAK;SACf,CAAC,CAAC;QAEH,MAAM,aAAa,GAAmB,EAAE,CAAC;QACzC,GAAG,CAAC,OAAO,CAAC,eAAe,CAAC,EAAE,CAAC,gBAAgB,EAAE,CAAC,OAAO,EAAE,EAAE;YAC3D,aAAa,CAAC,IAAI,CAAC,EAAE,UAAU,EAAE,OAAO,CAAC,UAAU,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;QAC7E,CAAC,CAAC,CAAC;QAEH,MAAM,GAAG,CAAC,KAAK,EAAE,CAAC;QAClB,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;QAEjB,MAAM,CAAC,aAAa,CAAC,CAAC,OAAO,CAAC;YAC5B,EAAE,UAAU,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE;YACvC,EAAE,UAAU,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE;YACvC,EAAE,UAAU,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE;YACxC,EAAE,UAAU,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE;SACzC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -45,10 +45,14 @@ describe(".public() marker", () => {
45
45
  expect(isPublic(exposed)).toBe(true);
46
46
  expect(exposed.name).toBe("audit.on-wash");
47
47
  });
48
- it("$public is non-enumerable (JSON.stringify ignores it)", () => {
48
+ it("$public is non-enumerable (own-keys doesn't surface it)", () => {
49
+ // Action is now a callable factory (function), so JSON.stringify on it
50
+ // returns undefined entirely — the relevant invariant is that `$public`
51
+ // is non-enumerable and absent from Object.keys / property iteration.
49
52
  const exposed = recordWash.public();
50
- const json = JSON.parse(JSON.stringify(exposed));
51
- expect(json.$public).toBeUndefined();
53
+ expect(Object.keys(exposed).includes("$public")).toBe(false);
54
+ // Same property must still be accessible by direct read.
55
+ expect(exposed.$public).toBe(true);
52
56
  });
53
57
  });
54
58
  //# sourceMappingURL=public-marker.test.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"public-marker.test.js","sourceRoot":"","sources":["../../src/__tests__/public-marker.test.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"public-marker.test.js","sourceRoot":"","sources":["../../src/__tests__/public-marker.test.ts"],"names":[],"mappings":"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"}
@@ -50,6 +50,19 @@ export interface ActorStore {
50
50
  * index `activeTimers.fireAt` for efficient querying.
51
51
  */
52
52
  listInstances(actorName: string, tenant?: string): Promise<readonly ActorInstance[]>;
53
+ /**
54
+ * Acquire a per-(actor, key, tenant) lock; resolve when the lock is
55
+ * held and return an `unlock` function. The runtime takes the lock
56
+ * around `load → reduce → save` so concurrent dispatches against the
57
+ * same actor key serialize — invariant safety without depending on
58
+ * storage-native locking.
59
+ *
60
+ * Implementations backed by real databases should prefer row-level
61
+ * locking (`SELECT … FOR UPDATE`, Mongo `findOneAndUpdate`, etc.)
62
+ * and treat this method as a no-op; in-memory stores need an explicit
63
+ * per-key Promise chain to avoid last-write-wins under burst load.
64
+ */
65
+ lockKey?(actorName: string, key: string, tenant?: string): Promise<() => void>;
53
66
  }
54
67
  /**
55
68
  * Process-local in-memory store. Each save deep-clones the instance to prevent
@@ -57,12 +70,23 @@ export interface ActorStore {
57
70
  */
58
71
  export declare class InMemoryActorStore implements ActorStore {
59
72
  private readonly entries;
73
+ /**
74
+ * Per-(actor, key, tenant) lock chain. Each lock acquisition awaits the
75
+ * tail of the chain and replaces it with its own resolved-on-release
76
+ * Promise. Concurrent dispatches against the same actor key serialize
77
+ * cleanly; different keys (or different actors / tenants) stay
78
+ * independent. Without this, two simultaneous dispatches both load the
79
+ * same pre-state, both compute next state, and the second save wins —
80
+ * the first event's effect vanishes.
81
+ */
82
+ private readonly lockChain;
60
83
  /**
61
84
  * Storage key includes tenant first so prefix scans by `(actor, tenant)`
62
85
  * are O(matching tenant) — and across-tenant scans (no tenant) are O(N)
63
86
  * by intent.
64
87
  */
65
88
  private cacheKey;
89
+ lockKey(actorName: string, key: string, tenant?: string): Promise<() => void>;
66
90
  load(actorName: string, key: string, tenant?: string): Promise<ActorInstance | null>;
67
91
  save(instance: ActorInstance): Promise<void>;
68
92
  exists(actorName: string, key: string, tenant?: string): Promise<boolean>;
@@ -1 +1 @@
1
- {"version":3,"file":"actor-store.d.ts","sourceRoot":"","sources":["../src/actor-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEtD,MAAM,WAAW,aAAa,CAAC,KAAK,GAAG,OAAO;IAC5C,gEAAgE;IAChE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,gEAAgE;IAChE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,yEAAyE;IACzE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,0BAA0B;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,gEAAgE;IAChE,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC;IACrB;;;OAGG;IACH,QAAQ,CAAC,YAAY,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC,CAAC;CACnE;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,UAAU;IACzB;;;;OAIG;IACH,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAAC;IACrF,IAAI,CAAC,QAAQ,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7C,MAAM,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC1E;;;;;;OAMG;IACH,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,aAAa,EAAE,CAAC,CAAC;CACtF;AAED;;;GAGG;AACH,qBAAa,kBAAmB,YAAW,UAAU;IACnD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAoC;IAE5D;;;;OAIG;IACH,OAAO,CAAC,QAAQ;IAIV,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,GAAE,MAAW,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IAKxF,IAAI,CAAC,QAAQ,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAO5C,MAAM,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,GAAE,MAAW,GAAG,OAAO,CAAC,OAAO,CAAC;IAI7E,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,aAAa,EAAE,CAAC;IAW1F,+DAA+D;IAC/D,IAAI,IAAI,MAAM;IAId,+CAA+C;IAC/C,KAAK,IAAI,IAAI;IAIb,OAAO,CAAC,KAAK;CAYd;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,eAAe,EACtB,GAAG,EAAE,MAAM,EACX,MAAM,GAAE,MAAW,GAClB,aAAa,CAWf"}
1
+ {"version":3,"file":"actor-store.d.ts","sourceRoot":"","sources":["../src/actor-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEtD,MAAM,WAAW,aAAa,CAAC,KAAK,GAAG,OAAO;IAC5C,gEAAgE;IAChE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,gEAAgE;IAChE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,yEAAyE;IACzE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,0BAA0B;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,gEAAgE;IAChE,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC;IACrB;;;OAGG;IACH,QAAQ,CAAC,YAAY,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC,CAAC;CACnE;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,UAAU;IACzB;;;;OAIG;IACH,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAAC;IACrF,IAAI,CAAC,QAAQ,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7C,MAAM,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC1E;;;;;;OAMG;IACH,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,aAAa,EAAE,CAAC,CAAC;IACrF;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,CAAC,CAAC;CAChF;AAED;;;GAGG;AACH,qBAAa,kBAAmB,YAAW,UAAU;IACnD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAoC;IAC5D;;;;;;;;OAQG;IACH,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAoC;IAE9D;;;;OAIG;IACH,OAAO,CAAC,QAAQ;IAIV,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,GAAE,MAAW,GAAG,OAAO,CAAC,MAAM,IAAI,CAAC;IAoBjF,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,GAAE,MAAW,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IAKxF,IAAI,CAAC,QAAQ,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAO5C,MAAM,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,GAAE,MAAW,GAAG,OAAO,CAAC,OAAO,CAAC;IAI7E,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,aAAa,EAAE,CAAC;IAW1F,+DAA+D;IAC/D,IAAI,IAAI,MAAM;IAId,+CAA+C;IAC/C,KAAK,IAAI,IAAI;IAIb,OAAO,CAAC,KAAK;CAYd;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,eAAe,EACtB,GAAG,EAAE,MAAM,EACX,MAAM,GAAE,MAAW,GAClB,aAAa,CAWf"}
@@ -15,6 +15,16 @@
15
15
  */
16
16
  export class InMemoryActorStore {
17
17
  entries = new Map();
18
+ /**
19
+ * Per-(actor, key, tenant) lock chain. Each lock acquisition awaits the
20
+ * tail of the chain and replaces it with its own resolved-on-release
21
+ * Promise. Concurrent dispatches against the same actor key serialize
22
+ * cleanly; different keys (or different actors / tenants) stay
23
+ * independent. Without this, two simultaneous dispatches both load the
24
+ * same pre-state, both compute next state, and the second save wins —
25
+ * the first event's effect vanishes.
26
+ */
27
+ lockChain = new Map();
18
28
  /**
19
29
  * Storage key includes tenant first so prefix scans by `(actor, tenant)`
20
30
  * are O(matching tenant) — and across-tenant scans (no tenant) are O(N)
@@ -23,6 +33,25 @@ export class InMemoryActorStore {
23
33
  cacheKey(actorName, key, tenant) {
24
34
  return `${tenant}::${actorName}::${key}`;
25
35
  }
36
+ async lockKey(actorName, key, tenant = "") {
37
+ const k = this.cacheKey(actorName, key, tenant);
38
+ const prev = this.lockChain.get(k) ?? Promise.resolve();
39
+ let release;
40
+ const next = new Promise((resolve) => {
41
+ release = resolve;
42
+ });
43
+ this.lockChain.set(k, next);
44
+ await prev;
45
+ return () => {
46
+ release();
47
+ // Clean up the chain entry IFF it's still ours — a later
48
+ // acquisition will have already replaced the value. Without this
49
+ // guard, slow chains keep `next` rooted indefinitely.
50
+ if (this.lockChain.get(k) === next) {
51
+ this.lockChain.delete(k);
52
+ }
53
+ };
54
+ }
26
55
  async load(actorName, key, tenant = "") {
27
56
  const stored = this.entries.get(this.cacheKey(actorName, key, tenant));
28
57
  return stored ? this.clone(stored) : null;
@@ -1 +1 @@
1
- {"version":3,"file":"actor-store.js","sourceRoot":"","sources":["../src/actor-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAgDH;;;GAGG;AACH,MAAM,OAAO,kBAAkB;IACZ,OAAO,GAAG,IAAI,GAAG,EAAyB,CAAC;IAE5D;;;;OAIG;IACK,QAAQ,CAAC,SAAiB,EAAE,GAAW,EAAE,MAAc;QAC7D,OAAO,GAAG,MAAM,KAAK,SAAS,KAAK,GAAG,EAAE,CAAC;IAC3C,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,SAAiB,EAAE,GAAW,EAAE,SAAiB,EAAE;QAC5D,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,SAAS,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC;QACvE,OAAO,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAC5C,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,QAAuB;QAChC,IAAI,CAAC,OAAO,CAAC,GAAG,CACd,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,SAAS,EAAE,QAAQ,CAAC,GAAG,EAAE,QAAQ,CAAC,MAAM,CAAC,EAChE,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CACrB,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,SAAiB,EAAE,GAAW,EAAE,SAAiB,EAAE;QAC9D,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,SAAS,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC;IACjE,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,SAAiB,EAAE,MAAe;QACpD,MAAM,MAAM,GAAoB,EAAE,CAAC;QACnC,KAAK,MAAM,CAAC,QAAQ,EAAE,KAAK,CAAC,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YAC7C,IAAI,KAAK,CAAC,SAAS,KAAK,SAAS;gBAAE,SAAS;YAC5C,IAAI,MAAM,KAAK,SAAS,IAAI,KAAK,CAAC,MAAM,KAAK,MAAM;gBAAE,SAAS;YAC9D,KAAK,QAAQ,CAAC;YACd,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;QACjC,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,+DAA+D;IAC/D,IAAI;QACF,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC;IAC3B,CAAC;IAED,+CAA+C;IAC/C,KAAK;QACH,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;IACvB,CAAC;IAEO,KAAK,CAAC,QAAuB;QACnC,OAAO;YACL,SAAS,EAAE,QAAQ,CAAC,SAAS;YAC7B,GAAG,EAAE,QAAQ,CAAC,GAAG;YACjB,MAAM,EAAE,QAAQ,CAAC,MAAM;YACvB,KAAK,EAAE,QAAQ,CAAC,KAAK;YACrB,IAAI,EAAE,eAAe,CAAC,QAAQ,CAAC,IAAI,CAAC;YACpC,YAAY,EAAE,eAAe,CAAC,QAAQ,CAAC,YAAY,CAElD;SACF,CAAC;IACJ,CAAC;CACF;AAED;;;;;GAKG;AACH,MAAM,UAAU,qBAAqB,CACnC,KAAsB,EACtB,GAAW,EACX,SAAiB,EAAE;IAEnB,OAAO;QACL,SAAS,EAAE,KAAK,CAAC,IAAI;QACrB,GAAG;QACH,MAAM;QACN,KAAK,EAAE,KAAK,CAAC,OAAO;QACpB,iEAAiE;QACjE,oDAAoD;QACpD,IAAI,EAAE,EAAa;QACnB,YAAY,EAAE,EAAE;KACjB,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"actor-store.js","sourceRoot":"","sources":["../src/actor-store.ts"],"names":[],"mappings":"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"}
@@ -31,6 +31,7 @@ import type { Logger } from "@nwire/logger";
31
31
  import type { DeadLetterSink } from "@nwire/dead-letter";
32
32
  import type { EventBus } from "@nwire/bus";
33
33
  import { type PluginDefinition } from "./define-plugin.js";
34
+ import { type AppPluginDefinition } from "@nwire/app";
34
35
  export interface TimerSchedulerOptions {
35
36
  /** Polling interval in milliseconds. Default: 60_000 (1 minute). */
36
37
  readonly intervalMs?: number;
@@ -45,8 +46,15 @@ export interface CreateAppOptions {
45
46
  * plugins.
46
47
  *
47
48
  * Boot order: declaration order. Shutdown order: reverse declaration.
49
+ *
50
+ * Both plugin flavours are accepted:
51
+ * - rich forge `PluginDefinition` (middleware / actorHooks / before /
52
+ * after / closure form);
53
+ * - narrow `@nwire/app` `AppPluginDefinition` (provide / on / boot /
54
+ * shutdown). The narrow shape is adapted to the rich shape at the
55
+ * boundary so consumers don't have to know which is which.
48
56
  */
49
- readonly plugins?: readonly PluginDefinition[];
57
+ readonly plugins?: readonly (PluginDefinition | AppPluginDefinition)[];
50
58
  /**
51
59
  * App-level config map — exposed to plugin closures via `PluginContext.config`.
52
60
  * Typically loaded from env at boot.
@@ -104,6 +112,13 @@ export interface App {
104
112
  readonly $nwireApp: true;
105
113
  readonly runtime: Runtime;
106
114
  readonly modules: readonly ModuleDefinition[];
115
+ /**
116
+ * Plugins registered into this app. Includes only proper plugins —
117
+ * modules participate in the SAME lifecycle event surface (PluginRegistered
118
+ * etc., with kind:"module") but appear in `modules`, not here. Scan +
119
+ * Studio consume both lists for the Plugins page.
120
+ */
121
+ readonly plugins: readonly PluginDefinition[];
107
122
  readonly container: Container;
108
123
  readonly appName: string;
109
124
  start(): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"create-app.d.ts","sourceRoot":"","sources":["../src/create-app.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,EAAiB,KAAK,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAEjE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,EAAsB,KAAK,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAoB5E,MAAM,WAAW,qBAAqB;IACpC,oEAAoE;IACpE,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,OAAO,EAAE,SAAS,gBAAgB,EAAE,CAAC;IAC9C;;;;;;;;OAQG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,gBAAgB,EAAE,CAAC;IAC/C;;;OAGG;IAEH,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACtC,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,CAAC;IAC/B,QAAQ,CAAC,UAAU,CAAC,EAAE,UAAU,CAAC;IACjC,QAAQ,CAAC,eAAe,CAAC,EAAE,eAAe,CAAC;IAC3C,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,cAAc,CAAC,EAAE,cAAc,CAAC;IACzC;;;;;;OAMG;IACH,QAAQ,CAAC,GAAG,CAAC,EAAE,QAAQ,CAAC;IACxB;;;OAGG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,OAAO,CAAC;IAChC;;;;OAIG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B;;;;;;;;;OASG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,qBAAqB,GAAG,IAAI,CAAC;IACvD;;;;;;;;;OASG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,GAAG,OAAO,iBAAiB,EAAE,gBAAgB,CAAC;CACzE;AAED,MAAM,WAAW,GAAG;IAClB,0EAA0E;IAC1E,QAAQ,CAAC,SAAS,EAAE,IAAI,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,OAAO,EAAE,SAAS,gBAAgB,EAAE,CAAC;IAC9C,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;IAC9B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB;;;;;OAKG;IACH,IAAI,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACrC,qDAAqD;IACrD,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACtB,oDAAoD;IACpD,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1B;;;;;;OAMG;IACH,sBAAsB,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAC/E;AAED,wBAAgB,SAAS,CAAC,OAAO,EAAE,gBAAgB,GAAG,GAAG,CA+axD"}
1
+ {"version":3,"file":"create-app.d.ts","sourceRoot":"","sources":["../src/create-app.ts"],"names":[],"mappings":"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"}