@nwire/handler 0.8.0 → 0.9.1

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.
@@ -3,166 +3,205 @@
3
3
  *
4
4
  * const GetStation = defineHandler("GetStation", {
5
5
  * input: z.object({ stationId: z.string() }),
6
+ * handler: async ({ input }) => loadStation(input.stationId),
6
7
  * returns: Station,
7
- * handler: async ({ input, db }) => db.stations.findById(input.stationId),
8
+ * errors: [NotFound],
8
9
  * });
9
10
  *
10
- * The shape is universal same primitive whether the operation is exposed
11
- * via HTTP, queue, MCP, CLI, or invoked directly via `execute(handler, input)`.
12
- * Every transport binds via its own `(binding, handler, options)` signature;
13
- * the binding narrows the input contract at the boundary, the handler is
14
- * the lowest-common-denominator inside.
11
+ * GetStation({ stationId: "abc" }) // mint a prepared op
12
+ * await GetStation({ stationId: "abc" }).run() // run it
13
+ * await GetStation.run({ input, signal }) // low-level hook surface
14
+ * GetStation.use(myMiddleware) // attach a hook chain step
15
+ * GetStation.on(observer) // attach a listener
15
16
  *
16
- * See: architecture-sketch.html §08.
17
+ * The handler IS a `Hook` from `@nwire/hooks`. `.use()` attaches chain steps;
18
+ * `.on()` attaches parallel listeners; `.run()` executes. The user's handler
19
+ * function is the innermost chain step — registered at construction with
20
+ * `Number.MIN_SAFE_INTEGER` priority so every `.use(...)` wraps around it.
17
21
  *
18
- * Field placement follows the freq table:
19
- * first-class input, handler, returns, errors, summary, policy, emits
20
- * meta — tags, description, version, deprecated, successor
21
- * settings — retry, timeout, cache, idempotency
22
+ * **Ctx is generic.** The handler's ctx is `BaseHookCtx & { input } & TExtras`
23
+ * where `TExtras` is inferred from the handler's param annotation, or pinned
24
+ * once via `defineHandlerWith<TExtras>()` at the app boundary. Whatever you
25
+ * pass to `.run(ctx)` is what reaches the handler body, fully typed. No
26
+ * declaration merging on ctx — composition by value.
22
27
  *
23
- * `meta` + `settings` are open bags; adapters extend them via TS declaration
24
- * merging without touching the core type.
25
- *
26
- * NOTE: forge has its own `defineHandler(action, fn)` that binds a handler
27
- * to an existing `ActionDefinition`. That signature stays inside `@nwire/forge`
28
- * because it depends on the action machinery. The standalone version lives
29
- * here because every transport needs it without the forge surface.
28
+ * `meta` + `settings` ARE globally augmentable open interfaces. Those are
29
+ * declarative per-handler tags (policy, retry, persona, SLO) that plugins
30
+ * must discover across every handler — different role from ctx, different
31
+ * mechanism by design.
30
32
  */
31
33
  import type { z } from "zod";
32
34
  import type { ZodTypeAny } from "@nwire/messages";
33
- import type { Container } from "@nwire/container";
34
- import { type Logger } from "@nwire/logger";
35
+ import { type BaseHookCtx, type ChainFn, type ListenerFn, type RunOptions, type RunResult, type UseOptions, type OnOptions, type TapFn } from "@nwire/hooks";
35
36
  import type { ErrorDefinition } from "./define-error.js";
36
37
  import type { ResponseSpec, ListResponseSpec } from "./response.js";
37
38
  import type { ResourceDefinition } from "./define-resource.js";
38
- /** Bags extensible via TS declaration merging — adapters add fields here. */
39
+ /**
40
+ * Empty bags — plugins extend via TS declaration merging.
41
+ *
42
+ * declare module "@nwire/handler" {
43
+ * interface HandlerSettings { retry?: { attempts: number } }
44
+ * }
45
+ *
46
+ * These hold *declarative config* (RBAC policies, retry strategies,
47
+ * SLO budgets, persona tags) — NOT runtime ctx. Different role, different
48
+ * mechanism: ctx is per-invocation runtime data composed by value;
49
+ * meta/settings are per-handler design-time tags plugins discover globally.
50
+ */
39
51
  export interface HandlerMeta {
40
- readonly tags?: readonly string[];
41
- readonly description?: string;
42
- readonly version?: number;
43
- readonly deprecated?: boolean;
44
- readonly successor?: string;
45
52
  }
46
53
  export interface HandlerSettings {
47
- readonly retry?: {
48
- attempts: number;
49
- backoff?: "linear" | "exponential";
50
- };
51
- readonly timeout?: number;
52
- readonly cache?: {
53
- ttl: number;
54
- };
55
- readonly idempotency?: (input: unknown) => string;
56
54
  }
55
+ /** Resolve a zod schema (or `undefined`) to the parsed input type. */
56
+ export type InferInput<S extends ZodTypeAny | undefined> = S extends ZodTypeAny ? z.output<S> : undefined;
57
57
  /**
58
- * Context delivered to every handler. The shape is intentionally minimal
59
- * adapters supply richer context via the container (resolve any registered
60
- * dep by name + destructure into the handler signature).
58
+ * The base ctx every handler receives hooks' `BaseHookCtx` (`signal` + typed
59
+ * `set`) plus the parsed `input`. Apps extend with their own `TExtras` via
60
+ * the `Ctx<TInput, TExtras>` alias below.
61
61
  */
62
- export interface HandlerContext<TInput = unknown> {
63
- /** Parsed + validated input (drawn from `config.input` schema). */
64
- readonly input: TInput;
65
- /** Look up a dependency by name. Most handlers destructure instead. */
66
- resolve<T = unknown>(name: string): T;
67
- /** Per-execution container scope. */
68
- readonly container: Container;
69
- /** Logger scoped to this execution (correlation/causation already attached). */
70
- readonly logger: Logger;
71
- /** Free-form bag for transport-specific extras (raw request, MCP progress, …). */
72
- readonly transport?: Record<string, unknown>;
62
+ export interface HandlerBaseCtx<TInput> extends BaseHookCtx {
63
+ input: TInput;
73
64
  }
65
+ /**
66
+ * Sugar for declaring a handler's ctx shape:
67
+ *
68
+ * handler: async ({ input, cradle, user }: Ctx<MyInput, { cradle: Cradle; user: User }>) => …
69
+ */
70
+ export type Ctx<TInput, TExtras extends object = object> = HandlerBaseCtx<TInput> & TExtras;
74
71
  /**
75
72
  * `returns` may be a single resource, a single response spec, or an array
76
73
  * of response specs (e.g. `[created(Station), accepted(StationHandle)]`).
77
74
  */
78
75
  export type HandlerReturnsSpec = ResourceDefinition | ResponseSpec | ListResponseSpec<ResourceDefinition> | ReadonlyArray<ResponseSpec | ListResponseSpec<ResourceDefinition>>;
79
- /**
80
- * Policy: a tag (`"admin"`), a list of tags (`["admin", "operator"]`), or
81
- * a tuple of `[action, subject]` for RBAC-style policies. Adapters
82
- * interpret the value per their authorization model.
83
- */
84
- export type HandlerPolicy = string | readonly string[] | readonly [string, string];
85
- export interface HandlerConfig<TInputSchema extends ZodTypeAny | undefined = ZodTypeAny | undefined, TOutput = unknown> {
76
+ export interface HandlerConfig<TInputSchema extends ZodTypeAny | undefined = undefined, TOutput = unknown, TExtras extends object = object> {
86
77
  /** Input schema. Optional for zero-arg handlers (health checks, listings without filters). */
87
78
  readonly input?: TInputSchema;
88
- /** The implementation. Receives the typed input + context. */
89
- readonly handler: (ctx: HandlerContext<TInputSchema extends ZodTypeAny ? z.output<TInputSchema> : undefined>) => TOutput | Promise<TOutput>;
79
+ /** The implementation. Receives the typed input + ctx fields contributed upstream. */
80
+ readonly handler: (ctx: Ctx<InferInput<TInputSchema>, TExtras>) => TOutput | Promise<TOutput>;
90
81
  /** Documented response shape(s). Drives OpenAPI + runtime body validation. */
91
82
  readonly returns?: HandlerReturnsSpec;
92
83
  /** Declared error values this handler may throw. */
93
84
  readonly errors?: readonly ErrorDefinition[];
94
- /** Events this handler may emit (action flavour). */
95
- readonly emits?: readonly unknown[];
96
- /** One-line intent. Surfaces in OpenAPI/MCP descriptions. */
85
+ /** One-line intent. Surfaces in OpenAPI / MCP / Studio. */
97
86
  readonly summary?: string;
98
- /** Authorization policy. Adapters (rbac, authz) consume this. */
99
- readonly policy?: HandlerPolicy;
100
- /** Rare-field bag — tags, description, version, deprecated, …. */
87
+ /** Multi-line prose. Surfaces in OpenAPI / MCP / Studio. */
88
+ readonly description?: string;
89
+ /** Open bag — plugins contribute fields via declaration merging. */
101
90
  readonly meta?: HandlerMeta;
102
- /** Behavior-tuning bag — retry, timeout, cache, idempotency. */
91
+ /** Open bag — plugins contribute fields via declaration merging. */
103
92
  readonly settings?: HandlerSettings;
104
93
  }
105
- export interface HandlerDefinition<TInputSchema extends ZodTypeAny | undefined = ZodTypeAny | undefined, TOutput = unknown> {
94
+ /**
95
+ * Hook ctx that flows through the chain when a handler runs. Extends the
96
+ * consumer's `TExtras` so middleware that wrote to ctx (or used `.set()`)
97
+ * is visible to subsequent steps + listeners.
98
+ */
99
+ export type HandlerRunCtx<TInput = unknown, TOutput = unknown, TExtras extends object = object> = Ctx<TInput, TExtras> & {
100
+ result?: TOutput;
101
+ };
102
+ /** Options passed to `PreparedOp.run()` — the high-level callable form. */
103
+ export interface PreparedOpRunOptions<TExtras extends object = object> {
104
+ readonly signal?: AbortSignal;
105
+ /**
106
+ * Extras to populate on ctx before the handler body runs. Required when
107
+ * `TExtras` declares fields the runtime must supply (`cradle`, `user`, …).
108
+ * Optional `{}` for handlers that declared no extras.
109
+ */
110
+ readonly ctx?: TExtras;
111
+ }
112
+ /**
113
+ * The value returned by calling a handler as a factory: `Handler(input)`.
114
+ * Holds the validated input and exposes `.run(opts?)` to execute.
115
+ */
116
+ export interface PreparedOp<TInput = unknown, TOutput = unknown, TExtras extends object = object> {
117
+ readonly input: TInput;
118
+ run(opts?: PreparedOpRunOptions<TExtras>): Promise<TOutput>;
119
+ }
120
+ /**
121
+ * The handler definition. Composes a `Hook<HandlerRunCtx>` for the chain
122
+ * surface (`.use` / `.on` / `.off` / `.run` / `.runDetailed` / `.tap`) and
123
+ * is callable as a factory that mints a `PreparedOp`.
124
+ */
125
+ export interface HandlerDefinition<TInputSchema extends ZodTypeAny | undefined = undefined, TOutput = unknown, TExtras extends object = object> {
106
126
  readonly $kind: "handler";
107
127
  readonly name: string;
108
- readonly config: HandlerConfig<TInputSchema, TOutput>;
128
+ readonly config: HandlerConfig<TInputSchema, TOutput, TExtras>;
129
+ (input: TInputSchema extends ZodTypeAny ? z.input<TInputSchema> : void): PreparedOp<InferInput<TInputSchema>, TOutput, TExtras>;
130
+ /** Hook chain attach — runs sequentially, can short-circuit. */
131
+ use(fn: ChainFn<HandlerRunCtx<InferInput<TInputSchema>, TOutput, TExtras>>, opts?: UseOptions): HandlerDefinition<TInputSchema, TOutput, TExtras>;
132
+ /** Listener attach — observes the final ctx, cannot mutate. */
133
+ on(fn: ListenerFn<HandlerRunCtx<InferInput<TInputSchema>, TOutput, TExtras>>, opts?: OnOptions): HandlerDefinition<TInputSchema, TOutput, TExtras>;
134
+ /** Detach a previously attached `.use()` or `.on()` fn. */
135
+ off(fn: ChainFn<HandlerRunCtx<InferInput<TInputSchema>, TOutput, TExtras>> | ListenerFn<HandlerRunCtx<InferInput<TInputSchema>, TOutput, TExtras>>): HandlerDefinition<TInputSchema, TOutput, TExtras>;
109
136
  /**
110
- * Convenience accessor equivalent to `config.handler`. Lets transports
111
- * write `handler.run(ctx)` without reaching into `.config`.
137
+ * Run the chain + listeners. The caller supplies the ctx — `input` +
138
+ * `signal` are filled in automatically; everything in `TExtras` must
139
+ * be present on the ctx object.
112
140
  */
113
- run(ctx: HandlerContext<TInputSchema extends ZodTypeAny ? z.output<TInputSchema> : undefined>): TOutput | Promise<TOutput>;
141
+ run(ctx: HandlerRunCtx<InferInput<TInputSchema>, TOutput, TExtras>, opts?: RunOptions): Promise<HandlerRunCtx<InferInput<TInputSchema>, TOutput, TExtras>>;
142
+ /** Same as `.run()` but returns the full observation trace. */
143
+ runDetailed(ctx: HandlerRunCtx<InferInput<TInputSchema>, TOutput, TExtras>, opts?: RunOptions): Promise<RunResult<HandlerRunCtx<InferInput<TInputSchema>, TOutput, TExtras>>>;
144
+ /** Subscribe to per-step observations. */
145
+ tap(observer: TapFn): () => void;
146
+ /** Step counts on the underlying hook. */
147
+ stepCounts(): {
148
+ readonly chain: number;
149
+ readonly listeners: number;
150
+ };
114
151
  }
152
+ /**
153
+ * `HandlerLike` — what `interface-builder.wire()` accepts.
154
+ *
155
+ * - a full `HandlerDefinition` (typed, hookable, has metadata) — the canonical path.
156
+ * - a bare async function (one-liners, health checks, escape hatch).
157
+ */
158
+ export type HandlerLike<TInput = unknown, TOutput = unknown> = HandlerDefinition<ZodTypeAny | undefined, TOutput, object> | ((input: TInput) => Promise<TOutput> | TOutput);
115
159
  /**
116
160
  * Define a handler — the operation primitive.
117
161
  *
118
162
  * const ListTodos = defineHandler("listTodos", {
119
163
  * input: z.object({ status: z.string().optional() }),
120
- * handler: async ({ input, resolve }) => {
121
- * const db = resolve<DB>("db");
122
- * return db.todos.findMany(input);
123
- * },
164
+ * handler: async ({ input }) => todos.findMany(input),
124
165
  * });
125
166
  *
126
167
  * // Direct invocation:
127
- * const todos = await execute(ListTodos, { status: "open" });
168
+ * const result = await ListTodos({ status: "open" }).run();
128
169
  *
129
- * // HTTP transport:
130
- * api.wire(get("/todos"), ListTodos);
170
+ * // Hook composition:
171
+ * ListTodos.use(withTimeout(5000));
172
+ * ListTodos.on(record => otel.span(...));
131
173
  *
132
- * // Queue transport (same handler):
133
- * workers.wire(job("listTodos"), ListTodos);
134
- */
135
- export declare function defineHandler<TInputSchema extends ZodTypeAny | undefined, TOutput>(name: string, config: HandlerConfig<TInputSchema, TOutput>): HandlerDefinition<TInputSchema, TOutput>;
136
- /** Type narrow. */
137
- export declare function isHandlerDefinition(x: unknown): x is HandlerDefinition;
138
- /**
139
- * Options for `execute()` — transport-agnostic. Adapters can pass a
140
- * container so the handler can `resolve()` its deps; if omitted, a
141
- * minimal stub container is supplied that throws on resolve.
174
+ * // Low-level hook surface (transports use this):
175
+ * await ListTodos.run({ input: { status: "open" }, signal });
142
176
  */
143
- export interface ExecuteOptions {
144
- readonly container?: Container;
145
- readonly logger?: Logger;
146
- readonly transport?: Record<string, unknown>;
147
- }
177
+ export declare function defineHandler<TInputSchema extends ZodTypeAny | undefined, TOutput, TExtras extends object = object>(name: string, config: HandlerConfig<TInputSchema, TOutput, TExtras>): HandlerDefinition<TInputSchema, TOutput, TExtras>;
148
178
  /**
149
- * Invoke a handler directly with input. The framework validates input
150
- * against the handler's `input` schema (if declared), constructs the
151
- * handler context, runs the handler, and returns its result.
179
+ * App-boundary sugar pin `TExtras` once so every handler in the app reads
180
+ * `ctx` as the bound shape without per-call annotations.
152
181
  *
153
- * const todos = await execute(ListTodos, { status: "open" });
182
+ * // app/action.ts
183
+ * type AppExtras = { cradle: AppCradle; user: User };
184
+ * export const action = defineHandlerWith<AppExtras>();
154
185
  *
155
- * This is the universal "any host can mount it" entry point. Transports
156
- * call into `execute()` after parsing the binding's payload; tests call
157
- * `execute()` directly to bypass transport machinery.
158
- */
159
- export declare function execute<TInputSchema extends ZodTypeAny | undefined, TOutput>(handler: HandlerDefinition<TInputSchema, TOutput>, input: TInputSchema extends ZodTypeAny ? z.input<TInputSchema> : any, options?: ExecuteOptions): Promise<TOutput>;
160
- /**
161
- * Type alias for a handler-or-callable. Transports `.wire()` accept either
162
- * a full `HandlerDefinition` (typed, validated) or a bare async function
163
- * (escape hatch for one-liners + health checks).
186
+ * // every handler file:
187
+ * import { action } from "@/action";
188
+ * const PlaceOrder = action("placeOrder", {
189
+ * input: z.object({ id: z.string() }),
190
+ * handler: async ({ input, cradle, user }) => … // fully typed, no annotation
191
+ * });
192
+ *
193
+ * // every transport / .run() call:
194
+ * PlaceOrder.run({ input, signal, cradle, user });
164
195
  */
165
- export type HandlerLike<TInput = unknown, TOutput = unknown> = HandlerDefinition<ZodTypeAny | undefined, TOutput> | ((input: TInput) => Promise<TOutput> | TOutput);
166
- /** Re-exports for the public surface. */
196
+ export declare function defineHandlerWith<TExtras extends object>(): <TInputSchema extends ZodTypeAny | undefined, TOutput>(name: string, config: HandlerConfig<TInputSchema, TOutput, TExtras>) => HandlerDefinition<TInputSchema, TOutput, TExtras>;
197
+ /** Type narrow. */
198
+ export declare function isHandlerDefinition(x: unknown): x is HandlerDefinition;
199
+ /** Extract the input type of a handler's schema (post-parse). */
200
+ export type HandlerInput<H> = H extends HandlerDefinition<infer S, unknown, object> ? InferInput<S> : never;
201
+ /** Extract the output type of a handler. */
202
+ export type HandlerOutput<H> = H extends HandlerDefinition<ZodTypeAny | undefined, infer O, object> ? O : never;
203
+ /** Extract the extras (TExtras) a handler requires on ctx. */
204
+ export type HandlerExtras<H> = H extends HandlerDefinition<ZodTypeAny | undefined, unknown, infer E> ? E : never;
205
+ /** Re-export from the response builders for ergonomics. */
167
206
  export type { ResponseInstance } from "./response.js";
168
207
  //# sourceMappingURL=define-handler.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"define-handler.d.ts","sourceRoot":"","sources":["../src/define-handler.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"define-handler.d.ts","sourceRoot":"","sources":["../src/define-handler.ts"],"names":[],"mappings":"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"}
@@ -3,114 +3,170 @@
3
3
  *
4
4
  * const GetStation = defineHandler("GetStation", {
5
5
  * input: z.object({ stationId: z.string() }),
6
+ * handler: async ({ input }) => loadStation(input.stationId),
6
7
  * returns: Station,
7
- * handler: async ({ input, db }) => db.stations.findById(input.stationId),
8
+ * errors: [NotFound],
8
9
  * });
9
10
  *
10
- * The shape is universal same primitive whether the operation is exposed
11
- * via HTTP, queue, MCP, CLI, or invoked directly via `execute(handler, input)`.
12
- * Every transport binds via its own `(binding, handler, options)` signature;
13
- * the binding narrows the input contract at the boundary, the handler is
14
- * the lowest-common-denominator inside.
11
+ * GetStation({ stationId: "abc" }) // mint a prepared op
12
+ * await GetStation({ stationId: "abc" }).run() // run it
13
+ * await GetStation.run({ input, signal }) // low-level hook surface
14
+ * GetStation.use(myMiddleware) // attach a hook chain step
15
+ * GetStation.on(observer) // attach a listener
15
16
  *
16
- * See: architecture-sketch.html §08.
17
+ * The handler IS a `Hook` from `@nwire/hooks`. `.use()` attaches chain steps;
18
+ * `.on()` attaches parallel listeners; `.run()` executes. The user's handler
19
+ * function is the innermost chain step — registered at construction with
20
+ * `Number.MIN_SAFE_INTEGER` priority so every `.use(...)` wraps around it.
17
21
  *
18
- * Field placement follows the freq table:
19
- * first-class input, handler, returns, errors, summary, policy, emits
20
- * meta — tags, description, version, deprecated, successor
21
- * settings — retry, timeout, cache, idempotency
22
+ * **Ctx is generic.** The handler's ctx is `BaseHookCtx & { input } & TExtras`
23
+ * where `TExtras` is inferred from the handler's param annotation, or pinned
24
+ * once via `defineHandlerWith<TExtras>()` at the app boundary. Whatever you
25
+ * pass to `.run(ctx)` is what reaches the handler body, fully typed. No
26
+ * declaration merging on ctx — composition by value.
22
27
  *
23
- * `meta` + `settings` are open bags; adapters extend them via TS declaration
24
- * merging without touching the core type.
25
- *
26
- * NOTE: forge has its own `defineHandler(action, fn)` that binds a handler
27
- * to an existing `ActionDefinition`. That signature stays inside `@nwire/forge`
28
- * because it depends on the action machinery. The standalone version lives
29
- * here because every transport needs it without the forge surface.
28
+ * `meta` + `settings` ARE globally augmentable open interfaces. Those are
29
+ * declarative per-handler tags (policy, retry, persona, SLO) that plugins
30
+ * must discover across every handler — different role from ctx, different
31
+ * mechanism by design.
32
+ */
33
+ import { hook, } from "@nwire/hooks";
34
+ /**
35
+ * Tag for the terminal chain step that calls the user's handler function.
36
+ * Registered with `Number.MIN_SAFE_INTEGER` priority so every `.use()` from
37
+ * the consumer wraps around it (higher priority = runs first / outermost).
30
38
  */
31
- import { NoopLogger } from "@nwire/logger";
39
+ const TERMINAL_STEP_NAME = "@nwire/handler/terminal";
32
40
  /**
33
41
  * Define a handler — the operation primitive.
34
42
  *
35
43
  * const ListTodos = defineHandler("listTodos", {
36
44
  * input: z.object({ status: z.string().optional() }),
37
- * handler: async ({ input, resolve }) => {
38
- * const db = resolve<DB>("db");
39
- * return db.todos.findMany(input);
40
- * },
45
+ * handler: async ({ input }) => todos.findMany(input),
41
46
  * });
42
47
  *
43
48
  * // Direct invocation:
44
- * const todos = await execute(ListTodos, { status: "open" });
49
+ * const result = await ListTodos({ status: "open" }).run();
45
50
  *
46
- * // HTTP transport:
47
- * api.wire(get("/todos"), ListTodos);
51
+ * // Hook composition:
52
+ * ListTodos.use(withTimeout(5000));
53
+ * ListTodos.on(record => otel.span(...));
48
54
  *
49
- * // Queue transport (same handler):
50
- * workers.wire(job("listTodos"), ListTodos);
55
+ * // Low-level hook surface (transports use this):
56
+ * await ListTodos.run({ input: { status: "open" }, signal });
51
57
  */
52
58
  export function defineHandler(name, config) {
53
- return {
54
- $kind: "handler",
55
- name,
56
- config,
57
- run(ctx) {
58
- return config.handler(ctx);
59
- },
59
+ const h = hook(name);
60
+ // Innermost step — runs the user's handler after every `.use()` has had
61
+ // its chance to wrap. Validation happens here (parse against config.input)
62
+ // so middleware that mutates ctx.input does so BEFORE validation. The
63
+ // chain ctx is forwarded so middleware-contributed fields (TExtras —
64
+ // cradle, user, tenant, logger, …) flow through.
65
+ h.use(async (ctx, next) => {
66
+ ctx.signal?.throwIfAborted();
67
+ const parsed = config.input ? config.input.parse(ctx.input) : ctx.input;
68
+ ctx.input = parsed;
69
+ const result = await config.handler(ctx);
70
+ ctx.result = result;
71
+ await next();
72
+ }, {
73
+ name: TERMINAL_STEP_NAME,
74
+ priority: Number.MIN_SAFE_INTEGER,
75
+ });
76
+ // The factory is a callable function. `Object.defineProperty` attaches the
77
+ // metadata + delegated hook methods + the `$kind` discriminator.
78
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
79
+ const factory = (input) => {
80
+ const prepared = {
81
+ input: input,
82
+ async run(opts) {
83
+ const ctx = {
84
+ input,
85
+ ...(opts?.ctx ?? {}),
86
+ };
87
+ const out = await h.run(ctx, { signal: opts?.signal });
88
+ return out.result;
89
+ },
90
+ };
91
+ return prepared;
60
92
  };
61
- }
62
- /** Type narrow. */
63
- export function isHandlerDefinition(x) {
64
- return typeof x === "object" && x !== null && x.$kind === "handler";
93
+ Object.defineProperties(factory, {
94
+ $kind: { value: "handler", enumerable: true },
95
+ name: { value: name, enumerable: true, configurable: true },
96
+ config: { value: config, enumerable: true },
97
+ toString: { value: () => name, enumerable: false },
98
+ $hook: { value: h, enumerable: false, configurable: true },
99
+ use: {
100
+ value: function use(fn, opts) {
101
+ h.use(fn, opts);
102
+ return factory;
103
+ },
104
+ enumerable: false,
105
+ },
106
+ on: {
107
+ value: function on(fn, opts) {
108
+ h.on(fn, opts);
109
+ return factory;
110
+ },
111
+ enumerable: false,
112
+ },
113
+ off: {
114
+ value: function off(fn) {
115
+ h.off(fn);
116
+ return factory;
117
+ },
118
+ enumerable: false,
119
+ },
120
+ run: {
121
+ value: function run(ctx, opts) {
122
+ return h.run(ctx, opts);
123
+ },
124
+ enumerable: false,
125
+ },
126
+ runDetailed: {
127
+ value: function runDetailed(ctx, opts) {
128
+ return h.runDetailed(ctx, opts);
129
+ },
130
+ enumerable: false,
131
+ },
132
+ tap: {
133
+ value: function tap(observer) {
134
+ return h.tap(observer);
135
+ },
136
+ enumerable: false,
137
+ },
138
+ stepCounts: {
139
+ value: function stepCounts() {
140
+ return h.stepCounts();
141
+ },
142
+ enumerable: false,
143
+ },
144
+ });
145
+ return factory;
65
146
  }
66
147
  /**
67
- * Invoke a handler directly with input. The framework validates input
68
- * against the handler's `input` schema (if declared), constructs the
69
- * handler context, runs the handler, and returns its result.
148
+ * App-boundary sugar pin `TExtras` once so every handler in the app reads
149
+ * `ctx` as the bound shape without per-call annotations.
150
+ *
151
+ * // app/action.ts
152
+ * type AppExtras = { cradle: AppCradle; user: User };
153
+ * export const action = defineHandlerWith<AppExtras>();
70
154
  *
71
- * const todos = await execute(ListTodos, { status: "open" });
155
+ * // every handler file:
156
+ * import { action } from "@/action";
157
+ * const PlaceOrder = action("placeOrder", {
158
+ * input: z.object({ id: z.string() }),
159
+ * handler: async ({ input, cradle, user }) => … // fully typed, no annotation
160
+ * });
72
161
  *
73
- * This is the universal "any host can mount it" entry point. Transports
74
- * call into `execute()` after parsing the binding's payload; tests call
75
- * `execute()` directly to bypass transport machinery.
162
+ * // every transport / .run() call:
163
+ * PlaceOrder.run({ input, signal, cradle, user });
76
164
  */
77
- export async function execute(handler,
78
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
79
- input, options = {}) {
80
- const schema = handler.config.input;
81
- const parsed = schema ? schema.parse(input) : input;
82
- const container = options.container ?? minimalContainer();
83
- const logger = options.logger ?? minimalLogger();
84
- const ctx = {
85
- input: parsed,
86
- container,
87
- resolve: (name) => container.resolve(name),
88
- logger,
89
- transport: options.transport,
90
- };
91
- return handler.run(ctx);
92
- }
93
- /** Minimal stub container — every resolve throws. Used when no container supplied. */
94
- function minimalContainer() {
95
- const stub = {
96
- resolve(name) {
97
- throw new Error(`execute(): no container provided — cannot resolve "${name}". ` +
98
- `Pass options.container or use a transport that wires one.`);
99
- },
100
- register() {
101
- throw new Error("execute(): minimal container is read-only");
102
- },
103
- createScope() {
104
- return minimalContainer();
105
- },
106
- has() {
107
- return false;
108
- },
109
- };
110
- return stub;
165
+ export function defineHandlerWith() {
166
+ return (name, config) => defineHandler(name, config);
111
167
  }
112
- /** Minimal stub logger. No-op every method. */
113
- function minimalLogger() {
114
- return new NoopLogger();
168
+ /** Type narrow. */
169
+ export function isHandlerDefinition(x) {
170
+ return typeof x === "function" && x.$kind === "handler";
115
171
  }
116
172
  //# sourceMappingURL=define-handler.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"define-handler.js","sourceRoot":"","sources":["../src/define-handler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAKH,OAAO,EAAE,UAAU,EAAe,MAAM,eAAe,CAAC;AAkGxD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,UAAU,aAAa,CAC3B,IAAY,EACZ,MAA4C;IAE5C,OAAO;QACL,KAAK,EAAE,SAAS;QAChB,IAAI;QACJ,MAAM;QACN,GAAG,CAAC,GAAG;YACL,OAAO,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAC7B,CAAC;KACF,CAAC;AACJ,CAAC;AAED,mBAAmB;AACnB,MAAM,UAAU,mBAAmB,CAAC,CAAU;IAC5C,OAAO,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,IAAI,IAAK,CAAyB,CAAC,KAAK,KAAK,SAAS,CAAC;AAC/F,CAAC;AAeD;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,OAAO,CAC3B,OAAiD;AACjD,8DAA8D;AAC9D,KAAoE,EACpE,UAA0B,EAAE;IAE5B,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC;IACpC,MAAM,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;IAEpD,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,gBAAgB,EAAE,CAAC;IAC1D,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,aAAa,EAAE,CAAC;IAEjD,MAAM,GAAG,GAAmB;QAC1B,KAAK,EAAE,MAAM;QACb,SAAS;QACT,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC;QAC1C,MAAM;QACN,SAAS,EAAE,OAAO,CAAC,SAAS;KAC7B,CAAC;IAEF,OAAO,OAAO,CAAC,GAAG,CAChB,GAA2F,CAC5F,CAAC;AACJ,CAAC;AAED,sFAAsF;AACtF,SAAS,gBAAgB;IACvB,MAAM,IAAI,GAAc;QACtB,OAAO,CAAI,IAAY;YACrB,MAAM,IAAI,KAAK,CACb,sDAAsD,IAAI,KAAK;gBAC7D,2DAA2D,CAC9D,CAAC;QACJ,CAAC;QACD,QAAQ;YACN,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAC;QAC/D,CAAC;QACD,WAAW;YACT,OAAO,gBAAgB,EAAE,CAAC;QAC5B,CAAC;QACD,GAAG;YACD,OAAO,KAAK,CAAC;QACf,CAAC;KACF,CAAC;IACF,OAAO,IAAI,CAAC;AACd,CAAC;AAED,+CAA+C;AAC/C,SAAS,aAAa;IACpB,OAAO,IAAI,UAAU,EAAE,CAAC;AAC1B,CAAC"}
1
+ {"version":3,"file":"define-handler.js","sourceRoot":"","sources":["../src/define-handler.ts"],"names":[],"mappings":"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"}