@silkweave/nestjs 1.9.1 → 1.11.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.
@@ -1,17 +1,17 @@
1
-
2
- $ tsdown
3
- ℹ tsdown v0.21.10 powered by rolldown v1.0.0-rc.17
4
- ℹ config file: /Users/atomic/projects/silkweave/silkweave/packages/nestjs/tsdown.config.ts
5
- ℹ entry: src/index.ts
6
- ℹ tsconfig: tsconfig.json
7
- ℹ Build start
8
- ℹ Hint: consider adding deps.onlyBundle option to avoid unintended bundling of dependencies, or set deps.onlyBundle: false to disable this hint.
9
- See more at https://tsdown.dev/options/dependencies#deps-onlybundle
10
- Detected dependencies in bundle:
11
- - rxjs
12
- ℹ build/index.mjs 337.24 kB │ gzip: 49.36 kB
13
- ℹ build/index.mjs.map 574.64 kB │ gzip: 86.89 kB
14
- ℹ build/index.d.mts.map  2.92 kB │ gzip: 1.06 kB
15
- ℹ build/index.d.mts  15.61 kB │ gzip: 5.45 kB
16
- ℹ 4 files, total: 930.42 kB
17
- ✔ Build complete in 1171ms
1
+ $ tsdown
2
+ ℹ tsdown v0.21.10 powered by rolldown v1.0.0-rc.17
3
+ ℹ config file: /Users/atomic/projects/silkweave/silkweave/packages/nestjs/tsdown.config.ts
4
+ ℹ entry: src/index.ts
5
+ ℹ tsconfig: tsconfig.json
6
+ ℹ Build start
7
+ ℹ Cleaning 4 files
8
+ ℹ Hint: consider adding deps.onlyBundle option to avoid unintended bundling of dependencies, or set deps.onlyBundle: false to disable this hint.
9
+ See more at https://tsdown.dev/options/dependencies#deps-onlybundle
10
+ Detected dependencies in bundle:
11
+ - rxjs
12
+ ℹ build/index.mjs 338.49 kB │ gzip: 49.77 kB
13
+ ℹ build/index.mjs.map 577.61 kB │ gzip: 87.77 kB
14
+ ℹ build/index.d.mts.map  2.99 kB │ gzip: 1.07 kB
15
+ ℹ build/index.d.mts  16.35 kB │ gzip: 5.75 kB
16
+ ℹ 4 files, total: 935.45 kB
17
+ ✔ Build complete in 742ms
@@ -11,9 +11,9 @@
11
11
  See more at https://tsdown.dev/options/dependencies#deps-onlybundle
12
12
  Detected dependencies in bundle:
13
13
  - rxjs
14
- ℹ build/index.mjs 337.24 kB │ gzip: 49.36 kB
15
- ℹ build/index.mjs.map 574.64 kB │ gzip: 86.89 kB
16
- ℹ build/index.d.mts.map  2.92 kB │ gzip: 1.06 kB
17
- ℹ build/index.d.mts  15.61 kB │ gzip: 5.45 kB
18
- ℹ 4 files, total: 930.42 kB
19
- ✔ Build complete in 831ms
14
+ ℹ build/index.mjs 337.92 kB │ gzip: 49.52 kB
15
+ ℹ build/index.mjs.map 576.49 kB │ gzip: 87.36 kB
16
+ ℹ build/index.d.mts.map  2.98 kB │ gzip: 1.07 kB
17
+ ℹ build/index.d.mts  15.96 kB │ gzip: 5.58 kB
18
+ ℹ 4 files, total: 933.34 kB
19
+ ✔ Build complete in 828ms
package/README.md CHANGED
@@ -47,11 +47,10 @@ export class UserActions {
47
47
  return this.db.getUser(input.id)
48
48
  }
49
49
 
50
- @UseGuards(AdminGuard)
50
+ @UseGuards(AdminGuard) // guard reads the request header on every transport, MCP included
51
51
  @Action({
52
52
  description: 'Ban a user',
53
- input: BanInput,
54
- transports: ['rest', 'trpc'] // exclude from MCP tools
53
+ input: BanInput
55
54
  })
56
55
  ban(input: z.infer<typeof BanInput>) {
57
56
  return this.db.banUser(input.id, input.reason)
@@ -98,7 +97,7 @@ The `users.list` and `users.get` actions are now reachable via:
98
97
  - **tRPC:** `client.usersList.query({ activeOnly: true })` and `client.usersGet.query({ id: '1' })`
99
98
  - **MCP:** tools `UsersList` and `UsersGet`
100
99
 
101
- `users.ban` skips MCP per its `transports: ['rest', 'trpc']` and is guarded by `@UseGuards(AdminGuard)` on every transport that has an HTTP request.
100
+ `users.ban` is guarded by `@UseGuards(AdminGuard)` on **every** transport - REST, tRPC, **and** MCP. The guard reads its credential from the request header (`switchToHttp().getRequest().headers`); over MCP the inbound tool-call headers are surfaced the same way (see [Guards & DI](#guards--di)).
102
101
 
103
102
  ## Decorators
104
103
 
@@ -110,6 +109,7 @@ The `users.list` and `users.get` actions are now reachable via:
110
109
  | `description` | `string` | *required* | Human-readable summary. Used as MCP tool description |
111
110
  | `input` | `z.ZodObject` | *required* | Zod object schema for the action's input |
112
111
  | `output` | `z.ZodObject` | - | Optional output schema (used by tRPC type inference) |
112
+ | `chunk` | `z.ZodType` | - | Schema for chunks yielded by a streaming (`async function*`) method. **Required** when the method is an async generator |
113
113
  | `kind` | `'query' \| 'mutation'` | `'mutation'` | `'query'` → GET in REST, `.query()` in tRPC. `'mutation'` → POST / `.mutation()` |
114
114
  | `transports` | `('rest' \| 'trpc' \| 'mcp')[]` | all | Allowlist of transports that expose this action |
115
115
  | `isEnabled` | `(ctx) => boolean` | - | Dynamic gate (AND-combined with `transports`) |
@@ -158,6 +158,24 @@ Mounts a tRPC HTTP handler built from `@silkweave/trpc`'s `buildRouter`.
158
158
 
159
159
  Action names with dots (e.g. `users.list`) collapse to camelCase procedure keys (`usersList`) - flat router in v1.
160
160
 
161
+ **Streaming.** An `@Action` method declared as an `async function*` (with a `chunk` schema) is registered as a tRPC **subscription** that streams each yielded chunk over SSE - exactly like a standalone `createAction({ chunk, run: async function*(){…} })`. `@UseGuards()` guards still run before the first chunk. This is what `useChat` + `@silkweave/ai`'s `silkweaveTransport()` consume.
162
+
163
+ ```ts
164
+ @Action({
165
+ description: 'Stream a countdown',
166
+ input: z.object({ from: z.number().int() }),
167
+ chunk: z.object({ n: z.number().int() })
168
+ })
169
+ async *countdown(input: { from: number }) {
170
+ for (let n = input.from; n >= 0; n -= 1) {
171
+ await new Promise((r) => setTimeout(r, 200))
172
+ yield { n }
173
+ }
174
+ }
175
+ ```
176
+
177
+ Declaring an async-generator method without a `chunk` schema throws at discovery time - the schema is required for typegen/tRPC to expose the subscription.
178
+
161
179
  ### `mcp(options?)`
162
180
 
163
181
  Mounts the MCP Streamable HTTP transport directly at `basePath`, with sideload (`{basePath}/resource/:id`), well-known auth metadata (`{basePath}/.well-known/...`), and the OAuth proxy routes (`{basePath}/authorize`, `/token`, `/register`, `/auth/callback`) namespaced under the same prefix. Composes the handler primitives from `@silkweave/mcp` - no Express sub-app.
@@ -172,7 +190,13 @@ Mounts the MCP Streamable HTTP transport directly at `basePath`, with sideload (
172
190
 
173
191
  ## Guards & DI
174
192
 
175
- Native NestJS `@UseGuards()` and `@UseInterceptors()` on `@Action` methods run for every HTTP-backed transport. Guards receive an `ExecutionContext` with the HTTP request in `switchToHttp().getRequest()`. The `Reflector` is also wired up so guards can read custom metadata.
193
+ Native NestJS `@UseGuards()` and `@UseInterceptors()` on `@Action` methods run for **every** transport - REST, tRPC, and MCP. Guards receive an `ExecutionContext` with the request in `switchToHttp().getRequest()`. The `Reflector` is also wired up so guards can read custom metadata.
194
+
195
+ **Headers over MCP.** REST and tRPC pass the raw HTTP request to the guard. For MCP (Streamable HTTP), the inbound tool-call request is surfaced as a stand-in `{ headers, url, params, query }` object built from the MCP SDK's `extra.requestInfo`, so a header-based guard - e.g. one reading `getRequest().headers['x-api-key']` - works unchanged. `ExecutionContext.getType()` is `'http'` whenever a request is available (and `'rpc'` for transports with none, e.g. MCP stdio). Caveats:
196
+
197
+ - Only **headers** (and the request `url`) cross the MCP boundary. There are no path `params` or `query` on an MCP tool call, so `getRequest().params` / `.query` are empty objects - guards relying on them degrade to "deny" rather than crash.
198
+ - A guard that denies (returns `false` or throws) produces a clean MCP tool error (`ForbiddenException`), not an HTTP 500.
199
+ - For OAuth 2.1 / bearer-token MCP auth, prefer `mcp({ auth })` and read the resolved identity from the silkweave context (`ctx.get('auth')`) inside the action; the header stand-in is for custom request-reading guards.
176
200
 
177
201
  Action methods are normal Nest provider methods - inject services via the constructor as usual.
178
202
 
package/build/index.d.mts CHANGED
@@ -157,7 +157,7 @@ declare function typegen(options: TypegenAdapterOptions): NestSilkweaveAdapter;
157
157
  declare const ACTION_METADATA = "__silkweave_action__";
158
158
  declare const ACTIONS_METADATA = "__silkweave_actions__";
159
159
  type Transport = 'rest' | 'trpc' | 'mcp';
160
- interface ActionMetadata<I extends object = object, O extends object = object> {
160
+ interface ActionMetadata<I extends object = object, O extends object = object, C = unknown> {
161
161
  /** Action name. Defaults to the kebab-cased method name. */
162
162
  name?: string;
163
163
  /** Human-readable description. Becomes the MCP tool description and REST OpenAPI summary. */
@@ -170,6 +170,13 @@ interface ActionMetadata<I extends object = object, O extends object = object> {
170
170
  output?: z$1.ZodType<O> & {
171
171
  shape: Record<string, z$1.ZodTypeAny>;
172
172
  };
173
+ /**
174
+ * Zod schema for individual chunks yielded by a streaming (async-generator)
175
+ * action method. Required when the decorated method is an `async function*`.
176
+ * Mirrors `Action.chunk` in @silkweave/core; typegen/trpc use it to expose
177
+ * the action as a tRPC subscription.
178
+ */
179
+ chunk?: z$1.ZodType<C>;
173
180
  /** `'query'` (GET in REST, `.query()` in tRPC) or `'mutation'` (POST in REST, `.mutation()` in tRPC). Default: `'mutation'`. */
174
181
  kind?: ActionKind;
175
182
  /** Allowlist of transports that should expose this action. Default: all registered transports. */
@@ -226,7 +233,7 @@ declare const ACTION_RESPONSE_KEY = "__silkweave_response__";
226
233
  * }
227
234
  * ```
228
235
  */
229
- declare function Action<I extends object = object, O extends object = object>(options: ActionMetadata<I, O>): MethodDecorator;
236
+ declare function Action<I extends object = object, O extends object = object, C = unknown>(options: ActionMetadata<I, O, C>): MethodDecorator;
230
237
  //#endregion
231
238
  //#region src/decorator/actions.d.ts
232
239
  /**
@@ -257,9 +264,10 @@ declare class ActionDiscovery {
257
264
  * a list of core `Action` objects ready to feed into `silkweave().actions()`.
258
265
  *
259
266
  * Action invocation is wrapped to (a) run `@UseGuards` guards declared on the
260
- * method or its class against the incoming HTTP request (read from
261
- * `ctx.get('request')`) and (b) bind `this` to the resolved Nest provider so
262
- * DI-injected dependencies remain available.
267
+ * method or its class against the incoming request (read from
268
+ * `ctx.get('request')`, populated by REST/tRPC and by MCP-over-HTTP from the
269
+ * SDK's `extra.requestInfo`) and (b) bind `this` to the resolved Nest provider
270
+ * so DI-injected dependencies remain available.
263
271
  */
264
272
  discover(): Action$1[];
265
273
  private toAction;
@@ -287,14 +295,19 @@ type GuardRef = Type<CanActivate> | CanActivate;
287
295
  */
288
296
  declare function collectGuards(reflector: Reflector, classRef: Type<unknown>, handler: (...args: unknown[]) => unknown): GuardRef[];
289
297
  /**
290
- * Run the configured guards against an HTTP request. Throws `ForbiddenException`
298
+ * Run the configured guards against a request. Throws `ForbiddenException`
291
299
  * if any guard rejects, mirroring Nest's HTTP request-pipeline behavior.
292
300
  *
293
301
  * Pass `null` for `response` when running on top of a tRPC or MCP request that
294
302
  * doesn't surface a raw response object; guards that introspect the response
295
303
  * will receive `null`.
304
+ *
305
+ * `contextType` is reflected through `ExecutionContext.getType()` so guards can
306
+ * branch on the transport. It is `'http'` for REST/tRPC and for MCP-over-HTTP
307
+ * (where a header-bearing request stand-in is available); transports without any
308
+ * HTTP request (e.g. MCP stdio) pass `'rpc'`.
296
309
  */
297
- declare function runGuards(guards: GuardRef[], moduleRef: ModuleRef, reflector: Reflector, classRef: Type<unknown>, handler: (...args: unknown[]) => unknown, request: unknown, response: unknown): Promise<void>;
310
+ declare function runGuards(guards: GuardRef[], moduleRef: ModuleRef, reflector: Reflector, classRef: Type<unknown>, handler: (...args: unknown[]) => unknown, request: unknown, response: unknown, contextType?: 'http' | 'rpc'): Promise<void>;
298
311
  //#endregion
299
312
  //#region src/lib/silkweave.module.d.ts
300
313
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/lib/types.ts","../src/adapter/mcp.ts","../src/adapter/rest.ts","../src/adapter/trpc.ts","../src/adapter/typegen.ts","../src/lib/metadata.ts","../src/decorator/action.ts","../src/decorator/actions.ts","../src/lib/discovery.ts","../src/lib/filter.ts","../src/lib/guards.ts","../src/lib/silkweave.module.ts"],"mappings":"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"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/lib/types.ts","../src/adapter/mcp.ts","../src/adapter/rest.ts","../src/adapter/trpc.ts","../src/adapter/typegen.ts","../src/lib/metadata.ts","../src/decorator/action.ts","../src/decorator/actions.ts","../src/lib/discovery.ts","../src/lib/filter.ts","../src/lib/guards.ts","../src/lib/silkweave.module.ts"],"mappings":";;;;;;;;;;;;;;;;;UAUiB,0BAAA;EAAA;EAEf,WAAA,EAAa,WAAA,CAAY,eAAA;;EAEzB,gBAAA,EAAkB,gBAAA;EAFL;EAIb,WAAA,EAAa,gBAAA;EAAA;EAEb,OAAA,EAAS,QAAA;AAAA;;;;;;;;UAUM,oBAAA;EAVf;EAAA,SAYS,IAAA;EAZM;;AAUjB;;;;EAViB,SAmBN,UAAA;EAAA;EAET,QAAA,CAAS,GAAA,EAAK,0BAAA;AAAA;AAAA,UAGC,sBAAA;EAHyB;EAKxC,SAAA,EAAW,gBAAA;EAFI;EAIf,QAAA,EAAU,oBAAA;;EAEV,OAAA,GAAU,MAAA;AAAA;AAAA,cAGC,wBAAA;;;UCtCI,iBAAA;;EAEf,QAAA;;EAEA,IAAA,GAAO,UAAA;;EAEP,IAAA,GAAO,WAAA;EDTQ;ECWf,iBAAA;;EAEA,WAAA;AAAA;;;;;;;;;;;;;;;iBA6Bc,GAAA,CAAI,OAAA,GAAS,iBAAA,GAAyB,oBAAA;;;UChCrC,kBAAA;;EAEf,QAAA;;EAEA,IAAA,GAAO,UAAA;AAAA;;;AFdT;;;;;;;;;iBEwIgB,IAAA,CAAK,OAAA,GAAS,kBAAA,GAA0B,oBAAA;;;UC5IvC,kBAAA;;EAEf,QAAA;;EAEA,IAAA,GAAO,UAAA;AAAA;;;AHAT;;;;;;;;;iBGcgB,IAAA,CAAK,OAAA,GAAS,kBAAA,GAA0B,oBAAA;;;UCnBvC,qBAAA;;EAEf,IAAA;;;;;;AJGF;EIIE,MAAA,GAAS,aAAA;;;;;;EAMT,OAAA;AAAA;;;;;;;;;;iBAYc,OAAA,CAAQ,OAAA,EAAS,qBAAA,GAAwB,oBAAA;;;cC7B5C,eAAA;AAAA,cACA,gBAAA;AAAA,KAED,SAAA;AAAA,UAEK,cAAA;;EAEf,IAAA;;EAEA,WAAA;ELFe;EKIf,KAAA,EAAO,GAAA,CAAE,OAAA,CAAQ,CAAA;IAAO,KAAA,EAAO,MAAA,SAAe,GAAA,CAAE,UAAA;EAAA;ELFnC;EKIb,MAAA,GAAS,GAAA,CAAE,OAAA,CAAQ,CAAA;IAAO,KAAA,EAAO,MAAA,SAAe,GAAA,CAAE,UAAA;EAAA;ELEnC;;;;;;EKKf,KAAA,GAAQ,GAAA,CAAE,OAAA,CAAQ,CAAA;ELPlB;EKSA,IAAA,GAAO,UAAA;ELPP;EKSA,UAAA,GAAa,SAAA;ELTE;EKWf,SAAA,IAAa,OAAA,EAAS,gBAAA;ELDP;EKGf,UAAA,GAAa,QAAA,CAAO,CAAA,EAAG,CAAA;;EAEvB,IAAA,UAAc,CAAA;ELHL;EKKT,WAAA;AAAA;AAAA,UAGe,oBAAA;ELCN;EKCT,MAAA;ELDwC;EKGxC,UAAA,GAAa,SAAA;AAAA;AAAA,UAGE,gBAAA;EACf,UAAA,GAAa,QAAA,SAAe,CAAA;AAAA;AAAA,KAGlB,iBAAA,GAAoB,cAAA,mBAAiC,gBAAA;AAAA,cAEpD,mBAAA;;;;;;;;;;;;ALzCb;;;;;;;;;;;;;;;;;;;;;iBMuBgB,MAAA,mEAAA,CACd,OAAA,EAAS,cAAA,CAAe,CAAA,EAAG,CAAA,EAAG,CAAA,IAC7B,eAAA;;;;;;;;;;;;ANzBH;;;;;iBOOgB,OAAA,CAAQ,eAAA,YAA0B,oBAAA,GAA4B,cAAA;;;cCEjE,eAAA;EAAA,iBAEQ,SAAA;EAAA,iBACA,OAAA;EAAA,iBACA,SAAA;EAAA,iBACA,SAAA;cAHA,SAAA,EAAW,gBAAA,EACX,OAAA,EAAS,eAAA,EACT,SAAA,EAAW,SAAA,EACX,SAAA,EAAW,SAAA;;;ARdhC;;;;;;;;EQ2BE,QAAA,CAAA,GAAY,QAAA;EAAA,QAqBJ,QAAA;AAAA;;;;;;;;;;;ARhDV;;iBSGgB,cAAA,CACd,UAAA,EAAY,SAAA,gBACZ,aAAA,IAAiB,GAAA,EAAK,gBAAA,8BACnB,GAAA,EAAK,gBAAA;;;KCVL,QAAA,GAAW,IAAA,CAAK,WAAA,IAAe,WAAA;;;;;;iBAOpB,aAAA,CACd,SAAA,EAAW,SAAA,EACX,QAAA,EAAU,IAAA,WACV,OAAA,MAAa,IAAA,0BACZ,QAAA;;AVPH;;;;;;;;;;;;iBUqCsB,SAAA,CACpB,MAAA,EAAQ,QAAA,IACR,SAAA,EAAW,SAAA,EACX,SAAA,EAAW,SAAA,EACX,QAAA,EAAU,IAAA,WACV,OAAA,MAAa,IAAA,yBACb,OAAA,WACA,QAAA,WACA,WAAA,oBACC,OAAA;;;;;;;;;AV9CH;;;;;;;;;;;;;;;;;;;;;AAkBA;cWOa,eAAA,YAA2B,UAAA;EAAA,iBAEe,OAAA;EAAA,iBAClC,SAAA;EAAA,iBACA,eAAA;cAFkC,OAAA,EAAS,sBAAA,EAC3C,SAAA,EAAW,eAAA,EACX,eAAA,EAAiB,eAAA;EAAA,OAG7B,OAAA,CAAQ,OAAA,EAAS,sBAAA,GAAyB,aAAA;EAajD,SAAA,CAAU,SAAA,EAAW,kBAAA;AAAA"}
package/build/index.mjs CHANGED
@@ -9035,16 +9035,21 @@ async function resolveGuard(ref, moduleRef) {
9035
9035
  return ref;
9036
9036
  }
9037
9037
  /**
9038
- * Run the configured guards against an HTTP request. Throws `ForbiddenException`
9038
+ * Run the configured guards against a request. Throws `ForbiddenException`
9039
9039
  * if any guard rejects, mirroring Nest's HTTP request-pipeline behavior.
9040
9040
  *
9041
9041
  * Pass `null` for `response` when running on top of a tRPC or MCP request that
9042
9042
  * doesn't surface a raw response object; guards that introspect the response
9043
9043
  * will receive `null`.
9044
+ *
9045
+ * `contextType` is reflected through `ExecutionContext.getType()` so guards can
9046
+ * branch on the transport. It is `'http'` for REST/tRPC and for MCP-over-HTTP
9047
+ * (where a header-bearing request stand-in is available); transports without any
9048
+ * HTTP request (e.g. MCP stdio) pass `'rpc'`.
9044
9049
  */
9045
- async function runGuards(guards, moduleRef, reflector, classRef, handler, request, response) {
9050
+ async function runGuards(guards, moduleRef, reflector, classRef, handler, request, response, contextType = "http") {
9046
9051
  if (guards.length === 0) return;
9047
- const context = new SilkweaveExecutionContext([request, response], classRef, handler, "http");
9052
+ const context = new SilkweaveExecutionContext([request, response], classRef, handler, contextType);
9048
9053
  for (const ref of guards) {
9049
9054
  const result = (await resolveGuard(ref, moduleRef)).canActivate(context);
9050
9055
  if (!((0, import_cjs.isObservable)(result) ? await (0, import_cjs.lastValueFrom)(result) : await Promise.resolve(result))) throw new ForbiddenException("Forbidden resource");
@@ -9078,9 +9083,10 @@ let ActionDiscovery = class ActionDiscovery {
9078
9083
  * a list of core `Action` objects ready to feed into `silkweave().actions()`.
9079
9084
  *
9080
9085
  * Action invocation is wrapped to (a) run `@UseGuards` guards declared on the
9081
- * method or its class against the incoming HTTP request (read from
9082
- * `ctx.get('request')`) and (b) bind `this` to the resolved Nest provider so
9083
- * DI-injected dependencies remain available.
9086
+ * method or its class against the incoming request (read from
9087
+ * `ctx.get('request')`, populated by REST/tRPC and by MCP-over-HTTP from the
9088
+ * SDK's `extra.requestInfo`) and (b) bind `this` to the resolved Nest provider
9089
+ * so DI-injected dependencies remain available.
9084
9090
  */
9085
9091
  discover() {
9086
9092
  const discovered = [];
@@ -9116,6 +9122,37 @@ let ActionDiscovery = class ActionDiscovery {
9116
9122
  const guards = collectGuards(this.reflector, d.classRef, d.method);
9117
9123
  const moduleRef = this.moduleRef;
9118
9124
  const reflector = this.reflector;
9125
+ const applyGuards = async (context) => {
9126
+ if (guards.length === 0) return;
9127
+ const request = context.getOptional("request");
9128
+ const response = context.getOptional("response") ?? null;
9129
+ const hasRequest = request != null;
9130
+ const guardRequest = hasRequest ? request : {
9131
+ headers: {},
9132
+ params: {},
9133
+ query: {}
9134
+ };
9135
+ await runGuards(guards, moduleRef, reflector, d.classRef, d.method, guardRequest, response, hasRequest ? "http" : "rpc");
9136
+ };
9137
+ if (d.method.constructor?.name === "AsyncGeneratorFunction") {
9138
+ if (!d.meta.chunk) throw new Error(`@Action "${name}" is an async generator but has no \`chunk\` schema`);
9139
+ const method = d.method;
9140
+ const instance = d.instance;
9141
+ return createAction({
9142
+ name,
9143
+ description: d.meta.description,
9144
+ input: d.meta.input,
9145
+ chunk: d.meta.chunk,
9146
+ kind: d.meta.kind ?? "mutation",
9147
+ args: d.meta.args,
9148
+ isEnabled,
9149
+ toolResult: d.meta.toolResult,
9150
+ run: async function* (input, context) {
9151
+ await applyGuards(context);
9152
+ yield* method.call(instance, input, context);
9153
+ }
9154
+ });
9155
+ }
9119
9156
  return createAction({
9120
9157
  name,
9121
9158
  description: d.meta.description,
@@ -9126,11 +9163,7 @@ let ActionDiscovery = class ActionDiscovery {
9126
9163
  isEnabled,
9127
9164
  toolResult: d.meta.toolResult,
9128
9165
  run: async (input, context) => {
9129
- if (guards.length > 0) {
9130
- const request = context.getOptional("request");
9131
- const response = context.getOptional("response");
9132
- await runGuards(guards, moduleRef, reflector, d.classRef, d.method, request, response);
9133
- }
9166
+ await applyGuards(context);
9134
9167
  return await d.method.call(d.instance, input, context);
9135
9168
  }
9136
9169
  });