hexok 1.0.1 → 2.1.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.
- package/README.md +9 -22
- package/dist/adapter.d.ts +18 -0
- package/dist/adapter.d.ts.map +1 -0
- package/dist/adapter.js +21 -0
- package/dist/adapter.js.map +1 -0
- package/dist/catalog.d.ts +88 -0
- package/dist/catalog.d.ts.map +1 -0
- package/dist/catalog.js +79 -0
- package/dist/catalog.js.map +1 -0
- package/dist/{core/coded-error.d.ts → coded-error.d.ts} +9 -4
- package/dist/coded-error.d.ts.map +1 -0
- package/dist/{core/coded-error.js → coded-error.js} +9 -4
- package/dist/coded-error.js.map +1 -0
- package/dist/cow-draft.d.ts.map +1 -0
- package/dist/cow-draft.js.map +1 -0
- package/dist/entity.d.ts +63 -0
- package/dist/entity.d.ts.map +1 -0
- package/dist/{domain/entity.js → entity.js} +52 -80
- package/dist/entity.js.map +1 -0
- package/dist/error-map.d.ts +22 -0
- package/dist/error-map.d.ts.map +1 -0
- package/dist/error-map.js +2 -0
- package/dist/error-map.js.map +1 -0
- package/dist/errors.d.ts +85 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +85 -0
- package/dist/errors.js.map +1 -0
- package/dist/event-handler.d.ts +31 -0
- package/dist/event-handler.d.ts.map +1 -0
- package/dist/event-handler.js +28 -0
- package/dist/event-handler.js.map +1 -0
- package/dist/event.d.ts +37 -0
- package/dist/event.d.ts.map +1 -0
- package/dist/event.js +44 -0
- package/dist/event.js.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +14 -0
- package/dist/index.js.map +1 -0
- package/dist/mapper.d.ts +100 -0
- package/dist/mapper.d.ts.map +1 -0
- package/dist/mapper.js +167 -0
- package/dist/mapper.js.map +1 -0
- package/dist/port.d.ts +20 -0
- package/dist/port.d.ts.map +1 -0
- package/dist/port.js +25 -0
- package/dist/port.js.map +1 -0
- package/dist/result.d.ts.map +1 -0
- package/dist/result.js.map +1 -0
- package/dist/schema.d.ts +37 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +50 -0
- package/dist/schema.js.map +1 -0
- package/dist/{core/standard-schema.d.ts → standard-schema.d.ts} +1 -1
- package/dist/standard-schema.d.ts.map +1 -0
- package/dist/standard-schema.js.map +1 -0
- package/dist/use-case.d.ts +183 -0
- package/dist/use-case.d.ts.map +1 -0
- package/dist/use-case.js +221 -0
- package/dist/use-case.js.map +1 -0
- package/dist/{core/schema.d.ts → validate.d.ts} +1 -1
- package/dist/validate.d.ts.map +1 -0
- package/dist/{core/schema.js → validate.js} +1 -1
- package/dist/validate.js.map +1 -0
- package/package.json +7 -26
- package/skills/hexok/SKILL.md +127 -0
- package/skills/hexok/references/adapter.md +66 -0
- package/skills/hexok/references/entity.md +74 -0
- package/skills/hexok/references/error.md +140 -0
- package/skills/hexok/references/event-catalog.md +57 -0
- package/skills/hexok/references/event-handler.md +56 -0
- package/skills/hexok/references/event.md +53 -0
- package/skills/hexok/references/mapper.md +77 -0
- package/skills/hexok/references/port.md +58 -0
- package/skills/hexok/references/schema.md +47 -0
- package/skills/hexok/references/use-case.md +164 -0
- package/dist/app/callable-use-case.d.ts +0 -34
- package/dist/app/callable-use-case.d.ts.map +0 -1
- package/dist/app/callable-use-case.js +0 -41
- package/dist/app/callable-use-case.js.map +0 -1
- package/dist/app/contract.d.ts +0 -46
- package/dist/app/contract.d.ts.map +0 -1
- package/dist/app/contract.js +0 -28
- package/dist/app/contract.js.map +0 -1
- package/dist/app/error-factory.d.ts +0 -9
- package/dist/app/error-factory.d.ts.map +0 -1
- package/dist/app/error-factory.js +0 -30
- package/dist/app/error-factory.js.map +0 -1
- package/dist/app/event-channel.d.ts +0 -133
- package/dist/app/event-channel.d.ts.map +0 -1
- package/dist/app/event-channel.js +0 -49
- package/dist/app/event-channel.js.map +0 -1
- package/dist/app/event-use-case.d.ts +0 -47
- package/dist/app/event-use-case.d.ts.map +0 -1
- package/dist/app/event-use-case.js +0 -54
- package/dist/app/event-use-case.js.map +0 -1
- package/dist/app/execute-ctx.d.ts +0 -92
- package/dist/app/execute-ctx.d.ts.map +0 -1
- package/dist/app/execute-ctx.js +0 -2
- package/dist/app/execute-ctx.js.map +0 -1
- package/dist/app/external-use-case.d.ts +0 -25
- package/dist/app/external-use-case.d.ts.map +0 -1
- package/dist/app/external-use-case.js +0 -25
- package/dist/app/external-use-case.js.map +0 -1
- package/dist/app/index.d.ts +0 -9
- package/dist/app/index.d.ts.map +0 -1
- package/dist/app/index.js +0 -8
- package/dist/app/index.js.map +0 -1
- package/dist/app/internal-use-case.d.ts +0 -26
- package/dist/app/internal-use-case.d.ts.map +0 -1
- package/dist/app/internal-use-case.js +0 -26
- package/dist/app/internal-use-case.js.map +0 -1
- package/dist/app/nest.d.ts +0 -9
- package/dist/app/nest.d.ts.map +0 -1
- package/dist/app/nest.js +0 -28
- package/dist/app/nest.js.map +0 -1
- package/dist/app/types.d.ts +0 -153
- package/dist/app/types.d.ts.map +0 -1
- package/dist/app/types.js +0 -17
- package/dist/app/types.js.map +0 -1
- package/dist/core/coded-error.d.ts.map +0 -1
- package/dist/core/coded-error.js.map +0 -1
- package/dist/core/error-map.d.ts +0 -21
- package/dist/core/error-map.d.ts.map +0 -1
- package/dist/core/error-map.js +0 -5
- package/dist/core/error-map.js.map +0 -1
- package/dist/core/index.d.ts +0 -6
- package/dist/core/index.d.ts.map +0 -1
- package/dist/core/index.js +0 -5
- package/dist/core/index.js.map +0 -1
- package/dist/core/result.d.ts.map +0 -1
- package/dist/core/result.js.map +0 -1
- package/dist/core/schema.d.ts.map +0 -1
- package/dist/core/schema.js.map +0 -1
- package/dist/core/standard-schema.d.ts.map +0 -1
- package/dist/core/standard-schema.js.map +0 -1
- package/dist/domain/capabilities.d.ts +0 -42
- package/dist/domain/capabilities.d.ts.map +0 -1
- package/dist/domain/capabilities.js +0 -2
- package/dist/domain/capabilities.js.map +0 -1
- package/dist/domain/catalog.d.ts +0 -46
- package/dist/domain/catalog.d.ts.map +0 -1
- package/dist/domain/catalog.js +0 -114
- package/dist/domain/catalog.js.map +0 -1
- package/dist/domain/channel.d.ts +0 -36
- package/dist/domain/channel.d.ts.map +0 -1
- package/dist/domain/channel.js +0 -2
- package/dist/domain/channel.js.map +0 -1
- package/dist/domain/cow-draft.d.ts.map +0 -1
- package/dist/domain/cow-draft.js.map +0 -1
- package/dist/domain/entity.d.ts +0 -120
- package/dist/domain/entity.d.ts.map +0 -1
- package/dist/domain/entity.js.map +0 -1
- package/dist/domain/envelope.d.ts +0 -59
- package/dist/domain/envelope.d.ts.map +0 -1
- package/dist/domain/envelope.js +0 -2
- package/dist/domain/envelope.js.map +0 -1
- package/dist/domain/event.d.ts +0 -44
- package/dist/domain/event.d.ts.map +0 -1
- package/dist/domain/event.js +0 -21
- package/dist/domain/event.js.map +0 -1
- package/dist/domain/index.d.ts +0 -8
- package/dist/domain/index.d.ts.map +0 -1
- package/dist/domain/index.js +0 -5
- package/dist/domain/index.js.map +0 -1
- package/dist/domain/port.d.ts +0 -45
- package/dist/domain/port.d.ts.map +0 -1
- package/dist/domain/port.js +0 -41
- package/dist/domain/port.js.map +0 -1
- package/dist/infra/adapter.d.ts +0 -22
- package/dist/infra/adapter.d.ts.map +0 -1
- package/dist/infra/adapter.js +0 -18
- package/dist/infra/adapter.js.map +0 -1
- package/dist/infra/index.d.ts +0 -3
- package/dist/infra/index.d.ts.map +0 -1
- package/dist/infra/index.js +0 -3
- package/dist/infra/index.js.map +0 -1
- package/dist/infra/mapper.d.ts +0 -48
- package/dist/infra/mapper.d.ts.map +0 -1
- package/dist/infra/mapper.js +0 -77
- package/dist/infra/mapper.js.map +0 -1
- package/dist/runtime/app.d.ts +0 -100
- package/dist/runtime/app.d.ts.map +0 -1
- package/dist/runtime/app.js +0 -292
- package/dist/runtime/app.js.map +0 -1
- package/dist/runtime/channel.d.ts +0 -34
- package/dist/runtime/channel.d.ts.map +0 -1
- package/dist/runtime/channel.js +0 -110
- package/dist/runtime/channel.js.map +0 -1
- package/dist/runtime/client.d.ts +0 -21
- package/dist/runtime/client.d.ts.map +0 -1
- package/dist/runtime/client.js +0 -2
- package/dist/runtime/client.js.map +0 -1
- package/dist/runtime/completeness.d.ts +0 -89
- package/dist/runtime/completeness.d.ts.map +0 -1
- package/dist/runtime/completeness.js +0 -2
- package/dist/runtime/completeness.js.map +0 -1
- package/dist/runtime/envelope.d.ts +0 -7
- package/dist/runtime/envelope.d.ts.map +0 -1
- package/dist/runtime/envelope.js +0 -69
- package/dist/runtime/envelope.js.map +0 -1
- package/dist/runtime/events.d.ts +0 -6
- package/dist/runtime/events.d.ts.map +0 -1
- package/dist/runtime/events.js +0 -48
- package/dist/runtime/events.js.map +0 -1
- package/dist/runtime/http-status.d.ts +0 -3
- package/dist/runtime/http-status.d.ts.map +0 -1
- package/dist/runtime/http-status.js +0 -11
- package/dist/runtime/http-status.js.map +0 -1
- package/dist/runtime/http.d.ts +0 -4
- package/dist/runtime/http.d.ts.map +0 -1
- package/dist/runtime/http.js +0 -58
- package/dist/runtime/http.js.map +0 -1
- package/dist/runtime/index.d.ts +0 -10
- package/dist/runtime/index.d.ts.map +0 -1
- package/dist/runtime/index.js +0 -6
- package/dist/runtime/index.js.map +0 -1
- package/dist/runtime/interceptor.d.ts +0 -61
- package/dist/runtime/interceptor.d.ts.map +0 -1
- package/dist/runtime/interceptor.js +0 -7
- package/dist/runtime/interceptor.js.map +0 -1
- package/dist/runtime/invoke.d.ts +0 -34
- package/dist/runtime/invoke.d.ts.map +0 -1
- package/dist/runtime/invoke.js +0 -235
- package/dist/runtime/invoke.js.map +0 -1
- package/dist/runtime/middleware.d.ts +0 -20
- package/dist/runtime/middleware.d.ts.map +0 -1
- package/dist/runtime/middleware.js +0 -2
- package/dist/runtime/middleware.js.map +0 -1
- package/dist/runtime/rpc.d.ts +0 -24
- package/dist/runtime/rpc.d.ts.map +0 -1
- package/dist/runtime/rpc.js +0 -16
- package/dist/runtime/rpc.js.map +0 -1
- package/dist/testing/app-test.d.ts +0 -77
- package/dist/testing/app-test.d.ts.map +0 -1
- package/dist/testing/app-test.js +0 -109
- package/dist/testing/app-test.js.map +0 -1
- package/dist/testing/in-memory-bus.d.ts +0 -19
- package/dist/testing/in-memory-bus.d.ts.map +0 -1
- package/dist/testing/in-memory-bus.js +0 -31
- package/dist/testing/in-memory-bus.js.map +0 -1
- package/dist/testing/in-memory-channel.d.ts +0 -32
- package/dist/testing/in-memory-channel.d.ts.map +0 -1
- package/dist/testing/in-memory-channel.js +0 -65
- package/dist/testing/in-memory-channel.js.map +0 -1
- package/dist/testing/in-memory-queue.d.ts +0 -24
- package/dist/testing/in-memory-queue.d.ts.map +0 -1
- package/dist/testing/in-memory-queue.js +0 -66
- package/dist/testing/in-memory-queue.js.map +0 -1
- package/dist/testing/in-memory-repository.d.ts +0 -44
- package/dist/testing/in-memory-repository.d.ts.map +0 -1
- package/dist/testing/in-memory-repository.js +0 -60
- package/dist/testing/in-memory-repository.js.map +0 -1
- package/dist/testing/index.d.ts +0 -6
- package/dist/testing/index.d.ts.map +0 -1
- package/dist/testing/index.js +0 -6
- package/dist/testing/index.js.map +0 -1
- /package/dist/{domain/cow-draft.d.ts → cow-draft.d.ts} +0 -0
- /package/dist/{domain/cow-draft.js → cow-draft.js} +0 -0
- /package/dist/{core/result.d.ts → result.d.ts} +0 -0
- /package/dist/{core/result.js → result.js} +0 -0
- /package/dist/{core/standard-schema.js → standard-schema.js} +0 -0
package/README.md
CHANGED
|
@@ -1,31 +1,18 @@
|
|
|
1
1
|
# hexok
|
|
2
2
|
|
|
3
|
-
|
|
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
4
|
|
|
5
|
-
|
|
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
6
|
|
|
7
|
-
|
|
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
8
|
|
|
9
|
-
|
|
10
|
-
npm i hexok
|
|
11
|
-
```
|
|
9
|
+
## Agent skill
|
|
12
10
|
|
|
13
|
-
|
|
11
|
+
This package's repository includes an agent skill named `hexok`. It walks a feature from the user story through entities, use cases, events, adapters, the gateway, and where handlers run. Install it from GitHub. `npx skills update` refreshes that install from GitHub.
|
|
14
12
|
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
import { App } from 'hexok/runtime'
|
|
19
|
-
import { App as TestApp, InMemoryRepository } from 'hexok/testing'
|
|
13
|
+
```bash
|
|
14
|
+
npx skills add crobinson42/hexok
|
|
15
|
+
npx skills update
|
|
20
16
|
```
|
|
21
17
|
|
|
22
|
-
|
|
23
|
-
| --- | --- |
|
|
24
|
-
| `hexok/core` | `Result`, Standard Schema V1, `ErrorMap`, `CodedError` |
|
|
25
|
-
| `hexok/domain` | `Entity`, `Port`, `EventCatalog`, `DomainEvent` |
|
|
26
|
-
| `hexok/app` | `ExternalUseCase`, `InternalUseCase`, `EventUseCase`, `EventChannel` |
|
|
27
|
-
| `hexok/infra` | `Mapper`, `Adapter.of` |
|
|
28
|
-
| `hexok/runtime` | `App.from`, interceptors, local client, HTTP |
|
|
29
|
-
| `hexok/testing` | `App.test`, in-memory adapters |
|
|
30
|
-
|
|
31
|
-
Full API: https://crobinson42.github.io/hexok/
|
|
18
|
+
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"}
|
package/dist/adapter.js
ADDED
|
@@ -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"}
|
package/dist/catalog.js
ADDED
|
@@ -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
|
-
*
|
|
4
|
-
*
|
|
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
|
-
*
|
|
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
|
|
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
|
-
*
|
|
3
|
-
*
|
|
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
|
-
*
|
|
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
|
|
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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"}
|
package/dist/entity.d.ts
ADDED
|
@@ -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":"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"}
|