@nwire/forge 0.9.2 → 0.10.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.
Files changed (291) hide show
  1. package/README.md +133 -155
  2. package/dist/foundation.d.ts +0 -13
  3. package/dist/foundation.js +2 -13
  4. package/dist/framework-events.d.ts +51 -54
  5. package/dist/framework-events.js +18 -65
  6. package/dist/{cli-runner.d.ts → helpers/cli-runner.d.ts} +2 -3
  7. package/dist/{cli-runner.js → helpers/cli-runner.js} +11 -27
  8. package/dist/{public-marker.d.ts → helpers/public-marker.d.ts} +0 -1
  9. package/dist/{public-marker.js → helpers/public-marker.js} +0 -1
  10. package/dist/{response.d.ts → helpers/response.d.ts} +0 -1
  11. package/dist/{response.js → helpers/response.js} +0 -1
  12. package/dist/helpers/retry-helpers.d.ts +22 -0
  13. package/dist/helpers/retry-helpers.js +43 -0
  14. package/dist/{validate.d.ts → helpers/validate.d.ts} +0 -1
  15. package/dist/{validate.js → helpers/validate.js} +0 -1
  16. package/dist/index.d.ts +42 -48
  17. package/dist/index.js +47 -55
  18. package/dist/{event-message.d.ts → messages/event-message.d.ts} +0 -1
  19. package/dist/{event-message.js → messages/event-message.js} +0 -1
  20. package/dist/{dev-logger.d.ts → observability/dev-logger.d.ts} +2 -2
  21. package/dist/{dev-logger.js → observability/dev-logger.js} +0 -30
  22. package/dist/{define-action.d.ts → primitives/define-action.d.ts} +0 -1
  23. package/dist/{define-action.js → primitives/define-action.js} +0 -1
  24. package/dist/{define-actor.d.ts → primitives/define-actor.d.ts} +0 -1
  25. package/dist/{define-actor.js → primitives/define-actor.js} +0 -1
  26. package/dist/{define-cron.d.ts → primitives/define-cron.d.ts} +0 -1
  27. package/dist/{define-cron.js → primitives/define-cron.js} +0 -1
  28. package/dist/{define-error.d.ts → primitives/define-error.d.ts} +0 -1
  29. package/dist/{define-error.js → primitives/define-error.js} +0 -1
  30. package/dist/{define-external-call.d.ts → primitives/define-external-call.d.ts} +0 -1
  31. package/dist/{define-external-call.js → primitives/define-external-call.js} +0 -1
  32. package/dist/{define-handler.d.ts → primitives/define-handler.d.ts} +29 -2
  33. package/dist/{define-handler.js → primitives/define-handler.js} +13 -2
  34. package/dist/{define-inbound-webhook.d.ts → primitives/define-inbound-webhook.d.ts} +1 -2
  35. package/dist/{define-inbound-webhook.js → primitives/define-inbound-webhook.js} +1 -2
  36. package/dist/{define-inbox.d.ts → primitives/define-inbox.d.ts} +0 -1
  37. package/dist/{define-inbox.js → primitives/define-inbox.js} +0 -1
  38. package/dist/{define-outbox.d.ts → primitives/define-outbox.d.ts} +0 -1
  39. package/dist/{define-outbox.js → primitives/define-outbox.js} +0 -1
  40. package/dist/{define-projection.d.ts → primitives/define-projection.d.ts} +0 -1
  41. package/dist/{define-projection.js → primitives/define-projection.js} +0 -1
  42. package/dist/{define-query.d.ts → primitives/define-query.d.ts} +1 -2
  43. package/dist/{define-query.js → primitives/define-query.js} +1 -2
  44. package/dist/{define-schema.d.ts → primitives/define-schema.d.ts} +1 -2
  45. package/dist/{define-schema.js → primitives/define-schema.js} +1 -2
  46. package/dist/{define-upcaster.d.ts → primitives/define-upcaster.d.ts} +0 -1
  47. package/dist/{define-upcaster.js → primitives/define-upcaster.js} +0 -1
  48. package/dist/{define-workflow.d.ts → primitives/define-workflow.d.ts} +2 -3
  49. package/dist/{define-workflow.js → primitives/define-workflow.js} +2 -3
  50. package/dist/runtime/create-forge-app.d.ts +64 -0
  51. package/dist/runtime/create-forge-app.js +78 -0
  52. package/dist/runtime/forge-dispatcher.d.ts +148 -0
  53. package/dist/{runtime.js → runtime/forge-dispatcher.js} +242 -571
  54. package/dist/runtime/forge-plugin.d.ts +59 -0
  55. package/dist/runtime/forge-plugin.js +121 -0
  56. package/dist/runtime/forge-types.d.ts +204 -0
  57. package/dist/runtime/forge-types.js +5 -0
  58. package/dist/{actor-store.d.ts → stores/actor-store.d.ts} +1 -2
  59. package/dist/{actor-store.js → stores/actor-store.js} +0 -1
  60. package/dist/{idempotency-store.d.ts → stores/idempotency-store.d.ts} +0 -1
  61. package/dist/{idempotency-store.js → stores/idempotency-store.js} +0 -1
  62. package/dist/{projection-store.d.ts → stores/projection-store.d.ts} +0 -1
  63. package/dist/{projection-store.js → stores/projection-store.js} +0 -1
  64. package/dist/{workflow-timer-store.d.ts → stores/workflow-timer-store.d.ts} +0 -1
  65. package/dist/{workflow-timer-store.js → stores/workflow-timer-store.js} +0 -1
  66. package/package.json +11 -11
  67. package/dist/__tests__/action-hooks.test.d.ts +0 -8
  68. package/dist/__tests__/action-hooks.test.d.ts.map +0 -1
  69. package/dist/__tests__/action-hooks.test.js +0 -95
  70. package/dist/__tests__/action-hooks.test.js.map +0 -1
  71. package/dist/__tests__/actor-methods.test.d.ts +0 -9
  72. package/dist/__tests__/actor-methods.test.d.ts.map +0 -1
  73. package/dist/__tests__/actor-methods.test.js +0 -210
  74. package/dist/__tests__/actor-methods.test.js.map +0 -1
  75. package/dist/__tests__/actor-schema-bound.test.d.ts +0 -6
  76. package/dist/__tests__/actor-schema-bound.test.d.ts.map +0 -1
  77. package/dist/__tests__/actor-schema-bound.test.js +0 -112
  78. package/dist/__tests__/actor-schema-bound.test.js.map +0 -1
  79. package/dist/__tests__/actor-workflow-hooks.test.d.ts +0 -8
  80. package/dist/__tests__/actor-workflow-hooks.test.d.ts.map +0 -1
  81. package/dist/__tests__/actor-workflow-hooks.test.js +0 -106
  82. package/dist/__tests__/actor-workflow-hooks.test.js.map +0 -1
  83. package/dist/__tests__/app-capabilities.test.d.ts +0 -19
  84. package/dist/__tests__/app-capabilities.test.d.ts.map +0 -1
  85. package/dist/__tests__/app-capabilities.test.js +0 -57
  86. package/dist/__tests__/app-capabilities.test.js.map +0 -1
  87. package/dist/__tests__/cli-runner.test.d.ts +0 -6
  88. package/dist/__tests__/cli-runner.test.d.ts.map +0 -1
  89. package/dist/__tests__/cli-runner.test.js +0 -158
  90. package/dist/__tests__/cli-runner.test.js.map +0 -1
  91. package/dist/__tests__/create-app.test.d.ts +0 -18
  92. package/dist/__tests__/create-app.test.d.ts.map +0 -1
  93. package/dist/__tests__/create-app.test.js +0 -189
  94. package/dist/__tests__/create-app.test.js.map +0 -1
  95. package/dist/__tests__/cross-service-bus.test.d.ts +0 -8
  96. package/dist/__tests__/cross-service-bus.test.d.ts.map +0 -1
  97. package/dist/__tests__/cross-service-bus.test.js +0 -139
  98. package/dist/__tests__/cross-service-bus.test.js.map +0 -1
  99. package/dist/__tests__/define-schema.test.d.ts +0 -5
  100. package/dist/__tests__/define-schema.test.d.ts.map +0 -1
  101. package/dist/__tests__/define-schema.test.js +0 -83
  102. package/dist/__tests__/define-schema.test.js.map +0 -1
  103. package/dist/__tests__/dev-logger.test.d.ts +0 -9
  104. package/dist/__tests__/dev-logger.test.d.ts.map +0 -1
  105. package/dist/__tests__/dev-logger.test.js +0 -126
  106. package/dist/__tests__/dev-logger.test.js.map +0 -1
  107. package/dist/__tests__/external-call.test.d.ts +0 -14
  108. package/dist/__tests__/external-call.test.d.ts.map +0 -1
  109. package/dist/__tests__/external-call.test.js +0 -99
  110. package/dist/__tests__/external-call.test.js.map +0 -1
  111. package/dist/__tests__/framework-events.test.d.ts +0 -13
  112. package/dist/__tests__/framework-events.test.d.ts.map +0 -1
  113. package/dist/__tests__/framework-events.test.js +0 -204
  114. package/dist/__tests__/framework-events.test.js.map +0 -1
  115. package/dist/__tests__/inline-handler.test.d.ts +0 -8
  116. package/dist/__tests__/inline-handler.test.d.ts.map +0 -1
  117. package/dist/__tests__/inline-handler.test.js +0 -101
  118. package/dist/__tests__/inline-handler.test.js.map +0 -1
  119. package/dist/__tests__/lifecycle-logging.test.d.ts +0 -12
  120. package/dist/__tests__/lifecycle-logging.test.d.ts.map +0 -1
  121. package/dist/__tests__/lifecycle-logging.test.js +0 -114
  122. package/dist/__tests__/lifecycle-logging.test.js.map +0 -1
  123. package/dist/__tests__/middleware.test.d.ts +0 -7
  124. package/dist/__tests__/middleware.test.d.ts.map +0 -1
  125. package/dist/__tests__/middleware.test.js +0 -109
  126. package/dist/__tests__/middleware.test.js.map +0 -1
  127. package/dist/__tests__/module-needs.test.d.ts +0 -10
  128. package/dist/__tests__/module-needs.test.d.ts.map +0 -1
  129. package/dist/__tests__/module-needs.test.js +0 -77
  130. package/dist/__tests__/module-needs.test.js.map +0 -1
  131. package/dist/__tests__/module-topo-sort.test.d.ts +0 -15
  132. package/dist/__tests__/module-topo-sort.test.d.ts.map +0 -1
  133. package/dist/__tests__/module-topo-sort.test.js +0 -105
  134. package/dist/__tests__/module-topo-sort.test.js.map +0 -1
  135. package/dist/__tests__/multi-tenancy.test.d.ts +0 -10
  136. package/dist/__tests__/multi-tenancy.test.d.ts.map +0 -1
  137. package/dist/__tests__/multi-tenancy.test.js +0 -122
  138. package/dist/__tests__/multi-tenancy.test.js.map +0 -1
  139. package/dist/__tests__/needs-topology.test.d.ts +0 -11
  140. package/dist/__tests__/needs-topology.test.d.ts.map +0 -1
  141. package/dist/__tests__/needs-topology.test.js +0 -82
  142. package/dist/__tests__/needs-topology.test.js.map +0 -1
  143. package/dist/__tests__/plugin-app-narrow.test.d.ts +0 -12
  144. package/dist/__tests__/plugin-app-narrow.test.d.ts.map +0 -1
  145. package/dist/__tests__/plugin-app-narrow.test.js +0 -77
  146. package/dist/__tests__/plugin-app-narrow.test.js.map +0 -1
  147. package/dist/__tests__/plugin-closure.test.d.ts +0 -15
  148. package/dist/__tests__/plugin-closure.test.d.ts.map +0 -1
  149. package/dist/__tests__/plugin-closure.test.js +0 -140
  150. package/dist/__tests__/plugin-closure.test.js.map +0 -1
  151. package/dist/__tests__/plugin-stress.test.d.ts +0 -21
  152. package/dist/__tests__/plugin-stress.test.d.ts.map +0 -1
  153. package/dist/__tests__/plugin-stress.test.js +0 -203
  154. package/dist/__tests__/plugin-stress.test.js.map +0 -1
  155. package/dist/__tests__/plugin.test.d.ts +0 -10
  156. package/dist/__tests__/plugin.test.d.ts.map +0 -1
  157. package/dist/__tests__/plugin.test.js +0 -225
  158. package/dist/__tests__/plugin.test.js.map +0 -1
  159. package/dist/__tests__/primitives.test.d.ts +0 -9
  160. package/dist/__tests__/primitives.test.d.ts.map +0 -1
  161. package/dist/__tests__/primitives.test.js +0 -434
  162. package/dist/__tests__/primitives.test.js.map +0 -1
  163. package/dist/__tests__/production-readiness.test.d.ts +0 -22
  164. package/dist/__tests__/production-readiness.test.d.ts.map +0 -1
  165. package/dist/__tests__/production-readiness.test.js +0 -196
  166. package/dist/__tests__/production-readiness.test.js.map +0 -1
  167. package/dist/__tests__/provider.test.d.ts +0 -6
  168. package/dist/__tests__/provider.test.d.ts.map +0 -1
  169. package/dist/__tests__/provider.test.js +0 -122
  170. package/dist/__tests__/provider.test.js.map +0 -1
  171. package/dist/__tests__/public-marker.test.d.ts +0 -7
  172. package/dist/__tests__/public-marker.test.d.ts.map +0 -1
  173. package/dist/__tests__/public-marker.test.js +0 -58
  174. package/dist/__tests__/public-marker.test.js.map +0 -1
  175. package/dist/__tests__/retry-dlq.test.d.ts +0 -6
  176. package/dist/__tests__/retry-dlq.test.d.ts.map +0 -1
  177. package/dist/__tests__/retry-dlq.test.js +0 -68
  178. package/dist/__tests__/retry-dlq.test.js.map +0 -1
  179. package/dist/__tests__/validate.test.d.ts +0 -5
  180. package/dist/__tests__/validate.test.d.ts.map +0 -1
  181. package/dist/__tests__/validate.test.js +0 -53
  182. package/dist/__tests__/validate.test.js.map +0 -1
  183. package/dist/__tests__/workflow-saga.test.d.ts +0 -7
  184. package/dist/__tests__/workflow-saga.test.d.ts.map +0 -1
  185. package/dist/__tests__/workflow-saga.test.js +0 -265
  186. package/dist/__tests__/workflow-saga.test.js.map +0 -1
  187. package/dist/actor-store.d.ts.map +0 -1
  188. package/dist/actor-store.js.map +0 -1
  189. package/dist/cli-runner.d.ts.map +0 -1
  190. package/dist/cli-runner.js.map +0 -1
  191. package/dist/create-app.d.ts +0 -146
  192. package/dist/create-app.d.ts.map +0 -1
  193. package/dist/create-app.js +0 -703
  194. package/dist/create-app.js.map +0 -1
  195. package/dist/define-action.d.ts.map +0 -1
  196. package/dist/define-action.js.map +0 -1
  197. package/dist/define-actor.d.ts.map +0 -1
  198. package/dist/define-actor.js.map +0 -1
  199. package/dist/define-app.d.ts +0 -104
  200. package/dist/define-app.d.ts.map +0 -1
  201. package/dist/define-app.js +0 -49
  202. package/dist/define-app.js.map +0 -1
  203. package/dist/define-cron.d.ts.map +0 -1
  204. package/dist/define-cron.js.map +0 -1
  205. package/dist/define-error.d.ts.map +0 -1
  206. package/dist/define-error.js.map +0 -1
  207. package/dist/define-external-call.d.ts.map +0 -1
  208. package/dist/define-external-call.js.map +0 -1
  209. package/dist/define-handler.d.ts.map +0 -1
  210. package/dist/define-handler.js.map +0 -1
  211. package/dist/define-inbound-webhook.d.ts.map +0 -1
  212. package/dist/define-inbound-webhook.js.map +0 -1
  213. package/dist/define-inbox.d.ts.map +0 -1
  214. package/dist/define-inbox.js.map +0 -1
  215. package/dist/define-initializer.d.ts +0 -54
  216. package/dist/define-initializer.d.ts.map +0 -1
  217. package/dist/define-initializer.js +0 -38
  218. package/dist/define-initializer.js.map +0 -1
  219. package/dist/define-middleware.d.ts +0 -8
  220. package/dist/define-middleware.d.ts.map +0 -1
  221. package/dist/define-middleware.js +0 -8
  222. package/dist/define-middleware.js.map +0 -1
  223. package/dist/define-model.d.ts +0 -10
  224. package/dist/define-model.d.ts.map +0 -1
  225. package/dist/define-model.js +0 -13
  226. package/dist/define-model.js.map +0 -1
  227. package/dist/define-module.d.ts +0 -160
  228. package/dist/define-module.d.ts.map +0 -1
  229. package/dist/define-module.js +0 -63
  230. package/dist/define-module.js.map +0 -1
  231. package/dist/define-outbox.d.ts.map +0 -1
  232. package/dist/define-outbox.js.map +0 -1
  233. package/dist/define-plugin.d.ts +0 -195
  234. package/dist/define-plugin.d.ts.map +0 -1
  235. package/dist/define-plugin.js +0 -220
  236. package/dist/define-plugin.js.map +0 -1
  237. package/dist/define-projection.d.ts.map +0 -1
  238. package/dist/define-projection.js.map +0 -1
  239. package/dist/define-provider.d.ts +0 -49
  240. package/dist/define-provider.d.ts.map +0 -1
  241. package/dist/define-provider.js +0 -45
  242. package/dist/define-provider.js.map +0 -1
  243. package/dist/define-query.d.ts.map +0 -1
  244. package/dist/define-query.js.map +0 -1
  245. package/dist/define-resolver.d.ts +0 -111
  246. package/dist/define-resolver.d.ts.map +0 -1
  247. package/dist/define-resolver.js +0 -146
  248. package/dist/define-resolver.js.map +0 -1
  249. package/dist/define-schema.d.ts.map +0 -1
  250. package/dist/define-schema.js.map +0 -1
  251. package/dist/define-upcaster.d.ts.map +0 -1
  252. package/dist/define-upcaster.js.map +0 -1
  253. package/dist/define-workflow.d.ts.map +0 -1
  254. package/dist/define-workflow.js.map +0 -1
  255. package/dist/dev-logger.d.ts.map +0 -1
  256. package/dist/dev-logger.js.map +0 -1
  257. package/dist/event-message.d.ts.map +0 -1
  258. package/dist/event-message.js.map +0 -1
  259. package/dist/foundation.d.ts.map +0 -1
  260. package/dist/foundation.js.map +0 -1
  261. package/dist/framework-event-bus.d.ts +0 -13
  262. package/dist/framework-event-bus.d.ts.map +0 -1
  263. package/dist/framework-event-bus.js +0 -13
  264. package/dist/framework-event-bus.js.map +0 -1
  265. package/dist/framework-events.d.ts.map +0 -1
  266. package/dist/framework-events.js.map +0 -1
  267. package/dist/idempotency-store.d.ts.map +0 -1
  268. package/dist/idempotency-store.js.map +0 -1
  269. package/dist/index.d.ts.map +0 -1
  270. package/dist/index.js.map +0 -1
  271. package/dist/module-surface.d.ts +0 -47
  272. package/dist/module-surface.d.ts.map +0 -1
  273. package/dist/module-surface.js +0 -65
  274. package/dist/module-surface.js.map +0 -1
  275. package/dist/projection-store.d.ts.map +0 -1
  276. package/dist/projection-store.js.map +0 -1
  277. package/dist/public-marker.d.ts.map +0 -1
  278. package/dist/public-marker.js.map +0 -1
  279. package/dist/response.d.ts.map +0 -1
  280. package/dist/response.js.map +0 -1
  281. package/dist/runtime.d.ts +0 -621
  282. package/dist/runtime.d.ts.map +0 -1
  283. package/dist/runtime.js.map +0 -1
  284. package/dist/validate.d.ts.map +0 -1
  285. package/dist/validate.js.map +0 -1
  286. package/dist/when.d.ts +0 -101
  287. package/dist/when.d.ts.map +0 -1
  288. package/dist/when.js +0 -57
  289. package/dist/when.js.map +0 -1
  290. package/dist/workflow-timer-store.d.ts.map +0 -1
  291. package/dist/workflow-timer-store.js.map +0 -1
package/README.md CHANGED
@@ -1,194 +1,172 @@
1
1
  # @nwire/forge
2
2
 
3
- > The framework's domain primitives actions, actors, events, workflows, projections, modules, plugins, and the runtime that fires them.
4
-
5
- Forge composes the lower packages (`@nwire/messages`, `@nwire/handler`,
6
- `@nwire/app`) into one ergonomic surface. You can drop down to any of
7
- them when you want a narrower import; forge stays the default for app code.
3
+ > Domain primitives: actions, actors, events, workflows, projections.
4
+ > Plus the runtime that fires them.
8
5
 
9
6
  ```bash
10
7
  pnpm add @nwire/forge zod
11
8
  ```
12
9
 
13
- ## 5-minute tour
14
-
15
- Two primitives carry most of an app: `defineSchema` declares the data shape +
16
- lifecycle, `defineActor` (closure form) declares the methods + transitions
17
- against it. Everything else (`defineAction`, `defineModule`, `createApp`)
18
- plugs in around them.
10
+ ## Quick tour
19
11
 
20
- ### 1. Declare the data + lifecycle with `defineSchema`
12
+ ### 1. Define an action
21
13
 
22
14
  ```ts
15
+ import { defineAction } from "@nwire/forge";
23
16
  import { z } from "zod";
24
- import { defineSchema } from "@nwire/forge";
25
-
26
- export const SubmissionData = defineSchema({
27
- name: "submission",
28
- key: "submissionId",
29
- fields: {
30
- submissionId: z.string(),
31
- studentId: z.string(),
32
- answer: z.string(),
33
- verdict: z.string().optional(),
34
- gradedAt: z.string().datetime().optional(),
35
- },
36
- states: {
37
- submitted: { initial: true },
38
- "under-review": {},
39
- graded: { final: true },
40
- },
17
+
18
+ export const placeOrder = defineAction({
19
+ name: "orders.place",
20
+ schema: z.object({
21
+ customerId: z.string(),
22
+ items: z.array(z.object({ sku: z.string(), qty: z.number().int().positive() })),
23
+ }),
24
+ });
25
+ ```
26
+
27
+ An action is a typed contract — a name + zod schema. The runtime
28
+ validates input on every dispatch.
29
+
30
+ ### 2. Define a handler
31
+
32
+ ```ts
33
+ import { defineHandler } from "@nwire/forge";
34
+
35
+ export const placeOrderHandler = defineHandler(placeOrder, async (input, ctx) => {
36
+ const orders = ctx.resolve<OrderRepo>("orders");
37
+ return orders.create(input);
38
+ });
39
+ ```
40
+
41
+ `(input, ctx)` is the canonical handler shape. `ctx` carries:
42
+
43
+ - `resolve<T>(name)` — pull bindings from the container
44
+ - `envelope` — tenant, user, correlation, causation
45
+ - `dispatch(action, input)` — fire other actions
46
+ - `enqueue(queueName, payload)` — defer work to a queue
47
+ - `emit(event, payload)` — emit a domain event
48
+
49
+ ### 3. Wire it into an App
50
+
51
+ ```ts
52
+ import { createApp } from "@nwire/app";
53
+ import { createForgePlugin } from "@nwire/forge";
54
+ import { post } from "@nwire/wires/http";
55
+
56
+ const app = createApp({
57
+ appName: "orders",
58
+ plugins: [createForgePlugin({})],
59
+ handlers: [placeOrderHandler],
60
+ });
61
+
62
+ // HTTP route dispatches the same handler
63
+ app.wire(post("/orders", { body: placeOrder.schema }), placeOrderHandler);
64
+ ```
65
+
66
+ `createForgePlugin({})` installs the dispatcher; handlers passed in
67
+ `createApp({ handlers })` register on it at boot.
68
+
69
+ ### 4. Dispatch from anywhere
70
+
71
+ ```ts
72
+ const dispatcher = app.container.resolve<ForgeDispatcher>("forge.dispatcher");
73
+
74
+ await dispatcher.dispatch(placeOrder, {
75
+ customerId: "c-1",
76
+ items: [{ sku: "WIDGET", qty: 2 }],
41
77
  });
42
78
  ```
43
79
 
44
- The schema is the single source of truth for the data model and the set of
45
- valid lifecycle states Studio renders it, persistent stores (`@nwire/store-mongo`,
46
- `@nwire/store-prisma`) read `storage.indexes` / `storage.unique` from it, and
47
- `defineActor` borrows `key` + `initial` + the state names off it.
80
+ The runtime validates input, opens an envelope, runs middleware, fires
81
+ `action.before` hooks, executes the handler, runs `action.after` hooks,
82
+ and surfaces telemetry. HTTP and queue adopters route through the same
83
+ path so dispatch semantics never differ by transport.
48
84
 
49
- ### 2. Bind methods + transitions with `defineActor` (closure form)
85
+ ## Actors
50
86
 
51
87
  ```ts
52
88
  import { defineActor } from "@nwire/forge";
53
- import { SubmissionData } from "./submission.schema";
54
- import { SubmissionWasFlagged, SubmissionWasGraded } from "./events";
55
-
56
- export const Submission = defineActor(
57
- SubmissionData,
58
- ({ data, id, validate, recordThat, when, methods, states }) => {
59
- const { underReview, graded } = states;
60
-
61
- // Methods enforce invariants and `recordThat` the events. They don't
62
- // mutate state directly `when(...)` below folds the recorded events
63
- // into state.
64
- const flag = (input: { reason: string }) => {
65
- validate(input, [(i) => i.reason.length > 0 || "reason required"]);
66
- recordThat(SubmissionWasFlagged({ submissionId: id, reason: input.reason }));
67
- };
68
- const grade = (input: { verdict: string }) => {
69
- recordThat(SubmissionWasGraded({ submissionId: id, verdict: input.verdict }));
70
- };
71
-
72
- when(SubmissionWasFlagged, (_e, { assign }) => {
73
- assign({}); // no field changes — state move only
74
- return underReview; // transition: submitted → under-review
75
- });
76
- when(SubmissionWasGraded, (e, { assign }) => {
77
- assign({ verdict: e.verdict, gradedAt: new Date().toISOString() });
78
- return graded; // transition into the final state
79
- });
80
-
81
- return methods({ flag, grade });
89
+
90
+ export const subscription = defineActor({
91
+ name: "subscription",
92
+ schema: z.object({
93
+ id: z.string(),
94
+ plan: z.enum(["free", "pro"]),
95
+ status: z.enum(["active", "past_due", "suspended"]),
96
+ }),
97
+ methods: {
98
+ suspend: ({ self }) => ({ ...self, status: "suspended" }),
99
+ activate: ({ self }) => ({ ...self, status: "active" }),
82
100
  },
83
- );
101
+ });
84
102
  ```
85
103
 
86
- The closure runs once at define time (to capture transitions + method names)
87
- and again per `ctx.use(Submission, id)` call (to bind methods over the live
88
- `data`). `recordThat` collects events the runtime publishes after the method
89
- returns; `when` is the matching fold — methods never write to state directly,
90
- so the actor's history is always the event log.
104
+ Actors carry state, version, and OCC. Methods receive the current state
105
+ and return the next state pure transitions. The dispatcher persists
106
+ through an `ActorStore` adapter.
91
107
 
92
- > See: [write paths (actor xor direct-DB)](https://nwire.dev/concepts/write-paths) — a handler picks one path per write; never both.
108
+ ## Workflows
93
109
 
94
- **Object form vs. closure form** — both exist. Use the closure form when you
95
- want typed `states.<name>` refs, want methods and folds in the same file, and
96
- want invariants on the input shape (`validate(...)`); use the object form
97
- (`defineActor(name, { schema, key, initial, states, methods })`) when the
98
- state machine is the whole story and you don't need per-method input
99
- validation.
110
+ ```ts
111
+ import { defineWorkflow } from "@nwire/forge";
112
+
113
+ export const paymentRenewal = defineWorkflow({
114
+ name: "payment.renewal",
115
+ on: { event: chargeFailed },
116
+ steps: {
117
+ holdGrace: async (ctx) => {
118
+ await ctx.schedule(suspendSubscription, { in: "48h" });
119
+ },
120
+ },
121
+ });
122
+ ```
123
+
124
+ Workflows react to events. `ctx.schedule(...)` arms timers, `ctx.dispatch(...)`
125
+ fires actions; state persists between hops via the actor store.
100
126
 
101
- ### 3. Wire it into a module + app
127
+ ## Projections
102
128
 
103
129
  ```ts
104
- import { defineAction, defineModule, createApp, AppBooted, ActionCompleted } from "@nwire/forge";
105
- import { z } from "zod";
130
+ import { defineProjection } from "@nwire/forge";
106
131
 
107
- export const flagSubmission = defineAction({
108
- name: "submissions.flag",
109
- schema: z.object({ submissionId: z.string(), reason: z.string() }),
110
- emits: [SubmissionWasFlagged],
111
- handler: async (input, { use }) => {
112
- const sub = await use(Submission, input.submissionId);
113
- sub.flag({ reason: input.reason }); // recorded event(s) published by runtime
132
+ export const queueDashboard = defineProjection({
133
+ name: "queue.dashboard",
134
+ on: { event: postSubmitted },
135
+ apply: async (state, event) => {
136
+ state.pending.push({ id: event.payload.postId, submittedAt: event.envelope.ts });
114
137
  },
115
138
  });
139
+ ```
116
140
 
117
- export const submissions = defineModule("submissions", {
118
- events: [SubmissionWasFlagged, SubmissionWasGraded],
119
- actors: [Submission],
120
- actions: [flagSubmission.public()],
121
- });
141
+ Projections build read models from events. Domain code reads them via
142
+ `ctx.resolve<ProjectionStore>("projection.queue.dashboard")`.
122
143
 
123
- const app = createApp({ modules: [submissions] });
124
- app.bus.on(AppBooted, ({ appName }) => console.log("booted:", appName));
125
- app.bus.on(ActionCompleted, ({ action }) => console.log("ran:", action.name));
144
+ ## Plugin options
126
145
 
127
- await app.start();
128
- await app.runtime.dispatch(flagSubmission, { submissionId: "s-1", reason: "off-topic" });
146
+ `createForgePlugin({...})` accepts:
147
+
148
+ ```ts
149
+ createForgePlugin({
150
+ workflows: [paymentRenewal],
151
+ projections: [queueDashboard],
152
+ queries: [listPending, queueTotals],
153
+ actors: [subscription],
154
+ externalCalls: [chargeStripe],
155
+ });
129
156
  ```
130
157
 
131
158
  ## Surface
132
159
 
133
- ### Domain primitives
134
-
135
- | Export | Role |
136
- | --------------------------------------------------------------------------------------------- | ------------------------------------------------------------ |
137
- | `defineAction` | User-visible commandvalidated input, emits events |
138
- | `defineEvent` | Past-tense fact (re-exported from `@nwire/messages`) |
139
- | `defineHandler` | Operation primitive — transport-agnostic |
140
- | `defineActor` | Aggregate with state, methods, optional state machine |
141
- | `defineSchema` | Data shape + lifecycle states + storage hints |
142
- | `defineProjection` | Read-model fold over events |
143
- | `defineQuery` | Projection-backed read function |
144
- | `defineWorkflow` | Reaction + saga unified — stateless or stateful |
145
- | `defineModule` | Bundle of actors + actions + events + projections + queries |
146
- | `defineApp` | App declaration (multi-wire instantiation) |
147
- | `createApp` | App runtime — boots modules, owns the bus and runtime |
148
- | `definePlugin` | Forge-richer plugin: middleware + actor hooks + before/after |
149
- | `defineResource` | Public response shape (field allowlist + OpenAPI schema) |
150
- | `defineError` | Typed throwable with status code |
151
- | `defineMiddleware` / `defineHook` / `pipe` | Reusable resolver chain pieces |
152
- | `defineCron` / `defineInbox` / `defineOutbox` / `defineExternalCall` / `defineInboundWebhook` | Orchestrator primitives |
153
- | `runCli(app, argv)` | Argv dispatcher — operator CLI without HTTP |
154
-
155
- ### Framework events
156
-
157
- Forge re-exports the app-lifecycle events from `@nwire/app`
158
- (`AppRegistering` / `AppBooting` / `AppBooted` / `AppReady` /
159
- `AppShuttingDown` / `AppShutdown`, `PluginRegistered` …, `WireMounting` …)
160
- and adds its own forge-local events:
161
-
162
- | Event | Mode | When |
163
- | ------------------------ | ----------- | ----------------------------------------------------- |
164
- | `ActionDispatching` | series-bail | Before handler runs. Return `false` to short-circuit. |
165
- | `ActionCompleted` | parallel | After handler returns successfully. |
166
- | `ActionFailed` | parallel | After handler throws. |
167
- | `EventRecording` | series-bail | Before an event is appended to the store. |
168
- | `EventRecorded` | parallel | After append succeeds. |
169
- | `builtInFrameworkEvents` | — | Catalog of every built-in (lifecycle + forge-local). |
170
-
171
- ### Re-exports
172
-
173
- - `MessageEnvelope`, `seedEnvelope`, `deriveEnvelope` from `@nwire/envelope`
174
- - `Logger` contract + `NoopLogger` / `ConsoleLogger` from `@nwire/logger`
175
- - `DeadLetterSink` + `InMemoryDeadLetterSink` from `@nwire/dead-letter`
176
-
177
- ## Picking the right entry point
178
-
179
- | You want… | Import from |
180
- | --------------------------------------- | ----------------- |
181
- | Full framework DX in one import | `@nwire/forge` |
182
- | Just operations (handlers / middleware) | `@nwire/handler` |
183
- | Just lifecycle + plugins | `@nwire/app` |
184
- | Just events + envelope | `@nwire/messages` |
160
+ - **Primitives** — `defineAction`, `defineActor`, `defineEvent`,
161
+ `defineWorkflow`, `defineProjection`, `defineQuery`, `defineHandler`
162
+ - **Plugin** — `createForgePlugin(options)`
163
+ - **Dispatcher** `ForgeDispatcher` (resolved as `"forge.dispatcher"`)
164
+ - **Helpers**`eventFactory`, `defineResource`, `NotFound`,
165
+ `defineUpcaster`, response builders
185
166
 
186
167
  ## Related
187
168
 
188
- - `@nwire/endpoint` — wraps the runtime in a process (graceful shutdown, probes).
189
- - `@nwire/http` — HTTP transport over the runtime.
190
- - `@nwire/hooks` — the dispatch substrate that powers `runtime.use(...)` and every framework event.
191
-
192
- ## Status
193
-
194
- v0.x — public surface is stable; `createApp` will extract to `@nwire/app` in a follow-up phase but imports won't change (re-exports preserved).
169
+ - [`@nwire/app`](../core-app)`createApp`, plugin lifecycle, runtime
170
+ - [`@nwire/handler`](../core-handler)handler contract + error envelope
171
+ - [`@nwire/messages`](../core-messages)typed envelope + zod helpers
172
+ - [`@nwire/koa`](../nwire-koa) — HTTP adopter that routes through the dispatcher
@@ -1,14 +1 @@
1
- /**
2
- * `@nwire/forge` — Nwire framework primitives.
3
- *
4
- * Public surface domain code uses: `defineAction`, `defineEvent`,
5
- * `defineHandler`, `defineActor`, `defineProjection`, `defineQuery`,
6
- * `defineWorkflow`, `defineModule`, `defineApp`, `definePlugin`,
7
- * `createApp`, `eventFactory`, the runtime, and the InMemory store defaults.
8
- *
9
- * `MessageEnvelope` and its constructors are re-exported from `@nwire/envelope`
10
- * so consumers don't need to import that package separately.
11
- */
12
- export { seedEnvelope, deriveEnvelope, type MessageEnvelope, type SeedEnvelopeInput, } from "@nwire/envelope";
13
1
  export * from "./index.js";
14
- //# sourceMappingURL=foundation.d.ts.map
@@ -1,14 +1,3 @@
1
- /**
2
- * `@nwire/forge` Nwire framework primitives.
3
- *
4
- * Public surface domain code uses: `defineAction`, `defineEvent`,
5
- * `defineHandler`, `defineActor`, `defineProjection`, `defineQuery`,
6
- * `defineWorkflow`, `defineModule`, `defineApp`, `definePlugin`,
7
- * `createApp`, `eventFactory`, the runtime, and the InMemory store defaults.
8
- *
9
- * `MessageEnvelope` and its constructors are re-exported from `@nwire/envelope`
10
- * so consumers don't need to import that package separately.
11
- */
12
- export { seedEnvelope, deriveEnvelope, } from "@nwire/envelope";
1
+ // Legacy entry alias — package.json + downstream aliases reference
2
+ // `foundation`. Real surface lives in `./index`.
13
3
  export * from "./index.js";
14
- //# sourceMappingURL=foundation.js.map
@@ -1,58 +1,55 @@
1
1
  /**
2
- * Framework events — re-exports of app-layer events + forge-specific events.
2
+ * Forge framework-hook augmentation.
3
3
  *
4
- * The generic infrastructure (`defineFrameworkEvent` +
5
- * `FrameworkEventDefinition`) and the app-lifecycle events (App* / Plugin* /
6
- * Wire*) live in `@nwire/app`; this module re-exports them so consumers
7
- * pulling from forge get one import line.
4
+ * Action-specific and event-recording slots are added to the kernel's
5
+ * `FrameworkHooks` registry via TS module augmentation. Slots are
6
+ * materialised at runtime by `Runtime.defineHook(...)` calls in forge's
7
+ * `Runtime` constructor; once materialised, plugin code accesses them via:
8
8
  *
9
- * The action-specific events (`ActionDispatching` / `ActionCompleted` /
10
- * `ActionFailed`) and event-recording events (`EventRecording` /
11
- * `EventRecorded`) are defined here because their payload types reference
12
- * forge-specific types (`ActionDefinition`, `HandlerContext`) and the
13
- * domain-event bus forge owns.
14
- */
15
- import { type FrameworkEventDefinition } from "@nwire/app";
16
- import type { ActionDefinition } from "./define-action.js";
17
- import type { HandlerContext } from "./define-handler.js";
18
- export { defineFrameworkEvent, AppRegistering, AppBooting, AppBooted, AppReady, AppShuttingDown, AppShutdown, PluginRegistered, PluginBooting, PluginBooted, PluginShuttingDown, PluginShutdown, WireMounting, WireMounted, WireUnmounted, builtInLifecycleEvents, type FrameworkEventDefinition, type FrameworkEventMode, } from "@nwire/app";
19
- /**
20
- * Fired before a dispatch reaches the handler. Interceptable: return
21
- * `false` to silently prevent execution, throw to fail with a specific
22
- * error, or mutate `payload.input` to transform what the handler sees.
23
- */
24
- export declare const ActionDispatching: FrameworkEventDefinition<{
25
- readonly action: ActionDefinition;
26
- readonly input: unknown;
27
- readonly ctx: HandlerContext;
28
- }>;
29
- /** Fired after a handler returns successfully. Observable; runs in parallel. */
30
- export declare const ActionCompleted: FrameworkEventDefinition<{
31
- readonly action: ActionDefinition;
32
- readonly input: unknown;
33
- readonly result: unknown;
34
- readonly durationMs: number;
35
- }>;
36
- /** Fired after a handler throws. Observable; runs in parallel. */
37
- export declare const ActionFailed: FrameworkEventDefinition<{
38
- readonly action: ActionDefinition;
39
- readonly input: unknown;
40
- readonly error: unknown;
41
- readonly durationMs: number;
42
- }>;
43
- /**
44
- * Fired before an event is persisted. Interceptable: return false to drop
45
- * the event (rarely useful in practice — events represent facts that
46
- * already happened). Throw to fail the dispatch that produced this event.
9
+ * runtime.hooks.ActionDispatching.use(async (p, next) => …); // veto-able
10
+ * runtime.hooks.ActionCompleted.on(({ action, result }) => …);
11
+ *
12
+ * App-lifecycle slots (App*, Plugin*, Wire*) live in `@nwire/app` and
13
+ * are pre-instantiated on every Runtime; this file only adds forge's
14
+ * domain-specific slots.
47
15
  */
48
- export declare const EventRecording: FrameworkEventDefinition<{
49
- readonly eventName: string;
50
- readonly payload: unknown;
51
- }>;
52
- /** Fired after an event is persisted + workflows have been notified. */
53
- export declare const EventRecorded: FrameworkEventDefinition<{
54
- readonly eventName: string;
55
- readonly payload: unknown;
56
- }>;
57
- export declare const builtInFrameworkEvents: readonly FrameworkEventDefinition<unknown>[];
58
- //# sourceMappingURL=framework-events.d.ts.map
16
+ import type { Hook } from "@nwire/hooks";
17
+ import type { ActionDefinition } from "./primitives/define-action.js";
18
+ import type { HandlerContext } from "./primitives/define-handler.js";
19
+ declare module "@nwire/app" {
20
+ interface FrameworkHooks {
21
+ /** Fired before a dispatch reaches the handler. Veto by skipping next(). */
22
+ ActionDispatching: Hook<{
23
+ readonly action: ActionDefinition;
24
+ readonly input: unknown;
25
+ readonly ctx: HandlerContext;
26
+ }>;
27
+ /** Fired after a handler returns successfully. Observe via .on(). */
28
+ ActionCompleted: Hook<{
29
+ readonly action: ActionDefinition;
30
+ readonly input: unknown;
31
+ readonly result: unknown;
32
+ readonly durationMs: number;
33
+ }>;
34
+ /** Fired after a handler throws. Observe via .on(). */
35
+ ActionFailed: Hook<{
36
+ readonly action: ActionDefinition;
37
+ readonly input: unknown;
38
+ readonly error: unknown;
39
+ readonly durationMs: number;
40
+ }>;
41
+ /** Fired before an event is persisted. Veto by skipping next() (rare). */
42
+ EventRecording: Hook<{
43
+ readonly eventName: string;
44
+ readonly payload: unknown;
45
+ }>;
46
+ /** Fired after an event is persisted + workflows notified. Observe via .on(). */
47
+ EventRecorded: Hook<{
48
+ readonly eventName: string;
49
+ readonly payload: unknown;
50
+ }>;
51
+ }
52
+ }
53
+ /** Forge-specific framework-hook slot names — used by Runtime to materialise. */
54
+ export declare const forgeFrameworkSlots: readonly ["ActionDispatching", "ActionCompleted", "ActionFailed", "EventRecording", "EventRecorded"];
55
+ export type ForgeFrameworkSlot = (typeof forgeFrameworkSlots)[number];
@@ -1,70 +1,23 @@
1
1
  /**
2
- * Framework events — re-exports of app-layer events + forge-specific events.
2
+ * Forge framework-hook augmentation.
3
3
  *
4
- * The generic infrastructure (`defineFrameworkEvent` +
5
- * `FrameworkEventDefinition`) and the app-lifecycle events (App* / Plugin* /
6
- * Wire*) live in `@nwire/app`; this module re-exports them so consumers
7
- * pulling from forge get one import line.
4
+ * Action-specific and event-recording slots are added to the kernel's
5
+ * `FrameworkHooks` registry via TS module augmentation. Slots are
6
+ * materialised at runtime by `Runtime.defineHook(...)` calls in forge's
7
+ * `Runtime` constructor; once materialised, plugin code accesses them via:
8
8
  *
9
- * The action-specific events (`ActionDispatching` / `ActionCompleted` /
10
- * `ActionFailed`) and event-recording events (`EventRecording` /
11
- * `EventRecorded`) are defined here because their payload types reference
12
- * forge-specific types (`ActionDefinition`, `HandlerContext`) and the
13
- * domain-event bus forge owns.
14
- */
15
- import { defineFrameworkEvent } from "@nwire/app";
16
- // ─── Re-exports from @nwire/app ────────────────────────────────────
17
- export { defineFrameworkEvent, AppRegistering, AppBooting, AppBooted, AppReady, AppShuttingDown, AppShutdown, PluginRegistered, PluginBooting, PluginBooted, PluginShuttingDown, PluginShutdown, WireMounting, WireMounted, WireUnmounted, builtInLifecycleEvents, } from "@nwire/app";
18
- // ─── Action dispatch (forge-local — depends on ActionDefinition) ───
19
- /**
20
- * Fired before a dispatch reaches the handler. Interceptable: return
21
- * `false` to silently prevent execution, throw to fail with a specific
22
- * error, or mutate `payload.input` to transform what the handler sees.
23
- */
24
- export const ActionDispatching = defineFrameworkEvent("nwire.action.dispatching", "series-bail");
25
- /** Fired after a handler returns successfully. Observable; runs in parallel. */
26
- export const ActionCompleted = defineFrameworkEvent("nwire.action.completed", "parallel");
27
- /** Fired after a handler throws. Observable; runs in parallel. */
28
- export const ActionFailed = defineFrameworkEvent("nwire.action.failed", "parallel");
29
- // ─── Event recording (forge-local — about the domain event bus) ────
30
- /**
31
- * Fired before an event is persisted. Interceptable: return false to drop
32
- * the event (rarely useful in practice — events represent facts that
33
- * already happened). Throw to fail the dispatch that produced this event.
34
- */
35
- export const EventRecording = defineFrameworkEvent("nwire.event.recording", "series-bail");
36
- /** Fired after an event is persisted + workflows have been notified. */
37
- export const EventRecorded = defineFrameworkEvent("nwire.event.recorded", "parallel");
38
- // ─── Catalog ────────────────────────────────────────────────────
39
- /**
40
- * Every built-in framework event — union of app-lifecycle (from @nwire/app)
41
- * and forge-specific (action + event-recording). Studio reads this list to
42
- * render the "what can I hook into?" page.
9
+ * runtime.hooks.ActionDispatching.use(async (p, next) => …); // veto-able
10
+ * runtime.hooks.ActionCompleted.on(({ action, result }) => …);
11
+ *
12
+ * App-lifecycle slots (App*, Plugin*, Wire*) live in `@nwire/app` and
13
+ * are pre-instantiated on every Runtime; this file only adds forge's
14
+ * domain-specific slots.
43
15
  */
44
- import { AppRegistering, AppBooting, AppBooted, AppReady, AppShuttingDown, AppShutdown, PluginRegistered, PluginBooting, PluginBooted, PluginShuttingDown, PluginShutdown, WireMounting, WireMounted, WireUnmounted, } from "@nwire/app";
45
- // Explicit annotation pins the type to the exported alias `FrameworkEventDefinition`
46
- // so the .d.ts emit stays portable (no transitive type leakage through the
47
- // `as const` array literal).
48
- export const builtInFrameworkEvents = [
49
- AppRegistering,
50
- AppBooting,
51
- AppBooted,
52
- AppReady,
53
- AppShuttingDown,
54
- AppShutdown,
55
- PluginRegistered,
56
- PluginBooting,
57
- PluginBooted,
58
- PluginShuttingDown,
59
- PluginShutdown,
60
- WireMounting,
61
- WireMounted,
62
- WireUnmounted,
63
- ActionDispatching,
64
- ActionCompleted,
65
- ActionFailed,
66
- EventRecording,
67
- EventRecorded,
16
+ /** Forge-specific framework-hook slot names used by Runtime to materialise. */
17
+ export const forgeFrameworkSlots = [
18
+ "ActionDispatching",
19
+ "ActionCompleted",
20
+ "ActionFailed",
21
+ "EventRecording",
22
+ "EventRecorded",
68
23
  ];
69
- void {};
70
- //# sourceMappingURL=framework-events.js.map
@@ -12,7 +12,7 @@
12
12
  *
13
13
  * #!/usr/bin/env node
14
14
  * import { runCli } from '@nwire/forge'
15
- * import { boot } from './app/boot.js'
15
+ * import { boot } from './app/boot'
16
16
  *
17
17
  * const app = await boot() // returns { learnflow: App }
18
18
  * const exitCode = await runCli(app.learnflow, process.argv.slice(2))
@@ -33,7 +33,7 @@
33
33
  * Wire-mode invariance: same domain handlers run in HTTP, queue, and CLI.
34
34
  * The CLI doesn't know about HTTP routes; it dispatches via the runtime.
35
35
  */
36
- import type { App } from "./create-app.js";
36
+ import type { ForgeApp as App } from "../runtime/create-forge-app.js";
37
37
  export interface RunCliOptions {
38
38
  /**
39
39
  * Override stdout/stderr — useful for tests. Defaults to console.log /
@@ -43,4 +43,3 @@ export interface RunCliOptions {
43
43
  readonly stderr?: (line: string) => void;
44
44
  }
45
45
  export declare function runCli(app: App, argv: readonly string[], options?: RunCliOptions): Promise<number>;
46
- //# sourceMappingURL=cli-runner.d.ts.map