@silkweave/nestjs 1.9.0 → 1.10.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 +7 -7
- package/.turbo/turbo-check.log +1 -2
- package/.turbo/turbo-lint.log +2 -0
- package/.turbo/turbo-prepack.log +19 -0
- package/README.md +36 -15
- package/build/index.d.mts +119 -89
- package/build/index.d.mts.map +1 -1
- package/build/index.mjs +197 -200
- package/build/index.mjs.map +1 -1
- package/package.json +12 -6
- package/src/adapter/mcp.ts +84 -37
- package/src/adapter/rest.ts +39 -57
- package/src/adapter/trpc.ts +27 -51
- package/src/adapter/typegen.ts +55 -0
- package/src/decorator/action.ts +2 -2
- package/src/decorator/actions.ts +1 -1
- package/src/index.ts +1 -1
- package/src/lib/discovery.ts +41 -14
- package/src/lib/executionContext.ts +3 -3
- package/src/lib/guards.ts +2 -2
- package/src/lib/metadata.ts +8 -1
- package/src/lib/silkweave.module.ts +40 -17
- package/src/lib/types.ts +35 -20
- package/tsconfig.tsbuildinfo +1 -1
- package/src/lib/silkweave.service.ts +0 -58
- package/src/lib/slot.ts +0 -51
package/src/lib/guards.ts
CHANGED
|
@@ -24,7 +24,7 @@ export function collectGuards(
|
|
|
24
24
|
async function resolveGuard(ref: GuardRef, moduleRef: ModuleRef): Promise<CanActivate> {
|
|
25
25
|
if (typeof ref === 'function') {
|
|
26
26
|
try {
|
|
27
|
-
return moduleRef.get(ref, { strict: false })
|
|
27
|
+
return await moduleRef.get(ref, { strict: false })
|
|
28
28
|
} catch {
|
|
29
29
|
return moduleRef.create(ref)
|
|
30
30
|
}
|
|
@@ -59,6 +59,6 @@ export async function runGuards(
|
|
|
59
59
|
throw new ForbiddenException('Forbidden resource')
|
|
60
60
|
}
|
|
61
61
|
}
|
|
62
|
-
// Reflector kept in the signature for future use (e.g., per-guard metadata)
|
|
62
|
+
// Reflector kept in the signature for future use (e.g., per-guard metadata) - unused here.
|
|
63
63
|
void reflector
|
|
64
64
|
}
|
package/src/lib/metadata.ts
CHANGED
|
@@ -6,7 +6,7 @@ export const ACTIONS_METADATA = '__silkweave_actions__'
|
|
|
6
6
|
|
|
7
7
|
export type Transport = 'rest' | 'trpc' | 'mcp'
|
|
8
8
|
|
|
9
|
-
export interface ActionMetadata<I extends object = object, O extends object = object> {
|
|
9
|
+
export interface ActionMetadata<I extends object = object, O extends object = object, C = unknown> {
|
|
10
10
|
/** Action name. Defaults to the kebab-cased method name. */
|
|
11
11
|
name?: string
|
|
12
12
|
/** Human-readable description. Becomes the MCP tool description and REST OpenAPI summary. */
|
|
@@ -15,6 +15,13 @@ export interface ActionMetadata<I extends object = object, O extends object = ob
|
|
|
15
15
|
input: z.ZodType<I> & { shape: Record<string, z.ZodTypeAny> }
|
|
16
16
|
/** Optional Zod object schema for the action's output (used by tRPC type inference). */
|
|
17
17
|
output?: z.ZodType<O> & { shape: Record<string, z.ZodTypeAny> }
|
|
18
|
+
/**
|
|
19
|
+
* Zod schema for individual chunks yielded by a streaming (async-generator)
|
|
20
|
+
* action method. Required when the decorated method is an `async function*`.
|
|
21
|
+
* Mirrors `Action.chunk` in @silkweave/core; typegen/trpc use it to expose
|
|
22
|
+
* the action as a tRPC subscription.
|
|
23
|
+
*/
|
|
24
|
+
chunk?: z.ZodType<C>
|
|
18
25
|
/** `'query'` (GET in REST, `.query()` in tRPC) or `'mutation'` (POST in REST, `.mutation()` in tRPC). Default: `'mutation'`. */
|
|
19
26
|
kind?: ActionKind
|
|
20
27
|
/** Allowlist of transports that should expose this action. Default: all registered transports. */
|
|
@@ -1,23 +1,22 @@
|
|
|
1
|
-
import { Module, type DynamicModule } from '@nestjs/common'
|
|
2
|
-
import { DiscoveryModule } from '@nestjs/core'
|
|
1
|
+
import { Inject, Module, type DynamicModule, type MiddlewareConsumer, type NestModule } from '@nestjs/common'
|
|
2
|
+
import { DiscoveryModule, HttpAdapterHost } from '@nestjs/core'
|
|
3
|
+
import { createContext } from '@silkweave/core'
|
|
3
4
|
import { ActionDiscovery } from './discovery.js'
|
|
4
|
-
import { SilkweaveService } from './silkweave.service.js'
|
|
5
5
|
import { SILKWEAVE_MODULE_OPTIONS, type SilkweaveModuleOptions } from './types.js'
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Root module for `@silkweave/nestjs`.
|
|
9
9
|
*
|
|
10
|
-
* Discovers every `@Action`-decorated method
|
|
11
|
-
* `
|
|
12
|
-
*
|
|
13
|
-
*
|
|
10
|
+
* Discovers every `@Action`-decorated method via `DiscoveryService` and
|
|
11
|
+
* registers the configured adapters (`rest()`, `trpc()`, `mcp()`) directly on
|
|
12
|
+
* Nest's HTTP adapter inside `configure()`. Because `configure()` runs during
|
|
13
|
+
* `registerModules` - before Nest's `registerRouter()` step - Silkweave's
|
|
14
|
+
* routes always sit ahead of every controller in the Express stack. There is
|
|
15
|
+
* no slot middleware, no race with Nest's 404 catch-all, and every route
|
|
16
|
+
* shows up in Nest's `RoutesResolver` logger.
|
|
14
17
|
*
|
|
15
18
|
* @example
|
|
16
19
|
* ```ts
|
|
17
|
-
* import { Module } from '@nestjs/common'
|
|
18
|
-
* import { SilkweaveModule, rest, trpc, mcp } from '@silkweave/nestjs'
|
|
19
|
-
* import { UsersModule } from './users.module.js'
|
|
20
|
-
*
|
|
21
20
|
* @Module({
|
|
22
21
|
* imports: [
|
|
23
22
|
* SilkweaveModule.forRoot({
|
|
@@ -27,15 +26,20 @@ import { SILKWEAVE_MODULE_OPTIONS, type SilkweaveModuleOptions } from './types.j
|
|
|
27
26
|
* trpc({ basePath: '/trpc' }),
|
|
28
27
|
* mcp({ basePath: '/mcp' })
|
|
29
28
|
* ]
|
|
30
|
-
* })
|
|
31
|
-
* UsersModule
|
|
29
|
+
* })
|
|
32
30
|
* ]
|
|
33
31
|
* })
|
|
34
32
|
* export class AppModule {}
|
|
35
33
|
* ```
|
|
36
34
|
*/
|
|
37
35
|
@Module({})
|
|
38
|
-
export class SilkweaveModule {
|
|
36
|
+
export class SilkweaveModule implements NestModule {
|
|
37
|
+
constructor(
|
|
38
|
+
@Inject(SILKWEAVE_MODULE_OPTIONS) private readonly options: SilkweaveModuleOptions,
|
|
39
|
+
private readonly discovery: ActionDiscovery,
|
|
40
|
+
private readonly httpAdapterHost: HttpAdapterHost
|
|
41
|
+
) { }
|
|
42
|
+
|
|
39
43
|
static forRoot(options: SilkweaveModuleOptions): DynamicModule {
|
|
40
44
|
return {
|
|
41
45
|
module: SilkweaveModule,
|
|
@@ -43,10 +47,29 @@ export class SilkweaveModule {
|
|
|
43
47
|
imports: [DiscoveryModule],
|
|
44
48
|
providers: [
|
|
45
49
|
{ provide: SILKWEAVE_MODULE_OPTIONS, useValue: options },
|
|
46
|
-
ActionDiscovery
|
|
47
|
-
SilkweaveService
|
|
50
|
+
ActionDiscovery
|
|
48
51
|
],
|
|
49
|
-
exports: [
|
|
52
|
+
exports: []
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
configure(_consumer: MiddlewareConsumer): void {
|
|
57
|
+
const httpAdapter = this.httpAdapterHost.httpAdapter
|
|
58
|
+
if (!httpAdapter) {
|
|
59
|
+
throw new Error('@silkweave/nestjs: HttpAdapterHost.httpAdapter is not available.')
|
|
60
|
+
}
|
|
61
|
+
const allActions = this.discovery.discover()
|
|
62
|
+
for (const adapter of this.options.adapters) {
|
|
63
|
+
const baseContext = createContext({ ...(this.options.context ?? {}), adapter: adapter.name })
|
|
64
|
+
const actions = adapter.allActions
|
|
65
|
+
? allActions
|
|
66
|
+
: allActions.filter((a) => !a.isEnabled || a.isEnabled(baseContext))
|
|
67
|
+
adapter.register({
|
|
68
|
+
httpAdapter,
|
|
69
|
+
silkweaveOptions: this.options.silkweave,
|
|
70
|
+
baseContext,
|
|
71
|
+
actions
|
|
72
|
+
})
|
|
50
73
|
}
|
|
51
74
|
}
|
|
52
75
|
}
|
package/src/lib/types.ts
CHANGED
|
@@ -1,36 +1,51 @@
|
|
|
1
1
|
import type { HttpAdapterHost } from '@nestjs/core'
|
|
2
|
-
import type {
|
|
2
|
+
import type { Action, SilkweaveContext, SilkweaveOptions } from '@silkweave/core'
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* placeholder middleware
|
|
8
|
-
* `
|
|
9
|
-
*
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
5
|
+
* Context passed to a Nest Silkweave adapter when `SilkweaveModule` wires it
|
|
6
|
+
* up. Adapters register their routes directly on `httpAdapter` (no
|
|
7
|
+
* placeholder middleware, no `silkweave()` builder), so they only fire
|
|
8
|
+
* `register()` once and own the rest of their lifecycle implicitly through
|
|
9
|
+
* Nest.
|
|
10
|
+
*/
|
|
11
|
+
export interface NestAdapterRegisterContext {
|
|
12
|
+
/** Nest's underlying HTTP adapter (Express or Fastify). */
|
|
13
|
+
httpAdapter: NonNullable<HttpAdapterHost['httpAdapter']>
|
|
14
|
+
/** Identity the adapter surfaces to clients (e.g. MCP server name). */
|
|
15
|
+
silkweaveOptions: SilkweaveOptions
|
|
16
|
+
/** Per-adapter context - already forked with `{ adapter: adapter.name, ...userContext }`. */
|
|
17
|
+
baseContext: SilkweaveContext
|
|
18
|
+
/** Actions filtered to those enabled on this adapter. */
|
|
19
|
+
actions: Action[]
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* A Silkweave Nest adapter. Each transport (REST, tRPC, MCP) implements this
|
|
24
|
+
* shape. `register()` is called from `SilkweaveModule.configure()` - which
|
|
25
|
+
* runs *before* Nest's controller routes are mapped - so adapter routes
|
|
26
|
+
* always sit ahead of any catch-all controllers in the framework's request
|
|
27
|
+
* pipeline.
|
|
16
28
|
*/
|
|
17
29
|
export interface NestSilkweaveAdapter {
|
|
18
|
-
/** Adapter discriminator
|
|
19
|
-
readonly name: 'rest' | 'trpc' | 'mcp'
|
|
30
|
+
/** Adapter discriminator - set on the silkweave context as `ctx.get('adapter')`. */
|
|
31
|
+
readonly name: 'rest' | 'trpc' | 'mcp' | 'typegen'
|
|
20
32
|
/**
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
* that
|
|
33
|
+
* When `true`, the adapter receives every discovered action regardless of
|
|
34
|
+
* each action's `transports` allowlist / `isEnabled` gate. Used by
|
|
35
|
+
* non-runtime adapters like `typegen()` that emit types for the entire
|
|
36
|
+
* action surface.
|
|
24
37
|
*/
|
|
25
|
-
|
|
38
|
+
readonly allActions?: boolean
|
|
39
|
+
/** Register this adapter's routes on Nest's HTTP server. */
|
|
40
|
+
register(ctx: NestAdapterRegisterContext): void
|
|
26
41
|
}
|
|
27
42
|
|
|
28
43
|
export interface SilkweaveModuleOptions {
|
|
29
|
-
/** Identity for the silkweave instance
|
|
44
|
+
/** Identity for the silkweave instance - surfaced to MCP clients, OpenAPI, etc. */
|
|
30
45
|
silkweave: SilkweaveOptions
|
|
31
46
|
/** Adapters to mount. Examples: `rest()`, `trpc()`, `mcp()`. */
|
|
32
47
|
adapters: NestSilkweaveAdapter[]
|
|
33
|
-
/** Initial context keys
|
|
48
|
+
/** Initial context keys merged into every adapter's `baseContext`. */
|
|
34
49
|
context?: Record<string, unknown>
|
|
35
50
|
}
|
|
36
51
|
|