@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.
- package/.turbo/turbo-build.log +17 -17
- package/.turbo/turbo-prepack.log +6 -6
- package/README.md +29 -5
- package/build/index.d.mts +20 -7
- package/build/index.d.mts.map +1 -1
- package/build/index.mjs +44 -11
- package/build/index.mjs.map +1 -1
- package/package.json +7 -7
- package/src/decorator/action.ts +2 -2
- package/src/lib/discovery.ts +44 -9
- package/src/lib/guards.ts +9 -3
- package/src/lib/metadata.ts +8 -1
- package/tsconfig.tsbuildinfo +1 -1
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
[34mℹ[39m
|
|
4
|
-
[34mℹ[39m
|
|
5
|
-
[34mℹ[39m
|
|
6
|
-
[34mℹ[39m
|
|
7
|
-
[34mℹ[39m
|
|
8
|
-
[34mℹ[39m Hint: consider adding [34mdeps.onlyBundle[39m option to avoid unintended bundling of dependencies, or set [34mdeps.onlyBundle: false[39m to disable this hint.
|
|
9
|
-
See more at [4mhttps://tsdown.dev/options/dependencies#deps-onlybundle[24m
|
|
10
|
-
Detected dependencies in bundle:
|
|
11
|
-
- [34mrxjs[39m
|
|
12
|
-
[34mℹ[39m [2mbuild/[22m[1mindex.mjs[22m [
|
|
13
|
-
[34mℹ[39m [2mbuild/[22mindex.mjs.map [
|
|
14
|
-
[34mℹ[39m [2mbuild/[22mindex.d.mts.map [2m 2.
|
|
15
|
-
[34mℹ[39m [2mbuild/[22m[32m[1mindex.d.mts[22m[39m [2m
|
|
16
|
-
[34mℹ[39m 4 files, total:
|
|
17
|
-
[32m✔[39m Build complete in [
|
|
1
|
+
$ tsdown
|
|
2
|
+
[34mℹ[39m [34mtsdown v0.21.10[39m powered by [38;2;255;126;23mrolldown v1.0.0-rc.17[39m
|
|
3
|
+
[34mℹ[39m config file: [4m/Users/atomic/projects/silkweave/silkweave/packages/nestjs/tsdown.config.ts[24m
|
|
4
|
+
[34mℹ[39m entry: [34msrc/index.ts[39m
|
|
5
|
+
[34mℹ[39m tsconfig: [34mtsconfig.json[39m
|
|
6
|
+
[34mℹ[39m Build start
|
|
7
|
+
[34mℹ[39m Cleaning 4 files
|
|
8
|
+
[34mℹ[39m Hint: consider adding [34mdeps.onlyBundle[39m option to avoid unintended bundling of dependencies, or set [34mdeps.onlyBundle: false[39m to disable this hint.
|
|
9
|
+
See more at [4mhttps://tsdown.dev/options/dependencies#deps-onlybundle[24m
|
|
10
|
+
Detected dependencies in bundle:
|
|
11
|
+
- [34mrxjs[39m
|
|
12
|
+
[34mℹ[39m [2mbuild/[22m[1mindex.mjs[22m [2m338.49 kB[22m [2m│ gzip: 49.77 kB[22m
|
|
13
|
+
[34mℹ[39m [2mbuild/[22mindex.mjs.map [2m577.61 kB[22m [2m│ gzip: 87.77 kB[22m
|
|
14
|
+
[34mℹ[39m [2mbuild/[22mindex.d.mts.map [2m 2.99 kB[22m [2m│ gzip: 1.07 kB[22m
|
|
15
|
+
[34mℹ[39m [2mbuild/[22m[32m[1mindex.d.mts[22m[39m [2m 16.35 kB[22m [2m│ gzip: 5.75 kB[22m
|
|
16
|
+
[34mℹ[39m 4 files, total: 935.45 kB
|
|
17
|
+
[32m✔[39m Build complete in [32m742ms[39m
|
package/.turbo/turbo-prepack.log
CHANGED
|
@@ -11,9 +11,9 @@
|
|
|
11
11
|
See more at [4mhttps://tsdown.dev/options/dependencies#deps-onlybundle[24m
|
|
12
12
|
Detected dependencies in bundle:
|
|
13
13
|
- [34mrxjs[39m
|
|
14
|
-
[34mℹ[39m [2mbuild/[22m[1mindex.mjs[22m [2m337.
|
|
15
|
-
[34mℹ[39m [2mbuild/[22mindex.mjs.map [
|
|
16
|
-
[34mℹ[39m [2mbuild/[22mindex.d.mts.map [2m 2.
|
|
17
|
-
[34mℹ[39m [2mbuild/[22m[32m[1mindex.d.mts[22m[39m [2m 15.
|
|
18
|
-
[34mℹ[39m 4 files, total:
|
|
19
|
-
[32m✔[39m Build complete in [
|
|
14
|
+
[34mℹ[39m [2mbuild/[22m[1mindex.mjs[22m [2m337.92 kB[22m [2m│ gzip: 49.52 kB[22m
|
|
15
|
+
[34mℹ[39m [2mbuild/[22mindex.mjs.map [2m576.49 kB[22m [2m│ gzip: 87.36 kB[22m
|
|
16
|
+
[34mℹ[39m [2mbuild/[22mindex.d.mts.map [2m 2.98 kB[22m [2m│ gzip: 1.07 kB[22m
|
|
17
|
+
[34mℹ[39m [2mbuild/[22m[32m[1mindex.d.mts[22m[39m [2m 15.96 kB[22m [2m│ gzip: 5.58 kB[22m
|
|
18
|
+
[34mℹ[39m 4 files, total: 933.34 kB
|
|
19
|
+
[32m✔[39m Build complete in [32m828ms[39m
|
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`
|
|
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
|
|
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
|
|
261
|
-
* `ctx.get('request')
|
|
262
|
-
*
|
|
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
|
|
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
|
/**
|
package/build/index.d.mts.map
CHANGED
|
@@ -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":";;;;;;;;;;;;;;;;;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;
|
|
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
|
|
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,
|
|
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
|
|
9082
|
-
* `ctx.get('request')
|
|
9083
|
-
*
|
|
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
|
-
|
|
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
|
});
|