hexok 1.0.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (259) hide show
  1. package/README.md +9 -0
  2. package/dist/adapter.d.ts +18 -0
  3. package/dist/adapter.d.ts.map +1 -0
  4. package/dist/adapter.js +21 -0
  5. package/dist/adapter.js.map +1 -0
  6. package/dist/catalog.d.ts +88 -0
  7. package/dist/catalog.d.ts.map +1 -0
  8. package/dist/catalog.js +79 -0
  9. package/dist/catalog.js.map +1 -0
  10. package/dist/{core/coded-error.d.ts → coded-error.d.ts} +9 -4
  11. package/dist/coded-error.d.ts.map +1 -0
  12. package/dist/{core/coded-error.js → coded-error.js} +9 -4
  13. package/dist/coded-error.js.map +1 -0
  14. package/dist/cow-draft.d.ts.map +1 -0
  15. package/dist/cow-draft.js.map +1 -0
  16. package/dist/entity.d.ts +63 -0
  17. package/dist/entity.d.ts.map +1 -0
  18. package/dist/{domain/entity.js → entity.js} +52 -80
  19. package/dist/entity.js.map +1 -0
  20. package/dist/error-map.d.ts +22 -0
  21. package/dist/error-map.d.ts.map +1 -0
  22. package/dist/error-map.js +2 -0
  23. package/dist/error-map.js.map +1 -0
  24. package/dist/errors.d.ts +85 -0
  25. package/dist/errors.d.ts.map +1 -0
  26. package/dist/errors.js +85 -0
  27. package/dist/errors.js.map +1 -0
  28. package/dist/event-handler.d.ts +31 -0
  29. package/dist/event-handler.d.ts.map +1 -0
  30. package/dist/event-handler.js +28 -0
  31. package/dist/event-handler.js.map +1 -0
  32. package/dist/event.d.ts +37 -0
  33. package/dist/event.d.ts.map +1 -0
  34. package/dist/event.js +44 -0
  35. package/dist/event.js.map +1 -0
  36. package/dist/index.d.ts +16 -0
  37. package/dist/index.d.ts.map +1 -0
  38. package/dist/index.js +14 -0
  39. package/dist/index.js.map +1 -0
  40. package/dist/mapper.d.ts +100 -0
  41. package/dist/mapper.d.ts.map +1 -0
  42. package/dist/mapper.js +167 -0
  43. package/dist/mapper.js.map +1 -0
  44. package/dist/port.d.ts +20 -0
  45. package/dist/port.d.ts.map +1 -0
  46. package/dist/port.js +25 -0
  47. package/dist/port.js.map +1 -0
  48. package/dist/result.d.ts.map +1 -0
  49. package/dist/result.js.map +1 -0
  50. package/dist/schema.d.ts +37 -0
  51. package/dist/schema.d.ts.map +1 -0
  52. package/dist/schema.js +50 -0
  53. package/dist/schema.js.map +1 -0
  54. package/dist/{core/standard-schema.d.ts → standard-schema.d.ts} +1 -1
  55. package/dist/standard-schema.d.ts.map +1 -0
  56. package/dist/standard-schema.js.map +1 -0
  57. package/dist/use-case.d.ts +183 -0
  58. package/dist/use-case.d.ts.map +1 -0
  59. package/dist/use-case.js +221 -0
  60. package/dist/use-case.js.map +1 -0
  61. package/dist/{core/schema.d.ts → validate.d.ts} +1 -1
  62. package/dist/validate.d.ts.map +1 -0
  63. package/dist/{core/schema.js → validate.js} +1 -1
  64. package/dist/validate.js.map +1 -0
  65. package/package.json +16 -26
  66. package/dist/app/api-use-case.d.ts +0 -52
  67. package/dist/app/api-use-case.d.ts.map +0 -1
  68. package/dist/app/api-use-case.js +0 -59
  69. package/dist/app/api-use-case.js.map +0 -1
  70. package/dist/app/callable-use-case.d.ts +0 -34
  71. package/dist/app/callable-use-case.d.ts.map +0 -1
  72. package/dist/app/callable-use-case.js +0 -41
  73. package/dist/app/callable-use-case.js.map +0 -1
  74. package/dist/app/contract.d.ts +0 -46
  75. package/dist/app/contract.d.ts.map +0 -1
  76. package/dist/app/contract.js +0 -28
  77. package/dist/app/contract.js.map +0 -1
  78. package/dist/app/error-factory.d.ts +0 -9
  79. package/dist/app/error-factory.d.ts.map +0 -1
  80. package/dist/app/error-factory.js +0 -30
  81. package/dist/app/error-factory.js.map +0 -1
  82. package/dist/app/event-channel.d.ts +0 -133
  83. package/dist/app/event-channel.d.ts.map +0 -1
  84. package/dist/app/event-channel.js +0 -49
  85. package/dist/app/event-channel.js.map +0 -1
  86. package/dist/app/event-use-case.d.ts +0 -47
  87. package/dist/app/event-use-case.d.ts.map +0 -1
  88. package/dist/app/event-use-case.js +0 -54
  89. package/dist/app/event-use-case.js.map +0 -1
  90. package/dist/app/execute-ctx.d.ts +0 -92
  91. package/dist/app/execute-ctx.d.ts.map +0 -1
  92. package/dist/app/execute-ctx.js +0 -2
  93. package/dist/app/execute-ctx.js.map +0 -1
  94. package/dist/app/external-use-case.d.ts +0 -25
  95. package/dist/app/external-use-case.d.ts.map +0 -1
  96. package/dist/app/external-use-case.js +0 -25
  97. package/dist/app/external-use-case.js.map +0 -1
  98. package/dist/app/index.d.ts +0 -9
  99. package/dist/app/index.d.ts.map +0 -1
  100. package/dist/app/index.js +0 -8
  101. package/dist/app/index.js.map +0 -1
  102. package/dist/app/internal-use-case.d.ts +0 -26
  103. package/dist/app/internal-use-case.d.ts.map +0 -1
  104. package/dist/app/internal-use-case.js +0 -26
  105. package/dist/app/internal-use-case.js.map +0 -1
  106. package/dist/app/nest.d.ts +0 -9
  107. package/dist/app/nest.d.ts.map +0 -1
  108. package/dist/app/nest.js +0 -28
  109. package/dist/app/nest.js.map +0 -1
  110. package/dist/app/types.d.ts +0 -153
  111. package/dist/app/types.d.ts.map +0 -1
  112. package/dist/app/types.js +0 -17
  113. package/dist/app/types.js.map +0 -1
  114. package/dist/core/coded-error.d.ts.map +0 -1
  115. package/dist/core/coded-error.js.map +0 -1
  116. package/dist/core/error-map.d.ts +0 -21
  117. package/dist/core/error-map.d.ts.map +0 -1
  118. package/dist/core/error-map.js +0 -5
  119. package/dist/core/error-map.js.map +0 -1
  120. package/dist/core/index.d.ts +0 -6
  121. package/dist/core/index.d.ts.map +0 -1
  122. package/dist/core/index.js +0 -5
  123. package/dist/core/index.js.map +0 -1
  124. package/dist/core/result.d.ts.map +0 -1
  125. package/dist/core/result.js.map +0 -1
  126. package/dist/core/schema.d.ts.map +0 -1
  127. package/dist/core/schema.js.map +0 -1
  128. package/dist/core/standard-schema.d.ts.map +0 -1
  129. package/dist/core/standard-schema.js.map +0 -1
  130. package/dist/domain/capabilities.d.ts +0 -42
  131. package/dist/domain/capabilities.d.ts.map +0 -1
  132. package/dist/domain/capabilities.js +0 -2
  133. package/dist/domain/capabilities.js.map +0 -1
  134. package/dist/domain/catalog.d.ts +0 -46
  135. package/dist/domain/catalog.d.ts.map +0 -1
  136. package/dist/domain/catalog.js +0 -114
  137. package/dist/domain/catalog.js.map +0 -1
  138. package/dist/domain/channel.d.ts +0 -36
  139. package/dist/domain/channel.d.ts.map +0 -1
  140. package/dist/domain/channel.js +0 -2
  141. package/dist/domain/channel.js.map +0 -1
  142. package/dist/domain/cow-draft.d.ts.map +0 -1
  143. package/dist/domain/cow-draft.js.map +0 -1
  144. package/dist/domain/entity.d.ts +0 -120
  145. package/dist/domain/entity.d.ts.map +0 -1
  146. package/dist/domain/entity.js.map +0 -1
  147. package/dist/domain/envelope.d.ts +0 -59
  148. package/dist/domain/envelope.d.ts.map +0 -1
  149. package/dist/domain/envelope.js +0 -2
  150. package/dist/domain/envelope.js.map +0 -1
  151. package/dist/domain/event.d.ts +0 -44
  152. package/dist/domain/event.d.ts.map +0 -1
  153. package/dist/domain/event.js +0 -21
  154. package/dist/domain/event.js.map +0 -1
  155. package/dist/domain/index.d.ts +0 -8
  156. package/dist/domain/index.d.ts.map +0 -1
  157. package/dist/domain/index.js +0 -5
  158. package/dist/domain/index.js.map +0 -1
  159. package/dist/domain/port.d.ts +0 -45
  160. package/dist/domain/port.d.ts.map +0 -1
  161. package/dist/domain/port.js +0 -41
  162. package/dist/domain/port.js.map +0 -1
  163. package/dist/infra/adapter.d.ts +0 -22
  164. package/dist/infra/adapter.d.ts.map +0 -1
  165. package/dist/infra/adapter.js +0 -18
  166. package/dist/infra/adapter.js.map +0 -1
  167. package/dist/infra/index.d.ts +0 -3
  168. package/dist/infra/index.d.ts.map +0 -1
  169. package/dist/infra/index.js +0 -3
  170. package/dist/infra/index.js.map +0 -1
  171. package/dist/infra/mapper.d.ts +0 -48
  172. package/dist/infra/mapper.d.ts.map +0 -1
  173. package/dist/infra/mapper.js +0 -77
  174. package/dist/infra/mapper.js.map +0 -1
  175. package/dist/runtime/app.d.ts +0 -100
  176. package/dist/runtime/app.d.ts.map +0 -1
  177. package/dist/runtime/app.js +0 -292
  178. package/dist/runtime/app.js.map +0 -1
  179. package/dist/runtime/channel.d.ts +0 -34
  180. package/dist/runtime/channel.d.ts.map +0 -1
  181. package/dist/runtime/channel.js +0 -110
  182. package/dist/runtime/channel.js.map +0 -1
  183. package/dist/runtime/client.d.ts +0 -21
  184. package/dist/runtime/client.d.ts.map +0 -1
  185. package/dist/runtime/client.js +0 -2
  186. package/dist/runtime/client.js.map +0 -1
  187. package/dist/runtime/completeness.d.ts +0 -89
  188. package/dist/runtime/completeness.d.ts.map +0 -1
  189. package/dist/runtime/completeness.js +0 -2
  190. package/dist/runtime/completeness.js.map +0 -1
  191. package/dist/runtime/envelope.d.ts +0 -7
  192. package/dist/runtime/envelope.d.ts.map +0 -1
  193. package/dist/runtime/envelope.js +0 -69
  194. package/dist/runtime/envelope.js.map +0 -1
  195. package/dist/runtime/events.d.ts +0 -6
  196. package/dist/runtime/events.d.ts.map +0 -1
  197. package/dist/runtime/events.js +0 -48
  198. package/dist/runtime/events.js.map +0 -1
  199. package/dist/runtime/http-status.d.ts +0 -3
  200. package/dist/runtime/http-status.d.ts.map +0 -1
  201. package/dist/runtime/http-status.js +0 -11
  202. package/dist/runtime/http-status.js.map +0 -1
  203. package/dist/runtime/http.d.ts +0 -4
  204. package/dist/runtime/http.d.ts.map +0 -1
  205. package/dist/runtime/http.js +0 -58
  206. package/dist/runtime/http.js.map +0 -1
  207. package/dist/runtime/index.d.ts +0 -10
  208. package/dist/runtime/index.d.ts.map +0 -1
  209. package/dist/runtime/index.js +0 -6
  210. package/dist/runtime/index.js.map +0 -1
  211. package/dist/runtime/interceptor.d.ts +0 -61
  212. package/dist/runtime/interceptor.d.ts.map +0 -1
  213. package/dist/runtime/interceptor.js +0 -7
  214. package/dist/runtime/interceptor.js.map +0 -1
  215. package/dist/runtime/invoke.d.ts +0 -34
  216. package/dist/runtime/invoke.d.ts.map +0 -1
  217. package/dist/runtime/invoke.js +0 -235
  218. package/dist/runtime/invoke.js.map +0 -1
  219. package/dist/runtime/middleware.d.ts +0 -20
  220. package/dist/runtime/middleware.d.ts.map +0 -1
  221. package/dist/runtime/middleware.js +0 -2
  222. package/dist/runtime/middleware.js.map +0 -1
  223. package/dist/runtime/rpc.d.ts +0 -24
  224. package/dist/runtime/rpc.d.ts.map +0 -1
  225. package/dist/runtime/rpc.js +0 -16
  226. package/dist/runtime/rpc.js.map +0 -1
  227. package/dist/testing/app-test.d.ts +0 -77
  228. package/dist/testing/app-test.d.ts.map +0 -1
  229. package/dist/testing/app-test.js +0 -109
  230. package/dist/testing/app-test.js.map +0 -1
  231. package/dist/testing/in-memory-broker.d.ts +0 -18
  232. package/dist/testing/in-memory-broker.d.ts.map +0 -1
  233. package/dist/testing/in-memory-broker.js +0 -42
  234. package/dist/testing/in-memory-broker.js.map +0 -1
  235. package/dist/testing/in-memory-bus.d.ts +0 -19
  236. package/dist/testing/in-memory-bus.d.ts.map +0 -1
  237. package/dist/testing/in-memory-bus.js +0 -31
  238. package/dist/testing/in-memory-bus.js.map +0 -1
  239. package/dist/testing/in-memory-channel.d.ts +0 -32
  240. package/dist/testing/in-memory-channel.d.ts.map +0 -1
  241. package/dist/testing/in-memory-channel.js +0 -65
  242. package/dist/testing/in-memory-channel.js.map +0 -1
  243. package/dist/testing/in-memory-queue.d.ts +0 -24
  244. package/dist/testing/in-memory-queue.d.ts.map +0 -1
  245. package/dist/testing/in-memory-queue.js +0 -66
  246. package/dist/testing/in-memory-queue.js.map +0 -1
  247. package/dist/testing/in-memory-repository.d.ts +0 -44
  248. package/dist/testing/in-memory-repository.d.ts.map +0 -1
  249. package/dist/testing/in-memory-repository.js +0 -60
  250. package/dist/testing/in-memory-repository.js.map +0 -1
  251. package/dist/testing/index.d.ts +0 -6
  252. package/dist/testing/index.d.ts.map +0 -1
  253. package/dist/testing/index.js +0 -6
  254. package/dist/testing/index.js.map +0 -1
  255. /package/dist/{domain/cow-draft.d.ts → cow-draft.d.ts} +0 -0
  256. /package/dist/{domain/cow-draft.js → cow-draft.js} +0 -0
  257. /package/dist/{core/result.d.ts → result.d.ts} +0 -0
  258. /package/dist/{core/result.js → result.js} +0 -0
  259. /package/dist/{core/standard-schema.js → standard-schema.js} +0 -0
package/README.md ADDED
@@ -0,0 +1,9 @@
1
+ # hexok
2
+
3
+ TypeScript primitives for hexagonal software: `Schema`, `Entity`, `UseCase`, `Port`, `Adapter`, `Mapper`, `Event`, `EventCatalog`, `EventHandler`, and `Errors`. A `Mapper` subclass implements `fromSource` and `toSource`; adapters call `toModel` and `fromModel`.
4
+
5
+ Import them from `hexok`. There is no HTTP layer and no composition root in this package. Construct use cases with the ports they need. A schema argument is a Standard Schema. Zod satisfies that interface. `@hexok/typebox` adapts a `typebox` 1 schematic: `typebox(schema)` infers `Static`, and `typeboxDecode(schema)` infers `StaticDecode` and decodes. `EventInstance<typeof Catalog>` is the catalog's event objects. `EventMessage<typeof Catalog>` is the `{ key, payload }` union an adapter sends. `message` and `parse` on the catalog convert between them.
6
+
7
+ `UseCase.context<Ctx, Spec>()` is a family factory for a per-call context, optional guards, optional hooks, and required statics. The optional argument is a settings object with no keys yet. Pass nothing. `{}` is allowed. `guard` and `hooks` are methods, not fields of that object. A missing `<Ctx>` type argument is a type error. `Spec` defaults to no required statics. `.guard(fn)` and `.hooks(def)` each return the same factory. Order does not matter. Either may be omitted. Another `.guard()` runs after guards already registered. A second `.hooks()` throws `hexok: UseCase hooks are already set` when the factory is created, if the first registration had at least one callback. An empty `.hooks({})` does not register hooks and does not wrap `execute`. The call is `{ ctx, spec, token, input }`. `input` is the argument passed to `execute`. The method receives that same value. Hexok does not validate it. `UseCase.GuardParameters<typeof Factory>` is that call. `UseCase.Ctx<typeof Factory>` is that `ctx`. Pass the factory. `.hooks` infers the value returned from `preExecute` as the `state` argument of `postExecute`, `onCatch`, and `onFinally`. If `preExecute` is omitted, that state is `void`. `postExecute` also receives `result`. `onFinally` receives `status: 'success'` with `result`, or `status: 'failure'` with `error`. The pipeline is guard (outside try), `preExecute`, the method, `postExecute`, `onCatch` then rethrow, `onFinally`. A guard throw does not enter the hooks. A throw inside `onCatch` replaces the error after `onFinally` sees the original one. `UseCase(token)` still has `execute(input)`.
8
+
9
+ The root [README](../../README.md) shows the shape. Tokens and schemas are arguments of each primitive, so they cannot be forgotten. `execute`, `handle`, and port methods are abstract, so a missing method is a compiler error on the class. `start`, `stop`, `parse`, and `set` are concrete methods you can override.
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Implementation of a port. Missing port methods are errors on the class.
3
+ * `start` and `stop` are optional overrides. The token is the port's token.
4
+ *
5
+ * ```ts
6
+ * class InMemoryUsers extends Adapter(UserRepository) {
7
+ * override async get(id: string): Promise<User | null> { ... }
8
+ * override async save(user: User): Promise<void> { ... }
9
+ * }
10
+ * ```
11
+ */
12
+ export declare function Adapter<P extends abstract new (...args: any[]) => object>(PortClass: P): (abstract new (...args: any[]) => {
13
+ /** Called by the application before the adapter is used. Override to connect. */
14
+ start(): Promise<void>;
15
+ /** Called by the application when it is finished with the adapter. Override to disconnect. */
16
+ stop(): Promise<void>;
17
+ }) & P;
18
+ //# sourceMappingURL=adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,wBAAgB,OAAO,CACrB,CAAC,SAAS,QAAQ,MAEhB,GAAG,IAAI,EAAE,GAAG,EAAE,KACX,MAAM,EACX,SAAS,EAAE,CAAC,2BAFD,GAAG,EAAE;IAId,iFAAiF;aAClE,OAAO,CAAC,IAAI,CAAC;IAE5B,8FAA8F;YAChF,OAAO,CAAC,IAAI,CAAC;OAI9B"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Implementation of a port. Missing port methods are errors on the class.
3
+ * `start` and `stop` are optional overrides. The token is the port's token.
4
+ *
5
+ * ```ts
6
+ * class InMemoryUsers extends Adapter(UserRepository) {
7
+ * override async get(id: string): Promise<User | null> { ... }
8
+ * override async save(user: User): Promise<void> { ... }
9
+ * }
10
+ * ```
11
+ */
12
+ export function Adapter(PortClass) {
13
+ class AdapterClass extends PortClass {
14
+ /** Called by the application before the adapter is used. Override to connect. */
15
+ async start() { }
16
+ /** Called by the application when it is finished with the adapter. Override to disconnect. */
17
+ async stop() { }
18
+ }
19
+ return AdapterClass;
20
+ }
21
+ //# sourceMappingURL=adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter.js","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,MAAM,UAAU,OAAO,CAKrB,SAAY;IACZ,MAAe,YAAa,SAAQ,SAAS;QAC3C,iFAAiF;QACjF,KAAK,CAAC,KAAK,KAAmB,CAAC;QAE/B,8FAA8F;QAC9F,KAAK,CAAC,IAAI,KAAmB,CAAC;KAC/B;IAED,OAAO,YAAY,CAAC;AACtB,CAAC"}
@@ -0,0 +1,88 @@
1
+ import type { StandardSchemaV1 } from './standard-schema.js';
2
+ /** Constructor registered on an {@link EventCatalog}. */
3
+ export type EventConstructor = {
4
+ /** Event name. */
5
+ readonly token: string;
6
+ /** Payload schema. */
7
+ readonly schema: StandardSchemaV1;
8
+ new (...args: any[]): object;
9
+ };
10
+ /**
11
+ * Named set of event classes. Map keys stay literal without `as const`.
12
+ * Duplicate event tokens throw when the catalog is defined.
13
+ *
14
+ * ```ts
15
+ * class DomainEvents extends EventCatalog('domain', {
16
+ * userCreated: UserCreated,
17
+ * }) {}
18
+ * ```
19
+ */
20
+ export declare function EventCatalog<const Token extends string, const Events extends Record<string, EventConstructor>>(token: Token, events: Events): (abstract new () => {}) & {
21
+ /** Catalog name. Literal type of the string passed to {@link EventCatalog}. */
22
+ readonly token: Token;
23
+ /** Event classes, in the shape passed to {@link EventCatalog}. */
24
+ readonly events: Events;
25
+ /** Registered class for `name`. Throws when `name` is not in this catalog. */
26
+ get<Name extends keyof Events & string>(name: Name): Events[Name];
27
+ /**
28
+ * Serializable `{ key, payload }` for an instance from this catalog.
29
+ * `key` is the map name. Throws when `event` is not registered here.
30
+ */
31
+ message(event: EventInstance<CatalogOf<Events>>): EventMessage<CatalogOf<Events>>;
32
+ /**
33
+ * Validate a `{ key, payload }` message and construct the event.
34
+ * Throws when `key` is not in this catalog.
35
+ * Throws `CodedError` `VALIDATION` when the payload schema rejects it.
36
+ */
37
+ parse(value: unknown): EventInstance<CatalogOf<Events>>;
38
+ };
39
+ /**
40
+ * Instance of an event class. Read from the constructor so
41
+ * {@link EventConstructor}'s `object` return does not erase it.
42
+ */
43
+ type EventInstanceOf<Event> = Event extends abstract new (...args: never[]) => infer Instance ? Instance : never;
44
+ /**
45
+ * Payload of an event class. Read from the instance so
46
+ * {@link EventConstructor}'s `object` return does not erase it.
47
+ */
48
+ type EventPayload<Event> = EventInstanceOf<Event> extends {
49
+ readonly payload: infer Payload;
50
+ } ? Payload : never;
51
+ /** Catalog shape {@link EventInstance} and {@link EventMessage} read. */
52
+ type CatalogOf<Events extends Record<string, EventConstructor>> = {
53
+ readonly events: Events;
54
+ };
55
+ /**
56
+ * Instance of one catalog entry, or every entry when `Key` is omitted.
57
+ * `token` is the event name. `payload` is the schema output.
58
+ *
59
+ * ```ts
60
+ * abstract publish(event: EventInstance<typeof DomainEvents>): Promise<void>
61
+ * publish(new UserCreated({ id, name, email }))
62
+ * ```
63
+ *
64
+ * `EventInstance<typeof DomainEvents, 'userCreated'>` keeps that one entry.
65
+ */
66
+ export type EventInstance<Catalog extends {
67
+ readonly events: Record<string, EventConstructor>;
68
+ }, Key extends keyof Catalog['events'] & string = keyof Catalog['events'] & string> = {
69
+ [K in Key]: EventInstanceOf<Catalog['events'][K]>;
70
+ }[Key];
71
+ /**
72
+ * `{ key, payload }` for one catalog entry, or every entry when `Key` is omitted.
73
+ * `key` is the catalog map name. The event token stays on the instance.
74
+ * Adapters send this value. {@link EventCatalog} `message` and `parse` convert
75
+ * it to and from an {@link EventInstance}.
76
+ *
77
+ * `EventMessage<typeof DomainEvents, 'userCreated'>` keeps that one entry.
78
+ */
79
+ export type EventMessage<Catalog extends {
80
+ readonly events: Record<string, EventConstructor>;
81
+ }, Key extends keyof Catalog['events'] & string = keyof Catalog['events'] & string> = {
82
+ [K in Key]: {
83
+ key: K;
84
+ payload: EventPayload<Catalog['events'][K]>;
85
+ };
86
+ }[Key];
87
+ export {};
88
+ //# sourceMappingURL=catalog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"catalog.d.ts","sourceRoot":"","sources":["../src/catalog.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAE7D,yDAAyD;AACzD,MAAM,MAAM,gBAAgB,GAAG;IAC7B,kBAAkB;IAClB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,sBAAsB;IACtB,QAAQ,CAAC,MAAM,EAAE,gBAAgB,CAAC;IAElC,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,MAAM,CAAC;CAC9B,CAAC;AAEF;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAC1B,KAAK,CAAC,KAAK,SAAS,MAAM,EAC1B,KAAK,CAAC,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,EACrD,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM;IAa1B,+EAA+E;oBACxD,KAAK;IAC5B,kEAAkE;qBAC1C,MAAM;IAE9B,8EAA8E;QACnE,IAAI,SAAS,MAAM,MAAM,GAAG,MAAM,QAAQ,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC;IAQxE;;;OAGG;mBAEM,aAAa,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,GACtC,YAAY,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IAgBlC;;;;OAIG;iBACiB,OAAO,GAAG,aAAa,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;EAsBjE;AAED;;;GAGG;AACH,KAAK,eAAe,CAAC,KAAK,IAAI,KAAK,SAAS,QAAQ,MAClD,GAAG,IAAI,EAAE,KAAK,EAAE,KACb,MAAM,QAAQ,GACf,QAAQ,GACR,KAAK,CAAC;AAEV;;;GAGG;AACH,KAAK,YAAY,CAAC,KAAK,IACrB,eAAe,CAAC,KAAK,CAAC,SAAS;IAC7B,QAAQ,CAAC,OAAO,EAAE,MAAM,OAAO,CAAC;CACjC,GACG,OAAO,GACP,KAAK,CAAC;AAEZ,yEAAyE;AACzE,KAAK,SAAS,CAAC,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,IAAI;IAChE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF;;;;;;;;;;GAUG;AACH,MAAM,MAAM,aAAa,CACvB,OAAO,SAAS;IAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAA;CAAE,EACrE,GAAG,SAAS,MAAM,OAAO,CAAC,QAAQ,CAAC,GAAG,MAAM,GAAG,MAAM,OAAO,CAAC,QAAQ,CAAC,GACpE,MAAM,IACN;KACD,CAAC,IAAI,GAAG,GAAG,eAAe,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;CAClD,CAAC,GAAG,CAAC,CAAC;AAEP;;;;;;;GAOG;AACH,MAAM,MAAM,YAAY,CACtB,OAAO,SAAS;IAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAA;CAAE,EACrE,GAAG,SAAS,MAAM,OAAO,CAAC,QAAQ,CAAC,GAAG,MAAM,GAAG,MAAM,OAAO,CAAC,QAAQ,CAAC,GACpE,MAAM,IACN;KACD,CAAC,IAAI,GAAG,GAAG;QACV,GAAG,EAAE,CAAC,CAAC;QACP,OAAO,EAAE,YAAY,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;KAC7C;CACF,CAAC,GAAG,CAAC,CAAC"}
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Named set of event classes. Map keys stay literal without `as const`.
3
+ * Duplicate event tokens throw when the catalog is defined.
4
+ *
5
+ * ```ts
6
+ * class DomainEvents extends EventCatalog('domain', {
7
+ * userCreated: UserCreated,
8
+ * }) {}
9
+ * ```
10
+ */
11
+ export function EventCatalog(token, events) {
12
+ const seen = new Set();
13
+ for (const event of Object.values(events)) {
14
+ if (seen.has(event.token)) {
15
+ throw new Error(`hexok: duplicate event "${event.token}" in catalog "${token}"`);
16
+ }
17
+ seen.add(event.token);
18
+ }
19
+ const registered = Object.freeze({ ...events });
20
+ class CatalogClass {
21
+ /** Catalog name. Literal type of the string passed to {@link EventCatalog}. */
22
+ static token = token;
23
+ /** Event classes, in the shape passed to {@link EventCatalog}. */
24
+ static events = registered;
25
+ /** Registered class for `name`. Throws when `name` is not in this catalog. */
26
+ static get(name) {
27
+ const event = registered[name];
28
+ if (event === undefined) {
29
+ throw new Error(`hexok: event "${name}" is not in catalog "${token}"`);
30
+ }
31
+ return event;
32
+ }
33
+ /**
34
+ * Serializable `{ key, payload }` for an instance from this catalog.
35
+ * `key` is the map name. Throws when `event` is not registered here.
36
+ */
37
+ static message(event) {
38
+ for (const key of Object.keys(registered)) {
39
+ const Ctor = registered[key];
40
+ if (Ctor !== undefined && event instanceof Ctor) {
41
+ // The instance type does not narrow to one catalog key.
42
+ const payload = event.payload;
43
+ return { key, payload };
44
+ }
45
+ }
46
+ const name = 'token' in event && typeof event.token === 'string'
47
+ ? event.token
48
+ : 'unknown';
49
+ throw new Error(`hexok: event "${name}" is not in catalog "${token}"`);
50
+ }
51
+ /**
52
+ * Validate a `{ key, payload }` message and construct the event.
53
+ * Throws when `key` is not in this catalog.
54
+ * Throws `CodedError` `VALIDATION` when the payload schema rejects it.
55
+ */
56
+ static parse(value) {
57
+ if (!isMessage(value)) {
58
+ throw new Error(`hexok: catalog "${token}" expected { key, payload }`);
59
+ }
60
+ if (!Object.hasOwn(registered, value.key)) {
61
+ throw new Error(`hexok: event "${value.key}" is not in catalog "${token}"`);
62
+ }
63
+ const EventClass = registered[value.key];
64
+ if (typeof EventClass.parse !== 'function') {
65
+ throw new Error(`hexok: event "${value.key}" in catalog "${token}" has no parse`);
66
+ }
67
+ return EventClass.parse(value.payload);
68
+ }
69
+ }
70
+ return CatalogClass;
71
+ }
72
+ function isMessage(value) {
73
+ if (typeof value !== 'object' || value === null)
74
+ return false;
75
+ if (!('key' in value) || typeof value.key !== 'string')
76
+ return false;
77
+ return 'payload' in value;
78
+ }
79
+ //# sourceMappingURL=catalog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"catalog.js","sourceRoot":"","sources":["../src/catalog.ts"],"names":[],"mappings":"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"}
@@ -1,14 +1,19 @@
1
1
  import type { StandardSchemaV1 } from './standard-schema.js';
2
2
  /**
3
- * Thrown by entity refusals and use-case error factories.
4
- * Carries `code`, optional `message`, and optional `data`.
3
+ * Code, message, and optional data. Schema checks throw this with code
4
+ * `VALIDATION`. The application catches it where errors bubble.
5
+ *
6
+ * Application refusals use an {@link Errors} catalog.
5
7
  *
6
8
  * ```ts
7
- * throw new CodedError({ code: 'NOT_FOUND', message: 'Incident not found' })
9
+ * new CodedError({
10
+ * code: 'VALIDATION',
11
+ * message: 'hexok: User validation failed',
12
+ * })
8
13
  * ```
9
14
  */
10
15
  export declare class CodedError<C extends string = string> extends Error {
11
- /** Machine-readable refusal code. Catch and switch on this; a runtime transport may map it to a status. */
16
+ /** Machine-readable code. Schema checks use `VALIDATION`. */
12
17
  readonly code: C;
13
18
  /** Optional payload. Set only when the constructor received `data`. */
14
19
  readonly data?: unknown;
@@ -0,0 +1 @@
1
+ {"version":3,"file":"coded-error.d.ts","sourceRoot":"","sources":["../src/coded-error.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAE7D;;;;;;;;;;;;GAYG;AACH,qBAAa,UAAU,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,CAAE,SAAQ,KAAK;IAC9D,6DAA6D;IAC7D,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;IACjB,uEAAuE;IACvE,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC;IAExB,oCAAoC;gBACxB,IAAI,EAAE;QAChB,IAAI,EAAE,CAAC,CAAC;QACR,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,IAAI,CAAC,EAAE,OAAO,CAAC;KAChB;CAQF;AAED,0FAA0F;AAC1F,wBAAgB,eAAe,CAC7B,OAAO,EAAE,MAAM,EACf,MAAM,CAAC,EAAE,SAAS,gBAAgB,CAAC,KAAK,EAAE,GACzC,UAAU,CAAC,YAAY,CAAC,CAM1B"}
@@ -1,13 +1,18 @@
1
1
  /**
2
- * Thrown by entity refusals and use-case error factories.
3
- * Carries `code`, optional `message`, and optional `data`.
2
+ * Code, message, and optional data. Schema checks throw this with code
3
+ * `VALIDATION`. The application catches it where errors bubble.
4
+ *
5
+ * Application refusals use an {@link Errors} catalog.
4
6
  *
5
7
  * ```ts
6
- * throw new CodedError({ code: 'NOT_FOUND', message: 'Incident not found' })
8
+ * new CodedError({
9
+ * code: 'VALIDATION',
10
+ * message: 'hexok: User validation failed',
11
+ * })
7
12
  * ```
8
13
  */
9
14
  export class CodedError extends Error {
10
- /** Machine-readable refusal code. Catch and switch on this; a runtime transport may map it to a status. */
15
+ /** Machine-readable code. Schema checks use `VALIDATION`. */
11
16
  code;
12
17
  /** Optional payload. Set only when the constructor received `data`. */
13
18
  data;
@@ -0,0 +1 @@
1
+ {"version":3,"file":"coded-error.js","sourceRoot":"","sources":["../src/coded-error.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;GAYG;AACH,MAAM,OAAO,UAAsC,SAAQ,KAAK;IAC9D,6DAA6D;IACpD,IAAI,CAAI;IACjB,uEAAuE;IAC9D,IAAI,CAAW;IAExB,oCAAoC;IACpC,YAAY,IAIX;QACC,KAAK,CAAC,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC;QACjC,IAAI,CAAC,IAAI,GAAG,YAAY,CAAC;QACzB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;QACtB,IAAI,MAAM,IAAI,IAAI,EAAE,CAAC;YACnB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;QACxB,CAAC;IACH,CAAC;CACF;AAED,0FAA0F;AAC1F,MAAM,UAAU,eAAe,CAC7B,OAAe,EACf,MAA0C;IAE1C,OAAO,IAAI,UAAU,CAAC;QACpB,IAAI,EAAE,YAAY;QAClB,OAAO;QACP,GAAG,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACtD,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cow-draft.d.ts","sourceRoot":"","sources":["../src/cow-draft.ts"],"names":[],"mappings":"AAIA,wBAAgB,aAAa,CAC3B,KAAK,EAAE,OAAO,GACb,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAKlC;AAMD,wBAAgB,aAAa,CAAC,CAAC,SAAS,MAAM,EAC5C,IAAI,EAAE,CAAC,EACP,KAAK,EAAE,OAAO,CAAC,MAAM,CAAC,GAAG,SAAS,EAClC,QAAQ,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,GAC3B;IAAE,IAAI,EAAE,CAAC,CAAC;IAAC,KAAK,EAAE,OAAO,CAAC,MAAM,CAAC,GAAG,SAAS,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,CA+FjE;AAED,wBAAgB,cAAc,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,CAAC,CAE7C;AAED,gEAAgE;AAChE,wBAAgB,UAAU,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,CAAC,CAEzC"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cow-draft.js","sourceRoot":"","sources":["../src/cow-draft.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,63 @@
1
+ import { type InferSchema, type ResolvedSchema, type SchemaSource } from './schema.js';
2
+ /** Recursively readonly view of entity props. `Date` values stay `Date`. */
3
+ export type DeepReadonly<T> = T extends Date ? T : T extends readonly (infer U)[] ? ReadonlyArray<DeepReadonly<U>> : T extends object ? {
4
+ readonly [K in keyof T]: DeepReadonly<T[K]>;
5
+ } : T;
6
+ /** `keyof object` is `never`; widen so an open props type still has string keys. */
7
+ type ChangedKey<P extends object> = keyof P extends never ? string : keyof P & string;
8
+ /** Public instance of an entity. Subclass methods stay on `this`. */
9
+ export interface EntityInstance<P extends object> {
10
+ readonly props: DeepReadonly<P>;
11
+ readonly isNew: boolean;
12
+ readonly isValidated: boolean;
13
+ readonly original: DeepReadonly<P> | undefined;
14
+ set(producer: (draft: P) => void): this;
15
+ validate(): this;
16
+ getChangedKeys(): Array<ChangedKey<P>>;
17
+ getChangedKeys(opts: {
18
+ deep: true;
19
+ }): string[];
20
+ getChangedKeys(opts?: {
21
+ deep?: boolean;
22
+ }): string[];
23
+ isDirty(): boolean;
24
+ commit(): this;
25
+ toProps(): DeepReadonly<P>;
26
+ toJSON(): DeepReadonly<P>;
27
+ }
28
+ type EntityHandle<Token extends string, S extends SchemaSource> = {
29
+ readonly token: Token;
30
+ readonly schema: ResolvedSchema<S>;
31
+ readonly prototype: EntityInstance<EntityProps<S>>;
32
+ create<T extends {
33
+ readonly prototype: EntityInstance<EntityProps<S>>;
34
+ }>(this: T, props: EntityProps<S> | DeepReadonly<EntityProps<S>>): T['prototype'];
35
+ restore<T extends {
36
+ readonly prototype: EntityInstance<EntityProps<S>>;
37
+ }>(this: T, props: EntityProps<S> | DeepReadonly<EntityProps<S>>): T['prototype'];
38
+ parse<T extends {
39
+ readonly prototype: EntityInstance<EntityProps<S>>;
40
+ }>(this: T, value: unknown): T['prototype'];
41
+ } & (abstract new (props: EntityProps<S>, init: never) => EntityInstance<EntityProps<S>>);
42
+ /**
43
+ * Mutable aggregate. The token and schema are arguments of {@link Entity},
44
+ * so a subclass cannot forget them. Rules are methods. A refusal throws an
45
+ * {@link Errors} catalog member. Override `set` only when the copy-on-write
46
+ * write path itself must change.
47
+ *
48
+ * ```ts
49
+ * class Incident extends Entity('Incident', incidentSchema) {
50
+ * close(now: Date): this {
51
+ * if (this.props.status === 'closed') throw DomainError.AlreadyClosed()
52
+ * return this.set((draft) => {
53
+ * draft.status = 'closed'
54
+ * draft.closedAt = now
55
+ * })
56
+ * }
57
+ * }
58
+ * ```
59
+ */
60
+ type EntityProps<S extends SchemaSource> = InferSchema<S> extends object ? InferSchema<S> : never;
61
+ export declare function Entity<const Token extends string, S extends SchemaSource>(token: Token, schema: S): EntityHandle<Token, S>;
62
+ export {};
63
+ //# sourceMappingURL=entity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entity.d.ts","sourceRoot":"","sources":["../src/entity.ts"],"names":[],"mappings":"AAOA,OAAO,EACL,KAAK,WAAW,EAChB,KAAK,cAAc,EACnB,KAAK,YAAY,EAElB,MAAM,aAAa,CAAC;AAMrB,4EAA4E;AAC5E,MAAM,MAAM,YAAY,CAAC,CAAC,IAAI,CAAC,SAAS,IAAI,GACxC,CAAC,GACD,CAAC,SAAS,SAAS,CAAC,MAAM,CAAC,CAAC,EAAE,GAC5B,aAAa,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,GAC9B,CAAC,SAAS,MAAM,GACd;IAAE,QAAQ,EAAE,CAAC,IAAI,MAAM,CAAC,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CAAE,GAC/C,CAAC,CAAC;AAWV,oFAAoF;AACpF,KAAK,UAAU,CAAC,CAAC,SAAS,MAAM,IAAI,MAAM,CAAC,SAAS,KAAK,GACrD,MAAM,GACN,MAAM,CAAC,GAAG,MAAM,CAAC;AAErB,qEAAqE;AACrE,MAAM,WAAW,cAAc,CAAC,CAAC,SAAS,MAAM;IAC9C,QAAQ,CAAC,KAAK,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC;IAChC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC;IAC9B,QAAQ,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC;IAC/C,GAAG,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,GAAG,IAAI,CAAC;IACxC,QAAQ,IAAI,IAAI,CAAC;IACjB,cAAc,IAAI,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;IACvC,cAAc,CAAC,IAAI,EAAE;QAAE,IAAI,EAAE,IAAI,CAAA;KAAE,GAAG,MAAM,EAAE,CAAC;IAC/C,cAAc,CAAC,IAAI,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,MAAM,EAAE,CAAC;IACpD,OAAO,IAAI,OAAO,CAAC;IACnB,MAAM,IAAI,IAAI,CAAC;IACf,OAAO,IAAI,YAAY,CAAC,CAAC,CAAC,CAAC;IAC3B,MAAM,IAAI,YAAY,CAAC,CAAC,CAAC,CAAC;CAC3B;AAED,KAAK,YAAY,CAAC,KAAK,SAAS,MAAM,EAAE,CAAC,SAAS,YAAY,IAAI;IAChE,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC,CAAC,CAAC;IACnC,QAAQ,CAAC,SAAS,EAAE,cAAc,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;IACnD,MAAM,CAAC,CAAC,SAAS;QAAE,QAAQ,CAAC,SAAS,EAAE,cAAc,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAA;KAAE,EACrE,IAAI,EAAE,CAAC,EACP,KAAK,EAAE,WAAW,CAAC,CAAC,CAAC,GAAG,YAAY,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,GACnD,CAAC,CAAC,WAAW,CAAC,CAAC;IAClB,OAAO,CAAC,CAAC,SAAS;QAAE,QAAQ,CAAC,SAAS,EAAE,cAAc,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAA;KAAE,EACtE,IAAI,EAAE,CAAC,EACP,KAAK,EAAE,WAAW,CAAC,CAAC,CAAC,GAAG,YAAY,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,GACnD,CAAC,CAAC,WAAW,CAAC,CAAC;IAClB,KAAK,CAAC,CAAC,SAAS;QAAE,QAAQ,CAAC,SAAS,EAAE,cAAc,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAA;KAAE,EACpE,IAAI,EAAE,CAAC,EACP,KAAK,EAAE,OAAO,GACb,CAAC,CAAC,WAAW,CAAC,CAAC;CACnB,GAAG,CAAC,QAAQ,MACX,KAAK,EAAE,WAAW,CAAC,CAAC,CAAC,EACrB,IAAI,EAAE,KAAK,KACR,cAAc,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAErC;;;;;;;;;;;;;;;;;GAiBG;AACH,KAAK,WAAW,CAAC,CAAC,SAAS,YAAY,IACrC,WAAW,CAAC,CAAC,CAAC,SAAS,MAAM,GAAG,WAAW,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC;AAEzD,wBAAgB,MAAM,CAAC,KAAK,CAAC,KAAK,SAAS,MAAM,EAAE,CAAC,SAAS,YAAY,EACvE,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,CAAC,GACR,YAAY,CAAC,KAAK,EAAE,CAAC,CAAC,CAkBxB"}
@@ -1,46 +1,38 @@
1
- import { CodedError, validate, validationError, } from '../core/index.js';
1
+ import { validationError } from './coded-error.js';
2
2
  import { applyCowDraft, cloneValue, frozenSnapshot, isPlainObject, } from './cow-draft.js';
3
+ import { schemaDefinition, } from './schema.js';
4
+ import { validate } from './validate.js';
3
5
  const EMPTY_CHANGED_KEYS = Object.freeze([]);
4
- /**
5
- * Aggregates mutate **this** via `set` and return `this`.
6
- * They never I/O, never publish, never hold ports.
7
- *
8
- * Validation, invariants, and declared refusals **throw**.
9
- * `create` / `parse` run the schema. `restore` does not — it rehydrates
10
- * mapper output as-is. `set` re-runs the schema after a write.
11
- * `validate()` is the optional fail-fast for a restored instance.
12
- *
13
- * ```ts
14
- * class Incident extends Entity<IncidentProps> {
15
- * static readonly key = 'Incident'
16
- * static readonly schema = z.object({ id: z.string(), status: z.enum(['open', 'closed']) })
17
- * static readonly errors = { ALREADY_CLOSED: { message: 'Incident already closed' } } as const
18
- * close(now: Date): this {
19
- * if (this.props.status === 'closed') Incident.error('ALREADY_CLOSED')
20
- * return this.set((draft) => {
21
- * draft.status = 'closed'
22
- * draft.closedAt = now
23
- * })
24
- * }
25
- * }
26
- * ```
27
- */
28
- export class Entity {
29
- /** Entity name used in validation and undeclared-error messages. Declare on each subclass. */
30
- static key;
31
- /** Standard Schema for `create` / `parse` / `set` / `validate()`. Declare on each subclass. */
6
+ export function Entity(token, schema) {
7
+ const definition = schemaDefinition(schema);
8
+ class EntityClass extends EntityBase {
9
+ /** Entity name. Literal type of the string passed to {@link Entity}. */
10
+ static token = token;
11
+ /** Schema used by `create`, `parse`, `set`, and `validate`. */
12
+ static schema = definition;
13
+ /** Nominal marker. Each `Entity(...)` call is a distinct class. */
14
+ #brand = true;
15
+ constructor(props) {
16
+ super(props);
17
+ void this.#brand;
18
+ }
19
+ }
20
+ return EntityClass;
21
+ }
22
+ class EntityBase {
23
+ /** Entity name used in validation messages. */
24
+ static token;
25
+ /** Schema for `create` / `parse` / `set` / `validate()`. */
32
26
  static schema;
33
- /** Declared refusal codes. Keys are the `error()` union. Declare on each subclass. */
34
- static errors;
35
27
  #isNew = false;
36
28
  #validated = false;
37
29
  #original = undefined;
38
30
  #owned = undefined;
39
31
  #snapshot = undefined;
40
- _props;
32
+ #props;
41
33
  /** Live props. Read-only; write through `set`. */
42
34
  get props() {
43
- return this._props;
35
+ return this.#props;
44
36
  }
45
37
  /** True after `create` until `commit`. `restore` / `parse` start false. */
46
38
  get isNew() {
@@ -59,22 +51,22 @@ export class Entity {
59
51
  */
60
52
  get original() {
61
53
  if (this.#original === undefined ||
62
- Object.is(this._props, this.#original)) {
54
+ Object.is(this.#props, this.#original)) {
63
55
  return undefined;
64
56
  }
65
57
  return this.#original;
66
58
  }
67
59
  constructor(props) {
68
- this._props = props;
60
+ this.#props = props;
69
61
  }
70
- /** Copy-on-write mutate. Edit `draft` and return `this`. Re-validates the schema after a write. */
62
+ /** Copy-on-write mutate. Edit `draft` and return `this`. Re-validates after a write. */
71
63
  set(producer) {
72
- const previousRoot = this._props;
73
- const backup = cloneValue(this._props);
64
+ const previousRoot = this.#props;
65
+ const backup = cloneValue(this.#props);
74
66
  const previousSnapshot = this.#snapshot;
75
- const wasOwned = this.#owned?.has(this._props) === true;
76
- const result = applyCowDraft(this._props, this.#owned, producer);
77
- this._props = result.root;
67
+ const wasOwned = this.#owned?.has(this.#props) === true;
68
+ const result = applyCowDraft(this.#props, this.#owned, producer);
69
+ this.#props = result.root;
78
70
  this.#owned = result.owned;
79
71
  if (result.wrote) {
80
72
  this.#snapshot = undefined;
@@ -82,7 +74,7 @@ export class Entity {
82
74
  this.#assertSchema();
83
75
  }
84
76
  catch (error) {
85
- this._props = wasOwned ? backup : previousRoot;
77
+ this.#props = wasOwned ? backup : previousRoot;
86
78
  this.#owned = wasOwned ? new WeakSet([backup]) : undefined;
87
79
  this.#snapshot = previousSnapshot;
88
80
  throw error;
@@ -105,18 +97,18 @@ export class Entity {
105
97
  }
106
98
  getChangedKeys(opts) {
107
99
  if (!this.#isNew &&
108
- (this.#original === undefined || Object.is(this._props, this.#original))) {
100
+ (this.#original === undefined || Object.is(this.#props, this.#original))) {
109
101
  return EMPTY_CHANGED_KEYS;
110
102
  }
111
103
  if (opts?.deep) {
112
104
  const out = [];
113
- diffDeep(this._props, this.#isNew ? undefined : this.#original, '', out);
105
+ diffDeep(this.#props, this.#isNew ? undefined : this.#original, '', out);
114
106
  return out.length === 0 ? EMPTY_CHANGED_KEYS : out;
115
107
  }
116
108
  if (this.#isNew) {
117
- return Object.keys(this._props);
109
+ return Object.keys(this.#props);
118
110
  }
119
- const current = this._props;
111
+ const current = this.#props;
120
112
  const original = this.#original;
121
113
  const keys = new Set([
122
114
  ...Object.keys(current),
@@ -134,9 +126,9 @@ export class Entity {
134
126
  isDirty() {
135
127
  return this.#isNew || this.getChangedKeys().length > 0;
136
128
  }
137
- /** Accept current props as original; `isNew` becomes false. Adapters after persist; not use-cases. */
129
+ /** Accept current props as original; `isNew` becomes false. */
138
130
  commit() {
139
- this.#original = this._props;
131
+ this.#original = this.#props;
140
132
  this.#isNew = false;
141
133
  this.#owned = undefined;
142
134
  return this;
@@ -144,7 +136,7 @@ export class Entity {
144
136
  /** Deep frozen snapshot for persistence and use-case output. Reused until the next `set`. */
145
137
  toProps() {
146
138
  if (this.#snapshot === undefined) {
147
- this.#snapshot = frozenSnapshot(this._props);
139
+ this.#snapshot = frozenSnapshot(this.#props);
148
140
  }
149
141
  return this.#snapshot;
150
142
  }
@@ -152,15 +144,6 @@ export class Entity {
152
144
  toJSON() {
153
145
  return this.toProps();
154
146
  }
155
- /**
156
- * Throw a declared entity error. Codes are the keys of the subclass
157
- * `static errors` when called as `Incident.error('ALREADY_CLOSED')`.
158
- * An undeclared code is a type error on that call, and a programming
159
- * error at runtime.
160
- */
161
- static error(code, data) {
162
- throwEntityError(this, code, data);
163
- }
164
147
  /**
165
148
  * Validate typed props and construct a new instance (`isNew: true`).
166
149
  * Throws `CodedError` `VALIDATION` if the schema rejects the props.
@@ -173,8 +156,8 @@ export class Entity {
173
156
  }
174
157
  /**
175
158
  * Reconstruct an existing instance (`isNew: false`) without running the
176
- * schema. Props are stored as given (no strip/defaults). `isValidated`
177
- * starts false until `set` writes or `validate()` runs.
159
+ * schema. Props are stored as given. `isValidated` starts false until
160
+ * `set` writes or `validate()` runs.
178
161
  */
179
162
  static restore(props) {
180
163
  const instance = construct(this, props);
@@ -182,8 +165,8 @@ export class Entity {
182
165
  return instance;
183
166
  }
184
167
  /**
185
- * Trust boundary for untyped input. Validates like `create`;
186
- * tracking matches `restore` (`isNew: false`).
168
+ * Trust boundary for untyped input. Validates like `create`.
169
+ * Tracking matches `restore` (`isNew: false`).
187
170
  * Throws `CodedError` `VALIDATION` if the schema rejects the value.
188
171
  */
189
172
  static parse(value) {
@@ -193,31 +176,31 @@ export class Entity {
193
176
  return instance;
194
177
  }
195
178
  #markNew() {
196
- this._props = { ...this._props };
179
+ this.#props = { ...this.#props };
197
180
  this.#original = undefined;
198
181
  this.#isNew = true;
199
182
  this.#owned = new WeakSet();
200
- this.#owned.add(this._props);
183
+ this.#owned.add(this.#props);
201
184
  this.#snapshot = undefined;
202
185
  }
203
186
  #markRestored() {
204
- this.#original = this._props;
187
+ this.#original = this.#props;
205
188
  this.#isNew = false;
206
189
  this.#owned = undefined;
207
190
  this.#snapshot = undefined;
208
191
  }
209
192
  #assertSchema() {
210
- const Ctor = this.constructor;
211
- const parsed = validate(Ctor.schema, this._props);
193
+ const ctor = this.constructor;
194
+ const parsed = validate(ctor.schema, this.#props);
212
195
  if (!parsed.ok) {
213
- throw validationError(`hexok: ${Ctor.key} validation failed`, parsed.issues);
196
+ throw validationError(`hexok: ${ctor.token} validation failed`, parsed.issues);
214
197
  }
215
198
  }
216
199
  }
217
200
  function instantiate(Ctor, value) {
218
201
  const parsed = validate(Ctor.schema, value);
219
202
  if (!parsed.ok) {
220
- throw validationError(`hexok: ${Ctor.key} validation failed`, parsed.issues);
203
+ throw validationError(`hexok: ${Ctor.token} validation failed`, parsed.issues);
221
204
  }
222
205
  return construct(Ctor, parsed.value);
223
206
  }
@@ -249,15 +232,4 @@ function diffDeep(current, original, path, out) {
249
232
  if (path)
250
233
  out.push(path);
251
234
  }
252
- function throwEntityError(ctor, code, data) {
253
- const def = ctor.errors[code];
254
- if (def === undefined) {
255
- throw new Error(`hexok: undeclared error "${code}" on ${ctor.key}`);
256
- }
257
- throw new CodedError({
258
- code,
259
- message: def.message ?? code,
260
- ...(data !== undefined ? { data } : {}),
261
- });
262
- }
263
235
  //# sourceMappingURL=entity.js.map