@nwire/runtime 0.11.0 → 0.12.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/index.d.ts CHANGED
@@ -7,7 +7,7 @@
7
7
  * plus runtime alone is enough to dispatch handlers with envelopes, install
8
8
  * capabilities, install middleware, and react to events without any App.
9
9
  */
10
- export { Runtime, createRuntime, isBuiltInHook, serializeError, type RuntimeOptions, type Telemetry, type TelemetryListener, type HookStepTelemetry, type DispatchHookCtx, type DispatchMiddleware, type SerializedError, type PluginDefinition, type PluginContext, } from "./runtime.js";
10
+ export { Runtime, createRuntime, isBuiltInHook, serializeError, type RuntimeOptions, type Telemetry, type TelemetryListener, type HookStepTelemetry, type DispatchHookCtx, type DispatchMiddleware, type SerializedError, type PluginDefinition, type PluginContext, type ListenerContext, } from "./runtime.js";
11
11
  export { createFrameworkHooks, type FrameworkHooks, type PluginKind } from "./framework-hooks.js";
12
12
  export { defineCapability, type Capability, type CapabilityBase } from "./capability.js";
13
13
  export type { OutboundStage, StagePosition, StageContext } from "./sink.js";
package/dist/runtime.d.ts CHANGED
@@ -10,7 +10,7 @@ import { type Hook } from "@nwire/hooks";
10
10
  import { type Logger } from "@nwire/logger";
11
11
  import { type MessageEnvelope } from "@nwire/envelope";
12
12
  import type { HandlerDefinition } from "@nwire/handler";
13
- import type { EventDefinition } from "@nwire/messages";
13
+ import type { EventDefinition, EventPayload } from "@nwire/messages";
14
14
  import { isBuiltInHook, type FrameworkHooks } from "./framework-hooks.js";
15
15
  import type { Capability } from "./capability.js";
16
16
  import type { OutboundStage } from "./sink.js";
@@ -292,22 +292,24 @@ export declare class Runtime {
292
292
  readonly signal?: AbortSignal;
293
293
  readonly parent?: MessageEnvelope;
294
294
  }): Promise<void>;
295
+ /** Resolve a dependency from the runtime's container. */
296
+ resolve<T = unknown>(name: string): T;
295
297
  /**
296
298
  * Register a listener for an event. Returns an unsubscribe. Listeners are
297
299
  * stored per `event.name` and fire in registration order via
298
300
  * `Promise.allSettled` when `emit(event, ...)` is called. Throwing
299
301
  * listeners are captured in telemetry but do not break sibling listeners.
300
302
  */
301
- when<TPayload>(event: EventDefinition & {
303
+ when<E extends EventDefinition & {
302
304
  readonly name: string;
303
- }, listener: (payload: TPayload, envelope: MessageEnvelope) => void | Promise<void>): () => void;
305
+ }>(event: E, listener: (payload: EventPayload<E>, ctx: ListenerContext) => void | Promise<void>): () => void;
304
306
  /**
305
307
  * Alias for {@link when} — same behavior, same return. Preserved for
306
308
  * call sites that prefer the longer name.
307
309
  */
308
- subscribe<TPayload>(event: EventDefinition & {
310
+ subscribe<E extends EventDefinition & {
309
311
  readonly name: string;
310
- }, listener: (payload: TPayload, envelope: MessageEnvelope) => void | Promise<void>): () => void;
312
+ }>(event: E, listener: (payload: EventPayload<E>, ctx: ListenerContext) => void | Promise<void>): () => void;
311
313
  /**
312
314
  * Broadcast an event to its subscribers. Validates payload against the
313
315
  * event's schema, mints a child envelope, fires every registered
@@ -324,6 +326,33 @@ export declare class Runtime {
324
326
  readonly parent?: MessageEnvelope;
325
327
  }): Promise<void>;
326
328
  }
329
+ /**
330
+ * Context handed to an event listener. A strict SUBSET of the workflow
331
+ * `when` ctx — so a `when(Event, (payload, ctx) => …)` block written in a
332
+ * listener moves into a `defineWorkflow` unchanged (the workflow adds
333
+ * `assign` / state / `schedule` on top). Every verb threads this event's
334
+ * envelope as the parent, so follow-up dispatches inherit the correlation
335
+ * chain.
336
+ */
337
+ export interface ListenerContext {
338
+ /** This event's envelope — tenant, user, correlation, causation. */
339
+ readonly envelope: MessageEnvelope;
340
+ /** Dispatch a follow-up action and await its result. */
341
+ send<I, O>(handler: HandlerDefinition<any, O, any> | string, input: I, partial?: Partial<MessageEnvelope> & {
342
+ readonly signal?: AbortSignal;
343
+ }): Promise<O>;
344
+ /** Publish another event. */
345
+ emit<E extends EventDefinition & {
346
+ readonly name: string;
347
+ readonly schema: {
348
+ parse(input: unknown): unknown;
349
+ };
350
+ }>(event: E, payload: EventPayload<E>, partial?: Partial<MessageEnvelope>): Promise<void>;
351
+ /** Resolve a dependency from the container. */
352
+ resolve<T = unknown>(name: string): T;
353
+ /** The runtime logger. */
354
+ readonly logger: Logger;
355
+ }
327
356
  /**
328
357
  * Canonical factory for a Runtime. Matches the foundation-doc shape
329
358
  * (`createRuntime(opts)`) so consumer code stays uniform across
@@ -390,8 +419,12 @@ export interface PluginContext<TOptions = void> {
390
419
  add(cap: Capability<unknown>): void;
391
420
  /** Install an outbound pipeline stage. */
392
421
  sink(stage: OutboundStage): void;
393
- /** Observe a framework hook — calls `runtime.hooks[name].on(fn)` under the hood. */
394
- on<K extends keyof FrameworkHooks>(name: K, fn: (payload: unknown) => void): void;
422
+ /**
423
+ * Observe a framework lifecycle hook calls `runtime.hooks[name].on(fn)`
424
+ * under the hood. The payload is typed from the named hook, so
425
+ * `on("AppBooted", ({ appName, bootedAt }) => …)` is fully inferred.
426
+ */
427
+ on<K extends keyof FrameworkHooks>(name: K, fn: (payload: FrameworkHooks[K] extends Hook<infer P> ? P : never) => void): void;
395
428
  boot(fn: () => Promise<void> | void): void;
396
429
  /** Async cleanup work to run at `runtime.stop()`. */
397
430
  dispose(fn: () => Promise<void> | void): void;
package/dist/runtime.js CHANGED
@@ -477,6 +477,10 @@ export class Runtime {
477
477
  });
478
478
  return Promise.resolve();
479
479
  }
480
+ /** Resolve a dependency from the runtime's container. */
481
+ resolve(name) {
482
+ return this.container.resolve(name);
483
+ }
480
484
  /**
481
485
  * Register a listener for an event. Returns an unsubscribe. Listeners are
482
486
  * stored per `event.name` and fire in registration order via
@@ -526,9 +530,19 @@ export class Runtime {
526
530
  const startedAt = performance.now();
527
531
  const subs = this.eventListeners.get(event.name);
528
532
  if (subs && subs.size > 0) {
533
+ // Listener ctx — the documented subset of the workflow `when` ctx,
534
+ // every verb threaded with this envelope as parent so follow-up
535
+ // dispatches inherit the correlation chain.
536
+ const listenerCtx = {
537
+ envelope,
538
+ send: (h, i, partial) => this.execute(h, i, { ...partial, parent: envelope }),
539
+ emit: (ev, p, partial) => this.emit(ev, p, { ...partial, parent: envelope }),
540
+ resolve: (name) => this.container.resolve(name),
541
+ logger: this._logger,
542
+ };
529
543
  // Wrap in async so a SYNC throw inside fn() rejects the wrapper
530
544
  // rather than escaping the .map(). allSettled then captures it.
531
- const results = await Promise.allSettled([...subs].map(async (fn) => fn(validated, envelope)));
545
+ const results = await Promise.allSettled([...subs].map(async (fn) => fn(validated, listenerCtx)));
532
546
  for (const r of results) {
533
547
  if (r.status === "rejected") {
534
548
  this.pushTelemetry({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nwire/runtime",
3
- "version": "0.11.0",
3
+ "version": "0.12.0",
4
4
  "description": "Nwire — envelope-execution substrate. Dispatch + emit + when + sink + capability registry. Extracted from @nwire/app for 0.11. Standalone usable without the App layer.",
5
5
  "keywords": [
6
6
  "capability",
@@ -27,12 +27,12 @@
27
27
  "access": "public"
28
28
  },
29
29
  "dependencies": {
30
- "@nwire/container": "0.11.0",
31
- "@nwire/handler": "0.11.0",
32
- "@nwire/logger": "0.11.0",
33
- "@nwire/messages": "0.11.0",
34
- "@nwire/envelope": "0.11.0",
35
- "@nwire/hooks": "0.11.0"
30
+ "@nwire/envelope": "0.12.0",
31
+ "@nwire/container": "0.12.0",
32
+ "@nwire/hooks": "0.12.0",
33
+ "@nwire/logger": "0.12.0",
34
+ "@nwire/messages": "0.12.0",
35
+ "@nwire/handler": "0.12.0"
36
36
  },
37
37
  "devDependencies": {
38
38
  "@types/node": "^22.19.9",