@silkweave/nestjs 1.10.0 → 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.
@@ -9,9 +9,9 @@ $ tsdown
9
9
  See more at https://tsdown.dev/options/dependencies#deps-onlybundle
10
10
  Detected dependencies in bundle:
11
11
  - rxjs
12
- ℹ build/index.mjs 337.92 kB │ gzip: 49.52 kB
13
- ℹ build/index.mjs.map 576.49 kB │ gzip: 87.36 kB
14
- ℹ build/index.d.mts.map  2.98 kB │ gzip: 1.07 kB
15
- ℹ build/index.d.mts  15.96 kB │ gzip: 5.58 kB
16
- ℹ 4 files, total: 933.34 kB
17
- ✔ Build complete in 1110ms
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
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
 
@@ -191,7 +190,13 @@ Mounts the MCP Streamable HTTP transport directly at `basePath`, with sideload (
191
190
 
192
191
  ## Guards & DI
193
192
 
194
- 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.
195
200
 
196
201
  Action methods are normal Nest provider methods - inject services via the constructor as usual.
197
202
 
package/build/index.d.mts CHANGED
@@ -264,9 +264,10 @@ declare class ActionDiscovery {
264
264
  * a list of core `Action` objects ready to feed into `silkweave().actions()`.
265
265
  *
266
266
  * Action invocation is wrapped to (a) run `@UseGuards` guards declared on the
267
- * method or its class against the incoming HTTP request (read from
268
- * `ctx.get('request')`) and (b) bind `this` to the resolved Nest provider so
269
- * 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.
270
271
  */
271
272
  discover(): Action$1[];
272
273
  private toAction;
@@ -294,14 +295,19 @@ type GuardRef = Type<CanActivate> | CanActivate;
294
295
  */
295
296
  declare function collectGuards(reflector: Reflector, classRef: Type<unknown>, handler: (...args: unknown[]) => unknown): GuardRef[];
296
297
  /**
297
- * Run the configured guards against an HTTP request. Throws `ForbiddenException`
298
+ * Run the configured guards against a request. Throws `ForbiddenException`
298
299
  * if any guard rejects, mirroring Nest's HTTP request-pipeline behavior.
299
300
  *
300
301
  * Pass `null` for `response` when running on top of a tRPC or MCP request that
301
302
  * doesn't surface a raw response object; guards that introspect the response
302
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'`.
303
309
  */
304
- 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>;
305
311
  //#endregion
306
312
  //#region src/lib/silkweave.module.d.ts
307
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":"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"}
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 = [];
@@ -9119,8 +9125,14 @@ let ActionDiscovery = class ActionDiscovery {
9119
9125
  const applyGuards = async (context) => {
9120
9126
  if (guards.length === 0) return;
9121
9127
  const request = context.getOptional("request");
9122
- const response = context.getOptional("response");
9123
- await runGuards(guards, moduleRef, reflector, d.classRef, d.method, request, response);
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");
9124
9136
  };
9125
9137
  if (d.method.constructor?.name === "AsyncGeneratorFunction") {
9126
9138
  if (!d.meta.chunk) throw new Error(`@Action "${name}" is an async generator but has no \`chunk\` schema`);