@nwire/messages 0.7.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/LICENSE +21 -0
- package/README.md +61 -0
- package/dist/__tests__/define-event.test.d.ts +5 -0
- package/dist/__tests__/define-event.test.d.ts.map +1 -0
- package/dist/__tests__/define-event.test.js +44 -0
- package/dist/__tests__/define-event.test.js.map +1 -0
- package/dist/commands/noop.command.d.ts +5 -0
- package/dist/commands/noop.command.d.ts.map +1 -0
- package/dist/commands/noop.command.js +10 -0
- package/dist/commands/noop.command.js.map +1 -0
- package/dist/events/service-booted.event.d.ts +7 -0
- package/dist/events/service-booted.event.d.ts.map +1 -0
- package/dist/events/service-booted.event.js +12 -0
- package/dist/events/service-booted.event.js.map +1 -0
- package/dist/message-contracts.d.ts +112 -0
- package/dist/message-contracts.d.ts.map +1 -0
- package/dist/message-contracts.js +47 -0
- package/dist/message-contracts.js.map +1 -0
- package/dist/messages.d.ts +13 -0
- package/dist/messages.d.ts.map +1 -0
- package/dist/messages.js +13 -0
- package/dist/messages.js.map +1 -0
- package/package.json +40 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Alex Gefter / 200apps Ltd.
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# @nwire/messages
|
|
2
|
+
|
|
3
|
+
> Command + event primitives — `defineCommand` / `defineEvent` and the message-envelope types.
|
|
4
|
+
|
|
5
|
+
## What it is
|
|
6
|
+
|
|
7
|
+
Typed message primitives for the CQRS surface: `defineCommand` for intent (one handler, one response) and `defineEvent` for facts (many subscribers, fan-out). Includes the visibility/scope/outcome enums and zod-binding types every Nwire transport, bus, and store agrees on.
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
pnpm add @nwire/messages
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Standalone use
|
|
16
|
+
|
|
17
|
+
For developers who want a typed message contract layer for their own architecture — works against any in-process bus, queue, or RPC.
|
|
18
|
+
|
|
19
|
+
```ts
|
|
20
|
+
import { z } from "zod";
|
|
21
|
+
import { defineCommand, defineEvent } from "@nwire/messages";
|
|
22
|
+
|
|
23
|
+
export const EnrolStudent = defineCommand("EnrolStudent", {
|
|
24
|
+
schema: z.object({ studentId: z.string(), courseId: z.string() }),
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
export const StudentWasEnrolled = defineEvent("StudentWasEnrolled", {
|
|
28
|
+
schema: z.object({ studentId: z.string(), courseId: z.string() }),
|
|
29
|
+
scope: "domain",
|
|
30
|
+
visibility: "public",
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
// Validate at the edge:
|
|
34
|
+
const payload = EnrolStudent.schema.parse(req.body);
|
|
35
|
+
// Construct an event message:
|
|
36
|
+
const msg = StudentWasEnrolled({ studentId: "s-1", courseId: "c-1" });
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Within nwire-app
|
|
40
|
+
|
|
41
|
+
For developers using this package as part of the Nwire stack. `@nwire/forge`'s `defineEvent` wraps this one with extra hooks (bus republish, projection fan-out). Touch `@nwire/messages` directly when you need just the contracts — typically in shared kits a foreign service imports.
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
import { defineEvent } from "@nwire/forge"; // adds bus + projection wiring
|
|
45
|
+
const StudentWasEnrolled = defineEvent("StudentWasEnrolled", {
|
|
46
|
+
schema: z.object({ studentId: z.string(), courseId: z.string() }),
|
|
47
|
+
}).public();
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## API
|
|
51
|
+
|
|
52
|
+
- `defineCommand(name, { schema })` — intent contract; one handler, one response.
|
|
53
|
+
- `defineEvent(name, { schema, scope?, visibility?, outcome? })` — fact contract; many subscribers.
|
|
54
|
+
- `CommandDefinition`, `EventDefinition`, `EventMessageOf`, `CommandPayload`, `EventPayload` — inferred types.
|
|
55
|
+
- `EventVisibility` / `EventScope` / `EventOutcome` — enums (`public`/`internal`, `domain`/`integration`, success/failure tags).
|
|
56
|
+
- `ServiceBootedEvent`, `NoopCommand` — built-in baseline contracts.
|
|
57
|
+
|
|
58
|
+
## See also
|
|
59
|
+
|
|
60
|
+
- [Architecture sketch §05 — Primitives tier](../../architecture-sketch.html#packages)
|
|
61
|
+
- Sibling packages: [@nwire/forge](../nwire-forge), [@nwire/bus](../nwire-bus), [@nwire/envelope](../nwire-envelope)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"define-event.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/define-event.test.ts"],"names":[],"mappings":"AAAA;;GAEG"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* defineEvent — returns a callable factory that IS the event definition.
|
|
3
|
+
*/
|
|
4
|
+
import { describe, it, expect } from "vitest";
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
import { defineEvent } from "../message-contracts.js";
|
|
7
|
+
describe("defineEvent (callable)", () => {
|
|
8
|
+
const AnswerWasSubmitted = defineEvent({
|
|
9
|
+
name: "submissions.answer-was-submitted",
|
|
10
|
+
description: "Avi just tapped Submit.",
|
|
11
|
+
outcome: "milestone",
|
|
12
|
+
audience: ["product"],
|
|
13
|
+
visibility: "public",
|
|
14
|
+
// Integration events require a version since Phase 42.2.
|
|
15
|
+
version: 1,
|
|
16
|
+
schema: z.object({
|
|
17
|
+
studentId: z.string(),
|
|
18
|
+
submittedAt: z.string().datetime(),
|
|
19
|
+
}),
|
|
20
|
+
});
|
|
21
|
+
it("preserves meta fields as own properties", () => {
|
|
22
|
+
expect(AnswerWasSubmitted.name).toBe("submissions.answer-was-submitted");
|
|
23
|
+
expect(AnswerWasSubmitted.description).toBe("Avi just tapped Submit.");
|
|
24
|
+
expect(AnswerWasSubmitted.outcome).toBe("milestone");
|
|
25
|
+
expect(AnswerWasSubmitted.audience).toEqual(["product"]);
|
|
26
|
+
expect(AnswerWasSubmitted.visibility).toBe("public");
|
|
27
|
+
expect(AnswerWasSubmitted.schema).toBeDefined();
|
|
28
|
+
});
|
|
29
|
+
it("is callable as a factory and validates payload", () => {
|
|
30
|
+
const at = new Date().toISOString();
|
|
31
|
+
const msg = AnswerWasSubmitted({ studentId: "alice", submittedAt: at });
|
|
32
|
+
expect(msg).toEqual({
|
|
33
|
+
eventName: "submissions.answer-was-submitted",
|
|
34
|
+
payload: { studentId: "alice", submittedAt: at },
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
it("throws on invalid payload via zod parse", () => {
|
|
38
|
+
expect(() => AnswerWasSubmitted({ studentId: "alice", submittedAt: "not-a-date" })).toThrow();
|
|
39
|
+
});
|
|
40
|
+
it("toString returns the event name", () => {
|
|
41
|
+
expect(String(AnswerWasSubmitted)).toBe("submissions.answer-was-submitted");
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
//# sourceMappingURL=define-event.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"define-event.test.js","sourceRoot":"","sources":["../../src/__tests__/define-event.test.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAEnD,QAAQ,CAAC,wBAAwB,EAAE,GAAG,EAAE;IACtC,MAAM,kBAAkB,GAAG,WAAW,CAAC;QACrC,IAAI,EAAE,kCAAkC;QACxC,WAAW,EAAE,yBAAyB;QACtC,OAAO,EAAE,WAAW;QACpB,QAAQ,EAAE,CAAC,SAAS,CAAC;QACrB,UAAU,EAAE,QAAQ;QACpB,yDAAyD;QACzD,OAAO,EAAE,CAAC;QACV,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;YACf,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE;YACrB,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;SACnC,CAAC;KACH,CAAC,CAAC;IAEH,EAAE,CAAC,yCAAyC,EAAE,GAAG,EAAE;QACjD,MAAM,CAAC,kBAAkB,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,kCAAkC,CAAC,CAAC;QACzE,MAAM,CAAC,kBAAkB,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC;QACvE,MAAM,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QACrD,MAAM,CAAC,kBAAkB,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;QACzD,MAAM,CAAC,kBAAkB,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACrD,MAAM,CAAC,kBAAkB,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE,CAAC;IAClD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gDAAgD,EAAE,GAAG,EAAE;QACxD,MAAM,EAAE,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QACpC,MAAM,GAAG,GAAG,kBAAkB,CAAC,EAAE,SAAS,EAAE,OAAO,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC,CAAC;QACxE,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC;YAClB,SAAS,EAAE,kCAAkC;YAC7C,OAAO,EAAE,EAAE,SAAS,EAAE,OAAO,EAAE,WAAW,EAAE,EAAE,EAAE;SACjD,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yCAAyC,EAAE,GAAG,EAAE;QACjD,MAAM,CAAC,GAAG,EAAE,CACV,kBAAkB,CAAC,EAAE,SAAS,EAAE,OAAO,EAAE,WAAW,EAAE,YAAY,EAAW,CAAC,CAC/E,CAAC,OAAO,EAAE,CAAC;IACd,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iCAAiC,EAAE,GAAG,EAAE;QACzC,MAAM,CAAC,MAAM,CAAC,kBAAkB,CAAC,CAAC,CAAC,IAAI,CAAC,kCAAkC,CAAC,CAAC;IAC9E,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"noop.command.d.ts","sourceRoot":"","sources":["../../src/commands/noop.command.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,eAAO,MAAM,WAAW;;kBAMtB,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { defineCommand } from "../message-contracts.js";
|
|
3
|
+
export const NoopCommand = defineCommand({
|
|
4
|
+
name: "system.noop",
|
|
5
|
+
description: "Placeholder command demonstrating the cross-service contract pattern.",
|
|
6
|
+
schema: z.object({
|
|
7
|
+
traceId: z.string().optional(),
|
|
8
|
+
}),
|
|
9
|
+
});
|
|
10
|
+
//# sourceMappingURL=noop.command.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"noop.command.js","sourceRoot":"","sources":["../../src/commands/noop.command.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAErD,MAAM,CAAC,MAAM,WAAW,GAAG,aAAa,CAAC;IACvC,IAAI,EAAE,aAAa;IACnB,WAAW,EAAE,uEAAuE;IACpF,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACf,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;KAC/B,CAAC;CACH,CAAC,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export declare const ServiceBootedEvent: import("../message-contracts.js").EventDefinition<z.ZodObject<{
|
|
3
|
+
service: z.ZodString;
|
|
4
|
+
version: z.ZodString;
|
|
5
|
+
bootedAt: z.ZodString;
|
|
6
|
+
}, z.core.$strip>>;
|
|
7
|
+
//# sourceMappingURL=service-booted.event.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service-booted.event.d.ts","sourceRoot":"","sources":["../../src/events/service-booted.event.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,eAAO,MAAM,kBAAkB;;;;kBAS7B,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { defineEvent } from "../message-contracts.js";
|
|
3
|
+
export const ServiceBootedEvent = defineEvent({
|
|
4
|
+
name: "system.service.booted",
|
|
5
|
+
description: "Emitted when a service finishes its boot sequence; consumed by ops dashboards and trace pipelines.",
|
|
6
|
+
schema: z.object({
|
|
7
|
+
service: z.string(),
|
|
8
|
+
version: z.string(),
|
|
9
|
+
bootedAt: z.string().datetime(),
|
|
10
|
+
}),
|
|
11
|
+
});
|
|
12
|
+
//# sourceMappingURL=service-booted.event.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service-booted.event.js","sourceRoot":"","sources":["../../src/events/service-booted.event.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAEnD,MAAM,CAAC,MAAM,kBAAkB,GAAG,WAAW,CAAC;IAC5C,IAAI,EAAE,uBAAuB;IAC7B,WAAW,EACT,oGAAoG;IACtG,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACf,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE;QACnB,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE;QACnB,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;KAChC,CAAC;CACH,CAAC,CAAC"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import type { z, ZodType } from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* Workspace alias for "any zod schema". Zod 4 dropped the `ZodTypeAny`
|
|
4
|
+
* export; this alias keeps the rest of the codebase reading naturally
|
|
5
|
+
* without a hundred `ZodType<any>` sprinkled inline.
|
|
6
|
+
*
|
|
7
|
+
* `ZodType<any>` preserves bivariance so concrete schemas (e.g.
|
|
8
|
+
* `ZodObject<{...}>`) assign to `ZodTypeAny` without complaint — the same
|
|
9
|
+
* behaviour zod 3 gave us out of the box.
|
|
10
|
+
*/
|
|
11
|
+
export type ZodTypeAny = ZodType<any>;
|
|
12
|
+
export interface CommandDefinition<TSchema extends ZodTypeAny = ZodTypeAny> {
|
|
13
|
+
readonly name: string;
|
|
14
|
+
readonly schema: TSchema;
|
|
15
|
+
readonly description?: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Event visibility — controls whether the event is part of the public,
|
|
19
|
+
* cross-bounded-context API of its module.
|
|
20
|
+
*
|
|
21
|
+
* - `'public'` (default) — exported as part of the module's public surface;
|
|
22
|
+
* other modules MAY listen to it via `when(SomeEvent, ...)`. The
|
|
23
|
+
* `@nwire/messages` workspace package re-exports public events for
|
|
24
|
+
* external consumers (frontends, BFFs, sync services).
|
|
25
|
+
* - `'internal'` — the event is module-internal. Other modules MUST NOT
|
|
26
|
+
* subscribe; the framework can warn or refuse cross-module listeners.
|
|
27
|
+
* Use for transient implementation-detail events.
|
|
28
|
+
*/
|
|
29
|
+
export type EventVisibility = "public" | "internal";
|
|
30
|
+
/**
|
|
31
|
+
* Domain outcome an event represents. Lets Studio score success rates and
|
|
32
|
+
* surface warnings/failures without parsing event names. Default `'success'`.
|
|
33
|
+
* - `'success'` — a positive thing happened (default)
|
|
34
|
+
* - `'failure'` — something failed in a domain-meaningful way (not a system error)
|
|
35
|
+
* - `'milestone'` — significant progress event (lesson completed, onboarding finished)
|
|
36
|
+
* - `'warning'` — anomaly that's not yet a failure (low confidence, manual review needed)
|
|
37
|
+
*/
|
|
38
|
+
export type EventOutcome = "success" | "failure" | "milestone" | "warning";
|
|
39
|
+
/**
|
|
40
|
+
* Event scope — the structural distinction between domain and integration.
|
|
41
|
+
*
|
|
42
|
+
* - `'domain'` — internal to a bounded context. Folded by actors, projections,
|
|
43
|
+
* reactions inside the BC. Never bus-eligible. Refactor freely.
|
|
44
|
+
* - `'integration'` — public contract on the bus. Versioned, audience-tagged,
|
|
45
|
+
* slim. Other BCs and services subscribe to these, not to domain events.
|
|
46
|
+
*
|
|
47
|
+
* `scope` is structural and complements `visibility`:
|
|
48
|
+
* - `scope: "domain"` → implies `visibility: "internal"` unless overridden
|
|
49
|
+
* - `scope: "integration"` → implies `visibility: "public"`
|
|
50
|
+
*
|
|
51
|
+
* If `scope` is omitted, the framework infers it from `visibility`.
|
|
52
|
+
*/
|
|
53
|
+
export type EventScope = "domain" | "integration";
|
|
54
|
+
export interface EventDefinitionMeta<TSchema extends ZodTypeAny = ZodTypeAny> {
|
|
55
|
+
readonly name: string;
|
|
56
|
+
readonly schema: TSchema;
|
|
57
|
+
readonly description?: string;
|
|
58
|
+
/** Defaults to `'public'`. */
|
|
59
|
+
readonly visibility?: EventVisibility;
|
|
60
|
+
/** Domain outcome semantics. Defaults to `'success'`. */
|
|
61
|
+
readonly outcome?: EventOutcome;
|
|
62
|
+
/**
|
|
63
|
+
* Relative business weight (e.g. `100` for money-flow events, `1` for
|
|
64
|
+
* telemetry chatter). Studio uses this to weight dashboards so a single
|
|
65
|
+
* payment-failed event doesn't get drowned out by a thousand pings.
|
|
66
|
+
*/
|
|
67
|
+
readonly businessWeight?: number;
|
|
68
|
+
/**
|
|
69
|
+
* Free-form audience tags — who cares about this event outside engineering?
|
|
70
|
+
* `['product']`, `['ops', 'support']`, `['finance']`.
|
|
71
|
+
*/
|
|
72
|
+
readonly audience?: readonly string[];
|
|
73
|
+
/**
|
|
74
|
+
* Domain vs integration scope. Domain events are BC-internal; integration
|
|
75
|
+
* events are versioned public contracts on the bus. If omitted, inferred
|
|
76
|
+
* from `visibility` (public → integration, internal → domain).
|
|
77
|
+
*/
|
|
78
|
+
readonly scope?: EventScope;
|
|
79
|
+
/**
|
|
80
|
+
* Integer version of an integration event's schema (`v1`, `v2`, ...).
|
|
81
|
+
* Required for `scope: "integration"`. Ignored for domain events.
|
|
82
|
+
*/
|
|
83
|
+
readonly version?: number;
|
|
84
|
+
}
|
|
85
|
+
/** Shape returned when an event definition is called as a factory. */
|
|
86
|
+
export interface EventMessageOf<TSchema extends ZodTypeAny> {
|
|
87
|
+
readonly eventName: string;
|
|
88
|
+
readonly payload: z.output<TSchema>;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* `defineEvent` returns a callable factory that *is* the event definition.
|
|
92
|
+
* Call it to mint a typed `EventMessage` (validates against the zod schema),
|
|
93
|
+
* or read its meta fields (`name`, `schema`, `outcome`, …) directly.
|
|
94
|
+
*
|
|
95
|
+
* const AnswerWasSubmitted = defineEvent({ name: "...", schema: ... })
|
|
96
|
+
* AnswerWasSubmitted.name // "submissions.answer-was-submitted"
|
|
97
|
+
* AnswerWasSubmitted({ ... }) // { eventName, payload }
|
|
98
|
+
*
|
|
99
|
+
* Domain→integration translation lives in `defineWorkflow`. Subscribe with
|
|
100
|
+
* `on(SourceEvent, async (e) => { await publish(TargetEvent({ ... })); })`.
|
|
101
|
+
*/
|
|
102
|
+
export type EventDefinition<TSchema extends ZodTypeAny = ZodTypeAny> = EventDefinitionMeta<TSchema> & ((payload: z.output<TSchema>) => EventMessageOf<TSchema>) & {
|
|
103
|
+
/** Module-manifest visibility marker. See `defineWorkflow.public()` notes. */
|
|
104
|
+
readonly $public?: true;
|
|
105
|
+
/** Return a callable event clone with `$public: true`. */
|
|
106
|
+
public: () => EventDefinition<TSchema>;
|
|
107
|
+
};
|
|
108
|
+
export declare function defineCommand<TSchema extends ZodTypeAny>(def: CommandDefinition<TSchema>): CommandDefinition<TSchema>;
|
|
109
|
+
export declare function defineEvent<TSchema extends ZodTypeAny>(def: EventDefinitionMeta<TSchema>): EventDefinition<TSchema>;
|
|
110
|
+
export type CommandPayload<C> = C extends CommandDefinition<infer S> ? z.output<S> : never;
|
|
111
|
+
export type EventPayload<E> = E extends EventDefinition<infer S> ? z.output<S> : never;
|
|
112
|
+
//# sourceMappingURL=message-contracts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"message-contracts.d.ts","sourceRoot":"","sources":["../src/message-contracts.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,MAAM,KAAK,CAAC;AAEtC;;;;;;;;GAQG;AAEH,MAAM,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;AAEtC,MAAM,WAAW,iBAAiB,CAAC,OAAO,SAAS,UAAU,GAAG,UAAU;IACxE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,eAAe,GAAG,QAAQ,GAAG,UAAU,CAAC;AAEpD;;;;;;;GAOG;AACH,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,SAAS,GAAG,WAAW,GAAG,SAAS,CAAC;AAE3E;;;;;;;;;;;;;GAaG;AACH,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,aAAa,CAAC;AAElD,MAAM,WAAW,mBAAmB,CAAC,OAAO,SAAS,UAAU,GAAG,UAAU;IAC1E,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,8BAA8B;IAC9B,QAAQ,CAAC,UAAU,CAAC,EAAE,eAAe,CAAC;IACtC,yDAAyD;IACzD,QAAQ,CAAC,OAAO,CAAC,EAAE,YAAY,CAAC;IAChC;;;;OAIG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC;;;OAGG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACtC;;;;OAIG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,UAAU,CAAC;IAC5B;;;OAGG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,sEAAsE;AACtE,MAAM,WAAW,cAAc,CAAC,OAAO,SAAS,UAAU;IACxD,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;CACrC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,eAAe,CAAC,OAAO,SAAS,UAAU,GAAG,UAAU,IACjE,mBAAmB,CAAC,OAAO,CAAC,GAC1B,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,cAAc,CAAC,OAAO,CAAC,CAAC,GAAG;IAC1D,8EAA8E;IAC9E,QAAQ,CAAC,OAAO,CAAC,EAAE,IAAI,CAAC;IACxB,0DAA0D;IAC1D,MAAM,EAAE,MAAM,eAAe,CAAC,OAAO,CAAC,CAAC;CACxC,CAAC;AAEN,wBAAgB,aAAa,CAAC,OAAO,SAAS,UAAU,EACtD,GAAG,EAAE,iBAAiB,CAAC,OAAO,CAAC,GAC9B,iBAAiB,CAAC,OAAO,CAAC,CAE5B;AAED,wBAAgB,WAAW,CAAC,OAAO,SAAS,UAAU,EACpD,GAAG,EAAE,mBAAmB,CAAC,OAAO,CAAC,GAChC,eAAe,CAAC,OAAO,CAAC,CAgD1B;AAED,MAAM,MAAM,cAAc,CAAC,CAAC,IAAI,CAAC,SAAS,iBAAiB,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC;AAC3F,MAAM,MAAM,YAAY,CAAC,CAAC,IAAI,CAAC,SAAS,eAAe,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
export function defineCommand(def) {
|
|
2
|
+
return def;
|
|
3
|
+
}
|
|
4
|
+
export function defineEvent(def) {
|
|
5
|
+
// Infer scope from visibility when not explicit.
|
|
6
|
+
const scope = def.scope ??
|
|
7
|
+
(def.visibility === "internal"
|
|
8
|
+
? "domain"
|
|
9
|
+
: def.visibility === "public"
|
|
10
|
+
? "integration"
|
|
11
|
+
: undefined);
|
|
12
|
+
// Integration events must carry a version.
|
|
13
|
+
if (scope === "integration" && def.version === undefined) {
|
|
14
|
+
throw new Error(`defineEvent("${def.name}"): integration events must specify \`version: <number>\`.`);
|
|
15
|
+
}
|
|
16
|
+
const factory = (payload) => ({
|
|
17
|
+
eventName: def.name,
|
|
18
|
+
payload: def.schema.parse(payload),
|
|
19
|
+
});
|
|
20
|
+
// `.public()` — the module-manifest visibility marker. Calling it
|
|
21
|
+
// returns a callable event factory clone with `$public: true`, leaving
|
|
22
|
+
// the original definition unmarked so it stays visibility-agnostic.
|
|
23
|
+
const publicMethod = function publicMarker() {
|
|
24
|
+
const cloned = defineEvent(def);
|
|
25
|
+
Object.defineProperty(cloned, "$public", {
|
|
26
|
+
value: true,
|
|
27
|
+
enumerable: false,
|
|
28
|
+
configurable: true,
|
|
29
|
+
});
|
|
30
|
+
return cloned;
|
|
31
|
+
};
|
|
32
|
+
Object.defineProperties(factory, {
|
|
33
|
+
name: { value: def.name, enumerable: true, configurable: true },
|
|
34
|
+
schema: { value: def.schema, enumerable: true },
|
|
35
|
+
description: { value: def.description, enumerable: true },
|
|
36
|
+
visibility: { value: def.visibility, enumerable: true },
|
|
37
|
+
outcome: { value: def.outcome, enumerable: true },
|
|
38
|
+
businessWeight: { value: def.businessWeight, enumerable: true },
|
|
39
|
+
audience: { value: def.audience, enumerable: true },
|
|
40
|
+
scope: { value: scope, enumerable: true },
|
|
41
|
+
version: { value: def.version, enumerable: true },
|
|
42
|
+
toString: { value: () => def.name, enumerable: false },
|
|
43
|
+
public: { value: publicMethod, enumerable: false, configurable: true },
|
|
44
|
+
});
|
|
45
|
+
return factory;
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=message-contracts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"message-contracts.js","sourceRoot":"","sources":["../src/message-contracts.ts"],"names":[],"mappings":"AAuHA,MAAM,UAAU,aAAa,CAC3B,GAA+B;IAE/B,OAAO,GAAG,CAAC;AACb,CAAC;AAED,MAAM,UAAU,WAAW,CACzB,GAAiC;IAEjC,iDAAiD;IACjD,MAAM,KAAK,GACT,GAAG,CAAC,KAAK;QACT,CAAC,GAAG,CAAC,UAAU,KAAK,UAAU;YAC5B,CAAC,CAAC,QAAQ;YACV,CAAC,CAAC,GAAG,CAAC,UAAU,KAAK,QAAQ;gBAC3B,CAAC,CAAC,aAAa;gBACf,CAAC,CAAC,SAAS,CAAC,CAAC;IACnB,2CAA2C;IAC3C,IAAI,KAAK,KAAK,aAAa,IAAI,GAAG,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;QACzD,MAAM,IAAI,KAAK,CACb,gBAAgB,GAAG,CAAC,IAAI,4DAA4D,CACrF,CAAC;IACJ,CAAC;IAED,MAAM,OAAO,GAAG,CAAC,OAA0B,EAA2B,EAAE,CAAC,CAAC;QACxE,SAAS,EAAE,GAAG,CAAC,IAAI;QACnB,OAAO,EAAE,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAsB;KACxD,CAAC,CAAC;IAEH,kEAAkE;IAClE,uEAAuE;IACvE,oEAAoE;IACpE,MAAM,YAAY,GAAG,SAAS,YAAY;QACxC,MAAM,MAAM,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC;QAChC,MAAM,CAAC,cAAc,CAAC,MAAM,EAAE,SAAS,EAAE;YACvC,KAAK,EAAE,IAAI;YACX,UAAU,EAAE,KAAK;YACjB,YAAY,EAAE,IAAI;SACnB,CAAC,CAAC;QACH,OAAO,MAAM,CAAC;IAChB,CAAC,CAAC;IAEF,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE;QAC/B,IAAI,EAAE,EAAE,KAAK,EAAE,GAAG,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE;QAC/D,MAAM,EAAE,EAAE,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE;QAC/C,WAAW,EAAE,EAAE,KAAK,EAAE,GAAG,CAAC,WAAW,EAAE,UAAU,EAAE,IAAI,EAAE;QACzD,UAAU,EAAE,EAAE,KAAK,EAAE,GAAG,CAAC,UAAU,EAAE,UAAU,EAAE,IAAI,EAAE;QACvD,OAAO,EAAE,EAAE,KAAK,EAAE,GAAG,CAAC,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE;QACjD,cAAc,EAAE,EAAE,KAAK,EAAE,GAAG,CAAC,cAAc,EAAE,UAAU,EAAE,IAAI,EAAE;QAC/D,QAAQ,EAAE,EAAE,KAAK,EAAE,GAAG,CAAC,QAAQ,EAAE,UAAU,EAAE,IAAI,EAAE;QACnD,KAAK,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE;QACzC,OAAO,EAAE,EAAE,KAAK,EAAE,GAAG,CAAC,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE;QACjD,QAAQ,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE;QACtD,MAAM,EAAE,EAAE,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE;KACvE,CAAC,CAAC;IACH,OAAO,OAAmC,CAAC;AAC7C,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@nwire/messages` — command + event contract primitives.
|
|
3
|
+
*
|
|
4
|
+
* `defineCommand` for intent (one handler, one response), `defineEvent` for
|
|
5
|
+
* facts (many subscribers, fan-out). Visibility/scope/outcome enums + zod-
|
|
6
|
+
* binding types every Nwire transport, bus, and store agrees on.
|
|
7
|
+
*
|
|
8
|
+
* See: architecture-sketch.html §05 (Primitives tier).
|
|
9
|
+
*/
|
|
10
|
+
export { defineCommand, defineEvent, type CommandDefinition, type EventDefinition, type EventDefinitionMeta, type EventMessageOf, type CommandPayload, type EventPayload, type EventVisibility, type EventOutcome, type EventScope, type ZodTypeAny, } from "./message-contracts.js";
|
|
11
|
+
export { NoopCommand } from "./commands/noop.command.js";
|
|
12
|
+
export { ServiceBootedEvent } from "./events/service-booted.event.js";
|
|
13
|
+
//# sourceMappingURL=messages.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../src/messages.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EACL,aAAa,EACb,WAAW,EACX,KAAK,iBAAiB,EACtB,KAAK,eAAe,EACpB,KAAK,mBAAmB,EACxB,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,KAAK,YAAY,EACjB,KAAK,eAAe,EACpB,KAAK,YAAY,EACjB,KAAK,UAAU,EACf,KAAK,UAAU,GAChB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC"}
|
package/dist/messages.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@nwire/messages` — command + event contract primitives.
|
|
3
|
+
*
|
|
4
|
+
* `defineCommand` for intent (one handler, one response), `defineEvent` for
|
|
5
|
+
* facts (many subscribers, fan-out). Visibility/scope/outcome enums + zod-
|
|
6
|
+
* binding types every Nwire transport, bus, and store agrees on.
|
|
7
|
+
*
|
|
8
|
+
* See: architecture-sketch.html §05 (Primitives tier).
|
|
9
|
+
*/
|
|
10
|
+
export { defineCommand, defineEvent, } from "./message-contracts.js";
|
|
11
|
+
export { NoopCommand } from "./commands/noop.command.js";
|
|
12
|
+
export { ServiceBootedEvent } from "./events/service-booted.event.js";
|
|
13
|
+
//# sourceMappingURL=messages.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"messages.js","sourceRoot":"","sources":["../src/messages.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EACL,aAAa,EACb,WAAW,GAWZ,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@nwire/messages",
|
|
3
|
+
"version": "0.7.0",
|
|
4
|
+
"description": "Nwire — typed command and event contracts. defineCommand, defineEvent with public/internal visibility. Zod-validated; shareable across the backend, frontends, BFFs.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"commands",
|
|
7
|
+
"contracts",
|
|
8
|
+
"events",
|
|
9
|
+
"messages",
|
|
10
|
+
"nwire"
|
|
11
|
+
],
|
|
12
|
+
"files": [
|
|
13
|
+
"dist",
|
|
14
|
+
"README.md"
|
|
15
|
+
],
|
|
16
|
+
"type": "module",
|
|
17
|
+
"main": "./dist/messages.js",
|
|
18
|
+
"types": "./dist/messages.d.ts",
|
|
19
|
+
"exports": {
|
|
20
|
+
".": {
|
|
21
|
+
"import": "./dist/messages.js",
|
|
22
|
+
"types": "./dist/messages.d.ts"
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"publishConfig": {
|
|
26
|
+
"access": "public"
|
|
27
|
+
},
|
|
28
|
+
"dependencies": {
|
|
29
|
+
"zod": "^4.0.0"
|
|
30
|
+
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"@types/node": "^22.19.9",
|
|
33
|
+
"typescript": "^5.9.3"
|
|
34
|
+
},
|
|
35
|
+
"scripts": {
|
|
36
|
+
"build": "tsc && node ../../scripts/fix-dist-extensions.mjs dist",
|
|
37
|
+
"dev": "tsc --watch",
|
|
38
|
+
"typecheck": "tsc --noEmit"
|
|
39
|
+
}
|
|
40
|
+
}
|