@nwire/messages 0.7.1 → 0.8.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/dist/message-contracts.d.ts +3 -0
- package/dist/message-contracts.d.ts.map +1 -1
- package/dist/message-contracts.js +3 -0
- package/dist/message-contracts.js.map +1 -1
- package/dist/messages.d.ts +2 -0
- package/dist/messages.d.ts.map +1 -1
- package/dist/messages.js +2 -0
- package/dist/messages.js.map +1 -1
- package/dist/source-location.d.ts +25 -0
- package/dist/source-location.d.ts.map +1 -0
- package/dist/source-location.js +52 -0
- package/dist/source-location.js.map +1 -0
- package/dist/validated.d.ts +44 -0
- package/dist/validated.d.ts.map +1 -0
- package/dist/validated.js +56 -0
- package/dist/validated.js.map +1 -0
- package/package.json +1 -1
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { z, ZodType } from "zod";
|
|
2
|
+
import { type SourceLocation } from "./source-location.js";
|
|
2
3
|
/**
|
|
3
4
|
* Workspace alias for "any zod schema". Zod 4 dropped the `ZodTypeAny`
|
|
4
5
|
* export; this alias keeps the rest of the codebase reading naturally
|
|
@@ -102,6 +103,8 @@ export interface EventMessageOf<TSchema extends ZodTypeAny> {
|
|
|
102
103
|
export type EventDefinition<TSchema extends ZodTypeAny = ZodTypeAny> = EventDefinitionMeta<TSchema> & ((payload: z.output<TSchema>) => EventMessageOf<TSchema>) & {
|
|
103
104
|
/** Module-manifest visibility marker. See `defineWorkflow.public()` notes. */
|
|
104
105
|
readonly $public?: true;
|
|
106
|
+
/** Where the event was declared. Studio uses this for IDE-open links. */
|
|
107
|
+
readonly $source?: SourceLocation;
|
|
105
108
|
/** Return a callable event clone with `$public: true`. */
|
|
106
109
|
public: () => EventDefinition<TSchema>;
|
|
107
110
|
};
|
|
@@ -1 +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;
|
|
1
|
+
{"version":3,"file":"message-contracts.d.ts","sourceRoot":"","sources":["../src/message-contracts.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
import { captureSourceLocation } from "./source-location.js";
|
|
1
2
|
export function defineCommand(def) {
|
|
2
3
|
return def;
|
|
3
4
|
}
|
|
4
5
|
export function defineEvent(def) {
|
|
6
|
+
const $source = captureSourceLocation();
|
|
5
7
|
// Infer scope from visibility when not explicit.
|
|
6
8
|
const scope = def.scope ??
|
|
7
9
|
(def.visibility === "internal"
|
|
@@ -41,6 +43,7 @@ export function defineEvent(def) {
|
|
|
41
43
|
version: { value: def.version, enumerable: true },
|
|
42
44
|
toString: { value: () => def.name, enumerable: false },
|
|
43
45
|
public: { value: publicMethod, enumerable: false, configurable: true },
|
|
46
|
+
$source: { value: $source, enumerable: false, configurable: true },
|
|
44
47
|
});
|
|
45
48
|
return factory;
|
|
46
49
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"message-contracts.js","sourceRoot":"","sources":["../src/message-contracts.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"message-contracts.js","sourceRoot":"","sources":["../src/message-contracts.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,qBAAqB,EAAuB,MAAM,mBAAmB,CAAC;AAyH/E,MAAM,UAAU,aAAa,CAC3B,GAA+B;IAE/B,OAAO,GAAG,CAAC;AACb,CAAC;AAED,MAAM,UAAU,WAAW,CACzB,GAAiC;IAEjC,MAAM,OAAO,GAAG,qBAAqB,EAAE,CAAC;IACxC,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;QACtE,OAAO,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE;KACnE,CAAC,CAAC;IACH,OAAO,OAAmC,CAAC;AAC7C,CAAC"}
|
package/dist/messages.d.ts
CHANGED
|
@@ -10,4 +10,6 @@
|
|
|
10
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
11
|
export { NoopCommand } from "./commands/noop.command.js";
|
|
12
12
|
export { ServiceBootedEvent } from "./events/service-booted.event.js";
|
|
13
|
+
export { captureSourceLocation, type SourceLocation } from "./source-location.js";
|
|
14
|
+
export { VALIDATED, markValidated, isValidated, type Validated } from "./validated.js";
|
|
13
15
|
//# sourceMappingURL=messages.d.ts.map
|
package/dist/messages.d.ts.map
CHANGED
|
@@ -1 +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"}
|
|
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;AAEnE,OAAO,EAAE,qBAAqB,EAAE,KAAK,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAE/E,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,WAAW,EAAE,KAAK,SAAS,EAAE,MAAM,aAAa,CAAC"}
|
package/dist/messages.js
CHANGED
|
@@ -10,4 +10,6 @@
|
|
|
10
10
|
export { defineCommand, defineEvent, } from "./message-contracts.js";
|
|
11
11
|
export { NoopCommand } from "./commands/noop.command.js";
|
|
12
12
|
export { ServiceBootedEvent } from "./events/service-booted.event.js";
|
|
13
|
+
export { captureSourceLocation } from "./source-location.js";
|
|
14
|
+
export { VALIDATED, markValidated, isValidated } from "./validated.js";
|
|
13
15
|
//# sourceMappingURL=messages.js.map
|
package/dist/messages.js.map
CHANGED
|
@@ -1 +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"}
|
|
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;AAEnE,OAAO,EAAE,qBAAqB,EAAuB,MAAM,mBAAmB,CAAC;AAE/E,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,WAAW,EAAkB,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Capture the source location of a `defineX` call so Studio can show
|
|
3
|
+
* "open in IDE" links next to every primitive.
|
|
4
|
+
*
|
|
5
|
+
* Walks the V8 stack at call time, skips frames inside `@nwire/*` and
|
|
6
|
+
* `packages/nwire-*` (the framework's own files), and returns the first
|
|
7
|
+
* user-code frame as `{ file, line, column }`.
|
|
8
|
+
*
|
|
9
|
+
* Cost: one synthetic `Error` per `defineX` call, paid once at module
|
|
10
|
+
* load. Negligible.
|
|
11
|
+
*/
|
|
12
|
+
export interface SourceLocation {
|
|
13
|
+
/** Absolute filesystem path, as V8 emits it. */
|
|
14
|
+
readonly file: string;
|
|
15
|
+
readonly line: number;
|
|
16
|
+
readonly column?: number;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Returns the caller's source location, skipping `skipFrames` immediate
|
|
20
|
+
* frames (default 1 — the caller itself) and any frame inside an `@nwire/*`
|
|
21
|
+
* package. Returns `undefined` if no user frame can be parsed (rare; happens
|
|
22
|
+
* inside REPLs and minified bundles).
|
|
23
|
+
*/
|
|
24
|
+
export declare function captureSourceLocation(skipFrames?: number): SourceLocation | undefined;
|
|
25
|
+
//# sourceMappingURL=source-location.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"source-location.d.ts","sourceRoot":"","sources":["../src/source-location.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,MAAM,WAAW,cAAc;IAC7B,gDAAgD;IAChD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AAWD;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,UAAU,SAAI,GAAG,cAAc,GAAG,SAAS,CAuBhF"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Capture the source location of a `defineX` call so Studio can show
|
|
3
|
+
* "open in IDE" links next to every primitive.
|
|
4
|
+
*
|
|
5
|
+
* Walks the V8 stack at call time, skips frames inside `@nwire/*` and
|
|
6
|
+
* `packages/nwire-*` (the framework's own files), and returns the first
|
|
7
|
+
* user-code frame as `{ file, line, column }`.
|
|
8
|
+
*
|
|
9
|
+
* Cost: one synthetic `Error` per `defineX` call, paid once at module
|
|
10
|
+
* load. Negligible.
|
|
11
|
+
*/
|
|
12
|
+
// `[\\/]` matches either POSIX (`/`) or Windows (`\`) path separators —
|
|
13
|
+
// V8 stack frames emit native separators per-platform, so the regex must
|
|
14
|
+
// accept both. Without this, every Win stack frame slipped past the filter
|
|
15
|
+
// and Studio's "open in IDE" link pointed at framework source.
|
|
16
|
+
const NWIRE_FRAME_RE = /(node_modules[\\/](@nwire[\\/]|\.pnpm[\\/]@nwire\+)|packages[\\/]nwire-)/;
|
|
17
|
+
const PAREN_RE = /\(([^()]+):(\d+):(\d+)\)\s*$/; // at someFn (/path:42:17)
|
|
18
|
+
const PLAIN_RE = /\s+at\s+([^()\s]+):(\d+):(\d+)\s*$/; // at /path:42:17 (anon)
|
|
19
|
+
/**
|
|
20
|
+
* Returns the caller's source location, skipping `skipFrames` immediate
|
|
21
|
+
* frames (default 1 — the caller itself) and any frame inside an `@nwire/*`
|
|
22
|
+
* package. Returns `undefined` if no user frame can be parsed (rare; happens
|
|
23
|
+
* inside REPLs and minified bundles).
|
|
24
|
+
*/
|
|
25
|
+
export function captureSourceLocation(skipFrames = 1) {
|
|
26
|
+
const origLimit = Error.stackTraceLimit;
|
|
27
|
+
Error.stackTraceLimit = 30;
|
|
28
|
+
const err = new Error();
|
|
29
|
+
Error.stackTraceLimit = origLimit;
|
|
30
|
+
if (!err.stack)
|
|
31
|
+
return undefined;
|
|
32
|
+
// Drop the first line ("Error") + however many frames the caller asked to skip.
|
|
33
|
+
const lines = err.stack.split("\n").slice(1 + skipFrames);
|
|
34
|
+
for (const raw of lines) {
|
|
35
|
+
if (NWIRE_FRAME_RE.test(raw))
|
|
36
|
+
continue;
|
|
37
|
+
const m = raw.match(PAREN_RE) ?? raw.match(PLAIN_RE);
|
|
38
|
+
if (!m)
|
|
39
|
+
continue;
|
|
40
|
+
const file = m[1];
|
|
41
|
+
// Internal frames sometimes show up as `node:internal/...` — skip.
|
|
42
|
+
if (file.startsWith("node:"))
|
|
43
|
+
continue;
|
|
44
|
+
return {
|
|
45
|
+
file,
|
|
46
|
+
line: Number(m[2]),
|
|
47
|
+
column: Number(m[3]),
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
return undefined;
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=source-location.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"source-location.js","sourceRoot":"","sources":["../src/source-location.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AASH,wEAAwE;AACxE,yEAAyE;AACzE,2EAA2E;AAC3E,+DAA+D;AAC/D,MAAM,cAAc,GAAG,0EAA0E,CAAC;AAElG,MAAM,QAAQ,GAAI,8BAA8B,CAAC,CAAG,0BAA0B;AAC9E,MAAM,QAAQ,GAAI,oCAAoC,CAAC,CAAC,wBAAwB;AAEhF;;;;;GAKG;AACH,MAAM,UAAU,qBAAqB,CAAC,UAAU,GAAG,CAAC;IAClD,MAAM,SAAS,GAAG,KAAK,CAAC,eAAe,CAAC;IACxC,KAAK,CAAC,eAAe,GAAG,EAAE,CAAC;IAC3B,MAAM,GAAG,GAAG,IAAI,KAAK,EAAE,CAAC;IACxB,KAAK,CAAC,eAAe,GAAG,SAAS,CAAC;IAClC,IAAI,CAAC,GAAG,CAAC,KAAK;QAAE,OAAO,SAAS,CAAC;IAEjC,gFAAgF;IAChF,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,UAAU,CAAC,CAAC;IAC1D,KAAK,MAAM,GAAG,IAAI,KAAK,EAAE,CAAC;QACxB,IAAI,cAAc,CAAC,IAAI,CAAC,GAAG,CAAC;YAAE,SAAS;QACvC,MAAM,CAAC,GAAG,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QACrD,IAAI,CAAC,CAAC;YAAE,SAAS;QACjB,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,CAAE,CAAC;QACnB,mEAAmE;QACnE,IAAI,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC;YAAE,SAAS;QACvC,OAAO;YACL,IAAI;YACJ,IAAI,EAAI,MAAM,CAAC,CAAC,CAAC,CAAC,CAAE,CAAC;YACrB,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAE,CAAC;SACtB,CAAC;IACJ,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `Validated<T>` — a brand marker for data already validated against its
|
|
3
|
+
* action / query / event schema.
|
|
4
|
+
*
|
|
5
|
+
* The framework parses input at trust boundaries (HTTP `parseAndValidate`,
|
|
6
|
+
* queue worker consume, bus inbound). The same data then flows into
|
|
7
|
+
* `runtime.dispatch`, which historically re-parses it against
|
|
8
|
+
* `action.schema`. That second parse is dead work — the data already
|
|
9
|
+
* matches `z.output<TSchema>`.
|
|
10
|
+
*
|
|
11
|
+
* This brand lets a boundary stamp its output as "trust me, I already
|
|
12
|
+
* parsed this" so the runtime can skip the redundant parse. Untrusted
|
|
13
|
+
* call sites (a user calling `runtime.dispatch(action, rawJson)` from
|
|
14
|
+
* application code) still hit the parse path because their input is
|
|
15
|
+
* unbranded.
|
|
16
|
+
*
|
|
17
|
+
* Design choices:
|
|
18
|
+
* - Symbol key, not a string field: cannot be accidentally serialized
|
|
19
|
+
* over the wire. A branded object that's JSON.stringified loses the
|
|
20
|
+
* brand — exactly what we want for cross-process boundaries.
|
|
21
|
+
* - Non-enumerable property: `Object.assign`, spread, and JSON
|
|
22
|
+
* serialization all drop the marker, so a re-shaped object loses
|
|
23
|
+
* its validation claim and the runtime safely re-parses.
|
|
24
|
+
* - Type brand is a phantom field on `T & { [VALIDATED]?: true }`,
|
|
25
|
+
* not a wrapper — boundary code passes the same object through, just
|
|
26
|
+
* tagged. Zero allocation for the type, one defineProperty for the tag.
|
|
27
|
+
*/
|
|
28
|
+
export declare const VALIDATED: unique symbol;
|
|
29
|
+
export type Validated<T> = T & {
|
|
30
|
+
readonly [VALIDATED]?: true;
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* Tag `value` as already validated. The brand survives identity but not
|
|
34
|
+
* structural copies — by design, so `{...validated}` or `JSON.parse` drops
|
|
35
|
+
* the claim and forces re-parse at the next boundary.
|
|
36
|
+
*
|
|
37
|
+
* Returns the same object reference (for primitives, returns the
|
|
38
|
+
* primitive unchanged — primitives can't carry brands, and the runtime
|
|
39
|
+
* detection falls back to the parse path).
|
|
40
|
+
*/
|
|
41
|
+
export declare function markValidated<T>(value: T): Validated<T>;
|
|
42
|
+
/** True if `value` carries the validated brand. */
|
|
43
|
+
export declare function isValidated(value: unknown): boolean;
|
|
44
|
+
//# sourceMappingURL=validated.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validated.d.ts","sourceRoot":"","sources":["../src/validated.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,eAAO,MAAM,SAAS,EAAE,OAAO,MAAgD,CAAC;AAEhF,MAAM,MAAM,SAAS,CAAC,CAAC,IAAI,CAAC,GAAG;IAAE,QAAQ,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,IAAI,CAAA;CAAE,CAAC;AAE/D;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC,CAWvD;AAED,mDAAmD;AACnD,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAMnD"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `Validated<T>` — a brand marker for data already validated against its
|
|
3
|
+
* action / query / event schema.
|
|
4
|
+
*
|
|
5
|
+
* The framework parses input at trust boundaries (HTTP `parseAndValidate`,
|
|
6
|
+
* queue worker consume, bus inbound). The same data then flows into
|
|
7
|
+
* `runtime.dispatch`, which historically re-parses it against
|
|
8
|
+
* `action.schema`. That second parse is dead work — the data already
|
|
9
|
+
* matches `z.output<TSchema>`.
|
|
10
|
+
*
|
|
11
|
+
* This brand lets a boundary stamp its output as "trust me, I already
|
|
12
|
+
* parsed this" so the runtime can skip the redundant parse. Untrusted
|
|
13
|
+
* call sites (a user calling `runtime.dispatch(action, rawJson)` from
|
|
14
|
+
* application code) still hit the parse path because their input is
|
|
15
|
+
* unbranded.
|
|
16
|
+
*
|
|
17
|
+
* Design choices:
|
|
18
|
+
* - Symbol key, not a string field: cannot be accidentally serialized
|
|
19
|
+
* over the wire. A branded object that's JSON.stringified loses the
|
|
20
|
+
* brand — exactly what we want for cross-process boundaries.
|
|
21
|
+
* - Non-enumerable property: `Object.assign`, spread, and JSON
|
|
22
|
+
* serialization all drop the marker, so a re-shaped object loses
|
|
23
|
+
* its validation claim and the runtime safely re-parses.
|
|
24
|
+
* - Type brand is a phantom field on `T & { [VALIDATED]?: true }`,
|
|
25
|
+
* not a wrapper — boundary code passes the same object through, just
|
|
26
|
+
* tagged. Zero allocation for the type, one defineProperty for the tag.
|
|
27
|
+
*/
|
|
28
|
+
export const VALIDATED = Symbol.for("@nwire/messages/validated");
|
|
29
|
+
/**
|
|
30
|
+
* Tag `value` as already validated. The brand survives identity but not
|
|
31
|
+
* structural copies — by design, so `{...validated}` or `JSON.parse` drops
|
|
32
|
+
* the claim and forces re-parse at the next boundary.
|
|
33
|
+
*
|
|
34
|
+
* Returns the same object reference (for primitives, returns the
|
|
35
|
+
* primitive unchanged — primitives can't carry brands, and the runtime
|
|
36
|
+
* detection falls back to the parse path).
|
|
37
|
+
*/
|
|
38
|
+
export function markValidated(value) {
|
|
39
|
+
if (value === null || (typeof value !== "object" && typeof value !== "function")) {
|
|
40
|
+
return value;
|
|
41
|
+
}
|
|
42
|
+
Object.defineProperty(value, VALIDATED, {
|
|
43
|
+
value: true,
|
|
44
|
+
enumerable: false,
|
|
45
|
+
configurable: true,
|
|
46
|
+
writable: false,
|
|
47
|
+
});
|
|
48
|
+
return value;
|
|
49
|
+
}
|
|
50
|
+
/** True if `value` carries the validated brand. */
|
|
51
|
+
export function isValidated(value) {
|
|
52
|
+
return (value !== null &&
|
|
53
|
+
(typeof value === "object" || typeof value === "function") &&
|
|
54
|
+
value[VALIDATED] === true);
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=validated.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validated.js","sourceRoot":"","sources":["../src/validated.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,MAAM,CAAC,MAAM,SAAS,GAAkB,MAAM,CAAC,GAAG,CAAC,2BAA2B,CAAC,CAAC;AAIhF;;;;;;;;GAQG;AACH,MAAM,UAAU,aAAa,CAAI,KAAQ;IACvC,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,OAAO,KAAK,KAAK,QAAQ,IAAI,OAAO,KAAK,KAAK,UAAU,CAAC,EAAE,CAAC;QACjF,OAAO,KAAqB,CAAC;IAC/B,CAAC;IACD,MAAM,CAAC,cAAc,CAAC,KAAK,EAAE,SAAS,EAAE;QACtC,KAAK,EAAE,IAAI;QACX,UAAU,EAAE,KAAK;QACjB,YAAY,EAAE,IAAI;QAClB,QAAQ,EAAE,KAAK;KAChB,CAAC,CAAC;IACH,OAAO,KAAqB,CAAC;AAC/B,CAAC;AAED,mDAAmD;AACnD,MAAM,UAAU,WAAW,CAAC,KAAc;IACxC,OAAO,CACL,KAAK,KAAK,IAAI;QACd,CAAC,OAAO,KAAK,KAAK,QAAQ,IAAI,OAAO,KAAK,KAAK,UAAU,CAAC;QACzD,KAAiC,CAAC,SAAS,CAAC,KAAK,IAAI,CACvD,CAAC;AACJ,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nwire/messages",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"description": "Nwire — typed command and event contracts. defineCommand, defineEvent with public/internal visibility. Zod-validated; shareable across the backend, frontends, BFFs.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"commands",
|