@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 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,5 @@
1
+ /**
2
+ * defineEvent — returns a callable factory that IS the event definition.
3
+ */
4
+ export {};
5
+ //# sourceMappingURL=define-event.test.d.ts.map
@@ -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,5 @@
1
+ import { z } from "zod";
2
+ export declare const NoopCommand: import("../message-contracts.js").CommandDefinition<z.ZodObject<{
3
+ traceId: z.ZodOptional<z.ZodString>;
4
+ }, z.core.$strip>>;
5
+ //# sourceMappingURL=noop.command.d.ts.map
@@ -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"}
@@ -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
+ }