@kabyeon/nexusjs 0.6.6 → 0.6.8
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/README.md +20 -10
- package/dist/auth/index.js.map +1 -1
- package/dist/cache/index.js.map +1 -1
- package/dist/cli/index.js.map +1 -1
- package/dist/config/index.js.map +1 -1
- package/dist/drive/index.js.map +1 -1
- package/dist/drizzle/index.js.map +1 -1
- package/dist/events/index.js.map +1 -1
- package/dist/grpc/index.js.map +1 -1
- package/dist/health/index.js.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/limiter/index.js.map +1 -1
- package/dist/logger/index.js.map +1 -1
- package/dist/mail/index.js.map +1 -1
- package/dist/openapi/index.js.map +1 -1
- package/dist/package.json +1 -1
- package/dist/queue/index.js.map +1 -1
- package/dist/redis/index.js.map +1 -1
- package/dist/schedule/index.js.map +1 -1
- package/dist/session/index.js.map +1 -1
- package/dist/shield/index.js.map +1 -1
- package/dist/tracing/index.js.map +1 -1
- package/dist/upload/index.js.map +1 -1
- package/dist/ws/index.js.map +1 -1
- package/package.json +1 -3
package/README.md
CHANGED
|
@@ -82,17 +82,29 @@ v0.4 release notes.
|
|
|
82
82
|
## Install
|
|
83
83
|
|
|
84
84
|
```bash
|
|
85
|
-
|
|
85
|
+
# Scaffold a new project
|
|
86
|
+
bunx create-nexusjs my-app
|
|
86
87
|
cd my-app
|
|
87
88
|
bun install
|
|
88
89
|
bun run dev
|
|
89
90
|
```
|
|
90
91
|
|
|
91
|
-
Or
|
|
92
|
+
Or use npm:
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
npx create-nexusjs my-app
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Manual setup in an existing project
|
|
92
99
|
|
|
93
100
|
```bash
|
|
94
101
|
bun add @kabyeon/nexusjs reflect-metadata zod hono
|
|
95
|
-
|
|
102
|
+
npx @kabyeon/nexusjs init
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Add the modules you need:
|
|
106
|
+
|
|
107
|
+
```bash
|
|
96
108
|
bun add @kabyeon/nexusjs/drizzle # the default ORM
|
|
97
109
|
bun add @kabyeon/nexusjs/auth # authentication
|
|
98
110
|
bun add @kabyeon/nexusjs/queue # background jobs
|
|
@@ -101,9 +113,7 @@ bun add @kabyeon/nexusjs/openapi # OpenAPI docs
|
|
|
101
113
|
```
|
|
102
114
|
|
|
103
115
|
Every module is its own bundle entry point — install only what you
|
|
104
|
-
use. The CLI (`nx`) is included with `@kabyeon/nexusjs
|
|
105
|
-
|
|
106
|
-
```
|
|
116
|
+
use. The CLI (`nx`) is included with `@kabyeon/nexusjs`.
|
|
107
117
|
|
|
108
118
|
---
|
|
109
119
|
|
|
@@ -813,10 +823,10 @@ v1.0, only major bumps will.
|
|
|
813
823
|
- **v0.2** (2026-05-15) — `@kabyeon/nexusjs/auth`, `@kabyeon/nexusjs/queue`, `@kabyeon/nexusjs/schedule`, `@kabyeon/nexusjs/events`, `@kabyeon/nexusjs/session`, full `nx` CLI.
|
|
814
824
|
- **v0.3** (2026-06-21) — production basics, cross-cutting features, `@kabyeon/nexusjs/drizzle` as the default ORM.
|
|
815
825
|
- **v0.4** (2026-06-22) — observability + DX: `@kabyeon/nexusjs/openapi`, `@kabyeon/nexusjs/upload`, `@kabyeon/nexusjs/sse`, `@kabyeon/nexusjs/tracing`, `@kabyeon/nexusjs/metrics`, request-scoped DI in core.
|
|
816
|
-
- **v0.5** (2026-06-
|
|
817
|
-
- **v0.6** (2026-06-
|
|
818
|
-
- **v0.6.1** (2026-06-
|
|
819
|
-
- **v0.6.3** (2026-06-
|
|
826
|
+
- **v0.5** (2026-06-22) — realtime + crypto + i18n + redis: `@kabyeon/nexusjs/ws`, `@kabyeon/nexusjs/crypto`, `@kabyeon/nexusjs/i18n`, `@kabyeon/nexusjs/redis`.
|
|
827
|
+
- **v0.6** (2026-06-22) — gRPC + tooling: `@kabyeon/nexusjs/grpc` (reflection-based server + typed client) and a publishable `dist/` pipeline (`bin` field, `dist/src/*` flatten).
|
|
828
|
+
- **v0.6.1** (2026-06-22) — patch: `nexus` → `@kabyeon/nexusjs` rename across all sources (191 files), `bin` field fix, `dist/src/*` flatten, docs in sync with the published name. No new features.
|
|
829
|
+
- **v0.6.3** (2026-06-22) — view engine extracted to `@kabyeon/nexusjs/view`, Eta adapter, file-based view paths, auto-detection by extension.
|
|
820
830
|
- **v0.6.4** (2026-06-22) — default view engine to Rendu, CLI view options include eta, Application auto-loads viewPaths from nx.config.ts, static file path fix, scaffold deduplication.
|
|
821
831
|
- **v0.6.6** (2026-06-22) — env-aware config, `nx db:generate`, built-in `sessionMiddleware()`, scaffold generates `.env`/`.env.local`/`.gitignore`, drizzle model import fix, `make:crud` repository fix.
|
|
822
832
|
|
package/dist/auth/index.js.map
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"sourcesContent": [
|
|
5
5
|
"/**\n * Metadata keys used by reflect-metadata for storing decorator data.\n *\n * These constants are the contract between decorators and the framework\n * core (DI container, router, validator).\n */\nexport const METADATA_KEY = {\n\t/** Marks a class as a Nest-style controller, stores route prefix. */\n\tCONTROLLER: \"nexus:controller\",\n\n\t/** Marks a class as an injectable provider. */\n\tINJECTABLE: \"nexus:injectable\",\n\n\t/** Marks a class as a repository. */\n\tREPOSITORY: \"nexus:repository\",\n\n\t/** Marks a class as a module. Stores module options. */\n\tMODULE: \"nexus:module\",\n\n\t/** HTTP method routes registered on a controller (Get/Post/...). */\n\tROUTES: \"nexus:routes\",\n\n\t/** Method parameter type metadata (body/query/param/headers/ctx). */\n\tPARAMS: \"nexus:params\",\n\n\t/** Validation schema per method (Zod schema or class). */\n\tVALIDATE: \"nexus:validate\",\n\n\t/** Class-level design:paramtypes (built-in). */\n\tPARAMTYPES: \"design:paramtypes\",\n\n\t/** Class-level design:type (built-in). */\n\tTYPE: \"design:type\",\n\n\t/** Class-level design:returntype (built-in). */\n\tRETURNTYPE: \"design:returntype\",\n\n\t/** Provider token to inject for a parameter (for custom tokens). */\n\tINJECT: \"nexus:inject\",\n} as const;\n\nexport type MetadataKey = (typeof METADATA_KEY)[keyof typeof METADATA_KEY];\n\n/** Available parameter decorator locations. */\nexport const PARAM_TYPES = {\n\tREQUEST: 0,\n\tRESPONSE: 1,\n\tNEXT: 2,\n\tBODY: 3,\n\tQUERY: 4,\n\tPARAM: 5,\n\tHEADERS: 6,\n\tCTX: 7,\n\tUSER: 8,\n} as const;\n\nexport type ParamType = (typeof PARAM_TYPES)[keyof typeof PARAM_TYPES];\n\n/** HTTP methods supported by the router. */\nexport const HTTP_METHODS = [\n\t\"GET\",\n\t\"POST\",\n\t\"PUT\",\n\t\"DELETE\",\n\t\"PATCH\",\n\t\"OPTIONS\",\n\t\"HEAD\",\n] as const;\nexport type HttpMethod = (typeof HTTP_METHODS)[number];\n",
|
|
6
6
|
"/**\n * @Controller decorator.\n *\n * Marks a class as a controller and registers a route prefix.\n * Routes inside the controller class are decorated with @Get/@Post/etc.\n *\n * @example\n * ```ts\n * @Controller('/users')\n * class UserController {\n * @Get('/')\n * list() { ... }\n * }\n * ```\n */\nimport \"reflect-metadata\";\nimport { METADATA_KEY } from \"../constants.js\";\nimport type { ControllerMetadata } from \"../di/tokens.js\";\n\nexport function Controller(prefix: string = \"/\"): ClassDecorator {\n\treturn (target: object) => {\n\t\tconst normalized = normalizePrefix(prefix);\n\t\tconst meta: ControllerMetadata = { prefix: normalized };\n\t\tReflect.defineMetadata(METADATA_KEY.CONTROLLER, meta, target);\n\t};\n}\n\nexport function getControllerMetadata(target: any): ControllerMetadata {\n\treturn (\n\t\tReflect.getMetadata(METADATA_KEY.CONTROLLER, target) ?? { prefix: \"/\" }\n\t);\n}\n\nexport function isController(target: any): boolean {\n\treturn Reflect.hasMetadata(METADATA_KEY.CONTROLLER, target);\n}\n\n/**\n * Normalize a prefix so we can safely concatenate it with handler paths.\n * - Empty string becomes '/'.\n * - Trailing slashes are trimmed (we re-add them on the join).\n * - No leading slash is added; the router always joins with `/`.\n */\nfunction normalizePrefix(prefix: string): string {\n\tif (!prefix) return \"\";\n\tif (prefix !== \"/\" && prefix.endsWith(\"/\")) {\n\t\treturn prefix.slice(0, -1);\n\t}\n\treturn prefix;\n}\n",
|
|
7
|
-
"/**\n * HTTP method decorators.\n *\n * `@Get`, `@Post`, `@Put`, `@Delete`, `@Patch`, `@Options`, `@Head` mark a\n * controller method as a route handler. The path argument is appended to\n * the controller's prefix.\n *\n * @example\n * ```ts\n * @Controller('/users')\n * class UserController {\n * @Get('/')\n * list() {}\n *\n * @Post('/')\n * create(@Body() body: CreateUserDto) {}\n * }\n * ```\n */\nimport \"reflect-metadata\";\nimport { HTTP_METHODS, METADATA_KEY, type HttpMethod } from \"../constants.js\";\nimport type { RouteMetadata } from \"../di/tokens.js\";\n\nfunction defineRoute(method: HttpMethod, path: string): MethodDecorator {\n\treturn (\n\t\ttarget: object,\n\t\tpropertyKey: string | symbol,\n\t\tdescriptor:
|
|
7
|
+
"/**\n * HTTP method decorators.\n *\n * `@Get`, `@Post`, `@Put`, `@Delete`, `@Patch`, `@Options`, `@Head` mark a\n * controller method as a route handler. The path argument is appended to\n * the controller's prefix.\n *\n * @example\n * ```ts\n * @Controller('/users')\n * class UserController {\n * @Get('/')\n * list() {}\n *\n * @Post('/')\n * create(@Body() body: CreateUserDto) {}\n * }\n * ```\n */\nimport \"reflect-metadata\";\nimport { HTTP_METHODS, METADATA_KEY, type HttpMethod } from \"../constants.js\";\nimport type { RouteMetadata } from \"../di/tokens.js\";\n\nfunction defineRoute(method: HttpMethod, path: string): MethodDecorator {\n\treturn (\n\t\ttarget: object,\n\t\tpropertyKey: string | symbol,\n\t\tdescriptor: TypedPropertyDescriptor<any>,\n\t) => {\n\t\tconst routes: RouteMetadata[] =\n\t\t\tReflect.getMetadata(METADATA_KEY.ROUTES, target.constructor) ?? [];\n\n\t\troutes.push({\n\t\t\tmethod,\n\t\t\tpath: normalizePath(path),\n\t\t\tpropertyKey,\n\t\t\thandler: descriptor.value,\n\t\t});\n\n\t\tReflect.defineMetadata(METADATA_KEY.ROUTES, routes, target.constructor);\n\t};\n}\n\nfunction normalizePath(path: string): string {\n\tif (!path || path === \"/\") return \"/\";\n\treturn path.startsWith(\"/\") ? path : `/${path}`;\n}\n\nexport const Get = (path: string = \"/\") => defineRoute(\"GET\", path);\nexport const Post = (path: string = \"/\") => defineRoute(\"POST\", path);\nexport const Put = (path: string = \"/\") => defineRoute(\"PUT\", path);\nexport const Delete = (path: string = \"/\") => defineRoute(\"DELETE\", path);\nexport const Patch = (path: string = \"/\") => defineRoute(\"PATCH\", path);\nexport const Options = (path: string = \"/\") => defineRoute(\"OPTIONS\", path);\nexport const Head = (path: string = \"/\") => defineRoute(\"HEAD\", path);\n\nexport function getRoutes(target: any): RouteMetadata[] {\n\treturn Reflect.getMetadata(METADATA_KEY.ROUTES, target) ?? [];\n}\n\nexport { HTTP_METHODS };\nexport type { RouteMetadata };\n",
|
|
8
8
|
"/**\n * Parameter decorators.\n *\n * These mark a controller method argument as a source of request data:\n * - `@Req()` → Hono context\n * - `@Res()` → Response helper\n * - `@Next()` → next() callback (for middleware-style handlers)\n * - `@Body()` → request body (parsed)\n * - `@Query('key')` → a single query param, or full query object\n * - `@Param('key')` → a single path param, or full params object\n * - `@Headers('k')` → a single header, or full headers object\n * - `@Ctx()` → Hono context (alias for @Req)\n * - `@User()` → authenticated user (resolved via auth provider)\n *\n * The metadata is read by the router at mount time to build the\n * handler invocation list.\n */\nimport \"reflect-metadata\";\nimport { METADATA_KEY, PARAM_TYPES } from \"../constants.js\";\nimport type { ParamMetadata } from \"../di/tokens.js\";\n\nexport function createParamDecorator(\n\ttype: number,\n\tdata?: string | object,\n): ParameterDecorator {\n\treturn (\n\t\ttarget: object,\n\t\tpropertyKey: string | symbol | undefined,\n\t\tparameterIndex: number,\n\t) => {\n\t\t// Method parameter: target is the prototype, propertyKey is the method name.\n\t\t// Constructor parameter: target is the class, propertyKey is undefined.\n\t\tif (propertyKey !== undefined) {\n\t\t\tconst params: ParamMetadata[] =\n\t\t\t\tReflect.getMetadata(METADATA_KEY.PARAMS, target, propertyKey) ?? [];\n\t\t\tparams.push({\n\t\t\t\tindex: parameterIndex,\n\t\t\t\ttype,\n\t\t\t\tname: typeof data === \"string\" ? data : undefined,\n\t\t\t\tdata: typeof data === \"object\" ? data : undefined,\n\t\t\t});\n\t\t\tReflect.defineMetadata(METADATA_KEY.PARAMS, params, target, propertyKey);\n\t\t} else {\n\t\t\tconst params: ParamMetadata[] =\n\t\t\t\tReflect.getMetadata(METADATA_KEY.PARAMS, target) ?? [];\n\t\t\tparams.push({\n\t\t\t\tindex: parameterIndex,\n\t\t\t\ttype,\n\t\t\t\tname: typeof data === \"string\" ? data : undefined,\n\t\t\t\tdata: typeof data === \"object\" ? data : undefined,\n\t\t\t});\n\t\t\tReflect.defineMetadata(METADATA_KEY.PARAMS, params, target);\n\t\t}\n\t};\n}\n\nexport const Req = () => createParamDecorator(PARAM_TYPES.REQUEST);\nexport const Res = () => createParamDecorator(PARAM_TYPES.RESPONSE);\nexport const Next = () => createParamDecorator(PARAM_TYPES.NEXT);\nexport const Body = (key?: string) =>\n\tcreateParamDecorator(PARAM_TYPES.BODY, key);\nexport const Query = (key?: string) =>\n\tcreateParamDecorator(PARAM_TYPES.QUERY, key);\nexport const Param = (key?: string) =>\n\tcreateParamDecorator(PARAM_TYPES.PARAM, key);\nexport const Headers = (key?: string) =>\n\tcreateParamDecorator(PARAM_TYPES.HEADERS, key);\nexport const Ctx = () => createParamDecorator(PARAM_TYPES.CTX);\nexport const User = () => createParamDecorator(PARAM_TYPES.USER);\n\nexport function getParamMetadata(\n\ttarget: any,\n\tpropertyKey: string | symbol,\n): ParamMetadata[] {\n\treturn Reflect.getMetadata(METADATA_KEY.PARAMS, target, propertyKey) ?? [];\n}\n\nexport { PARAM_TYPES };\n",
|
|
9
9
|
"/**\n * @Validate decorator.\n *\n * Attaches Zod schemas (or class validators) to a route handler. Each\n * schema is run against the corresponding request part before the handler\n * executes; failed validation throws or returns a 400 response.\n *\n * @example\n * ```ts\n * const UserSchema = z.object({ name: z.string(), email: z.email() });\n *\n * @Post('/')\n * @Validate({ body: UserSchema })\n * create(@Body() body: z.infer<typeof UserSchema>) { ... }\n * ```\n */\nimport \"reflect-metadata\";\nimport { METADATA_KEY } from \"../constants.js\";\nimport type { ValidationMetadata } from \"../di/tokens.js\";\n\nexport function Validate(options: ValidationMetadata): MethodDecorator {\n\treturn (\n\t\ttarget: object,\n\t\tpropertyKey: string | symbol,\n\t\tdescriptor: PropertyDescriptor,\n\t) => {\n\t\tReflect.defineMetadata(\n\t\t\tMETADATA_KEY.VALIDATE,\n\t\t\toptions,\n\t\t\ttarget.constructor,\n\t\t\tpropertyKey,\n\t\t);\n\t};\n}\n\nexport function getValidationMetadata(\n\ttarget: any,\n\tpropertyKey: string | symbol,\n): ValidationMetadata | undefined {\n\treturn Reflect.getMetadata(METADATA_KEY.VALIDATE, target, propertyKey);\n}\n",
|
|
10
10
|
"/**\n * `createAuth()` — wrap better-auth's `betterAuth()` factory with\n * NexusJS-friendly defaults.\n *\n * This is the **only** place that talks to better-auth directly. Every\n * other NexusJS auth module consumes the resulting `Auth` instance via\n * DI or the registered token.\n *\n * Why an adapter layer instead of calling `betterAuth()` directly?\n * 1. NexusJS users write `auth.config.ts`, not raw better-auth options.\n * The adapter translates between the two.\n * 2. Plugin selection (jwt, passkey) is toggled by boolean flags,\n * not by importing plugin objects.\n * 3. Cookie / CORS / cross-subdomain defaults match Hono's `cors()`\n * middleware so the two never conflict.\n *\n * Usage:\n * // src/auth/auth.ts\n * import { createAuth } from 'nexusjs/auth';\n * export const auth = createAuth({\n * basePath: '/api/auth',\n * emailAndPassword: { enabled: true },\n * socialProviders: {\n * github: {\n * clientId: process.env.GITHUB_CLIENT_ID!,\n * clientSecret: process.env.GITHUB_CLIENT_SECRET!,\n * },\n * },\n * });\n */\n\nimport { betterAuth } from \"better-auth\";\nimport type { AuthConfig } from \"./types.js\";\n\ntype BetterAuthInstance = ReturnType<typeof betterAuth>;\n\n/**\n * Create a better-auth instance with NexusJS-friendly defaults.\n *\n * @param config NexusJS-shaped config (see types.ts).\n * @returns A `better-auth` Auth instance.\n */\nexport function createAuth(config: AuthConfig = {}): BetterAuthInstance {\n\tconst secret = config.secret ?? process.env[\"BETTER_AUTH_SECRET\"];\n\tconst baseURL = config.baseUrl ?? process.env[\"BETTER_AUTH_URL\"];\n\n\tif (!secret) {\n\t\tthrow new Error(\n\t\t\t\"[nexus/auth] BETTER_AUTH_SECRET is required. \" +\n\t\t\t\t\"Generate one with `openssl rand -base64 32` and add it to .env.\",\n\t\t);\n\t}\n\tif (!baseURL) {\n\t\tthrow new Error(\n\t\t\t\"[nexus/auth] BETTER_AUTH_URL is required (e.g. http://localhost:3000).\",\n\t\t);\n\t}\n\n\tconst plugins: Array<unknown> = [];\n\n\t// JWT plugin — opt-in.\n\tif (config.jwt?.enabled) {\n\t\t// Lazy import so the plugin's transitive dependencies don't load\n\t\t// when the user hasn't asked for JWT.\n\t\t// eslint-disable-next-line @typescript-eslint/no-require-imports\n\t\tconst { jwt } = require(\"better-auth/plugins\");\n\t\tplugins.push(\n\t\t\tjwt({\n\t\t\t\tjwks: {\n\t\t\t\t\tpath: config.jwt.jwksPath ?? \"/api/auth/jwks\",\n\t\t\t\t},\n\t\t\t\tissuer: config.jwt.issuer ?? baseURL,\n\t\t\t\taudience: config.jwt.audience ?? baseURL,\n\t\t\t\texpiresIn: config.jwt.expiresIn ?? 60 * 15,\n\t\t\t}),\n\t\t);\n\t}\n\n\t// Passkey plugin — opt-in.\n\tif (config.passkey?.enabled) {\n\t\t// eslint-disable-next-line @typescript-eslint/no-require-imports\n\t\tconst { passkey } = require(\"better-auth/plugins\");\n\t\tplugins.push(\n\t\t\tpasskey({\n\t\t\t\trpName: config.passkey.rpName,\n\t\t\t\trpID: config.passkey.rpId,\n\t\t\t\torigin: config.passkey.origin,\n\t\t\t}),\n\t\t);\n\t}\n\n\treturn betterAuth({\n\t\tsecret,\n\t\tbaseURL,\n\t\tbasePath: config.basePath ?? \"/api/auth\",\n\t\temailAndPassword: {\n\t\t\tenabled: config.emailAndPassword?.enabled ?? true,\n\t\t\trequireEmailVerification:\n\t\t\t\tconfig.emailAndPassword?.requireEmailVerification ?? false,\n\t\t\tminPasswordLength: config.emailAndPassword?.minPasswordLength ?? 8,\n\t\t\tmaxPasswordLength: config.emailAndPassword?.maxPasswordLength ?? 128,\n\t\t},\n\t\tsession: {\n\t\t\texpiresIn: config.sessionExpiresInSeconds ?? 60 * 60 * 24 * 7, // 7 days\n\t\t},\n\t\tsocialProviders: config.socialProviders as never,\n\t\tadvanced: {\n\t\t\tcookies: {\n\t\t\t\tsessionToken: {\n\t\t\t\t\tattributes: {\n\t\t\t\t\t\tsameSite: (config.cookieSameSite ?? \"lax\") as\n\t\t\t\t\t\t\t| \"lax\"\n\t\t\t\t\t\t\t| \"strict\"\n\t\t\t\t\t\t\t| \"none\",\n\t\t\t\t\t\tsecure:\n\t\t\t\t\t\t\tconfig.cookieSecure ?? process.env[\"NODE_ENV\"] === \"production\",\n\t\t\t\t\t\t...(config.cookieDomain ? { domain: config.cookieDomain } : {}),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tcrossSubDomainCookies: config.crossSubDomainCookies?.enabled\n\t\t\t\t? {\n\t\t\t\t\t\tenabled: true,\n\t\t\t\t\t\tdomain: config.crossSubDomainCookies.domain,\n\t\t\t\t\t}\n\t\t\t\t: undefined,\n\t\t},\n\t\tplugins,\n\t} as never) as unknown as BetterAuthInstance;\n}\n\n/**\n * Type alias for the returned auth instance — convenient for DI token\n * typings.\n */\nexport type NexusAuth = ReturnType<typeof createAuth>;\n",
|
package/dist/cache/index.js.map
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"sourcesContent": [
|
|
5
5
|
"/**\n * Metadata keys used by reflect-metadata for storing decorator data.\n *\n * These constants are the contract between decorators and the framework\n * core (DI container, router, validator).\n */\nexport const METADATA_KEY = {\n\t/** Marks a class as a Nest-style controller, stores route prefix. */\n\tCONTROLLER: \"nexus:controller\",\n\n\t/** Marks a class as an injectable provider. */\n\tINJECTABLE: \"nexus:injectable\",\n\n\t/** Marks a class as a repository. */\n\tREPOSITORY: \"nexus:repository\",\n\n\t/** Marks a class as a module. Stores module options. */\n\tMODULE: \"nexus:module\",\n\n\t/** HTTP method routes registered on a controller (Get/Post/...). */\n\tROUTES: \"nexus:routes\",\n\n\t/** Method parameter type metadata (body/query/param/headers/ctx). */\n\tPARAMS: \"nexus:params\",\n\n\t/** Validation schema per method (Zod schema or class). */\n\tVALIDATE: \"nexus:validate\",\n\n\t/** Class-level design:paramtypes (built-in). */\n\tPARAMTYPES: \"design:paramtypes\",\n\n\t/** Class-level design:type (built-in). */\n\tTYPE: \"design:type\",\n\n\t/** Class-level design:returntype (built-in). */\n\tRETURNTYPE: \"design:returntype\",\n\n\t/** Provider token to inject for a parameter (for custom tokens). */\n\tINJECT: \"nexus:inject\",\n} as const;\n\nexport type MetadataKey = (typeof METADATA_KEY)[keyof typeof METADATA_KEY];\n\n/** Available parameter decorator locations. */\nexport const PARAM_TYPES = {\n\tREQUEST: 0,\n\tRESPONSE: 1,\n\tNEXT: 2,\n\tBODY: 3,\n\tQUERY: 4,\n\tPARAM: 5,\n\tHEADERS: 6,\n\tCTX: 7,\n\tUSER: 8,\n} as const;\n\nexport type ParamType = (typeof PARAM_TYPES)[keyof typeof PARAM_TYPES];\n\n/** HTTP methods supported by the router. */\nexport const HTTP_METHODS = [\n\t\"GET\",\n\t\"POST\",\n\t\"PUT\",\n\t\"DELETE\",\n\t\"PATCH\",\n\t\"OPTIONS\",\n\t\"HEAD\",\n] as const;\nexport type HttpMethod = (typeof HTTP_METHODS)[number];\n",
|
|
6
6
|
"/**\n * @Controller decorator.\n *\n * Marks a class as a controller and registers a route prefix.\n * Routes inside the controller class are decorated with @Get/@Post/etc.\n *\n * @example\n * ```ts\n * @Controller('/users')\n * class UserController {\n * @Get('/')\n * list() { ... }\n * }\n * ```\n */\nimport \"reflect-metadata\";\nimport { METADATA_KEY } from \"../constants.js\";\nimport type { ControllerMetadata } from \"../di/tokens.js\";\n\nexport function Controller(prefix: string = \"/\"): ClassDecorator {\n\treturn (target: object) => {\n\t\tconst normalized = normalizePrefix(prefix);\n\t\tconst meta: ControllerMetadata = { prefix: normalized };\n\t\tReflect.defineMetadata(METADATA_KEY.CONTROLLER, meta, target);\n\t};\n}\n\nexport function getControllerMetadata(target: any): ControllerMetadata {\n\treturn (\n\t\tReflect.getMetadata(METADATA_KEY.CONTROLLER, target) ?? { prefix: \"/\" }\n\t);\n}\n\nexport function isController(target: any): boolean {\n\treturn Reflect.hasMetadata(METADATA_KEY.CONTROLLER, target);\n}\n\n/**\n * Normalize a prefix so we can safely concatenate it with handler paths.\n * - Empty string becomes '/'.\n * - Trailing slashes are trimmed (we re-add them on the join).\n * - No leading slash is added; the router always joins with `/`.\n */\nfunction normalizePrefix(prefix: string): string {\n\tif (!prefix) return \"\";\n\tif (prefix !== \"/\" && prefix.endsWith(\"/\")) {\n\t\treturn prefix.slice(0, -1);\n\t}\n\treturn prefix;\n}\n",
|
|
7
|
-
"/**\n * HTTP method decorators.\n *\n * `@Get`, `@Post`, `@Put`, `@Delete`, `@Patch`, `@Options`, `@Head` mark a\n * controller method as a route handler. The path argument is appended to\n * the controller's prefix.\n *\n * @example\n * ```ts\n * @Controller('/users')\n * class UserController {\n * @Get('/')\n * list() {}\n *\n * @Post('/')\n * create(@Body() body: CreateUserDto) {}\n * }\n * ```\n */\nimport \"reflect-metadata\";\nimport { HTTP_METHODS, METADATA_KEY, type HttpMethod } from \"../constants.js\";\nimport type { RouteMetadata } from \"../di/tokens.js\";\n\nfunction defineRoute(method: HttpMethod, path: string): MethodDecorator {\n\treturn (\n\t\ttarget: object,\n\t\tpropertyKey: string | symbol,\n\t\tdescriptor:
|
|
7
|
+
"/**\n * HTTP method decorators.\n *\n * `@Get`, `@Post`, `@Put`, `@Delete`, `@Patch`, `@Options`, `@Head` mark a\n * controller method as a route handler. The path argument is appended to\n * the controller's prefix.\n *\n * @example\n * ```ts\n * @Controller('/users')\n * class UserController {\n * @Get('/')\n * list() {}\n *\n * @Post('/')\n * create(@Body() body: CreateUserDto) {}\n * }\n * ```\n */\nimport \"reflect-metadata\";\nimport { HTTP_METHODS, METADATA_KEY, type HttpMethod } from \"../constants.js\";\nimport type { RouteMetadata } from \"../di/tokens.js\";\n\nfunction defineRoute(method: HttpMethod, path: string): MethodDecorator {\n\treturn (\n\t\ttarget: object,\n\t\tpropertyKey: string | symbol,\n\t\tdescriptor: TypedPropertyDescriptor<any>,\n\t) => {\n\t\tconst routes: RouteMetadata[] =\n\t\t\tReflect.getMetadata(METADATA_KEY.ROUTES, target.constructor) ?? [];\n\n\t\troutes.push({\n\t\t\tmethod,\n\t\t\tpath: normalizePath(path),\n\t\t\tpropertyKey,\n\t\t\thandler: descriptor.value,\n\t\t});\n\n\t\tReflect.defineMetadata(METADATA_KEY.ROUTES, routes, target.constructor);\n\t};\n}\n\nfunction normalizePath(path: string): string {\n\tif (!path || path === \"/\") return \"/\";\n\treturn path.startsWith(\"/\") ? path : `/${path}`;\n}\n\nexport const Get = (path: string = \"/\") => defineRoute(\"GET\", path);\nexport const Post = (path: string = \"/\") => defineRoute(\"POST\", path);\nexport const Put = (path: string = \"/\") => defineRoute(\"PUT\", path);\nexport const Delete = (path: string = \"/\") => defineRoute(\"DELETE\", path);\nexport const Patch = (path: string = \"/\") => defineRoute(\"PATCH\", path);\nexport const Options = (path: string = \"/\") => defineRoute(\"OPTIONS\", path);\nexport const Head = (path: string = \"/\") => defineRoute(\"HEAD\", path);\n\nexport function getRoutes(target: any): RouteMetadata[] {\n\treturn Reflect.getMetadata(METADATA_KEY.ROUTES, target) ?? [];\n}\n\nexport { HTTP_METHODS };\nexport type { RouteMetadata };\n",
|
|
8
8
|
"/**\n * Parameter decorators.\n *\n * These mark a controller method argument as a source of request data:\n * - `@Req()` → Hono context\n * - `@Res()` → Response helper\n * - `@Next()` → next() callback (for middleware-style handlers)\n * - `@Body()` → request body (parsed)\n * - `@Query('key')` → a single query param, or full query object\n * - `@Param('key')` → a single path param, or full params object\n * - `@Headers('k')` → a single header, or full headers object\n * - `@Ctx()` → Hono context (alias for @Req)\n * - `@User()` → authenticated user (resolved via auth provider)\n *\n * The metadata is read by the router at mount time to build the\n * handler invocation list.\n */\nimport \"reflect-metadata\";\nimport { METADATA_KEY, PARAM_TYPES } from \"../constants.js\";\nimport type { ParamMetadata } from \"../di/tokens.js\";\n\nexport function createParamDecorator(\n\ttype: number,\n\tdata?: string | object,\n): ParameterDecorator {\n\treturn (\n\t\ttarget: object,\n\t\tpropertyKey: string | symbol | undefined,\n\t\tparameterIndex: number,\n\t) => {\n\t\t// Method parameter: target is the prototype, propertyKey is the method name.\n\t\t// Constructor parameter: target is the class, propertyKey is undefined.\n\t\tif (propertyKey !== undefined) {\n\t\t\tconst params: ParamMetadata[] =\n\t\t\t\tReflect.getMetadata(METADATA_KEY.PARAMS, target, propertyKey) ?? [];\n\t\t\tparams.push({\n\t\t\t\tindex: parameterIndex,\n\t\t\t\ttype,\n\t\t\t\tname: typeof data === \"string\" ? data : undefined,\n\t\t\t\tdata: typeof data === \"object\" ? data : undefined,\n\t\t\t});\n\t\t\tReflect.defineMetadata(METADATA_KEY.PARAMS, params, target, propertyKey);\n\t\t} else {\n\t\t\tconst params: ParamMetadata[] =\n\t\t\t\tReflect.getMetadata(METADATA_KEY.PARAMS, target) ?? [];\n\t\t\tparams.push({\n\t\t\t\tindex: parameterIndex,\n\t\t\t\ttype,\n\t\t\t\tname: typeof data === \"string\" ? data : undefined,\n\t\t\t\tdata: typeof data === \"object\" ? data : undefined,\n\t\t\t});\n\t\t\tReflect.defineMetadata(METADATA_KEY.PARAMS, params, target);\n\t\t}\n\t};\n}\n\nexport const Req = () => createParamDecorator(PARAM_TYPES.REQUEST);\nexport const Res = () => createParamDecorator(PARAM_TYPES.RESPONSE);\nexport const Next = () => createParamDecorator(PARAM_TYPES.NEXT);\nexport const Body = (key?: string) =>\n\tcreateParamDecorator(PARAM_TYPES.BODY, key);\nexport const Query = (key?: string) =>\n\tcreateParamDecorator(PARAM_TYPES.QUERY, key);\nexport const Param = (key?: string) =>\n\tcreateParamDecorator(PARAM_TYPES.PARAM, key);\nexport const Headers = (key?: string) =>\n\tcreateParamDecorator(PARAM_TYPES.HEADERS, key);\nexport const Ctx = () => createParamDecorator(PARAM_TYPES.CTX);\nexport const User = () => createParamDecorator(PARAM_TYPES.USER);\n\nexport function getParamMetadata(\n\ttarget: any,\n\tpropertyKey: string | symbol,\n): ParamMetadata[] {\n\treturn Reflect.getMetadata(METADATA_KEY.PARAMS, target, propertyKey) ?? [];\n}\n\nexport { PARAM_TYPES };\n",
|
|
9
9
|
"/**\n * @Validate decorator.\n *\n * Attaches Zod schemas (or class validators) to a route handler. Each\n * schema is run against the corresponding request part before the handler\n * executes; failed validation throws or returns a 400 response.\n *\n * @example\n * ```ts\n * const UserSchema = z.object({ name: z.string(), email: z.email() });\n *\n * @Post('/')\n * @Validate({ body: UserSchema })\n * create(@Body() body: z.infer<typeof UserSchema>) { ... }\n * ```\n */\nimport \"reflect-metadata\";\nimport { METADATA_KEY } from \"../constants.js\";\nimport type { ValidationMetadata } from \"../di/tokens.js\";\n\nexport function Validate(options: ValidationMetadata): MethodDecorator {\n\treturn (\n\t\ttarget: object,\n\t\tpropertyKey: string | symbol,\n\t\tdescriptor: PropertyDescriptor,\n\t) => {\n\t\tReflect.defineMetadata(\n\t\t\tMETADATA_KEY.VALIDATE,\n\t\t\toptions,\n\t\t\ttarget.constructor,\n\t\t\tpropertyKey,\n\t\t);\n\t};\n}\n\nexport function getValidationMetadata(\n\ttarget: any,\n\tpropertyKey: string | symbol,\n): ValidationMetadata | undefined {\n\treturn Reflect.getMetadata(METADATA_KEY.VALIDATE, target, propertyKey);\n}\n",
|
|
10
10
|
"/**\n * `nexusjs/cache` — application-level caching.\n *\n * Two backends ship out of the box:\n * - `MemoryStore` — single-process LRU with TTL eviction\n * - `RedisStore` — multi-pod via ioredis (peer dep, optional)\n *\n * const cache = new CacheService({ store: new MemoryStore({ max: 10_000 }) });\n * await cache.set('user:42', user, 60); // 60-second TTL\n * const u = await cache.get<User>('user:42');\n *\n * Decorators are also provided for service methods:\n *\n * @Cacheable('user', (id: string) => id, 60)\n * async findById(id: string) { ... }\n */\n\nimport \"reflect-metadata\";\nimport { METADATA_KEY } from \"../core/constants.js\";\n\n/** A single cache entry. */\nexport interface CacheEntry<T = unknown> {\n\tvalue: T;\n\t/** Unix-ms timestamp when this entry expires. 0 = never. */\n\texpiresAt: number;\n\t/** Stash tags for invalidation. */\n\ttags?: string[];\n}\n\n/** Storage backend for cache entries. */\nexport interface CacheStore {\n\treadonly kind: string;\n\t/** Get a value. Returns `undefined` if missing or expired. */\n\tget<T = unknown>(key: string): Promise<T | undefined>;\n\t/** Set a value with optional TTL (seconds) and tags. */\n\tset<T = unknown>(\n\t\tkey: string,\n\t\tvalue: T,\n\t\topts?: CacheSetOptions,\n\t): Promise<void>;\n\t/** Delete a single key. */\n\tdelete(key: string): Promise<boolean>;\n\t/** Delete every key matching `pattern` (glob: `*`, `**`). */\n\tclear(pattern?: string): Promise<number>;\n\t/** Wrap a function with cache-or-compute semantics. */\n\twrap<T>(key: string, fn: () => Promise<T>, ttl?: number): Promise<T>;\n\t/**\n\t * Remove every entry tagged with `tag`. Backends without a tag\n\t * index (e.g. MemoryStore) return 0.\n\t */\n\tinvalidateByTag?(tag: string): Promise<number>;\n\t/** Sweep expired entries. Backends without a sweep loop return 0. */\n\tgc?(): Promise<number>;\n\t/** Optional: free resources. */\n\tclose?(): Promise<void>;\n}\n\n/** Options for `set()`. */\nexport interface CacheSetOptions {\n\t/** Time-to-live in seconds. 0 = forever. */\n\tttl?: number;\n\t/** Tags for grouped invalidation. */\n\ttags?: string[];\n}\n\nexport interface CacheConfig {\n\t/** Storage backend. Default: in-memory LRU. */\n\tstore?: CacheStore;\n\t/** Default TTL in seconds when none is provided. Default: 60. */\n\tdefaultTtl?: number;\n\t/** Prefix prepended to all keys. Default: 'nexusjs'. */\n\tprefix?: string;\n}\n\n/** Internal metadata key. */\nexport const CACHEABLE_META = \"nexus:cache:cacheable\";\nexport const CACHE_INVALIDATE_META = \"nexus:cache:invalidate\";\n\n/** @Cacheable decorator. Caches the result of a method. */\nexport function Cacheable(\n\tprefix: string,\n\tkeyFn: (...args: any[]) => string,\n\tttlSeconds = 60,\n): MethodDecorator {\n\treturn (\n\t\ttarget: any,\n\t\tpropertyKey: string | symbol,\n\t\tdescriptor: PropertyDescriptor,\n\t) => {\n\t\tconst existing: CacheableSpec[] =\n\t\t\tReflect.getMetadata(CACHEABLE_META, target.constructor) ?? [];\n\t\texisting.push({\n\t\t\tprefix,\n\t\t\tkeyFn,\n\t\t\tttl: ttlSeconds,\n\t\t\tpropertyKey,\n\t\t\toriginal: descriptor.value,\n\t\t});\n\t\tReflect.defineMetadata(CACHEABLE_META, existing, target.constructor);\n\t};\n}\n\n/** @CacheInvalidate decorator. Removes matching keys after a method runs. */\nexport function CacheInvalidate(\n\tprefix: string,\n\tkeyFn: (...args: any[]) => string,\n): MethodDecorator {\n\treturn (\n\t\ttarget: any,\n\t\tpropertyKey: string | symbol,\n\t\tdescriptor: PropertyDescriptor,\n\t) => {\n\t\tconst existing: CacheInvalidateSpec[] =\n\t\t\tReflect.getMetadata(CACHE_INVALIDATE_META, target.constructor) ?? [];\n\t\texisting.push({ prefix, keyFn, propertyKey, original: descriptor.value });\n\t\tReflect.defineMetadata(CACHE_INVALIDATE_META, existing, target.constructor);\n\t};\n}\n\nexport interface CacheableSpec {\n\tprefix: string;\n\tkeyFn: (...args: any[]) => string;\n\tttl: number;\n\tpropertyKey: string | symbol;\n\toriginal: (...args: any[]) => any;\n}\n\nexport interface CacheInvalidateSpec {\n\tprefix: string;\n\tkeyFn: (...args: any[]) => string;\n\tpropertyKey: string | symbol;\n\toriginal: (...args: any[]) => any;\n}\n\nexport function getCacheableSpecs(target: any): CacheableSpec[] {\n\treturn Reflect.getMetadata(CACHEABLE_META, target) ?? [];\n}\nexport function getCacheInvalidateSpecs(target: any): CacheInvalidateSpec[] {\n\treturn Reflect.getMetadata(CACHE_INVALIDATE_META, target) ?? [];\n}\n\nexport { METADATA_KEY };\n",
|
package/dist/cli/index.js.map
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"/**\n * Module scanner.\n *\n * Reads the @Module({...}) metadata and recursively registers all\n * providers/controllers from imports, registering exports into the\n * parent container so cross-module injection works.\n */\nimport { METADATA_KEY } from \"../constants.js\";\nimport type { ApplicationContainer, DIContainer } from \"./container.js\";\nimport type { ModuleOptions, Provider, Type } from \"./tokens.js\";\n\ninterface ScanResult {\n\t/** Controllers registered by this module. */\n\tcontrollers: Type[];\n\t/** Providers registered locally (classes + non-class providers). */\n\tproviders: Provider[];\n\t/** Tokens exported by this module. */\n\texports: any[];\n\t/** Container holding the module's locally-scoped providers. */\n\tcontainer: DIContainer;\n}\n\nexport class ModuleScanner {\n\tprivate scanned = new Map<Type<any>, ScanResult>();\n\n\tconstructor(private root: ApplicationContainer) {}\n\n\t/**\n\t * Scan a module tree starting from `rootModule`, registering all\n\t * providers and controllers into the appropriate containers.\n\t */\n\tscan(rootModule: Type<any>): { root: ScanResult; modules: ScanResult[] } {\n\t\tconst rootResult = this.scanModule(rootModule, this.root);\n\t\tconst all = [...this.scanned.values()];\n\t\treturn { root: rootResult, modules: all };\n\t}\n\n\t/**\n\t * Scan one module. Recurses into its `imports`, then registers its\n\t * providers and controllers. Exports are exposed to the parent\n\t * container.\n\t */\n\tprivate scanModule(\n\t\tmoduleClass: Type<any>,\n\t\tparentContainer: DIContainer,\n\t): ScanResult {\n\t\tif (this.scanned.has(moduleClass)) {\n\t\t\treturn this.scanned.get(moduleClass)!;\n\t\t}\n\n\t\tconst options = this.readModuleOptions(moduleClass);\n\t\tconst container = parentContainer.createChild();\n\t\tthis.root.registerModule(moduleClass, container);\n\n\t\t// Pre-fill the slot to break import cycles when modules reference each other.\n\t\tconst placeholder: ScanResult = {\n\t\t\tcontrollers: [],\n\t\t\tproviders: [],\n\t\t\texports: [],\n\t\t\tcontainer,\n\t\t};\n\t\tthis.scanned.set(moduleClass, placeholder);\n\n\t\t// Recurse into imports first so dependent tokens exist.\n\t\tfor (const imported of options.imports ?? []) {\n\t\t\tconst importedResult = this.scanModule(imported, parentContainer);\n\t\t\t// Expose imports' exports to the parent's container so the importing\n\t\t\t// module can resolve them.\n\t\t\tfor (const exp of importedResult.exports) {\n\t\t\t\tif (!parentContainer.has(exp)) {\n\t\t\t\t\t// Re-export by creating a passthrough provider that resolves from\n\t\t\t\t\t// the imported module's container.\n\t\t\t\t\tparentContainer.register({\n\t\t\t\t\t\tprovide: exp,\n\t\t\t\t\t\tuseFactory: () => importedResult.container.resolve(exp),\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Register providers (and controllers as providers for DI).\n\t\tconst providers = [\n\t\t\t...(options.providers ?? []),\n\t\t\t...(options.controllers ?? []),\n\t\t];\n\t\tcontainer.register(providers);\n\n\t\t// Expose declared exports from this module's container to the parent.\n\t\tfor (const exp of options.exports ?? []) {\n\t\t\tif (!parentContainer.has(exp)) {\n\t\t\t\tparentContainer.register({\n\t\t\t\t\tprovide: exp,\n\t\t\t\t\tuseFactory: () => container.resolve(exp),\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tconst result: ScanResult = {\n\t\t\tcontrollers: options.controllers ?? [],\n\t\t\tproviders: options.providers ?? [],\n\t\t\texports: options.exports ?? [],\n\t\t\tcontainer,\n\t\t};\n\t\tthis.scanned.set(moduleClass, result);\n\t\treturn result;\n\t}\n\n\tprivate readModuleOptions(moduleClass: Type<any>): ModuleOptions {\n\t\tconst meta = Reflect.getMetadata(METADATA_KEY.MODULE, moduleClass) as\n\t\t\t| ModuleOptions\n\t\t\t| undefined;\n\t\tif (!meta) {\n\t\t\tthrow new Error(\n\t\t\t\t`Class \"${moduleClass.name}\" is missing the @Module() decorator.`,\n\t\t\t);\n\t\t}\n\t\treturn meta;\n\t}\n\n\t/** Get a previously-scanned module's result (debug aid). */\n\tget(moduleClass: Type<any>): ScanResult | undefined {\n\t\treturn this.scanned.get(moduleClass);\n\t}\n}\n",
|
|
9
9
|
"/**\n * HTTP middleware primitives.\n *\n * Middleware in Nexus is just a Hono-compatible function: `(c, next) => ...`.\n * The framework exposes a few ready-made middlewares (logger, CORS, error)\n * and lets users write their own.\n */\nimport type { Context, Next } from \"hono\";\n\n/** A Nexus/Hono middleware signature. */\nexport type Middleware = (c: Context, next: Next) => any | Promise<any>;\n\n/** Simple request logger. Logs method, URL, status, duration. */\nexport function logger(): Middleware {\n\treturn async (c, next) => {\n\t\tconst start = performance.now();\n\t\tawait next();\n\t\tconst ms = (performance.now() - start).toFixed(2);\n\t\tconst status = c.res.status;\n\t\tconsole.log(`[${c.req.method}] ${c.req.path} -> ${status} (${ms}ms)`);\n\t\treturn;\n\t};\n}\n\n/**\n * CORS middleware.\n *\n * An explicit origin (string or string[]) is required. The function does\n * not default to '*' because that is unsafe with credentials. Pass '*'\n * explicitly via `origin: '*'` only if you know your API has no cookies.\n */\nexport function cors(options: {\n\torigin: string | string[];\n\tmethods?: string[];\n\theaders?: string[];\n\tcredentials?: boolean;\n}): Middleware {\n\tconst origin = options.origin;\n\tconst methods = options.methods ?? [\n\t\t\"GET\",\n\t\t\"POST\",\n\t\t\"PUT\",\n\t\t\"DELETE\",\n\t\t\"PATCH\",\n\t\t\"OPTIONS\",\n\t\t\"HEAD\",\n\t];\n\tconst headerList = options.headers ?? [\"Content-Type\", \"Authorization\"];\n\tconst headersValue = Array.isArray(headerList)\n\t\t? headerList.join(\",\")\n\t\t: headerList;\n\n\treturn async (c, next) => {\n\t\tconst set = (key: string, value: string) => {\n\t\t\tc.res.headers.set(key, value);\n\t\t};\n\t\tset(\n\t\t\t\"Access-Control-Allow-Origin\",\n\t\t\tArray.isArray(origin) ? origin.join(\",\") : origin,\n\t\t);\n\t\tset(\"Access-Control-Allow-Methods\", methods.join(\",\"));\n\t\tset(\"Access-Control-Allow-Headers\", headersValue);\n\t\tif (options.credentials) set(\"Access-Control-Allow-Credentials\", \"true\");\n\n\t\tif (c.req.method === \"OPTIONS\") {\n\t\t\treturn c.body(null, 204);\n\t\t}\n\t\tawait next();\n\t\treturn;\n\t};\n}\n\n/**\n * Catch-all error handler. Translates errors with `status` and `body`\n * properties into JSON responses.\n */\nexport function errorHandler(): Middleware {\n\treturn async (c, next) => {\n\t\ttry {\n\t\t\tawait next();\n\t\t} catch (err: any) {\n\t\t\tconst status = err?.status ?? 500;\n\t\t\tconst body = err?.body ?? {\n\t\t\t\terror: err?.message ?? \"Internal Server Error\",\n\t\t\t};\n\t\t\treturn c.json(body, status as any);\n\t\t}\n\t\treturn;\n\t};\n}\n",
|
|
10
10
|
"/**\n * @Controller decorator.\n *\n * Marks a class as a controller and registers a route prefix.\n * Routes inside the controller class are decorated with @Get/@Post/etc.\n *\n * @example\n * ```ts\n * @Controller('/users')\n * class UserController {\n * @Get('/')\n * list() { ... }\n * }\n * ```\n */\nimport \"reflect-metadata\";\nimport { METADATA_KEY } from \"../constants.js\";\nimport type { ControllerMetadata } from \"../di/tokens.js\";\n\nexport function Controller(prefix: string = \"/\"): ClassDecorator {\n\treturn (target: object) => {\n\t\tconst normalized = normalizePrefix(prefix);\n\t\tconst meta: ControllerMetadata = { prefix: normalized };\n\t\tReflect.defineMetadata(METADATA_KEY.CONTROLLER, meta, target);\n\t};\n}\n\nexport function getControllerMetadata(target: any): ControllerMetadata {\n\treturn (\n\t\tReflect.getMetadata(METADATA_KEY.CONTROLLER, target) ?? { prefix: \"/\" }\n\t);\n}\n\nexport function isController(target: any): boolean {\n\treturn Reflect.hasMetadata(METADATA_KEY.CONTROLLER, target);\n}\n\n/**\n * Normalize a prefix so we can safely concatenate it with handler paths.\n * - Empty string becomes '/'.\n * - Trailing slashes are trimmed (we re-add them on the join).\n * - No leading slash is added; the router always joins with `/`.\n */\nfunction normalizePrefix(prefix: string): string {\n\tif (!prefix) return \"\";\n\tif (prefix !== \"/\" && prefix.endsWith(\"/\")) {\n\t\treturn prefix.slice(0, -1);\n\t}\n\treturn prefix;\n}\n",
|
|
11
|
-
"/**\n * HTTP method decorators.\n *\n * `@Get`, `@Post`, `@Put`, `@Delete`, `@Patch`, `@Options`, `@Head` mark a\n * controller method as a route handler. The path argument is appended to\n * the controller's prefix.\n *\n * @example\n * ```ts\n * @Controller('/users')\n * class UserController {\n * @Get('/')\n * list() {}\n *\n * @Post('/')\n * create(@Body() body: CreateUserDto) {}\n * }\n * ```\n */\nimport \"reflect-metadata\";\nimport { HTTP_METHODS, METADATA_KEY, type HttpMethod } from \"../constants.js\";\nimport type { RouteMetadata } from \"../di/tokens.js\";\n\nfunction defineRoute(method: HttpMethod, path: string): MethodDecorator {\n\treturn (\n\t\ttarget: object,\n\t\tpropertyKey: string | symbol,\n\t\tdescriptor:
|
|
11
|
+
"/**\n * HTTP method decorators.\n *\n * `@Get`, `@Post`, `@Put`, `@Delete`, `@Patch`, `@Options`, `@Head` mark a\n * controller method as a route handler. The path argument is appended to\n * the controller's prefix.\n *\n * @example\n * ```ts\n * @Controller('/users')\n * class UserController {\n * @Get('/')\n * list() {}\n *\n * @Post('/')\n * create(@Body() body: CreateUserDto) {}\n * }\n * ```\n */\nimport \"reflect-metadata\";\nimport { HTTP_METHODS, METADATA_KEY, type HttpMethod } from \"../constants.js\";\nimport type { RouteMetadata } from \"../di/tokens.js\";\n\nfunction defineRoute(method: HttpMethod, path: string): MethodDecorator {\n\treturn (\n\t\ttarget: object,\n\t\tpropertyKey: string | symbol,\n\t\tdescriptor: TypedPropertyDescriptor<any>,\n\t) => {\n\t\tconst routes: RouteMetadata[] =\n\t\t\tReflect.getMetadata(METADATA_KEY.ROUTES, target.constructor) ?? [];\n\n\t\troutes.push({\n\t\t\tmethod,\n\t\t\tpath: normalizePath(path),\n\t\t\tpropertyKey,\n\t\t\thandler: descriptor.value,\n\t\t});\n\n\t\tReflect.defineMetadata(METADATA_KEY.ROUTES, routes, target.constructor);\n\t};\n}\n\nfunction normalizePath(path: string): string {\n\tif (!path || path === \"/\") return \"/\";\n\treturn path.startsWith(\"/\") ? path : `/${path}`;\n}\n\nexport const Get = (path: string = \"/\") => defineRoute(\"GET\", path);\nexport const Post = (path: string = \"/\") => defineRoute(\"POST\", path);\nexport const Put = (path: string = \"/\") => defineRoute(\"PUT\", path);\nexport const Delete = (path: string = \"/\") => defineRoute(\"DELETE\", path);\nexport const Patch = (path: string = \"/\") => defineRoute(\"PATCH\", path);\nexport const Options = (path: string = \"/\") => defineRoute(\"OPTIONS\", path);\nexport const Head = (path: string = \"/\") => defineRoute(\"HEAD\", path);\n\nexport function getRoutes(target: any): RouteMetadata[] {\n\treturn Reflect.getMetadata(METADATA_KEY.ROUTES, target) ?? [];\n}\n\nexport { HTTP_METHODS };\nexport type { RouteMetadata };\n",
|
|
12
12
|
"/**\n * Parameter decorators.\n *\n * These mark a controller method argument as a source of request data:\n * - `@Req()` → Hono context\n * - `@Res()` → Response helper\n * - `@Next()` → next() callback (for middleware-style handlers)\n * - `@Body()` → request body (parsed)\n * - `@Query('key')` → a single query param, or full query object\n * - `@Param('key')` → a single path param, or full params object\n * - `@Headers('k')` → a single header, or full headers object\n * - `@Ctx()` → Hono context (alias for @Req)\n * - `@User()` → authenticated user (resolved via auth provider)\n *\n * The metadata is read by the router at mount time to build the\n * handler invocation list.\n */\nimport \"reflect-metadata\";\nimport { METADATA_KEY, PARAM_TYPES } from \"../constants.js\";\nimport type { ParamMetadata } from \"../di/tokens.js\";\n\nexport function createParamDecorator(\n\ttype: number,\n\tdata?: string | object,\n): ParameterDecorator {\n\treturn (\n\t\ttarget: object,\n\t\tpropertyKey: string | symbol | undefined,\n\t\tparameterIndex: number,\n\t) => {\n\t\t// Method parameter: target is the prototype, propertyKey is the method name.\n\t\t// Constructor parameter: target is the class, propertyKey is undefined.\n\t\tif (propertyKey !== undefined) {\n\t\t\tconst params: ParamMetadata[] =\n\t\t\t\tReflect.getMetadata(METADATA_KEY.PARAMS, target, propertyKey) ?? [];\n\t\t\tparams.push({\n\t\t\t\tindex: parameterIndex,\n\t\t\t\ttype,\n\t\t\t\tname: typeof data === \"string\" ? data : undefined,\n\t\t\t\tdata: typeof data === \"object\" ? data : undefined,\n\t\t\t});\n\t\t\tReflect.defineMetadata(METADATA_KEY.PARAMS, params, target, propertyKey);\n\t\t} else {\n\t\t\tconst params: ParamMetadata[] =\n\t\t\t\tReflect.getMetadata(METADATA_KEY.PARAMS, target) ?? [];\n\t\t\tparams.push({\n\t\t\t\tindex: parameterIndex,\n\t\t\t\ttype,\n\t\t\t\tname: typeof data === \"string\" ? data : undefined,\n\t\t\t\tdata: typeof data === \"object\" ? data : undefined,\n\t\t\t});\n\t\t\tReflect.defineMetadata(METADATA_KEY.PARAMS, params, target);\n\t\t}\n\t};\n}\n\nexport const Req = () => createParamDecorator(PARAM_TYPES.REQUEST);\nexport const Res = () => createParamDecorator(PARAM_TYPES.RESPONSE);\nexport const Next = () => createParamDecorator(PARAM_TYPES.NEXT);\nexport const Body = (key?: string) =>\n\tcreateParamDecorator(PARAM_TYPES.BODY, key);\nexport const Query = (key?: string) =>\n\tcreateParamDecorator(PARAM_TYPES.QUERY, key);\nexport const Param = (key?: string) =>\n\tcreateParamDecorator(PARAM_TYPES.PARAM, key);\nexport const Headers = (key?: string) =>\n\tcreateParamDecorator(PARAM_TYPES.HEADERS, key);\nexport const Ctx = () => createParamDecorator(PARAM_TYPES.CTX);\nexport const User = () => createParamDecorator(PARAM_TYPES.USER);\n\nexport function getParamMetadata(\n\ttarget: any,\n\tpropertyKey: string | symbol,\n): ParamMetadata[] {\n\treturn Reflect.getMetadata(METADATA_KEY.PARAMS, target, propertyKey) ?? [];\n}\n\nexport { PARAM_TYPES };\n",
|
|
13
13
|
"/**\n * @Validate decorator.\n *\n * Attaches Zod schemas (or class validators) to a route handler. Each\n * schema is run against the corresponding request part before the handler\n * executes; failed validation throws or returns a 400 response.\n *\n * @example\n * ```ts\n * const UserSchema = z.object({ name: z.string(), email: z.email() });\n *\n * @Post('/')\n * @Validate({ body: UserSchema })\n * create(@Body() body: z.infer<typeof UserSchema>) { ... }\n * ```\n */\nimport \"reflect-metadata\";\nimport { METADATA_KEY } from \"../constants.js\";\nimport type { ValidationMetadata } from \"../di/tokens.js\";\n\nexport function Validate(options: ValidationMetadata): MethodDecorator {\n\treturn (\n\t\ttarget: object,\n\t\tpropertyKey: string | symbol,\n\t\tdescriptor: PropertyDescriptor,\n\t) => {\n\t\tReflect.defineMetadata(\n\t\t\tMETADATA_KEY.VALIDATE,\n\t\t\toptions,\n\t\t\ttarget.constructor,\n\t\t\tpropertyKey,\n\t\t);\n\t};\n}\n\nexport function getValidationMetadata(\n\ttarget: any,\n\tpropertyKey: string | symbol,\n): ValidationMetadata | undefined {\n\treturn Reflect.getMetadata(METADATA_KEY.VALIDATE, target, propertyKey);\n}\n",
|
|
14
14
|
"/**\n * Zod-based validation pipeline.\n *\n * `validateRequest` runs the configured Zod schemas for each request part\n * and either returns the parsed value or throws a ValidationError.\n *\n * Schemas are read from @Validate({ body, query, params, headers }) on the\n * handler method.\n */\nimport type { ZodError, ZodSchema } from \"zod\";\nimport type { ValidationMetadata } from \"../di/tokens.js\";\n\nexport class ValidationError extends Error {\n\treadonly status = 400;\n\treadonly issues: ZodError[\"issues\"];\n\n\tconstructor(zodError: ZodError) {\n\t\tsuper(\"Validation failed\");\n\t\tthis.name = \"ValidationError\";\n\t\tthis.issues = zodError.issues;\n\t}\n}\n\nexport interface ValidationInput {\n\tbody?: unknown;\n\tquery?: unknown;\n\tparams?: unknown;\n\theaders?: unknown;\n}\n\nexport interface ValidationResult {\n\tbody?: unknown;\n\tquery?: unknown;\n\tparams?: unknown;\n\theaders?: unknown;\n}\n\n/**\n * Validate the request using the handler's @Validate metadata. Returns\n * parsed values keyed by part. Throws ValidationError on the first\n * failure (body → query → params → headers order).\n */\nexport function validateRequest(\n\tmetadata: ValidationMetadata | undefined,\n\tinput: ValidationInput,\n): ValidationResult {\n\tif (!metadata) return input as ValidationResult;\n\n\tconst result: ValidationResult = {};\n\n\tif (metadata.body) result.body = runSchema(metadata.body, input.body, \"body\");\n\telse result.body = input.body;\n\n\tif (metadata.query)\n\t\tresult.query = runSchema(metadata.query, input.query, \"query\");\n\telse result.query = input.query;\n\n\tif (metadata.params)\n\t\tresult.params = runSchema(metadata.params, input.params, \"params\");\n\telse result.params = input.params;\n\n\tif (metadata.headers)\n\t\tresult.headers = runSchema(metadata.headers, input.headers, \"headers\");\n\telse result.headers = input.headers;\n\n\treturn result;\n}\n\nfunction runSchema(schema: any, value: unknown, part: string): unknown {\n\tif (!isZodSchema(schema)) {\n\t\t// Allow passing a class validator or function as an escape hatch.\n\t\tif (typeof schema === \"function\") return schema(value);\n\t\tthrow new Error(\n\t\t\t`@Validate \"${part}\" must be a Zod schema or validator function. Got ${typeof schema}.`,\n\t\t);\n\t}\n\tconst parsed = schema.safeParse(value);\n\tif (!parsed.success) {\n\t\tthrow new ValidationError(parsed.error);\n\t}\n\treturn parsed.data;\n}\n\nfunction isZodSchema(value: any): value is ZodSchema {\n\treturn (\n\t\tvalue !== null &&\n\t\ttypeof value === \"object\" &&\n\t\ttypeof value.safeParse === \"function\"\n\t);\n}\n\n/**\n * Default error formatter for ValidationError.\n * Renders a JSON body suitable for the framework's HTTP layer.\n */\nexport function formatValidationError(err: ValidationError): {\n\tstatus: number;\n\tbody: { error: string; issues: ZodError[\"issues\"] };\n} {\n\treturn {\n\t\tstatus: err.status,\n\t\tbody: {\n\t\t\terror: err.message,\n\t\t\tissues: err.issues,\n\t\t},\n\t};\n}\n",
|
package/dist/config/index.js.map
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"sourcesContent": [
|
|
5
5
|
"/**\n * Metadata keys used by reflect-metadata for storing decorator data.\n *\n * These constants are the contract between decorators and the framework\n * core (DI container, router, validator).\n */\nexport const METADATA_KEY = {\n\t/** Marks a class as a Nest-style controller, stores route prefix. */\n\tCONTROLLER: \"nexus:controller\",\n\n\t/** Marks a class as an injectable provider. */\n\tINJECTABLE: \"nexus:injectable\",\n\n\t/** Marks a class as a repository. */\n\tREPOSITORY: \"nexus:repository\",\n\n\t/** Marks a class as a module. Stores module options. */\n\tMODULE: \"nexus:module\",\n\n\t/** HTTP method routes registered on a controller (Get/Post/...). */\n\tROUTES: \"nexus:routes\",\n\n\t/** Method parameter type metadata (body/query/param/headers/ctx). */\n\tPARAMS: \"nexus:params\",\n\n\t/** Validation schema per method (Zod schema or class). */\n\tVALIDATE: \"nexus:validate\",\n\n\t/** Class-level design:paramtypes (built-in). */\n\tPARAMTYPES: \"design:paramtypes\",\n\n\t/** Class-level design:type (built-in). */\n\tTYPE: \"design:type\",\n\n\t/** Class-level design:returntype (built-in). */\n\tRETURNTYPE: \"design:returntype\",\n\n\t/** Provider token to inject for a parameter (for custom tokens). */\n\tINJECT: \"nexus:inject\",\n} as const;\n\nexport type MetadataKey = (typeof METADATA_KEY)[keyof typeof METADATA_KEY];\n\n/** Available parameter decorator locations. */\nexport const PARAM_TYPES = {\n\tREQUEST: 0,\n\tRESPONSE: 1,\n\tNEXT: 2,\n\tBODY: 3,\n\tQUERY: 4,\n\tPARAM: 5,\n\tHEADERS: 6,\n\tCTX: 7,\n\tUSER: 8,\n} as const;\n\nexport type ParamType = (typeof PARAM_TYPES)[keyof typeof PARAM_TYPES];\n\n/** HTTP methods supported by the router. */\nexport const HTTP_METHODS = [\n\t\"GET\",\n\t\"POST\",\n\t\"PUT\",\n\t\"DELETE\",\n\t\"PATCH\",\n\t\"OPTIONS\",\n\t\"HEAD\",\n] as const;\nexport type HttpMethod = (typeof HTTP_METHODS)[number];\n",
|
|
6
6
|
"/**\n * @Controller decorator.\n *\n * Marks a class as a controller and registers a route prefix.\n * Routes inside the controller class are decorated with @Get/@Post/etc.\n *\n * @example\n * ```ts\n * @Controller('/users')\n * class UserController {\n * @Get('/')\n * list() { ... }\n * }\n * ```\n */\nimport \"reflect-metadata\";\nimport { METADATA_KEY } from \"../constants.js\";\nimport type { ControllerMetadata } from \"../di/tokens.js\";\n\nexport function Controller(prefix: string = \"/\"): ClassDecorator {\n\treturn (target: object) => {\n\t\tconst normalized = normalizePrefix(prefix);\n\t\tconst meta: ControllerMetadata = { prefix: normalized };\n\t\tReflect.defineMetadata(METADATA_KEY.CONTROLLER, meta, target);\n\t};\n}\n\nexport function getControllerMetadata(target: any): ControllerMetadata {\n\treturn (\n\t\tReflect.getMetadata(METADATA_KEY.CONTROLLER, target) ?? { prefix: \"/\" }\n\t);\n}\n\nexport function isController(target: any): boolean {\n\treturn Reflect.hasMetadata(METADATA_KEY.CONTROLLER, target);\n}\n\n/**\n * Normalize a prefix so we can safely concatenate it with handler paths.\n * - Empty string becomes '/'.\n * - Trailing slashes are trimmed (we re-add them on the join).\n * - No leading slash is added; the router always joins with `/`.\n */\nfunction normalizePrefix(prefix: string): string {\n\tif (!prefix) return \"\";\n\tif (prefix !== \"/\" && prefix.endsWith(\"/\")) {\n\t\treturn prefix.slice(0, -1);\n\t}\n\treturn prefix;\n}\n",
|
|
7
|
-
"/**\n * HTTP method decorators.\n *\n * `@Get`, `@Post`, `@Put`, `@Delete`, `@Patch`, `@Options`, `@Head` mark a\n * controller method as a route handler. The path argument is appended to\n * the controller's prefix.\n *\n * @example\n * ```ts\n * @Controller('/users')\n * class UserController {\n * @Get('/')\n * list() {}\n *\n * @Post('/')\n * create(@Body() body: CreateUserDto) {}\n * }\n * ```\n */\nimport \"reflect-metadata\";\nimport { HTTP_METHODS, METADATA_KEY, type HttpMethod } from \"../constants.js\";\nimport type { RouteMetadata } from \"../di/tokens.js\";\n\nfunction defineRoute(method: HttpMethod, path: string): MethodDecorator {\n\treturn (\n\t\ttarget: object,\n\t\tpropertyKey: string | symbol,\n\t\tdescriptor:
|
|
7
|
+
"/**\n * HTTP method decorators.\n *\n * `@Get`, `@Post`, `@Put`, `@Delete`, `@Patch`, `@Options`, `@Head` mark a\n * controller method as a route handler. The path argument is appended to\n * the controller's prefix.\n *\n * @example\n * ```ts\n * @Controller('/users')\n * class UserController {\n * @Get('/')\n * list() {}\n *\n * @Post('/')\n * create(@Body() body: CreateUserDto) {}\n * }\n * ```\n */\nimport \"reflect-metadata\";\nimport { HTTP_METHODS, METADATA_KEY, type HttpMethod } from \"../constants.js\";\nimport type { RouteMetadata } from \"../di/tokens.js\";\n\nfunction defineRoute(method: HttpMethod, path: string): MethodDecorator {\n\treturn (\n\t\ttarget: object,\n\t\tpropertyKey: string | symbol,\n\t\tdescriptor: TypedPropertyDescriptor<any>,\n\t) => {\n\t\tconst routes: RouteMetadata[] =\n\t\t\tReflect.getMetadata(METADATA_KEY.ROUTES, target.constructor) ?? [];\n\n\t\troutes.push({\n\t\t\tmethod,\n\t\t\tpath: normalizePath(path),\n\t\t\tpropertyKey,\n\t\t\thandler: descriptor.value,\n\t\t});\n\n\t\tReflect.defineMetadata(METADATA_KEY.ROUTES, routes, target.constructor);\n\t};\n}\n\nfunction normalizePath(path: string): string {\n\tif (!path || path === \"/\") return \"/\";\n\treturn path.startsWith(\"/\") ? path : `/${path}`;\n}\n\nexport const Get = (path: string = \"/\") => defineRoute(\"GET\", path);\nexport const Post = (path: string = \"/\") => defineRoute(\"POST\", path);\nexport const Put = (path: string = \"/\") => defineRoute(\"PUT\", path);\nexport const Delete = (path: string = \"/\") => defineRoute(\"DELETE\", path);\nexport const Patch = (path: string = \"/\") => defineRoute(\"PATCH\", path);\nexport const Options = (path: string = \"/\") => defineRoute(\"OPTIONS\", path);\nexport const Head = (path: string = \"/\") => defineRoute(\"HEAD\", path);\n\nexport function getRoutes(target: any): RouteMetadata[] {\n\treturn Reflect.getMetadata(METADATA_KEY.ROUTES, target) ?? [];\n}\n\nexport { HTTP_METHODS };\nexport type { RouteMetadata };\n",
|
|
8
8
|
"/**\n * Parameter decorators.\n *\n * These mark a controller method argument as a source of request data:\n * - `@Req()` → Hono context\n * - `@Res()` → Response helper\n * - `@Next()` → next() callback (for middleware-style handlers)\n * - `@Body()` → request body (parsed)\n * - `@Query('key')` → a single query param, or full query object\n * - `@Param('key')` → a single path param, or full params object\n * - `@Headers('k')` → a single header, or full headers object\n * - `@Ctx()` → Hono context (alias for @Req)\n * - `@User()` → authenticated user (resolved via auth provider)\n *\n * The metadata is read by the router at mount time to build the\n * handler invocation list.\n */\nimport \"reflect-metadata\";\nimport { METADATA_KEY, PARAM_TYPES } from \"../constants.js\";\nimport type { ParamMetadata } from \"../di/tokens.js\";\n\nexport function createParamDecorator(\n\ttype: number,\n\tdata?: string | object,\n): ParameterDecorator {\n\treturn (\n\t\ttarget: object,\n\t\tpropertyKey: string | symbol | undefined,\n\t\tparameterIndex: number,\n\t) => {\n\t\t// Method parameter: target is the prototype, propertyKey is the method name.\n\t\t// Constructor parameter: target is the class, propertyKey is undefined.\n\t\tif (propertyKey !== undefined) {\n\t\t\tconst params: ParamMetadata[] =\n\t\t\t\tReflect.getMetadata(METADATA_KEY.PARAMS, target, propertyKey) ?? [];\n\t\t\tparams.push({\n\t\t\t\tindex: parameterIndex,\n\t\t\t\ttype,\n\t\t\t\tname: typeof data === \"string\" ? data : undefined,\n\t\t\t\tdata: typeof data === \"object\" ? data : undefined,\n\t\t\t});\n\t\t\tReflect.defineMetadata(METADATA_KEY.PARAMS, params, target, propertyKey);\n\t\t} else {\n\t\t\tconst params: ParamMetadata[] =\n\t\t\t\tReflect.getMetadata(METADATA_KEY.PARAMS, target) ?? [];\n\t\t\tparams.push({\n\t\t\t\tindex: parameterIndex,\n\t\t\t\ttype,\n\t\t\t\tname: typeof data === \"string\" ? data : undefined,\n\t\t\t\tdata: typeof data === \"object\" ? data : undefined,\n\t\t\t});\n\t\t\tReflect.defineMetadata(METADATA_KEY.PARAMS, params, target);\n\t\t}\n\t};\n}\n\nexport const Req = () => createParamDecorator(PARAM_TYPES.REQUEST);\nexport const Res = () => createParamDecorator(PARAM_TYPES.RESPONSE);\nexport const Next = () => createParamDecorator(PARAM_TYPES.NEXT);\nexport const Body = (key?: string) =>\n\tcreateParamDecorator(PARAM_TYPES.BODY, key);\nexport const Query = (key?: string) =>\n\tcreateParamDecorator(PARAM_TYPES.QUERY, key);\nexport const Param = (key?: string) =>\n\tcreateParamDecorator(PARAM_TYPES.PARAM, key);\nexport const Headers = (key?: string) =>\n\tcreateParamDecorator(PARAM_TYPES.HEADERS, key);\nexport const Ctx = () => createParamDecorator(PARAM_TYPES.CTX);\nexport const User = () => createParamDecorator(PARAM_TYPES.USER);\n\nexport function getParamMetadata(\n\ttarget: any,\n\tpropertyKey: string | symbol,\n): ParamMetadata[] {\n\treturn Reflect.getMetadata(METADATA_KEY.PARAMS, target, propertyKey) ?? [];\n}\n\nexport { PARAM_TYPES };\n",
|
|
9
9
|
"/**\n * @Validate decorator.\n *\n * Attaches Zod schemas (or class validators) to a route handler. Each\n * schema is run against the corresponding request part before the handler\n * executes; failed validation throws or returns a 400 response.\n *\n * @example\n * ```ts\n * const UserSchema = z.object({ name: z.string(), email: z.email() });\n *\n * @Post('/')\n * @Validate({ body: UserSchema })\n * create(@Body() body: z.infer<typeof UserSchema>) { ... }\n * ```\n */\nimport \"reflect-metadata\";\nimport { METADATA_KEY } from \"../constants.js\";\nimport type { ValidationMetadata } from \"../di/tokens.js\";\n\nexport function Validate(options: ValidationMetadata): MethodDecorator {\n\treturn (\n\t\ttarget: object,\n\t\tpropertyKey: string | symbol,\n\t\tdescriptor: PropertyDescriptor,\n\t) => {\n\t\tReflect.defineMetadata(\n\t\t\tMETADATA_KEY.VALIDATE,\n\t\t\toptions,\n\t\t\ttarget.constructor,\n\t\t\tpropertyKey,\n\t\t);\n\t};\n}\n\nexport function getValidationMetadata(\n\ttarget: any,\n\tpropertyKey: string | symbol,\n): ValidationMetadata | undefined {\n\treturn Reflect.getMetadata(METADATA_KEY.VALIDATE, target, propertyKey);\n}\n",
|
|
10
10
|
"/**\n * @Module decorator.\n *\n * Marks a class as a Nest-style module: a logical grouping of\n * controllers and providers with explicit imports/exports.\n *\n * @example\n * ```ts\n * @Module({\n * imports: [UserModule],\n * controllers: [UserController],\n * providers: [UserService],\n * exports: [UserService],\n * })\n * class AppModule {}\n * ```\n */\nimport \"reflect-metadata\";\nimport { METADATA_KEY } from \"../constants.js\";\nimport type { ModuleOptions, Type } from \"../di/tokens.js\";\n\nexport function Module(options: ModuleOptions = {}): ClassDecorator {\n\treturn (target: object) => {\n\t\tReflect.defineMetadata(METADATA_KEY.MODULE, options, target);\n\t};\n}\n\n/** Read the @Module options from a class. */\nexport function getModuleOptions(target: Type<any>): ModuleOptions {\n\treturn Reflect.getMetadata(METADATA_KEY.MODULE, target) ?? {};\n}\n",
|
package/dist/drive/index.js.map
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"sourcesContent": [
|
|
5
5
|
"/**\n * Metadata keys used by reflect-metadata for storing decorator data.\n *\n * These constants are the contract between decorators and the framework\n * core (DI container, router, validator).\n */\nexport const METADATA_KEY = {\n\t/** Marks a class as a Nest-style controller, stores route prefix. */\n\tCONTROLLER: \"nexus:controller\",\n\n\t/** Marks a class as an injectable provider. */\n\tINJECTABLE: \"nexus:injectable\",\n\n\t/** Marks a class as a repository. */\n\tREPOSITORY: \"nexus:repository\",\n\n\t/** Marks a class as a module. Stores module options. */\n\tMODULE: \"nexus:module\",\n\n\t/** HTTP method routes registered on a controller (Get/Post/...). */\n\tROUTES: \"nexus:routes\",\n\n\t/** Method parameter type metadata (body/query/param/headers/ctx). */\n\tPARAMS: \"nexus:params\",\n\n\t/** Validation schema per method (Zod schema or class). */\n\tVALIDATE: \"nexus:validate\",\n\n\t/** Class-level design:paramtypes (built-in). */\n\tPARAMTYPES: \"design:paramtypes\",\n\n\t/** Class-level design:type (built-in). */\n\tTYPE: \"design:type\",\n\n\t/** Class-level design:returntype (built-in). */\n\tRETURNTYPE: \"design:returntype\",\n\n\t/** Provider token to inject for a parameter (for custom tokens). */\n\tINJECT: \"nexus:inject\",\n} as const;\n\nexport type MetadataKey = (typeof METADATA_KEY)[keyof typeof METADATA_KEY];\n\n/** Available parameter decorator locations. */\nexport const PARAM_TYPES = {\n\tREQUEST: 0,\n\tRESPONSE: 1,\n\tNEXT: 2,\n\tBODY: 3,\n\tQUERY: 4,\n\tPARAM: 5,\n\tHEADERS: 6,\n\tCTX: 7,\n\tUSER: 8,\n} as const;\n\nexport type ParamType = (typeof PARAM_TYPES)[keyof typeof PARAM_TYPES];\n\n/** HTTP methods supported by the router. */\nexport const HTTP_METHODS = [\n\t\"GET\",\n\t\"POST\",\n\t\"PUT\",\n\t\"DELETE\",\n\t\"PATCH\",\n\t\"OPTIONS\",\n\t\"HEAD\",\n] as const;\nexport type HttpMethod = (typeof HTTP_METHODS)[number];\n",
|
|
6
6
|
"/**\n * @Controller decorator.\n *\n * Marks a class as a controller and registers a route prefix.\n * Routes inside the controller class are decorated with @Get/@Post/etc.\n *\n * @example\n * ```ts\n * @Controller('/users')\n * class UserController {\n * @Get('/')\n * list() { ... }\n * }\n * ```\n */\nimport \"reflect-metadata\";\nimport { METADATA_KEY } from \"../constants.js\";\nimport type { ControllerMetadata } from \"../di/tokens.js\";\n\nexport function Controller(prefix: string = \"/\"): ClassDecorator {\n\treturn (target: object) => {\n\t\tconst normalized = normalizePrefix(prefix);\n\t\tconst meta: ControllerMetadata = { prefix: normalized };\n\t\tReflect.defineMetadata(METADATA_KEY.CONTROLLER, meta, target);\n\t};\n}\n\nexport function getControllerMetadata(target: any): ControllerMetadata {\n\treturn (\n\t\tReflect.getMetadata(METADATA_KEY.CONTROLLER, target) ?? { prefix: \"/\" }\n\t);\n}\n\nexport function isController(target: any): boolean {\n\treturn Reflect.hasMetadata(METADATA_KEY.CONTROLLER, target);\n}\n\n/**\n * Normalize a prefix so we can safely concatenate it with handler paths.\n * - Empty string becomes '/'.\n * - Trailing slashes are trimmed (we re-add them on the join).\n * - No leading slash is added; the router always joins with `/`.\n */\nfunction normalizePrefix(prefix: string): string {\n\tif (!prefix) return \"\";\n\tif (prefix !== \"/\" && prefix.endsWith(\"/\")) {\n\t\treturn prefix.slice(0, -1);\n\t}\n\treturn prefix;\n}\n",
|
|
7
|
-
"/**\n * HTTP method decorators.\n *\n * `@Get`, `@Post`, `@Put`, `@Delete`, `@Patch`, `@Options`, `@Head` mark a\n * controller method as a route handler. The path argument is appended to\n * the controller's prefix.\n *\n * @example\n * ```ts\n * @Controller('/users')\n * class UserController {\n * @Get('/')\n * list() {}\n *\n * @Post('/')\n * create(@Body() body: CreateUserDto) {}\n * }\n * ```\n */\nimport \"reflect-metadata\";\nimport { HTTP_METHODS, METADATA_KEY, type HttpMethod } from \"../constants.js\";\nimport type { RouteMetadata } from \"../di/tokens.js\";\n\nfunction defineRoute(method: HttpMethod, path: string): MethodDecorator {\n\treturn (\n\t\ttarget: object,\n\t\tpropertyKey: string | symbol,\n\t\tdescriptor:
|
|
7
|
+
"/**\n * HTTP method decorators.\n *\n * `@Get`, `@Post`, `@Put`, `@Delete`, `@Patch`, `@Options`, `@Head` mark a\n * controller method as a route handler. The path argument is appended to\n * the controller's prefix.\n *\n * @example\n * ```ts\n * @Controller('/users')\n * class UserController {\n * @Get('/')\n * list() {}\n *\n * @Post('/')\n * create(@Body() body: CreateUserDto) {}\n * }\n * ```\n */\nimport \"reflect-metadata\";\nimport { HTTP_METHODS, METADATA_KEY, type HttpMethod } from \"../constants.js\";\nimport type { RouteMetadata } from \"../di/tokens.js\";\n\nfunction defineRoute(method: HttpMethod, path: string): MethodDecorator {\n\treturn (\n\t\ttarget: object,\n\t\tpropertyKey: string | symbol,\n\t\tdescriptor: TypedPropertyDescriptor<any>,\n\t) => {\n\t\tconst routes: RouteMetadata[] =\n\t\t\tReflect.getMetadata(METADATA_KEY.ROUTES, target.constructor) ?? [];\n\n\t\troutes.push({\n\t\t\tmethod,\n\t\t\tpath: normalizePath(path),\n\t\t\tpropertyKey,\n\t\t\thandler: descriptor.value,\n\t\t});\n\n\t\tReflect.defineMetadata(METADATA_KEY.ROUTES, routes, target.constructor);\n\t};\n}\n\nfunction normalizePath(path: string): string {\n\tif (!path || path === \"/\") return \"/\";\n\treturn path.startsWith(\"/\") ? path : `/${path}`;\n}\n\nexport const Get = (path: string = \"/\") => defineRoute(\"GET\", path);\nexport const Post = (path: string = \"/\") => defineRoute(\"POST\", path);\nexport const Put = (path: string = \"/\") => defineRoute(\"PUT\", path);\nexport const Delete = (path: string = \"/\") => defineRoute(\"DELETE\", path);\nexport const Patch = (path: string = \"/\") => defineRoute(\"PATCH\", path);\nexport const Options = (path: string = \"/\") => defineRoute(\"OPTIONS\", path);\nexport const Head = (path: string = \"/\") => defineRoute(\"HEAD\", path);\n\nexport function getRoutes(target: any): RouteMetadata[] {\n\treturn Reflect.getMetadata(METADATA_KEY.ROUTES, target) ?? [];\n}\n\nexport { HTTP_METHODS };\nexport type { RouteMetadata };\n",
|
|
8
8
|
"/**\n * Parameter decorators.\n *\n * These mark a controller method argument as a source of request data:\n * - `@Req()` → Hono context\n * - `@Res()` → Response helper\n * - `@Next()` → next() callback (for middleware-style handlers)\n * - `@Body()` → request body (parsed)\n * - `@Query('key')` → a single query param, or full query object\n * - `@Param('key')` → a single path param, or full params object\n * - `@Headers('k')` → a single header, or full headers object\n * - `@Ctx()` → Hono context (alias for @Req)\n * - `@User()` → authenticated user (resolved via auth provider)\n *\n * The metadata is read by the router at mount time to build the\n * handler invocation list.\n */\nimport \"reflect-metadata\";\nimport { METADATA_KEY, PARAM_TYPES } from \"../constants.js\";\nimport type { ParamMetadata } from \"../di/tokens.js\";\n\nexport function createParamDecorator(\n\ttype: number,\n\tdata?: string | object,\n): ParameterDecorator {\n\treturn (\n\t\ttarget: object,\n\t\tpropertyKey: string | symbol | undefined,\n\t\tparameterIndex: number,\n\t) => {\n\t\t// Method parameter: target is the prototype, propertyKey is the method name.\n\t\t// Constructor parameter: target is the class, propertyKey is undefined.\n\t\tif (propertyKey !== undefined) {\n\t\t\tconst params: ParamMetadata[] =\n\t\t\t\tReflect.getMetadata(METADATA_KEY.PARAMS, target, propertyKey) ?? [];\n\t\t\tparams.push({\n\t\t\t\tindex: parameterIndex,\n\t\t\t\ttype,\n\t\t\t\tname: typeof data === \"string\" ? data : undefined,\n\t\t\t\tdata: typeof data === \"object\" ? data : undefined,\n\t\t\t});\n\t\t\tReflect.defineMetadata(METADATA_KEY.PARAMS, params, target, propertyKey);\n\t\t} else {\n\t\t\tconst params: ParamMetadata[] =\n\t\t\t\tReflect.getMetadata(METADATA_KEY.PARAMS, target) ?? [];\n\t\t\tparams.push({\n\t\t\t\tindex: parameterIndex,\n\t\t\t\ttype,\n\t\t\t\tname: typeof data === \"string\" ? data : undefined,\n\t\t\t\tdata: typeof data === \"object\" ? data : undefined,\n\t\t\t});\n\t\t\tReflect.defineMetadata(METADATA_KEY.PARAMS, params, target);\n\t\t}\n\t};\n}\n\nexport const Req = () => createParamDecorator(PARAM_TYPES.REQUEST);\nexport const Res = () => createParamDecorator(PARAM_TYPES.RESPONSE);\nexport const Next = () => createParamDecorator(PARAM_TYPES.NEXT);\nexport const Body = (key?: string) =>\n\tcreateParamDecorator(PARAM_TYPES.BODY, key);\nexport const Query = (key?: string) =>\n\tcreateParamDecorator(PARAM_TYPES.QUERY, key);\nexport const Param = (key?: string) =>\n\tcreateParamDecorator(PARAM_TYPES.PARAM, key);\nexport const Headers = (key?: string) =>\n\tcreateParamDecorator(PARAM_TYPES.HEADERS, key);\nexport const Ctx = () => createParamDecorator(PARAM_TYPES.CTX);\nexport const User = () => createParamDecorator(PARAM_TYPES.USER);\n\nexport function getParamMetadata(\n\ttarget: any,\n\tpropertyKey: string | symbol,\n): ParamMetadata[] {\n\treturn Reflect.getMetadata(METADATA_KEY.PARAMS, target, propertyKey) ?? [];\n}\n\nexport { PARAM_TYPES };\n",
|
|
9
9
|
"/**\n * @Validate decorator.\n *\n * Attaches Zod schemas (or class validators) to a route handler. Each\n * schema is run against the corresponding request part before the handler\n * executes; failed validation throws or returns a 400 response.\n *\n * @example\n * ```ts\n * const UserSchema = z.object({ name: z.string(), email: z.email() });\n *\n * @Post('/')\n * @Validate({ body: UserSchema })\n * create(@Body() body: z.infer<typeof UserSchema>) { ... }\n * ```\n */\nimport \"reflect-metadata\";\nimport { METADATA_KEY } from \"../constants.js\";\nimport type { ValidationMetadata } from \"../di/tokens.js\";\n\nexport function Validate(options: ValidationMetadata): MethodDecorator {\n\treturn (\n\t\ttarget: object,\n\t\tpropertyKey: string | symbol,\n\t\tdescriptor: PropertyDescriptor,\n\t) => {\n\t\tReflect.defineMetadata(\n\t\t\tMETADATA_KEY.VALIDATE,\n\t\t\toptions,\n\t\t\ttarget.constructor,\n\t\t\tpropertyKey,\n\t\t);\n\t};\n}\n\nexport function getValidationMetadata(\n\ttarget: any,\n\tpropertyKey: string | symbol,\n): ValidationMetadata | undefined {\n\treturn Reflect.getMetadata(METADATA_KEY.VALIDATE, target, propertyKey);\n}\n",
|
|
10
10
|
"/**\n * `nexusjs/drive` — file storage abstraction.\n *\n * const drive = new DriveService({ driver: new LocalDriver({ root: '/var/data' }) });\n * await drive.put('avatars/42.png', bytes, { contentType: 'image/png' });\n * const buf = await drive.get('avatars/42.png');\n *\n * Drivers:\n * - `LocalDriver` — local filesystem\n * - `MemoryDriver` — in-memory map (tests, ephemeral)\n * - `S3Driver` — AWS S3 / Cloudflare R2 (peer dep: @aws-sdk/client-s3)\n *\n * drive.getSignedUrl('avatars/42.png', { expiresIn: 3600 });\n * drive.exists('avatars/42.png');\n * drive.delete('avatars/42.png');\n * drive.list('avatars/');\n */\n\nimport \"reflect-metadata\";\n\n/** File content: Buffer, Uint8Array, or string. */\nexport type FileContent = Buffer | Uint8Array | string;\n\n/** Metadata returned by `head()`. */\nexport interface FileMetadata {\n\t/** Full key. */\n\tkey: string;\n\t/** Size in bytes. */\n\tsize: number;\n\t/** Detected MIME type, if known. */\n\tcontentType?: string;\n\t/** Last-modified time (unix-ms). */\n\tlastModified: number;\n\t/** ETag, if available. */\n\tetag?: string;\n\t/** Custom user metadata. */\n\tmetadata?: Record<string, string>;\n}\n\n/** Options for `put()`. */\nexport interface PutOptions {\n\t/** MIME type. Auto-detected if omitted. */\n\tcontentType?: string;\n\t/** Cache-Control header. */\n\tcacheControl?: string;\n\t/** Custom user metadata. */\n\tmetadata?: Record<string, string>;\n\t/** S3-style ACL (`public-read`, `private`, etc.). */\n\tacl?: string;\n}\n\n/** Options for signed URL. */\nexport interface SignedUrlOptions {\n\t/** Time until the URL expires, in seconds. */\n\texpiresIn?: number;\n\t/** Force download with the given filename. */\n\tasAttachment?: string;\n\t/** Override the Content-Type of the response. */\n\tcontentType?: string;\n\t/** Method. Default: GET. */\n\tmethod?: \"GET\" | \"PUT\" | \"DELETE\";\n}\n\n/** Options for listing. */\nexport interface ListOptions {\n\t/** Return only keys with this prefix. */\n\tprefix?: string;\n\t/** Maximum results. */\n\tlimit?: number;\n\t/** Pagination cursor. */\n\tcursor?: string;\n}\n\n/** A single listing result. */\nexport interface ListResult {\n\tkeys: string[];\n\t/** True if more results are available. */\n\thasMore: boolean;\n\t/** Cursor for the next page. */\n\tcursor?: string;\n}\n\n/** A driver is a single backing store. */\nexport interface StorageDriver {\n\treadonly kind: string;\n\tput(key: string, body: FileContent, opts?: PutOptions): Promise<void>;\n\tget(key: string): Promise<Buffer>;\n\tdelete(key: string): Promise<boolean>;\n\texists(key: string): Promise<boolean>;\n\thead(key: string): Promise<FileMetadata>;\n\tlist(opts?: ListOptions): Promise<ListResult>;\n\tgetSignedUrl(key: string, opts?: SignedUrlOptions): Promise<string>;\n\tcopy(src: string, dest: string): Promise<void>;\n\tmove(src: string, dest: string): Promise<void>;\n}\n\n/** Top-level Drive configuration. */\nexport interface DriveConfig {\n\t/** Storage driver. Default: in-memory. */\n\tdriver?: StorageDriver;\n\t/** Default visibility hint passed to drivers that support it. */\n\tdefaultVisibility?: \"public\" | \"private\";\n\t/** Custom URL builder for `getSignedUrl` (default returns a `nexus://` URL). */\n\tsignedUrlBuilder?: (key: string, opts?: SignedUrlOptions) => Promise<string>;\n}\n",
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"sourcesContent": [
|
|
5
5
|
"/**\n * Metadata keys used by reflect-metadata for storing decorator data.\n *\n * These constants are the contract between decorators and the framework\n * core (DI container, router, validator).\n */\nexport const METADATA_KEY = {\n\t/** Marks a class as a Nest-style controller, stores route prefix. */\n\tCONTROLLER: \"nexus:controller\",\n\n\t/** Marks a class as an injectable provider. */\n\tINJECTABLE: \"nexus:injectable\",\n\n\t/** Marks a class as a repository. */\n\tREPOSITORY: \"nexus:repository\",\n\n\t/** Marks a class as a module. Stores module options. */\n\tMODULE: \"nexus:module\",\n\n\t/** HTTP method routes registered on a controller (Get/Post/...). */\n\tROUTES: \"nexus:routes\",\n\n\t/** Method parameter type metadata (body/query/param/headers/ctx). */\n\tPARAMS: \"nexus:params\",\n\n\t/** Validation schema per method (Zod schema or class). */\n\tVALIDATE: \"nexus:validate\",\n\n\t/** Class-level design:paramtypes (built-in). */\n\tPARAMTYPES: \"design:paramtypes\",\n\n\t/** Class-level design:type (built-in). */\n\tTYPE: \"design:type\",\n\n\t/** Class-level design:returntype (built-in). */\n\tRETURNTYPE: \"design:returntype\",\n\n\t/** Provider token to inject for a parameter (for custom tokens). */\n\tINJECT: \"nexus:inject\",\n} as const;\n\nexport type MetadataKey = (typeof METADATA_KEY)[keyof typeof METADATA_KEY];\n\n/** Available parameter decorator locations. */\nexport const PARAM_TYPES = {\n\tREQUEST: 0,\n\tRESPONSE: 1,\n\tNEXT: 2,\n\tBODY: 3,\n\tQUERY: 4,\n\tPARAM: 5,\n\tHEADERS: 6,\n\tCTX: 7,\n\tUSER: 8,\n} as const;\n\nexport type ParamType = (typeof PARAM_TYPES)[keyof typeof PARAM_TYPES];\n\n/** HTTP methods supported by the router. */\nexport const HTTP_METHODS = [\n\t\"GET\",\n\t\"POST\",\n\t\"PUT\",\n\t\"DELETE\",\n\t\"PATCH\",\n\t\"OPTIONS\",\n\t\"HEAD\",\n] as const;\nexport type HttpMethod = (typeof HTTP_METHODS)[number];\n",
|
|
6
6
|
"/**\n * @Controller decorator.\n *\n * Marks a class as a controller and registers a route prefix.\n * Routes inside the controller class are decorated with @Get/@Post/etc.\n *\n * @example\n * ```ts\n * @Controller('/users')\n * class UserController {\n * @Get('/')\n * list() { ... }\n * }\n * ```\n */\nimport \"reflect-metadata\";\nimport { METADATA_KEY } from \"../constants.js\";\nimport type { ControllerMetadata } from \"../di/tokens.js\";\n\nexport function Controller(prefix: string = \"/\"): ClassDecorator {\n\treturn (target: object) => {\n\t\tconst normalized = normalizePrefix(prefix);\n\t\tconst meta: ControllerMetadata = { prefix: normalized };\n\t\tReflect.defineMetadata(METADATA_KEY.CONTROLLER, meta, target);\n\t};\n}\n\nexport function getControllerMetadata(target: any): ControllerMetadata {\n\treturn (\n\t\tReflect.getMetadata(METADATA_KEY.CONTROLLER, target) ?? { prefix: \"/\" }\n\t);\n}\n\nexport function isController(target: any): boolean {\n\treturn Reflect.hasMetadata(METADATA_KEY.CONTROLLER, target);\n}\n\n/**\n * Normalize a prefix so we can safely concatenate it with handler paths.\n * - Empty string becomes '/'.\n * - Trailing slashes are trimmed (we re-add them on the join).\n * - No leading slash is added; the router always joins with `/`.\n */\nfunction normalizePrefix(prefix: string): string {\n\tif (!prefix) return \"\";\n\tif (prefix !== \"/\" && prefix.endsWith(\"/\")) {\n\t\treturn prefix.slice(0, -1);\n\t}\n\treturn prefix;\n}\n",
|
|
7
|
-
"/**\n * HTTP method decorators.\n *\n * `@Get`, `@Post`, `@Put`, `@Delete`, `@Patch`, `@Options`, `@Head` mark a\n * controller method as a route handler. The path argument is appended to\n * the controller's prefix.\n *\n * @example\n * ```ts\n * @Controller('/users')\n * class UserController {\n * @Get('/')\n * list() {}\n *\n * @Post('/')\n * create(@Body() body: CreateUserDto) {}\n * }\n * ```\n */\nimport \"reflect-metadata\";\nimport { HTTP_METHODS, METADATA_KEY, type HttpMethod } from \"../constants.js\";\nimport type { RouteMetadata } from \"../di/tokens.js\";\n\nfunction defineRoute(method: HttpMethod, path: string): MethodDecorator {\n\treturn (\n\t\ttarget: object,\n\t\tpropertyKey: string | symbol,\n\t\tdescriptor:
|
|
7
|
+
"/**\n * HTTP method decorators.\n *\n * `@Get`, `@Post`, `@Put`, `@Delete`, `@Patch`, `@Options`, `@Head` mark a\n * controller method as a route handler. The path argument is appended to\n * the controller's prefix.\n *\n * @example\n * ```ts\n * @Controller('/users')\n * class UserController {\n * @Get('/')\n * list() {}\n *\n * @Post('/')\n * create(@Body() body: CreateUserDto) {}\n * }\n * ```\n */\nimport \"reflect-metadata\";\nimport { HTTP_METHODS, METADATA_KEY, type HttpMethod } from \"../constants.js\";\nimport type { RouteMetadata } from \"../di/tokens.js\";\n\nfunction defineRoute(method: HttpMethod, path: string): MethodDecorator {\n\treturn (\n\t\ttarget: object,\n\t\tpropertyKey: string | symbol,\n\t\tdescriptor: TypedPropertyDescriptor<any>,\n\t) => {\n\t\tconst routes: RouteMetadata[] =\n\t\t\tReflect.getMetadata(METADATA_KEY.ROUTES, target.constructor) ?? [];\n\n\t\troutes.push({\n\t\t\tmethod,\n\t\t\tpath: normalizePath(path),\n\t\t\tpropertyKey,\n\t\t\thandler: descriptor.value,\n\t\t});\n\n\t\tReflect.defineMetadata(METADATA_KEY.ROUTES, routes, target.constructor);\n\t};\n}\n\nfunction normalizePath(path: string): string {\n\tif (!path || path === \"/\") return \"/\";\n\treturn path.startsWith(\"/\") ? path : `/${path}`;\n}\n\nexport const Get = (path: string = \"/\") => defineRoute(\"GET\", path);\nexport const Post = (path: string = \"/\") => defineRoute(\"POST\", path);\nexport const Put = (path: string = \"/\") => defineRoute(\"PUT\", path);\nexport const Delete = (path: string = \"/\") => defineRoute(\"DELETE\", path);\nexport const Patch = (path: string = \"/\") => defineRoute(\"PATCH\", path);\nexport const Options = (path: string = \"/\") => defineRoute(\"OPTIONS\", path);\nexport const Head = (path: string = \"/\") => defineRoute(\"HEAD\", path);\n\nexport function getRoutes(target: any): RouteMetadata[] {\n\treturn Reflect.getMetadata(METADATA_KEY.ROUTES, target) ?? [];\n}\n\nexport { HTTP_METHODS };\nexport type { RouteMetadata };\n",
|
|
8
8
|
"/**\n * Parameter decorators.\n *\n * These mark a controller method argument as a source of request data:\n * - `@Req()` → Hono context\n * - `@Res()` → Response helper\n * - `@Next()` → next() callback (for middleware-style handlers)\n * - `@Body()` → request body (parsed)\n * - `@Query('key')` → a single query param, or full query object\n * - `@Param('key')` → a single path param, or full params object\n * - `@Headers('k')` → a single header, or full headers object\n * - `@Ctx()` → Hono context (alias for @Req)\n * - `@User()` → authenticated user (resolved via auth provider)\n *\n * The metadata is read by the router at mount time to build the\n * handler invocation list.\n */\nimport \"reflect-metadata\";\nimport { METADATA_KEY, PARAM_TYPES } from \"../constants.js\";\nimport type { ParamMetadata } from \"../di/tokens.js\";\n\nexport function createParamDecorator(\n\ttype: number,\n\tdata?: string | object,\n): ParameterDecorator {\n\treturn (\n\t\ttarget: object,\n\t\tpropertyKey: string | symbol | undefined,\n\t\tparameterIndex: number,\n\t) => {\n\t\t// Method parameter: target is the prototype, propertyKey is the method name.\n\t\t// Constructor parameter: target is the class, propertyKey is undefined.\n\t\tif (propertyKey !== undefined) {\n\t\t\tconst params: ParamMetadata[] =\n\t\t\t\tReflect.getMetadata(METADATA_KEY.PARAMS, target, propertyKey) ?? [];\n\t\t\tparams.push({\n\t\t\t\tindex: parameterIndex,\n\t\t\t\ttype,\n\t\t\t\tname: typeof data === \"string\" ? data : undefined,\n\t\t\t\tdata: typeof data === \"object\" ? data : undefined,\n\t\t\t});\n\t\t\tReflect.defineMetadata(METADATA_KEY.PARAMS, params, target, propertyKey);\n\t\t} else {\n\t\t\tconst params: ParamMetadata[] =\n\t\t\t\tReflect.getMetadata(METADATA_KEY.PARAMS, target) ?? [];\n\t\t\tparams.push({\n\t\t\t\tindex: parameterIndex,\n\t\t\t\ttype,\n\t\t\t\tname: typeof data === \"string\" ? data : undefined,\n\t\t\t\tdata: typeof data === \"object\" ? data : undefined,\n\t\t\t});\n\t\t\tReflect.defineMetadata(METADATA_KEY.PARAMS, params, target);\n\t\t}\n\t};\n}\n\nexport const Req = () => createParamDecorator(PARAM_TYPES.REQUEST);\nexport const Res = () => createParamDecorator(PARAM_TYPES.RESPONSE);\nexport const Next = () => createParamDecorator(PARAM_TYPES.NEXT);\nexport const Body = (key?: string) =>\n\tcreateParamDecorator(PARAM_TYPES.BODY, key);\nexport const Query = (key?: string) =>\n\tcreateParamDecorator(PARAM_TYPES.QUERY, key);\nexport const Param = (key?: string) =>\n\tcreateParamDecorator(PARAM_TYPES.PARAM, key);\nexport const Headers = (key?: string) =>\n\tcreateParamDecorator(PARAM_TYPES.HEADERS, key);\nexport const Ctx = () => createParamDecorator(PARAM_TYPES.CTX);\nexport const User = () => createParamDecorator(PARAM_TYPES.USER);\n\nexport function getParamMetadata(\n\ttarget: any,\n\tpropertyKey: string | symbol,\n): ParamMetadata[] {\n\treturn Reflect.getMetadata(METADATA_KEY.PARAMS, target, propertyKey) ?? [];\n}\n\nexport { PARAM_TYPES };\n",
|
|
9
9
|
"/**\n * @Validate decorator.\n *\n * Attaches Zod schemas (or class validators) to a route handler. Each\n * schema is run against the corresponding request part before the handler\n * executes; failed validation throws or returns a 400 response.\n *\n * @example\n * ```ts\n * const UserSchema = z.object({ name: z.string(), email: z.email() });\n *\n * @Post('/')\n * @Validate({ body: UserSchema })\n * create(@Body() body: z.infer<typeof UserSchema>) { ... }\n * ```\n */\nimport \"reflect-metadata\";\nimport { METADATA_KEY } from \"../constants.js\";\nimport type { ValidationMetadata } from \"../di/tokens.js\";\n\nexport function Validate(options: ValidationMetadata): MethodDecorator {\n\treturn (\n\t\ttarget: object,\n\t\tpropertyKey: string | symbol,\n\t\tdescriptor: PropertyDescriptor,\n\t) => {\n\t\tReflect.defineMetadata(\n\t\t\tMETADATA_KEY.VALIDATE,\n\t\t\toptions,\n\t\t\ttarget.constructor,\n\t\t\tpropertyKey,\n\t\t);\n\t};\n}\n\nexport function getValidationMetadata(\n\ttarget: any,\n\tpropertyKey: string | symbol,\n): ValidationMetadata | undefined {\n\treturn Reflect.getMetadata(METADATA_KEY.VALIDATE, target, propertyKey);\n}\n",
|
|
10
10
|
"/**\n * `nexusjs/drizzle` — Drizzle ORM integration. Default ORM for NexusJS.\n *\n * @Module({\n * imports: [\n * DrizzleModule.forRoot({\n * dialect: 'postgres',\n * url: process.env.DATABASE_URL!,\n * }),\n * ],\n * })\n *\n * class UserService {\n * constructor(@Inject(DrizzleService.TOKEN) private db: DrizzleService) {}\n * list() { return this.db.select().from(users).all(); }\n * }\n *\n * Drivers:\n * - `postgres` — node-postgres / postgres.js\n * - `mysql` — mysql2\n * - `sqlite` — better-sqlite3 / libsql\n * - `bun-sqlite`— bun:sqlite (built-in)\n * - `d1` — Cloudflare D1 (Workers)\n *\n * Lucid gap closure:\n * - `DrizzleRepository<TTable, TRow>` — repository pattern (model + queries)\n * - `DrizzleModel` — base class for entity models\n * - `@Table()`, `@Column()`, `@PrimaryKey()` decorators\n * - `db.migrate(folder)` — automatic migrations\n * - `db.transaction(fn)` — ACID transactions\n *\n * Raw queries:\n * - `db.raw\\`SELECT * FROM users WHERE id = ${id}\\`` — parameterized, safe.\n */\n\nimport \"reflect-metadata\";\n\n// ---------------------------------------------------------------------------\n// Dialect\n// ---------------------------------------------------------------------------\n\nexport type DrizzleDialect =\n\t| \"postgres\"\n\t| \"mysql\"\n\t| \"sqlite\"\n\t| \"bun-sqlite\"\n\t| \"d1\";\n\n// ---------------------------------------------------------------------------\n// Connection options\n// ---------------------------------------------------------------------------\n\nexport interface PostgresConnectionOptions {\n\t/** Postgres connection URL. */\n\turl?: string;\n\t/** Individual connection fields (alternative to `url`). */\n\thost?: string;\n\tport?: number;\n\tuser?: string;\n\tpassword?: string;\n\tdatabase?: string;\n\t/** SSL mode. */\n\tssl?: boolean | \"require\" | \"prefer\" | \"allow\";\n\t/** Pool settings. */\n\tpool?: { max?: number; idleTimeoutMs?: number; connectionTimeoutMs?: number };\n\t/** Schema (default 'public'). */\n\tschema?: string;\n}\n\nexport interface MysqlConnectionOptions {\n\turl?: string;\n\thost?: string;\n\tport?: number;\n\tuser?: string;\n\tpassword?: string;\n\tdatabase?: string;\n\tpool?: { max?: number; idleTimeoutMs?: number; connectionTimeoutMs?: number };\n}\n\nexport interface SqliteConnectionOptions {\n\t/** File path or ':memory:'. */\n\tfilename: string;\n\t/** Optional readonly mode. */\n\treadonly?: boolean;\n}\n\nexport interface D1ConnectionOptions {\n\t/** A Cloudflare D1 binding (D1Database). */\n\tbinding: unknown;\n}\n\nexport type ConnectionOptions =\n\t| { dialect: \"postgres\"; connection: PostgresConnectionOptions }\n\t| { dialect: \"mysql\"; connection: MysqlConnectionOptions }\n\t| { dialect: \"sqlite\"; connection: SqliteConnectionOptions }\n\t| { dialect: \"bun-sqlite\"; connection: SqliteConnectionOptions }\n\t| { dialect: \"d1\"; connection: D1ConnectionOptions };\n\n// ---------------------------------------------------------------------------\n// Top-level config\n// ---------------------------------------------------------------------------\n\nexport interface DrizzleConfig {\n\tdialect: DrizzleDialect;\n\t/** Connection details. Dialect-specific. */\n\tconnection:\n\t\t| PostgresConnectionOptions\n\t\t| MysqlConnectionOptions\n\t\t| SqliteConnectionOptions\n\t\t| D1ConnectionOptions;\n\t/** Enable query logging. */\n\tlogging?: boolean | ((query: string, params: unknown[]) => void);\n\t/** Schema name (Postgres only). Default: 'public'. */\n\tschema?: string;\n\t/** Migration folder. Used by `db.migrate(folder)`. */\n\tmigrationsFolder?: string;\n\t/** Whether to auto-run migrations on boot. */\n\tautoMigrate?: boolean;\n}\n\n// ---------------------------------------------------------------------------\n// Migrations\n// ---------------------------------------------------------------------------\n\nexport interface MigrationMeta {\n\t/** Folder filename (e.g. '0001_init.sql'). */\n\tfilename: string;\n\t/** Hash of the file content. */\n\thash: string;\n}\n\nexport interface MigrationRecord {\n\tid: number;\n\thash: string;\n\t/** When this migration was applied. */\n\tappliedAt: Date;\n}\n\nexport interface MigrateResult {\n\t/** Newly-applied migrations. */\n\tapplied: MigrationRecord[];\n\t/** Total count after this run. */\n\ttotal: number;\n}\n\n// ---------------------------------------------------------------------------\n// Raw query result\n// ---------------------------------------------------------------------------\n\nexport interface RawQueryResult<T = Record<string, unknown>> {\n\trows: T[];\n\t/** Number of affected rows (UPDATE/DELETE/INSERT). */\n\taffectedRows: number;\n\t/** Insert ID (MySQL/SQLite). */\n\tinsertId?: number | string;\n}\n\n// ---------------------------------------------------------------------------\n// Decorator metadata\n// ---------------------------------------------------------------------------\n\nexport interface ColumnMetadata {\n\tname: string;\n\ttype: string;\n\tnullable: boolean;\n\tprimaryKey: boolean;\n\tautoIncrement: boolean;\n\tunique: boolean;\n\tdefault?: unknown;\n\treferences?: {\n\t\ttable: string;\n\t\tcolumn: string;\n\t\tonDelete?: \"cascade\" | \"set null\" | \"restrict\";\n\t};\n}\n\nexport interface TableMetadata {\n\tname: string;\n\tcolumns: Map<string, ColumnMetadata>;\n}\n\n/** Internal metadata key. */\nexport const DRIZZLE_TABLE_META = \"nexus:drizzle:table\";\n\nexport interface DrizzleTransaction {\n\t/** Run a callback in this transaction. */\n\tcommit<T>(fn: (tx: DrizzleTransaction) => Promise<T>): Promise<T>;\n\t/** Roll back the transaction. */\n\trollback(): Promise<void>;\n}\n",
|
package/dist/events/index.js.map
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"sourcesContent": [
|
|
5
5
|
"/**\n * Metadata keys used by reflect-metadata for storing decorator data.\n *\n * These constants are the contract between decorators and the framework\n * core (DI container, router, validator).\n */\nexport const METADATA_KEY = {\n\t/** Marks a class as a Nest-style controller, stores route prefix. */\n\tCONTROLLER: \"nexus:controller\",\n\n\t/** Marks a class as an injectable provider. */\n\tINJECTABLE: \"nexus:injectable\",\n\n\t/** Marks a class as a repository. */\n\tREPOSITORY: \"nexus:repository\",\n\n\t/** Marks a class as a module. Stores module options. */\n\tMODULE: \"nexus:module\",\n\n\t/** HTTP method routes registered on a controller (Get/Post/...). */\n\tROUTES: \"nexus:routes\",\n\n\t/** Method parameter type metadata (body/query/param/headers/ctx). */\n\tPARAMS: \"nexus:params\",\n\n\t/** Validation schema per method (Zod schema or class). */\n\tVALIDATE: \"nexus:validate\",\n\n\t/** Class-level design:paramtypes (built-in). */\n\tPARAMTYPES: \"design:paramtypes\",\n\n\t/** Class-level design:type (built-in). */\n\tTYPE: \"design:type\",\n\n\t/** Class-level design:returntype (built-in). */\n\tRETURNTYPE: \"design:returntype\",\n\n\t/** Provider token to inject for a parameter (for custom tokens). */\n\tINJECT: \"nexus:inject\",\n} as const;\n\nexport type MetadataKey = (typeof METADATA_KEY)[keyof typeof METADATA_KEY];\n\n/** Available parameter decorator locations. */\nexport const PARAM_TYPES = {\n\tREQUEST: 0,\n\tRESPONSE: 1,\n\tNEXT: 2,\n\tBODY: 3,\n\tQUERY: 4,\n\tPARAM: 5,\n\tHEADERS: 6,\n\tCTX: 7,\n\tUSER: 8,\n} as const;\n\nexport type ParamType = (typeof PARAM_TYPES)[keyof typeof PARAM_TYPES];\n\n/** HTTP methods supported by the router. */\nexport const HTTP_METHODS = [\n\t\"GET\",\n\t\"POST\",\n\t\"PUT\",\n\t\"DELETE\",\n\t\"PATCH\",\n\t\"OPTIONS\",\n\t\"HEAD\",\n] as const;\nexport type HttpMethod = (typeof HTTP_METHODS)[number];\n",
|
|
6
6
|
"/**\n * @Controller decorator.\n *\n * Marks a class as a controller and registers a route prefix.\n * Routes inside the controller class are decorated with @Get/@Post/etc.\n *\n * @example\n * ```ts\n * @Controller('/users')\n * class UserController {\n * @Get('/')\n * list() { ... }\n * }\n * ```\n */\nimport \"reflect-metadata\";\nimport { METADATA_KEY } from \"../constants.js\";\nimport type { ControllerMetadata } from \"../di/tokens.js\";\n\nexport function Controller(prefix: string = \"/\"): ClassDecorator {\n\treturn (target: object) => {\n\t\tconst normalized = normalizePrefix(prefix);\n\t\tconst meta: ControllerMetadata = { prefix: normalized };\n\t\tReflect.defineMetadata(METADATA_KEY.CONTROLLER, meta, target);\n\t};\n}\n\nexport function getControllerMetadata(target: any): ControllerMetadata {\n\treturn (\n\t\tReflect.getMetadata(METADATA_KEY.CONTROLLER, target) ?? { prefix: \"/\" }\n\t);\n}\n\nexport function isController(target: any): boolean {\n\treturn Reflect.hasMetadata(METADATA_KEY.CONTROLLER, target);\n}\n\n/**\n * Normalize a prefix so we can safely concatenate it with handler paths.\n * - Empty string becomes '/'.\n * - Trailing slashes are trimmed (we re-add them on the join).\n * - No leading slash is added; the router always joins with `/`.\n */\nfunction normalizePrefix(prefix: string): string {\n\tif (!prefix) return \"\";\n\tif (prefix !== \"/\" && prefix.endsWith(\"/\")) {\n\t\treturn prefix.slice(0, -1);\n\t}\n\treturn prefix;\n}\n",
|
|
7
|
-
"/**\n * HTTP method decorators.\n *\n * `@Get`, `@Post`, `@Put`, `@Delete`, `@Patch`, `@Options`, `@Head` mark a\n * controller method as a route handler. The path argument is appended to\n * the controller's prefix.\n *\n * @example\n * ```ts\n * @Controller('/users')\n * class UserController {\n * @Get('/')\n * list() {}\n *\n * @Post('/')\n * create(@Body() body: CreateUserDto) {}\n * }\n * ```\n */\nimport \"reflect-metadata\";\nimport { HTTP_METHODS, METADATA_KEY, type HttpMethod } from \"../constants.js\";\nimport type { RouteMetadata } from \"../di/tokens.js\";\n\nfunction defineRoute(method: HttpMethod, path: string): MethodDecorator {\n\treturn (\n\t\ttarget: object,\n\t\tpropertyKey: string | symbol,\n\t\tdescriptor:
|
|
7
|
+
"/**\n * HTTP method decorators.\n *\n * `@Get`, `@Post`, `@Put`, `@Delete`, `@Patch`, `@Options`, `@Head` mark a\n * controller method as a route handler. The path argument is appended to\n * the controller's prefix.\n *\n * @example\n * ```ts\n * @Controller('/users')\n * class UserController {\n * @Get('/')\n * list() {}\n *\n * @Post('/')\n * create(@Body() body: CreateUserDto) {}\n * }\n * ```\n */\nimport \"reflect-metadata\";\nimport { HTTP_METHODS, METADATA_KEY, type HttpMethod } from \"../constants.js\";\nimport type { RouteMetadata } from \"../di/tokens.js\";\n\nfunction defineRoute(method: HttpMethod, path: string): MethodDecorator {\n\treturn (\n\t\ttarget: object,\n\t\tpropertyKey: string | symbol,\n\t\tdescriptor: TypedPropertyDescriptor<any>,\n\t) => {\n\t\tconst routes: RouteMetadata[] =\n\t\t\tReflect.getMetadata(METADATA_KEY.ROUTES, target.constructor) ?? [];\n\n\t\troutes.push({\n\t\t\tmethod,\n\t\t\tpath: normalizePath(path),\n\t\t\tpropertyKey,\n\t\t\thandler: descriptor.value,\n\t\t});\n\n\t\tReflect.defineMetadata(METADATA_KEY.ROUTES, routes, target.constructor);\n\t};\n}\n\nfunction normalizePath(path: string): string {\n\tif (!path || path === \"/\") return \"/\";\n\treturn path.startsWith(\"/\") ? path : `/${path}`;\n}\n\nexport const Get = (path: string = \"/\") => defineRoute(\"GET\", path);\nexport const Post = (path: string = \"/\") => defineRoute(\"POST\", path);\nexport const Put = (path: string = \"/\") => defineRoute(\"PUT\", path);\nexport const Delete = (path: string = \"/\") => defineRoute(\"DELETE\", path);\nexport const Patch = (path: string = \"/\") => defineRoute(\"PATCH\", path);\nexport const Options = (path: string = \"/\") => defineRoute(\"OPTIONS\", path);\nexport const Head = (path: string = \"/\") => defineRoute(\"HEAD\", path);\n\nexport function getRoutes(target: any): RouteMetadata[] {\n\treturn Reflect.getMetadata(METADATA_KEY.ROUTES, target) ?? [];\n}\n\nexport { HTTP_METHODS };\nexport type { RouteMetadata };\n",
|
|
8
8
|
"/**\n * Parameter decorators.\n *\n * These mark a controller method argument as a source of request data:\n * - `@Req()` → Hono context\n * - `@Res()` → Response helper\n * - `@Next()` → next() callback (for middleware-style handlers)\n * - `@Body()` → request body (parsed)\n * - `@Query('key')` → a single query param, or full query object\n * - `@Param('key')` → a single path param, or full params object\n * - `@Headers('k')` → a single header, or full headers object\n * - `@Ctx()` → Hono context (alias for @Req)\n * - `@User()` → authenticated user (resolved via auth provider)\n *\n * The metadata is read by the router at mount time to build the\n * handler invocation list.\n */\nimport \"reflect-metadata\";\nimport { METADATA_KEY, PARAM_TYPES } from \"../constants.js\";\nimport type { ParamMetadata } from \"../di/tokens.js\";\n\nexport function createParamDecorator(\n\ttype: number,\n\tdata?: string | object,\n): ParameterDecorator {\n\treturn (\n\t\ttarget: object,\n\t\tpropertyKey: string | symbol | undefined,\n\t\tparameterIndex: number,\n\t) => {\n\t\t// Method parameter: target is the prototype, propertyKey is the method name.\n\t\t// Constructor parameter: target is the class, propertyKey is undefined.\n\t\tif (propertyKey !== undefined) {\n\t\t\tconst params: ParamMetadata[] =\n\t\t\t\tReflect.getMetadata(METADATA_KEY.PARAMS, target, propertyKey) ?? [];\n\t\t\tparams.push({\n\t\t\t\tindex: parameterIndex,\n\t\t\t\ttype,\n\t\t\t\tname: typeof data === \"string\" ? data : undefined,\n\t\t\t\tdata: typeof data === \"object\" ? data : undefined,\n\t\t\t});\n\t\t\tReflect.defineMetadata(METADATA_KEY.PARAMS, params, target, propertyKey);\n\t\t} else {\n\t\t\tconst params: ParamMetadata[] =\n\t\t\t\tReflect.getMetadata(METADATA_KEY.PARAMS, target) ?? [];\n\t\t\tparams.push({\n\t\t\t\tindex: parameterIndex,\n\t\t\t\ttype,\n\t\t\t\tname: typeof data === \"string\" ? data : undefined,\n\t\t\t\tdata: typeof data === \"object\" ? data : undefined,\n\t\t\t});\n\t\t\tReflect.defineMetadata(METADATA_KEY.PARAMS, params, target);\n\t\t}\n\t};\n}\n\nexport const Req = () => createParamDecorator(PARAM_TYPES.REQUEST);\nexport const Res = () => createParamDecorator(PARAM_TYPES.RESPONSE);\nexport const Next = () => createParamDecorator(PARAM_TYPES.NEXT);\nexport const Body = (key?: string) =>\n\tcreateParamDecorator(PARAM_TYPES.BODY, key);\nexport const Query = (key?: string) =>\n\tcreateParamDecorator(PARAM_TYPES.QUERY, key);\nexport const Param = (key?: string) =>\n\tcreateParamDecorator(PARAM_TYPES.PARAM, key);\nexport const Headers = (key?: string) =>\n\tcreateParamDecorator(PARAM_TYPES.HEADERS, key);\nexport const Ctx = () => createParamDecorator(PARAM_TYPES.CTX);\nexport const User = () => createParamDecorator(PARAM_TYPES.USER);\n\nexport function getParamMetadata(\n\ttarget: any,\n\tpropertyKey: string | symbol,\n): ParamMetadata[] {\n\treturn Reflect.getMetadata(METADATA_KEY.PARAMS, target, propertyKey) ?? [];\n}\n\nexport { PARAM_TYPES };\n",
|
|
9
9
|
"/**\n * @Validate decorator.\n *\n * Attaches Zod schemas (or class validators) to a route handler. Each\n * schema is run against the corresponding request part before the handler\n * executes; failed validation throws or returns a 400 response.\n *\n * @example\n * ```ts\n * const UserSchema = z.object({ name: z.string(), email: z.email() });\n *\n * @Post('/')\n * @Validate({ body: UserSchema })\n * create(@Body() body: z.infer<typeof UserSchema>) { ... }\n * ```\n */\nimport \"reflect-metadata\";\nimport { METADATA_KEY } from \"../constants.js\";\nimport type { ValidationMetadata } from \"../di/tokens.js\";\n\nexport function Validate(options: ValidationMetadata): MethodDecorator {\n\treturn (\n\t\ttarget: object,\n\t\tpropertyKey: string | symbol,\n\t\tdescriptor: PropertyDescriptor,\n\t) => {\n\t\tReflect.defineMetadata(\n\t\t\tMETADATA_KEY.VALIDATE,\n\t\t\toptions,\n\t\t\ttarget.constructor,\n\t\t\tpropertyKey,\n\t\t);\n\t};\n}\n\nexport function getValidationMetadata(\n\ttarget: any,\n\tpropertyKey: string | symbol,\n): ValidationMetadata | undefined {\n\treturn Reflect.getMetadata(METADATA_KEY.VALIDATE, target, propertyKey);\n}\n",
|
|
10
10
|
"/**\n * In-process event emitter with wildcard matching, priorities, and\n * guards. Mirrors `@nestjs/event-emitter` and AdonisJS's emitter.\n *\n * Wildcards:\n * - star (single segment) — `user.star` matches `user.created`\n * - double-star (multi segment) — `star-star` matches `user.created` and `user.profile.updated`\n * - exact — `user.created` matches only itself\n *\n * Priority: lower runs first (default 5). When two listeners have the\n * same priority, registration order is preserved (FIFO).\n *\n * Guards: a listener can register an `if(payload) → boolean` predicate;\n * when it returns false, the listener is skipped.\n *\n * Errors: by default, a throwing listener does NOT stop the rest of\n * the dispatch — errors are collected in `EmitResult.errors`. Set\n * `EventsConfig.throwOnError: true` to make `emit()` reject instead.\n */\n\nimport type {\n\tEventName,\n\tEventPriority,\n\tEventListener,\n\tListenerOptions,\n\tEmitResult,\n\tEventEmitter,\n\tEmitterEvent,\n\tEmitterEventListener,\n\tEventsConfig,\n} from \"./types.js\";\n\ninterface InternalListener {\n\tid: string;\n\tpattern: string;\n\tregex: RegExp | null; // null = exact match\n\tpriority: EventPriority;\n\tguard?: (payload: any) => boolean | Promise<boolean>;\n\tonce: boolean;\n\tlistener: EventListener;\n\tcreatedAt: number;\n}\n\nexport class NexusEventEmitter implements EventEmitter {\n\t#listeners: InternalListener[] = [];\n\t#emitterListeners = new Set<EmitterEventListener>();\n\t#maxPerPattern: number;\n\t#throwOnError: boolean;\n\t#defaultPriority: EventPriority;\n\t#nextId = 1;\n\n\tconstructor(config: EventsConfig = {}) {\n\t\tthis.#maxPerPattern = config.maxListenersPerPattern ?? 10;\n\t\tthis.#throwOnError = config.throwOnError ?? false;\n\t\tthis.#defaultPriority = config.defaultPriority ?? 5;\n\t}\n\n\t// ===========================================================================\n\t// Public API\n\t// ===========================================================================\n\n\ton<T = unknown>(\n\t\tpattern: EventName,\n\t\tlistener: EventListener<T>,\n\t\toptions: ListenerOptions = {},\n\t): string {\n\t\tconst existing = this.#listeners.filter((l) => l.pattern === pattern);\n\t\tif (existing.length >= this.#maxPerPattern) {\n\t\t\tthrow new Error(\n\t\t\t\t`[events] Too many listeners registered for \"${pattern}\" ` +\n\t\t\t\t\t`(max ${this.#maxPerPattern}). Increase \\`maxListenersPerPattern\\` ` +\n\t\t\t\t\t`or call \\`off()\\` on stale listeners.`,\n\t\t\t);\n\t\t}\n\t\tconst id = this.#allocateId();\n\t\tconst internal: InternalListener = {\n\t\t\tid,\n\t\t\tpattern,\n\t\t\tregex: compilePattern(pattern),\n\t\t\tpriority: options.priority ?? this.#defaultPriority,\n\t\t\tonce: options.once ?? false,\n\t\t\tlistener: listener as EventListener,\n\t\t\tcreatedAt: Date.now(),\n\t\t};\n\t\tif (options.if !== undefined) {\n\t\t\tinternal.guard = options.if as (\n\t\t\t\tpayload: any,\n\t\t\t) => boolean | Promise<boolean>;\n\t\t}\n\t\tthis.#listeners.push(internal);\n\t\tthis.#sortListeners();\n\t\tthis.#emitEmitterEvent({ kind: \"listener:registered\", id, pattern });\n\t\treturn id;\n\t}\n\n\tonce<T = unknown>(\n\t\tpattern: EventName,\n\t\tlistener: EventListener<T>,\n\t\toptions: Omit<ListenerOptions, \"once\"> = {},\n\t): string {\n\t\treturn this.on(pattern, listener, { ...options, once: true });\n\t}\n\n\toff(idOrPattern: string): number {\n\t\tconst before = this.#listeners.length;\n\t\tconst removed: InternalListener[] = [];\n\t\tthis.#listeners = this.#listeners.filter((l) => {\n\t\t\tconst match = l.id === idOrPattern || l.pattern === idOrPattern;\n\t\t\tif (match) removed.push(l);\n\t\t\treturn !match;\n\t\t});\n\t\tfor (const r of removed) {\n\t\t\tthis.#emitEmitterEvent({ kind: \"listener:removed\", id: r.id });\n\t\t}\n\t\treturn before - this.#listeners.length;\n\t}\n\n\tasync emit<T = unknown>(name: EventName, payload?: T): Promise<EmitResult> {\n\t\tconst result: EmitResult = {\n\t\t\tname,\n\t\t\tmatched: 0,\n\t\t\tcompleted: 0,\n\t\t\tfailed: 0,\n\t\t\terrors: [],\n\t\t};\n\t\tconst matches = this.#matchingListeners(name);\n\t\tresult.matched = matches.length;\n\t\tif (matches.length === 0) return result;\n\n\t\t// Run guards in parallel (they're cheap), then dispatch in priority order.\n\t\tconst eligible: Array<{ listener: InternalListener; payload: any }> = [];\n\t\tfor (const l of matches) {\n\t\t\tif (l.guard) {\n\t\t\t\ttry {\n\t\t\t\t\tconst ok = await l.guard(payload);\n\t\t\t\t\tif (!ok) {\n\t\t\t\t\t\tthis.#emitEmitterEvent({\n\t\t\t\t\t\t\tkind: \"listener:skipped\",\n\t\t\t\t\t\t\tid: l.id,\n\t\t\t\t\t\t\tpattern: l.pattern,\n\t\t\t\t\t\t\treason: \"guard\",\n\t\t\t\t\t\t});\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t} catch {\n\t\t\t\t\t// Guard threw — skip.\n\t\t\t\t\tthis.#emitEmitterEvent({\n\t\t\t\t\t\tkind: \"listener:skipped\",\n\t\t\t\t\t\tid: l.id,\n\t\t\t\t\t\tpattern: l.pattern,\n\t\t\t\t\t\treason: \"guard\",\n\t\t\t\t\t});\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\t\t\teligible.push({ listener: l, payload });\n\t\t}\n\n\t\t// Dispatch eligible listeners in priority order.\n\t\t// `once` listeners are removed on success or failure.\n\t\tconst toRemove: InternalListener[] = [];\n\t\tfor (const { listener, payload: p } of eligible) {\n\t\t\tconst start = Date.now();\n\t\t\ttry {\n\t\t\t\tawait listener.listener(p);\n\t\t\t\tresult.completed++;\n\t\t\t\tthis.#emitEmitterEvent({\n\t\t\t\t\tkind: \"listener:fired\",\n\t\t\t\t\tid: listener.id,\n\t\t\t\t\tpattern: listener.pattern,\n\t\t\t\t\tdurationMs: Date.now() - start,\n\t\t\t\t});\n\t\t\t} catch (err) {\n\t\t\t\tresult.failed++;\n\t\t\t\tconst error = err instanceof Error ? err : new Error(String(err));\n\t\t\t\tresult.errors.push({\n\t\t\t\t\tlistenerId: listener.id,\n\t\t\t\t\tlistenerName: listener.pattern,\n\t\t\t\t\terror: error.message,\n\t\t\t\t});\n\t\t\t\tthis.#emitEmitterEvent({\n\t\t\t\t\tkind: \"listener:failed\",\n\t\t\t\t\tid: listener.id,\n\t\t\t\t\tpattern: listener.pattern,\n\t\t\t\t\terror,\n\t\t\t\t});\n\t\t\t\tif (this.#throwOnError) {\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t} finally {\n\t\t\t\tif (listener.once) toRemove.push(listener);\n\t\t\t}\n\t\t}\n\t\tif (toRemove.length > 0) {\n\t\t\tconst ids = new Set(toRemove.map((l) => l.id));\n\t\t\tthis.#listeners = this.#listeners.filter((l) => !ids.has(l.id));\n\t\t}\n\t\treturn result;\n\t}\n\n\temitSync<T = unknown>(name: EventName, payload?: T): EmitResult {\n\t\tconst result: EmitResult = {\n\t\t\tname,\n\t\t\tmatched: 0,\n\t\t\tcompleted: 0,\n\t\t\tfailed: 0,\n\t\t\terrors: [],\n\t\t};\n\t\tconst matches = this.#matchingListeners(name);\n\t\tresult.matched = matches.length;\n\t\tif (matches.length === 0) return result;\n\n\t\tconst toRemove: InternalListener[] = [];\n\t\tfor (const l of matches) {\n\t\t\tif (l.guard) {\n\t\t\t\tlet ok: boolean;\n\t\t\t\ttry {\n\t\t\t\t\tok = l.guard(payload) as boolean;\n\t\t\t\t} catch {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (!ok) continue;\n\t\t\t}\n\t\t\tconst start = Date.now();\n\t\t\ttry {\n\t\t\t\tconst ret = l.listener(payload);\n\t\t\t\tif (ret && typeof (ret as Promise<unknown>).then === \"function\") {\n\t\t\t\t\t// Promise — fire-and-forget; not awaited in sync mode.\n\t\t\t\t\t(ret as Promise<unknown>).then(\n\t\t\t\t\t\t() => {\n\t\t\t\t\t\t\tresult.completed++;\n\t\t\t\t\t\t\tif (l.once) toRemove.push(l);\n\t\t\t\t\t\t},\n\t\t\t\t\t\t(err: unknown) => {\n\t\t\t\t\t\t\tresult.failed++;\n\t\t\t\t\t\t\tresult.errors.push({\n\t\t\t\t\t\t\t\tlistenerId: l.id,\n\t\t\t\t\t\t\t\tlistenerName: l.pattern,\n\t\t\t\t\t\t\t\terror: err instanceof Error ? err.message : String(err),\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tif (l.once) toRemove.push(l);\n\t\t\t\t\t\t},\n\t\t\t\t\t);\n\t\t\t\t} else {\n\t\t\t\t\tresult.completed++;\n\t\t\t\t\tif (l.once) toRemove.push(l);\n\t\t\t\t}\n\t\t\t\tthis.#emitEmitterEvent({\n\t\t\t\t\tkind: \"listener:fired\",\n\t\t\t\t\tid: l.id,\n\t\t\t\t\tpattern: l.pattern,\n\t\t\t\t\tdurationMs: Date.now() - start,\n\t\t\t\t});\n\t\t\t} catch (err) {\n\t\t\t\tresult.failed++;\n\t\t\t\tconst error = err instanceof Error ? err : new Error(String(err));\n\t\t\t\tresult.errors.push({\n\t\t\t\t\tlistenerId: l.id,\n\t\t\t\t\tlistenerName: l.pattern,\n\t\t\t\t\terror: error.message,\n\t\t\t\t});\n\t\t\t\tif (l.once) toRemove.push(l);\n\t\t\t}\n\t\t}\n\t\tif (toRemove.length > 0) {\n\t\t\tconst ids = new Set(toRemove.map((l) => l.id));\n\t\t\tthis.#listeners = this.#listeners.filter((l) => !ids.has(l.id));\n\t\t}\n\t\treturn result;\n\t}\n\n\tlistenerCount(pattern?: EventName): number {\n\t\tif (pattern === undefined) return this.#listeners.length;\n\t\treturn this.#listeners.filter((l) => l.pattern === pattern).length;\n\t}\n\n\tlistListeners(pattern?: EventName): Array<{\n\t\tid: string;\n\t\tpattern: string;\n\t\tpriority: EventPriority;\n\t\tonce: boolean;\n\t}> {\n\t\tconst list =\n\t\t\tpattern === undefined\n\t\t\t\t? this.#listeners\n\t\t\t\t: this.#listeners.filter((l) => l.pattern === pattern);\n\t\treturn list.map((l) => ({\n\t\t\tid: l.id,\n\t\t\tpattern: l.pattern,\n\t\t\tpriority: l.priority,\n\t\t\tonce: l.once,\n\t\t}));\n\t}\n\n\tremoveAllListeners(): void {\n\t\tconst ids = this.#listeners.map((l) => l.id);\n\t\tthis.#listeners = [];\n\t\tfor (const id of ids) {\n\t\t\tthis.#emitEmitterEvent({ kind: \"listener:removed\", id });\n\t\t}\n\t}\n\n\t/** Subscribe to emitter-internal events (registration, firing, etc.). */\n\tonEmitterEvent(listener: EmitterEventListener): () => void {\n\t\tthis.#emitterListeners.add(listener);\n\t\treturn () => this.#emitterListeners.delete(listener);\n\t}\n\n\t// ===========================================================================\n\t// Internal\n\t// ===========================================================================\n\n\t#allocateId(): string {\n\t\treturn `evt-${this.#nextId++}`;\n\t}\n\n\t#matchingListeners(name: EventName): InternalListener[] {\n\t\treturn this.#listeners.filter((l) => {\n\t\t\tif (l.regex === null) return l.pattern === name;\n\t\t\treturn l.regex.test(name);\n\t\t});\n\t}\n\n\t#sortListeners(): void {\n\t\t// Stable sort: by priority asc, then createdAt asc.\n\t\tthis.#listeners.sort((a, b) => {\n\t\t\tif (a.priority !== b.priority) return a.priority - b.priority;\n\t\t\treturn a.createdAt - b.createdAt;\n\t\t});\n\t}\n\n\t#emitEmitterEvent(event: EmitterEvent): void {\n\t\tfor (const l of this.#emitterListeners) {\n\t\t\tvoid Promise.resolve(l(event));\n\t\t}\n\t}\n}\n\n// ---------------------------------------------------------------------------\n// Pattern compiler\n// ---------------------------------------------------------------------------\n\n/**\n * Compile an event-name pattern into a RegExp. `null` means exact\n * match (no wildcards).\n *\n * Strategy:\n * 1. Replace `**` and `*` with sentinel placeholders that survive\n * regex escaping.\n * 2. Escape all other regex metacharacters.\n * 3. Replace placeholders with the actual regex fragments\n * (`**` → `.*`, `*` → `[^.]+`).\n */\nexport function compilePattern(pattern: string): RegExp | null {\n\tif (!pattern.includes(\"*\")) return null;\n\n\tconst DOUBLE = \"\\x00DOUBLE\\x00\";\n\tconst SINGLE = \"\\x00SINGLE\\x00\";\n\tlet p = pattern.split(\"**\").join(DOUBLE).split(\"*\").join(SINGLE);\n\n\t// Escape regex metacharacters (except our placeholders, which are\n\t// control characters that have no regex meaning).\n\tp = p.replace(/[.+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n\n\tp = p.split(DOUBLE).join(\".*\").split(SINGLE).join(\"[^.]+\");\n\treturn new RegExp(`^${p}$`);\n}\n",
|
package/dist/grpc/index.js.map
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"sourcesContent": [
|
|
5
5
|
"/**\n * Metadata keys used by reflect-metadata for storing decorator data.\n *\n * These constants are the contract between decorators and the framework\n * core (DI container, router, validator).\n */\nexport const METADATA_KEY = {\n\t/** Marks a class as a Nest-style controller, stores route prefix. */\n\tCONTROLLER: \"nexus:controller\",\n\n\t/** Marks a class as an injectable provider. */\n\tINJECTABLE: \"nexus:injectable\",\n\n\t/** Marks a class as a repository. */\n\tREPOSITORY: \"nexus:repository\",\n\n\t/** Marks a class as a module. Stores module options. */\n\tMODULE: \"nexus:module\",\n\n\t/** HTTP method routes registered on a controller (Get/Post/...). */\n\tROUTES: \"nexus:routes\",\n\n\t/** Method parameter type metadata (body/query/param/headers/ctx). */\n\tPARAMS: \"nexus:params\",\n\n\t/** Validation schema per method (Zod schema or class). */\n\tVALIDATE: \"nexus:validate\",\n\n\t/** Class-level design:paramtypes (built-in). */\n\tPARAMTYPES: \"design:paramtypes\",\n\n\t/** Class-level design:type (built-in). */\n\tTYPE: \"design:type\",\n\n\t/** Class-level design:returntype (built-in). */\n\tRETURNTYPE: \"design:returntype\",\n\n\t/** Provider token to inject for a parameter (for custom tokens). */\n\tINJECT: \"nexus:inject\",\n} as const;\n\nexport type MetadataKey = (typeof METADATA_KEY)[keyof typeof METADATA_KEY];\n\n/** Available parameter decorator locations. */\nexport const PARAM_TYPES = {\n\tREQUEST: 0,\n\tRESPONSE: 1,\n\tNEXT: 2,\n\tBODY: 3,\n\tQUERY: 4,\n\tPARAM: 5,\n\tHEADERS: 6,\n\tCTX: 7,\n\tUSER: 8,\n} as const;\n\nexport type ParamType = (typeof PARAM_TYPES)[keyof typeof PARAM_TYPES];\n\n/** HTTP methods supported by the router. */\nexport const HTTP_METHODS = [\n\t\"GET\",\n\t\"POST\",\n\t\"PUT\",\n\t\"DELETE\",\n\t\"PATCH\",\n\t\"OPTIONS\",\n\t\"HEAD\",\n] as const;\nexport type HttpMethod = (typeof HTTP_METHODS)[number];\n",
|
|
6
6
|
"/**\n * @Controller decorator.\n *\n * Marks a class as a controller and registers a route prefix.\n * Routes inside the controller class are decorated with @Get/@Post/etc.\n *\n * @example\n * ```ts\n * @Controller('/users')\n * class UserController {\n * @Get('/')\n * list() { ... }\n * }\n * ```\n */\nimport \"reflect-metadata\";\nimport { METADATA_KEY } from \"../constants.js\";\nimport type { ControllerMetadata } from \"../di/tokens.js\";\n\nexport function Controller(prefix: string = \"/\"): ClassDecorator {\n\treturn (target: object) => {\n\t\tconst normalized = normalizePrefix(prefix);\n\t\tconst meta: ControllerMetadata = { prefix: normalized };\n\t\tReflect.defineMetadata(METADATA_KEY.CONTROLLER, meta, target);\n\t};\n}\n\nexport function getControllerMetadata(target: any): ControllerMetadata {\n\treturn (\n\t\tReflect.getMetadata(METADATA_KEY.CONTROLLER, target) ?? { prefix: \"/\" }\n\t);\n}\n\nexport function isController(target: any): boolean {\n\treturn Reflect.hasMetadata(METADATA_KEY.CONTROLLER, target);\n}\n\n/**\n * Normalize a prefix so we can safely concatenate it with handler paths.\n * - Empty string becomes '/'.\n * - Trailing slashes are trimmed (we re-add them on the join).\n * - No leading slash is added; the router always joins with `/`.\n */\nfunction normalizePrefix(prefix: string): string {\n\tif (!prefix) return \"\";\n\tif (prefix !== \"/\" && prefix.endsWith(\"/\")) {\n\t\treturn prefix.slice(0, -1);\n\t}\n\treturn prefix;\n}\n",
|
|
7
|
-
"/**\n * HTTP method decorators.\n *\n * `@Get`, `@Post`, `@Put`, `@Delete`, `@Patch`, `@Options`, `@Head` mark a\n * controller method as a route handler. The path argument is appended to\n * the controller's prefix.\n *\n * @example\n * ```ts\n * @Controller('/users')\n * class UserController {\n * @Get('/')\n * list() {}\n *\n * @Post('/')\n * create(@Body() body: CreateUserDto) {}\n * }\n * ```\n */\nimport \"reflect-metadata\";\nimport { HTTP_METHODS, METADATA_KEY, type HttpMethod } from \"../constants.js\";\nimport type { RouteMetadata } from \"../di/tokens.js\";\n\nfunction defineRoute(method: HttpMethod, path: string): MethodDecorator {\n\treturn (\n\t\ttarget: object,\n\t\tpropertyKey: string | symbol,\n\t\tdescriptor:
|
|
7
|
+
"/**\n * HTTP method decorators.\n *\n * `@Get`, `@Post`, `@Put`, `@Delete`, `@Patch`, `@Options`, `@Head` mark a\n * controller method as a route handler. The path argument is appended to\n * the controller's prefix.\n *\n * @example\n * ```ts\n * @Controller('/users')\n * class UserController {\n * @Get('/')\n * list() {}\n *\n * @Post('/')\n * create(@Body() body: CreateUserDto) {}\n * }\n * ```\n */\nimport \"reflect-metadata\";\nimport { HTTP_METHODS, METADATA_KEY, type HttpMethod } from \"../constants.js\";\nimport type { RouteMetadata } from \"../di/tokens.js\";\n\nfunction defineRoute(method: HttpMethod, path: string): MethodDecorator {\n\treturn (\n\t\ttarget: object,\n\t\tpropertyKey: string | symbol,\n\t\tdescriptor: TypedPropertyDescriptor<any>,\n\t) => {\n\t\tconst routes: RouteMetadata[] =\n\t\t\tReflect.getMetadata(METADATA_KEY.ROUTES, target.constructor) ?? [];\n\n\t\troutes.push({\n\t\t\tmethod,\n\t\t\tpath: normalizePath(path),\n\t\t\tpropertyKey,\n\t\t\thandler: descriptor.value,\n\t\t});\n\n\t\tReflect.defineMetadata(METADATA_KEY.ROUTES, routes, target.constructor);\n\t};\n}\n\nfunction normalizePath(path: string): string {\n\tif (!path || path === \"/\") return \"/\";\n\treturn path.startsWith(\"/\") ? path : `/${path}`;\n}\n\nexport const Get = (path: string = \"/\") => defineRoute(\"GET\", path);\nexport const Post = (path: string = \"/\") => defineRoute(\"POST\", path);\nexport const Put = (path: string = \"/\") => defineRoute(\"PUT\", path);\nexport const Delete = (path: string = \"/\") => defineRoute(\"DELETE\", path);\nexport const Patch = (path: string = \"/\") => defineRoute(\"PATCH\", path);\nexport const Options = (path: string = \"/\") => defineRoute(\"OPTIONS\", path);\nexport const Head = (path: string = \"/\") => defineRoute(\"HEAD\", path);\n\nexport function getRoutes(target: any): RouteMetadata[] {\n\treturn Reflect.getMetadata(METADATA_KEY.ROUTES, target) ?? [];\n}\n\nexport { HTTP_METHODS };\nexport type { RouteMetadata };\n",
|
|
8
8
|
"/**\n * Parameter decorators.\n *\n * These mark a controller method argument as a source of request data:\n * - `@Req()` → Hono context\n * - `@Res()` → Response helper\n * - `@Next()` → next() callback (for middleware-style handlers)\n * - `@Body()` → request body (parsed)\n * - `@Query('key')` → a single query param, or full query object\n * - `@Param('key')` → a single path param, or full params object\n * - `@Headers('k')` → a single header, or full headers object\n * - `@Ctx()` → Hono context (alias for @Req)\n * - `@User()` → authenticated user (resolved via auth provider)\n *\n * The metadata is read by the router at mount time to build the\n * handler invocation list.\n */\nimport \"reflect-metadata\";\nimport { METADATA_KEY, PARAM_TYPES } from \"../constants.js\";\nimport type { ParamMetadata } from \"../di/tokens.js\";\n\nexport function createParamDecorator(\n\ttype: number,\n\tdata?: string | object,\n): ParameterDecorator {\n\treturn (\n\t\ttarget: object,\n\t\tpropertyKey: string | symbol | undefined,\n\t\tparameterIndex: number,\n\t) => {\n\t\t// Method parameter: target is the prototype, propertyKey is the method name.\n\t\t// Constructor parameter: target is the class, propertyKey is undefined.\n\t\tif (propertyKey !== undefined) {\n\t\t\tconst params: ParamMetadata[] =\n\t\t\t\tReflect.getMetadata(METADATA_KEY.PARAMS, target, propertyKey) ?? [];\n\t\t\tparams.push({\n\t\t\t\tindex: parameterIndex,\n\t\t\t\ttype,\n\t\t\t\tname: typeof data === \"string\" ? data : undefined,\n\t\t\t\tdata: typeof data === \"object\" ? data : undefined,\n\t\t\t});\n\t\t\tReflect.defineMetadata(METADATA_KEY.PARAMS, params, target, propertyKey);\n\t\t} else {\n\t\t\tconst params: ParamMetadata[] =\n\t\t\t\tReflect.getMetadata(METADATA_KEY.PARAMS, target) ?? [];\n\t\t\tparams.push({\n\t\t\t\tindex: parameterIndex,\n\t\t\t\ttype,\n\t\t\t\tname: typeof data === \"string\" ? data : undefined,\n\t\t\t\tdata: typeof data === \"object\" ? data : undefined,\n\t\t\t});\n\t\t\tReflect.defineMetadata(METADATA_KEY.PARAMS, params, target);\n\t\t}\n\t};\n}\n\nexport const Req = () => createParamDecorator(PARAM_TYPES.REQUEST);\nexport const Res = () => createParamDecorator(PARAM_TYPES.RESPONSE);\nexport const Next = () => createParamDecorator(PARAM_TYPES.NEXT);\nexport const Body = (key?: string) =>\n\tcreateParamDecorator(PARAM_TYPES.BODY, key);\nexport const Query = (key?: string) =>\n\tcreateParamDecorator(PARAM_TYPES.QUERY, key);\nexport const Param = (key?: string) =>\n\tcreateParamDecorator(PARAM_TYPES.PARAM, key);\nexport const Headers = (key?: string) =>\n\tcreateParamDecorator(PARAM_TYPES.HEADERS, key);\nexport const Ctx = () => createParamDecorator(PARAM_TYPES.CTX);\nexport const User = () => createParamDecorator(PARAM_TYPES.USER);\n\nexport function getParamMetadata(\n\ttarget: any,\n\tpropertyKey: string | symbol,\n): ParamMetadata[] {\n\treturn Reflect.getMetadata(METADATA_KEY.PARAMS, target, propertyKey) ?? [];\n}\n\nexport { PARAM_TYPES };\n",
|
|
9
9
|
"/**\n * @Validate decorator.\n *\n * Attaches Zod schemas (or class validators) to a route handler. Each\n * schema is run against the corresponding request part before the handler\n * executes; failed validation throws or returns a 400 response.\n *\n * @example\n * ```ts\n * const UserSchema = z.object({ name: z.string(), email: z.email() });\n *\n * @Post('/')\n * @Validate({ body: UserSchema })\n * create(@Body() body: z.infer<typeof UserSchema>) { ... }\n * ```\n */\nimport \"reflect-metadata\";\nimport { METADATA_KEY } from \"../constants.js\";\nimport type { ValidationMetadata } from \"../di/tokens.js\";\n\nexport function Validate(options: ValidationMetadata): MethodDecorator {\n\treturn (\n\t\ttarget: object,\n\t\tpropertyKey: string | symbol,\n\t\tdescriptor: PropertyDescriptor,\n\t) => {\n\t\tReflect.defineMetadata(\n\t\t\tMETADATA_KEY.VALIDATE,\n\t\t\toptions,\n\t\t\ttarget.constructor,\n\t\t\tpropertyKey,\n\t\t);\n\t};\n}\n\nexport function getValidationMetadata(\n\ttarget: any,\n\tpropertyKey: string | symbol,\n): ValidationMetadata | undefined {\n\treturn Reflect.getMetadata(METADATA_KEY.VALIDATE, target, propertyKey);\n}\n",
|
|
10
10
|
"/**\n * `GrpcService` — the main gRPC service.\n *\n * Owns the @grpc/grpc-js server, the loaded proto definition, and\n * the registered service implementations. The service is\n * registered in the DI container; the user calls `start()` to\n * bind the server to a port.\n *\n * const grpc = container.resolve(GrpcService);\n * await grpc.start();\n * // ...\n * await grpc.stop();\n *\n * The framework also exposes a `client<T>('ServiceName')` helper\n * for creating typed clients against the same (or a different)\n * server. Clients returned by this method are async — each method\n * returns a Promise.\n */\n\nimport { existsSync } from \"node:fs\";\nimport { resolve as resolvePath } from \"node:path\";\nimport {\n\tloadPackageDefinition,\n\tServer as GrpcServer,\n\tServerCredentials,\n\tcredentials as grpcCredentials,\n} from \"@grpc/grpc-js\";\nimport * as protoLoader from \"@grpc/proto-loader\";\nimport {\n\tgetGrpcMethodNames,\n\tgetGrpcServiceName,\n} from \"./decorators.js\";\nimport type { GrpcConfig } from \"./types.js\";\n// logger is injected via the service in production; we use\n// console here to avoid a circular dependency with @core/logger.\n\nexport const GRPC_SERVICE_TOKEN = Symbol.for(\"nexus:GrpcService\");\n\nexport class GrpcService {\n\treadonly name = \"grpc\";\n\t#config: Required<Omit<GrpcConfig, \"tls\" | \"onBound\">> &\n\t\tPick<GrpcConfig, \"tls\" | \"onBound\">;\n\t#server: GrpcServer | null = null;\n\t#bound = false;\n\t#proto: any = null;\n\t#instanceByService: Map<string, unknown> = new Map();\n\t#clientCtors: Map<string, new (url: string, creds: any) => any> = new Map();\n\t#resolve: (<T>(token: unknown) => T) | null = null;\n\t#host: string | null = null;\n\t#port: number | null = null;\n\n\tconstructor(config: GrpcConfig) {\n\t\tthis.#config = {\n\t\t\tprotoPath: config.protoPath,\n\t\t\tpackage: config.package ?? \"\",\n\t\t\tservices: config.services ?? [],\n\t\t\tport: config.port ?? 50051,\n\t\t\thost: config.host ?? \"0.0.0.0\",\n\t\t\ttls: config.tls,\n\t\t\tonBound: config.onBound,\n\t\t};\n\t}\n\n\t/** True if the server is currently bound to a port. */\n\tget isRunning(): boolean {\n\t\treturn this.#bound;\n\t}\n\n\t/** The actual host the server bound to. `null` until start(). */\n\tget host(): string | null {\n\t\treturn this.#host;\n\t}\n\n\t/** Inject a resolver function. Called by GrpcModule.forRoot(). */\n\tsetResolver(resolve: <T>(token: unknown) => T): void {\n\t\tthis.#resolve = resolve;\n\t}\n\n\t/** The actual port the server bound to. `null` until start(). */\n\tget port(): number | null {\n\t\treturn this.#port;\n\t}\n\n\t/**\n\t * Load the .proto file(s) and prepare the server.\n\t * Idempotent — call once at boot, before `start()`.\n\t */\n\tasync prepare(resolve: <T>(token: unknown) => T): Promise<void> {\n\t\t// Load proto(s)\n\t\tconst files = Array.isArray(this.#config.protoPath)\n\t\t\t? this.#config.protoPath\n\t\t\t: [this.#config.protoPath];\n\t\tfor (const f of files) {\n\t\t\tif (!existsSync(f)) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`[grpc] proto file not found: ${f}. ` +\n\t\t\t\t\t\t`Resolve the path relative to your project root.`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\t// loadPackageDefinition takes a single PackageDefinition. We\n\t\t// load each .proto separately and merge them into one\n\t\t// package tree.\n\t\tconst merged: Record<string, unknown> = {};\n\t\tfor (const f of files) {\n\t\t\tconst def = protoLoader.loadSync(f, {\n\t\t\t\tkeepCase: false,\n\t\t\t\tlongs: String,\n\t\t\t\tenums: String,\n\t\t\t\tdefaults: true,\n\t\t\t\toneofs: true,\n\t\t\t});\n\t\t\tconst loaded = loadPackageDefinition(def);\n\t\t\tObject.assign(merged, loaded);\n\t\t}\n\t\tthis.#proto = merged;\n\n\t\t// Build the server and register services\n\t\tthis.#server = new GrpcServer();\n\t\tfor (const ServiceImpl of this.#config.services) {\n\t\t\tconst svcName = getGrpcServiceName(ServiceImpl);\n\t\t\tif (!svcName) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`[grpc] service ${ServiceImpl.name} is missing @GrpcService(name)`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst methodNames = getGrpcMethodNames(ServiceImpl.prototype);\n\t\t\t// @grpc/proto-loader produces nested objects, so we walk\n\t\t\t// the package path: proto.<package>.<serviceName>.\n\t\t\tconst segments = this.#config.package\n\t\t\t\t? this.#config.package.split(\".\")\n\t\t\t\t: [];\n\t\t\tsegments.push(svcName);\n\t\t\tlet svcSpec: { service: any; prototype?: unknown } | Record<string, unknown> | undefined =\n\t\t\t\tthis.#proto as Record<string, unknown>;\n\t\t\tfor (const seg of segments) {\n\t\t\t\tif (svcSpec && typeof svcSpec === \"object\" && seg in svcSpec) {\n\t\t\t\t\tsvcSpec = (svcSpec as Record<string, unknown>)[seg] as typeof svcSpec;\n\t\t\t\t} else {\n\t\t\t\t\tsvcSpec = undefined;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (!svcSpec) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`[grpc] service \"${segments.join(\".\")}\" not found in proto definition. ` +\n\t\t\t\t\t\t`Check the .proto file and the @GrpcService name.`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// Resolve the implementation from the DI container\n\t\t\tconst instance = resolve(ServiceImpl);\n\t\t\tthis.#instanceByService.set(svcName, instance);\n\n\t\t\t// Build the handler map. For each @GrpcMethod, wrap\n\t\t\t// the user's method so it can be called as\n\t\t\t// (call, callback) => void and we await the Promise.\n\t\t\tconst handlers: Record<string, any> = {};\n\t\t\tfor (const [methodKey, protoMethodName] of Object.entries(\n\t\t\t\tmethodNames,\n\t\t\t)) {\n\t\t\t\tconst fn = (instance as Record<string, (...args: unknown[]) => unknown>)[\n\t\t\t\t\tmethodKey\n\t\t\t\t];\n\t\t\t\tif (typeof fn !== \"function\") continue;\n\t\t\t\t// Bind the method to the instance so `this` is preserved\n\t\t\t\t// (the user's handler may rely on `this` to access\n\t\t\t\t// injected dependencies).\n\t\t\t\thandlers[protoMethodName] = makeUnaryHandler(fn, instance);\n\t\t\t}\n\n\t\t\t// svcSpec is the Client constructor; .service is the ServiceDefinition.\n\t\t\tthis.#server!.addService((svcSpec as { service: any }).service, handlers);\n\t\t\tthis.#clientCtors.set(svcName, svcSpec as unknown as new (...a: any[]) => any);\n\t\t}\n\t}\n\n\t/**\n\t * Bind the server to the configured host/port. Resolves when\n\t * the port is bound. Use `port: 0` in tests to let the OS\n\t * pick a free port; the actual port is available via the\n\t * `port` getter or the `onBound` callback.\n\t */\n\tasync start(): Promise<void> {\n\t\tif (this.#resolve && !this.#server) {\n\t\t\tawait this.prepare(this.#resolve);\n\t\t}\n\t\tif (!this.#server) {\n\t\t\tthrow new Error(\n\t\t\t\t\"[grpc] start() called before prepare(). Call prepare() first \" +\n\t\t\t\t\t\"(typically done automatically by the DI module).\",\n\t\t\t);\n\t\t}\n\t\tif (this.isRunning) return;\n\n\t\tconst creds = this.#config.tls\n\t\t\t? ServerCredentials.createSsl(\n\t\t\t\t\tthis.#config.tls.cert as Buffer,\n\t\t\t\t\tArray.isArray(this.#config.tls.key) ? this.#config.tls.key[0] : (this.#config.tls.key as Buffer),\n\t\t\t\t)\n\t\t\t: ServerCredentials.createInsecure();\n\n\t\tconst port: number = await new Promise((resolveP, rejectP) => {\n\t\t\t\t// bindAsync(port: \"host:port\", creds, callback) — the\n\t\t\t// first arg is a single string, not separate host/port.\n\t\t\t(this.#server as GrpcServer).bindAsync(\n\t\t\t\t`${this.#config.host}:${this.#config.port}`,\n\t\t\t\tcreds,\n\t\t\t\t(err: Error | null, p: number) => {\n\t\t\t\t\t\t\t\treturn err ? rejectP(err) : resolveP(p);\n\t\t\t\t},\n\t\t\t);\n\t\t});\n\t\tthis.#host = this.#config.host;\n\t\tthis.#port = port;\n\t\tthis.#bound = true;\n\t\tconsole.log(\n\t\t\t`✓ gRPC server listening on ${this.#config.tls ? \"https\" : \"http\"}://${this.#host}:${this.#port}`,\n\t\t);\n\t\tthis.#config.onBound?.(this.#host, this.#port);\n\t}\n\n\t/** Stop the server and release the port. */\n\tasync stop(): Promise<void> {\n\t\tif (!this.#server) return;\n\t\t// tryShutdown waits for all pending RPCs to complete. If\n\t\t// a client is hung, this can hang forever. Race it against\n\t\t// a 1s timeout and force-shutdown if it doesn't complete.\n\t\tawait Promise.race([\n\t\t\tnew Promise<void>((resolveP, rejectP) => {\n\t\t\t\t(this.#server as GrpcServer).tryShutdown((err?: Error) =>\n\t\t\t\t\terr ? rejectP(err) : resolveP(),\n\t\t\t\t);\n\t\t\t}),\n\t\t\tnew Promise<void>((resolveP) => setTimeout(resolveP, 1000)),\n\t\t]).catch(() => {\n\t\t\t(this.#server as GrpcServer).forceShutdown();\n\t\t});\n\t\tthis.#server = null;\n\t\tthis.#host = null;\n\t\tthis.#port = null;\n\t\tthis.#bound = false;\n\t}\n\n\t/**\n\t * Build a typed client for a gRPC service. The returned object\n\t * has one Promise-returning method per service method defined\n\t * in the .proto file. Method names are converted to\n\t * camelCase on the client side to match JS convention\n\t * (e.g. `FindById` → `findById`).\n\t */\n\tclient<T = Record<string, (...args: unknown[]) => Promise<unknown>>>(\n\t\tserviceName: string,\n\t\toptions: { url: string; tls?: boolean } = {\n\t\t\turl: `127.0.0.1:${this.#port ?? 50051}`,\n\t\t},\n\t): T {\n\t\tif (!this.#proto) {\n\t\t\tthrow new Error(\n\t\t\t\t\"[grpc] client() called before prepare(). \" +\n\t\t\t\t\t\"Did you forget to call grpc.start()?\",\n\t\t\t);\n\t\t}\n\t\t// Walk the nested proto package to find the service spec.\n\t\tconst segments = this.#config.package\n\t\t\t? this.#config.package.split(\".\")\n\t\t\t: [];\n\t\tsegments.push(serviceName);\n\t\tlet svcSpec: { service: any; prototype?: unknown } | Record<string, unknown> | undefined =\n\t\t\tthis.#proto as Record<string, unknown>;\n\t\tfor (const seg of segments) {\n\t\t\tif (svcSpec && typeof svcSpec === \"object\" && seg in svcSpec) {\n\t\t\t\tsvcSpec = (svcSpec as Record<string, unknown>)[seg] as typeof svcSpec;\n\t\t\t} else {\n\t\t\t\tsvcSpec = undefined;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif (!svcSpec) {\n\t\t\tthrow new Error(\n\t\t\t\t`[grpc] service \"${segments.join(\".\")}\" not found in proto definition`,\n\t\t\t);\n\t\t}\n\t\t// svcSpec is the Client constructor itself.\n\t\tconst ClientCtor = svcSpec as unknown as {\n\t\t\tnew (url: string, creds: unknown): Record<string, (...args: unknown[]) => unknown>;\n\t\t\tservice: Record<string, Record<string, unknown>>;\n\t\t};\n\t\tconst creds = options.tls\n\t\t\t? // @ts-ignore\n\t\t\t\trequire(\"@grpc/grpc-js\").credentials.createSsl()\n\t\t\t: // @ts-ignore\n\t\t\t\trequire(\"@grpc/grpc-js\").credentials.createInsecure();\n\t\tconst underlying = new ClientCtor(options.url, creds);\n\t\t// ServiceDefinition lists methods in PascalCase (proto form).\n\t\t// The client exposes them as camelCase on its prototype.\n\t\tconst protoMethodNames = Object.keys(ClientCtor.service);\n\t\tconst methodNames = protoMethodNames.map(\n\t\t\t(n) => n.charAt(0).toLowerCase() + n.slice(1),\n\t\t);\n\t\tconst wrapped: Record<string, (...args: unknown[]) => Promise<unknown>> = {};\n\t\tfor (const methodName of methodNames) {\n\t\t\t// @ts-ignore - method exists on the prototype at runtime.\n\t\t\tconst fn = underlying[methodName];\n\t\t\tif (typeof fn !== \"function\") continue;\n\t\t\twrapped[methodName] = (req: unknown) =>\n\t\t\t\tnew Promise((resolveP, rejectP) => {\n\t\t\t\t\tfn.call(underlying, req, (err: Error | null, res: unknown) => {\n\t\t\t\t\t\tif (err) {\n\t\t\t\t\t\t\trejectP(err);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tresolveP(res);\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t});\n\t\t}\n\t\treturn wrapped as unknown as T;\n\t}\n}\n\n/**\n * Wrap a user's async method so it can be passed to gRPC's\n * callback-style handlers. Translates thrown errors into gRPC's\n * status code 13 (INTERNAL) by default.\n */\nfunction makeUnaryHandler(fn: (...args: unknown[]) => unknown, instance: unknown) {\n\treturn (call: unknown, callback: (err: unknown, res?: unknown) => void) => {\n\t\tconst req = (call as { request: unknown }).request;\n\t\t// Bind the method to the instance so `this` is preserved.\n\t\t// Use .then/.catch so we can correctly forward both\n\t\t// synchronous throws and async rejections to gRPC.\n\t\tlet result: unknown;\n\t\ttry {\n\t\t\tresult = fn.call(instance, req);\n\t\t} catch (syncErr) {\n\t\t\tconst e = syncErr as Error;\n\t\t\tconst code = (e as Error & { code?: number }).code ?? 13;\n\t\t\tcallback({ code, details: e.message });\n\t\t\treturn;\n\t\t}\n\t\tPromise.resolve(result).then(\n\t\t\t(value) => callback(null, value),\n\t\t\t(err: Error) => {\n\t\t\t\tconst code = (err as Error & { code?: number }).code ?? 13;\n\t\t\t\t// gRPC expects a plain { code, details } object, NOT\n\t\t\t\t// an Error instance.\n\t\t\t\tcallback({ code, details: err.message });\n\t\t\t},\n\t\t);\n\t};\n}\n\nexport default GrpcService;\n",
|
package/dist/health/index.js.map
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"sourcesContent": [
|
|
5
5
|
"/**\n * Metadata keys used by reflect-metadata for storing decorator data.\n *\n * These constants are the contract between decorators and the framework\n * core (DI container, router, validator).\n */\nexport const METADATA_KEY = {\n\t/** Marks a class as a Nest-style controller, stores route prefix. */\n\tCONTROLLER: \"nexus:controller\",\n\n\t/** Marks a class as an injectable provider. */\n\tINJECTABLE: \"nexus:injectable\",\n\n\t/** Marks a class as a repository. */\n\tREPOSITORY: \"nexus:repository\",\n\n\t/** Marks a class as a module. Stores module options. */\n\tMODULE: \"nexus:module\",\n\n\t/** HTTP method routes registered on a controller (Get/Post/...). */\n\tROUTES: \"nexus:routes\",\n\n\t/** Method parameter type metadata (body/query/param/headers/ctx). */\n\tPARAMS: \"nexus:params\",\n\n\t/** Validation schema per method (Zod schema or class). */\n\tVALIDATE: \"nexus:validate\",\n\n\t/** Class-level design:paramtypes (built-in). */\n\tPARAMTYPES: \"design:paramtypes\",\n\n\t/** Class-level design:type (built-in). */\n\tTYPE: \"design:type\",\n\n\t/** Class-level design:returntype (built-in). */\n\tRETURNTYPE: \"design:returntype\",\n\n\t/** Provider token to inject for a parameter (for custom tokens). */\n\tINJECT: \"nexus:inject\",\n} as const;\n\nexport type MetadataKey = (typeof METADATA_KEY)[keyof typeof METADATA_KEY];\n\n/** Available parameter decorator locations. */\nexport const PARAM_TYPES = {\n\tREQUEST: 0,\n\tRESPONSE: 1,\n\tNEXT: 2,\n\tBODY: 3,\n\tQUERY: 4,\n\tPARAM: 5,\n\tHEADERS: 6,\n\tCTX: 7,\n\tUSER: 8,\n} as const;\n\nexport type ParamType = (typeof PARAM_TYPES)[keyof typeof PARAM_TYPES];\n\n/** HTTP methods supported by the router. */\nexport const HTTP_METHODS = [\n\t\"GET\",\n\t\"POST\",\n\t\"PUT\",\n\t\"DELETE\",\n\t\"PATCH\",\n\t\"OPTIONS\",\n\t\"HEAD\",\n] as const;\nexport type HttpMethod = (typeof HTTP_METHODS)[number];\n",
|
|
6
6
|
"/**\n * @Controller decorator.\n *\n * Marks a class as a controller and registers a route prefix.\n * Routes inside the controller class are decorated with @Get/@Post/etc.\n *\n * @example\n * ```ts\n * @Controller('/users')\n * class UserController {\n * @Get('/')\n * list() { ... }\n * }\n * ```\n */\nimport \"reflect-metadata\";\nimport { METADATA_KEY } from \"../constants.js\";\nimport type { ControllerMetadata } from \"../di/tokens.js\";\n\nexport function Controller(prefix: string = \"/\"): ClassDecorator {\n\treturn (target: object) => {\n\t\tconst normalized = normalizePrefix(prefix);\n\t\tconst meta: ControllerMetadata = { prefix: normalized };\n\t\tReflect.defineMetadata(METADATA_KEY.CONTROLLER, meta, target);\n\t};\n}\n\nexport function getControllerMetadata(target: any): ControllerMetadata {\n\treturn (\n\t\tReflect.getMetadata(METADATA_KEY.CONTROLLER, target) ?? { prefix: \"/\" }\n\t);\n}\n\nexport function isController(target: any): boolean {\n\treturn Reflect.hasMetadata(METADATA_KEY.CONTROLLER, target);\n}\n\n/**\n * Normalize a prefix so we can safely concatenate it with handler paths.\n * - Empty string becomes '/'.\n * - Trailing slashes are trimmed (we re-add them on the join).\n * - No leading slash is added; the router always joins with `/`.\n */\nfunction normalizePrefix(prefix: string): string {\n\tif (!prefix) return \"\";\n\tif (prefix !== \"/\" && prefix.endsWith(\"/\")) {\n\t\treturn prefix.slice(0, -1);\n\t}\n\treturn prefix;\n}\n",
|
|
7
|
-
"/**\n * HTTP method decorators.\n *\n * `@Get`, `@Post`, `@Put`, `@Delete`, `@Patch`, `@Options`, `@Head` mark a\n * controller method as a route handler. The path argument is appended to\n * the controller's prefix.\n *\n * @example\n * ```ts\n * @Controller('/users')\n * class UserController {\n * @Get('/')\n * list() {}\n *\n * @Post('/')\n * create(@Body() body: CreateUserDto) {}\n * }\n * ```\n */\nimport \"reflect-metadata\";\nimport { HTTP_METHODS, METADATA_KEY, type HttpMethod } from \"../constants.js\";\nimport type { RouteMetadata } from \"../di/tokens.js\";\n\nfunction defineRoute(method: HttpMethod, path: string): MethodDecorator {\n\treturn (\n\t\ttarget: object,\n\t\tpropertyKey: string | symbol,\n\t\tdescriptor:
|
|
7
|
+
"/**\n * HTTP method decorators.\n *\n * `@Get`, `@Post`, `@Put`, `@Delete`, `@Patch`, `@Options`, `@Head` mark a\n * controller method as a route handler. The path argument is appended to\n * the controller's prefix.\n *\n * @example\n * ```ts\n * @Controller('/users')\n * class UserController {\n * @Get('/')\n * list() {}\n *\n * @Post('/')\n * create(@Body() body: CreateUserDto) {}\n * }\n * ```\n */\nimport \"reflect-metadata\";\nimport { HTTP_METHODS, METADATA_KEY, type HttpMethod } from \"../constants.js\";\nimport type { RouteMetadata } from \"../di/tokens.js\";\n\nfunction defineRoute(method: HttpMethod, path: string): MethodDecorator {\n\treturn (\n\t\ttarget: object,\n\t\tpropertyKey: string | symbol,\n\t\tdescriptor: TypedPropertyDescriptor<any>,\n\t) => {\n\t\tconst routes: RouteMetadata[] =\n\t\t\tReflect.getMetadata(METADATA_KEY.ROUTES, target.constructor) ?? [];\n\n\t\troutes.push({\n\t\t\tmethod,\n\t\t\tpath: normalizePath(path),\n\t\t\tpropertyKey,\n\t\t\thandler: descriptor.value,\n\t\t});\n\n\t\tReflect.defineMetadata(METADATA_KEY.ROUTES, routes, target.constructor);\n\t};\n}\n\nfunction normalizePath(path: string): string {\n\tif (!path || path === \"/\") return \"/\";\n\treturn path.startsWith(\"/\") ? path : `/${path}`;\n}\n\nexport const Get = (path: string = \"/\") => defineRoute(\"GET\", path);\nexport const Post = (path: string = \"/\") => defineRoute(\"POST\", path);\nexport const Put = (path: string = \"/\") => defineRoute(\"PUT\", path);\nexport const Delete = (path: string = \"/\") => defineRoute(\"DELETE\", path);\nexport const Patch = (path: string = \"/\") => defineRoute(\"PATCH\", path);\nexport const Options = (path: string = \"/\") => defineRoute(\"OPTIONS\", path);\nexport const Head = (path: string = \"/\") => defineRoute(\"HEAD\", path);\n\nexport function getRoutes(target: any): RouteMetadata[] {\n\treturn Reflect.getMetadata(METADATA_KEY.ROUTES, target) ?? [];\n}\n\nexport { HTTP_METHODS };\nexport type { RouteMetadata };\n",
|
|
8
8
|
"/**\n * Parameter decorators.\n *\n * These mark a controller method argument as a source of request data:\n * - `@Req()` → Hono context\n * - `@Res()` → Response helper\n * - `@Next()` → next() callback (for middleware-style handlers)\n * - `@Body()` → request body (parsed)\n * - `@Query('key')` → a single query param, or full query object\n * - `@Param('key')` → a single path param, or full params object\n * - `@Headers('k')` → a single header, or full headers object\n * - `@Ctx()` → Hono context (alias for @Req)\n * - `@User()` → authenticated user (resolved via auth provider)\n *\n * The metadata is read by the router at mount time to build the\n * handler invocation list.\n */\nimport \"reflect-metadata\";\nimport { METADATA_KEY, PARAM_TYPES } from \"../constants.js\";\nimport type { ParamMetadata } from \"../di/tokens.js\";\n\nexport function createParamDecorator(\n\ttype: number,\n\tdata?: string | object,\n): ParameterDecorator {\n\treturn (\n\t\ttarget: object,\n\t\tpropertyKey: string | symbol | undefined,\n\t\tparameterIndex: number,\n\t) => {\n\t\t// Method parameter: target is the prototype, propertyKey is the method name.\n\t\t// Constructor parameter: target is the class, propertyKey is undefined.\n\t\tif (propertyKey !== undefined) {\n\t\t\tconst params: ParamMetadata[] =\n\t\t\t\tReflect.getMetadata(METADATA_KEY.PARAMS, target, propertyKey) ?? [];\n\t\t\tparams.push({\n\t\t\t\tindex: parameterIndex,\n\t\t\t\ttype,\n\t\t\t\tname: typeof data === \"string\" ? data : undefined,\n\t\t\t\tdata: typeof data === \"object\" ? data : undefined,\n\t\t\t});\n\t\t\tReflect.defineMetadata(METADATA_KEY.PARAMS, params, target, propertyKey);\n\t\t} else {\n\t\t\tconst params: ParamMetadata[] =\n\t\t\t\tReflect.getMetadata(METADATA_KEY.PARAMS, target) ?? [];\n\t\t\tparams.push({\n\t\t\t\tindex: parameterIndex,\n\t\t\t\ttype,\n\t\t\t\tname: typeof data === \"string\" ? data : undefined,\n\t\t\t\tdata: typeof data === \"object\" ? data : undefined,\n\t\t\t});\n\t\t\tReflect.defineMetadata(METADATA_KEY.PARAMS, params, target);\n\t\t}\n\t};\n}\n\nexport const Req = () => createParamDecorator(PARAM_TYPES.REQUEST);\nexport const Res = () => createParamDecorator(PARAM_TYPES.RESPONSE);\nexport const Next = () => createParamDecorator(PARAM_TYPES.NEXT);\nexport const Body = (key?: string) =>\n\tcreateParamDecorator(PARAM_TYPES.BODY, key);\nexport const Query = (key?: string) =>\n\tcreateParamDecorator(PARAM_TYPES.QUERY, key);\nexport const Param = (key?: string) =>\n\tcreateParamDecorator(PARAM_TYPES.PARAM, key);\nexport const Headers = (key?: string) =>\n\tcreateParamDecorator(PARAM_TYPES.HEADERS, key);\nexport const Ctx = () => createParamDecorator(PARAM_TYPES.CTX);\nexport const User = () => createParamDecorator(PARAM_TYPES.USER);\n\nexport function getParamMetadata(\n\ttarget: any,\n\tpropertyKey: string | symbol,\n): ParamMetadata[] {\n\treturn Reflect.getMetadata(METADATA_KEY.PARAMS, target, propertyKey) ?? [];\n}\n\nexport { PARAM_TYPES };\n",
|
|
9
9
|
"/**\n * @Validate decorator.\n *\n * Attaches Zod schemas (or class validators) to a route handler. Each\n * schema is run against the corresponding request part before the handler\n * executes; failed validation throws or returns a 400 response.\n *\n * @example\n * ```ts\n * const UserSchema = z.object({ name: z.string(), email: z.email() });\n *\n * @Post('/')\n * @Validate({ body: UserSchema })\n * create(@Body() body: z.infer<typeof UserSchema>) { ... }\n * ```\n */\nimport \"reflect-metadata\";\nimport { METADATA_KEY } from \"../constants.js\";\nimport type { ValidationMetadata } from \"../di/tokens.js\";\n\nexport function Validate(options: ValidationMetadata): MethodDecorator {\n\treturn (\n\t\ttarget: object,\n\t\tpropertyKey: string | symbol,\n\t\tdescriptor: PropertyDescriptor,\n\t) => {\n\t\tReflect.defineMetadata(\n\t\t\tMETADATA_KEY.VALIDATE,\n\t\t\toptions,\n\t\t\ttarget.constructor,\n\t\t\tpropertyKey,\n\t\t);\n\t};\n}\n\nexport function getValidationMetadata(\n\ttarget: any,\n\tpropertyKey: string | symbol,\n): ValidationMetadata | undefined {\n\treturn Reflect.getMetadata(METADATA_KEY.VALIDATE, target, propertyKey);\n}\n",
|
|
10
10
|
"/**\n * Health check types — the contract for `nexusjs/health`.\n *\n * Mirrors `@nestjs/terminus` and `@adonisjs/health`. Three check\n * kinds:\n *\n * - **Liveness** — am I alive? Used by Kubernetes to decide when\n * to restart the pod. Should be a fast, in-process check.\n *\n * - **Readiness** — am I ready to serve traffic? Used by load\n * balancers and K8s to decide when to send requests. May include\n * DB / cache pings.\n *\n * - **Startup** — has my initialization finished? Used by K8s to\n * gate deployment rollouts.\n *\n * Each check returns a `HealthIndicatorResult`. `status: 'up'` means\n * the check passed; `down` means it failed (the indicator's data\n * carries the error message).\n */\n\nexport type HealthStatus = \"up\" | \"down\";\n\nexport interface HealthIndicatorResult<T = unknown> {\n\t/** Whether the check passed. */\n\tstatus: HealthStatus;\n\t/** Optional data attached to the check (e.g. ping latency). */\n\tdata?: T;\n\t/** Error message when status is 'down'. */\n\tmessage?: string;\n}\n\n/**\n * A single health indicator. Indicators are usually singletons that\n * wrap a connection (DB, cache, HTTP API). The `check()` method\n * performs a fast liveness probe.\n *\n * class DbHealthIndicator extends HealthIndicator {\n * name = 'database';\n * async check() {\n * await this.db.ping();\n * return { status: 'up' };\n * }\n * }\n */\nexport abstract class HealthIndicator {\n\tabstract readonly name: string;\n\tabstract check(): Promise<HealthIndicatorResult>;\n}\n\n/** Result of one check plus its indicator name. */\nexport interface HealthCheckEntry {\n\tname: string;\n\tresult: HealthIndicatorResult;\n}\n\n/** Result of `HealthCheckService.check([...])`. */\nexport interface HealthCheckResult {\n\t/** Aggregate status. `'up'` iff every indicator returned `'up'`. */\n\tstatus: HealthStatus;\n\t/** Per-indicator results. */\n\tresults: HealthCheckEntry[];\n\t/** Total wall-clock time (ms). */\n\tdurationMs: number;\n\t/** ISO timestamp. */\n\ttimestamp: string;\n}\n\n/** Which kind of check we're running. */\nexport type HealthCheckKind = \"liveness\" | \"readiness\" | \"startup\";\n\n/** Configuration for the HealthModule. */\nexport interface HealthConfig {\n\t/**\n\t * Path for the liveness probe. Default: `/health/live`.\n\t * Set to null to disable.\n\t */\n\tlivenessPath?: string | null;\n\t/**\n\t * Path for the readiness probe. Default: `/health/ready`.\n\t */\n\treadinessPath?: string | null;\n\t/**\n\t * Path for the startup probe. Default: `/health/startup`.\n\t */\n\tstartupPath?: string | null;\n\t/**\n\t * Optional token to gate the health endpoints. When set, requests\n\t * must include `Authorization: Bearer <token>`. Useful for\n\t * protecting internal health endpoints from public exposure.\n\t */\n\tauthToken?: string;\n\t/**\n\t * Built-in indicators to register automatically. Currently\n\t * supports 'memory' (heap pressure). 'disk' and 'http' require\n\t * additional config (see config docs).\n\t */\n\tbuiltIn?: {\n\t\tmemory?: boolean | { threshold?: number /* heap pressure 0-1 */ };\n\t\tdisk?: { threshold?: number /* fraction free, e.g. 0.1 */; path?: string };\n\t\thttp?: { url: string; timeoutMs?: number };\n\t};\n}\n",
|