@webpieces/http-routing 0.3.252 → 0.3.254

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webpieces/http-routing",
3
- "version": "0.3.252",
3
+ "version": "0.3.254",
4
4
  "description": "Decorator-based routing with auto-wiring for WebPieces",
5
5
  "type": "commonjs",
6
6
  "main": "./src/index.js",
@@ -21,9 +21,9 @@
21
21
  "access": "public"
22
22
  },
23
23
  "dependencies": {
24
- "@webpieces/http-api": "0.3.252",
25
- "@webpieces/http-filters": "0.3.252",
26
- "@webpieces/wp-logging": "0.3.252",
24
+ "@webpieces/http-api": "0.3.254",
25
+ "@webpieces/http-filters": "0.3.254",
26
+ "@webpieces/wp-logging": "0.3.254",
27
27
  "inversify": "7.10.4",
28
28
  "minimatch": "10.0.1"
29
29
  }
@@ -7,16 +7,16 @@ import type { ServiceIdentifier } from 'inversify';
7
7
  export declare const ROUTING_METADATA_KEYS: {
8
8
  CONTROLLER: string;
9
9
  NOT_CONTROLLER: string;
10
+ API_IMPLEMENTATION: string;
10
11
  SOURCE_FILEPATH: string;
11
12
  };
12
13
  /**
13
- * @Controller decorator to mark a class as a controller.
14
- * This is a server-side only decorator.
14
+ * @Controller decorator marks a controller (server-side only).
15
15
  *
16
16
  * Usage:
17
17
  * ```typescript
18
18
  * @Controller()
19
- * export class SaveController implements SaveApi {
19
+ * export class SaveController {
20
20
  * // ...
21
21
  * }
22
22
  * ```
@@ -39,7 +39,7 @@ export declare function isController(controllerClass: any): boolean;
39
39
  * Usage:
40
40
  * ```typescript
41
41
  * @NotController()
42
- * export class Server2Simulator extends Server2Api { ... }
42
+ * export class Server2Simulator { ... }
43
43
  * ```
44
44
  */
45
45
  export declare function NotController(): ClassDecorator;
@@ -48,16 +48,43 @@ export declare function NotController(): ClassDecorator;
48
48
  * Server-side only.
49
49
  */
50
50
  export declare function isNotController(controllerClass: object): boolean;
51
+ /**
52
+ * @ApiImplementation decorator — marks the top-of-DAG implementation class in a LIBRARY
53
+ * (a `role:designed-lib` project) whose DI design should be generated.
54
+ *
55
+ * It is the library-side analog of `@Controller`: where a server's design roots on its
56
+ * `@Controller` classes, a designed-lib's design roots on its `@ApiImplementation` classes.
57
+ * A `role:designed-lib` project is REQUIRED to have at least one such class — otherwise the
58
+ * DI-graph generator has no root and fails.
59
+ *
60
+ * Put it on the top implementation class a library exports and binds in its `ContainerModule`
61
+ * (e.g. the class an app injects to drive the library). Like `@Controller`, this is a pure
62
+ * marker read by the static DI-graph analyzer (by decorator name); it registers nothing at
63
+ * runtime on its own.
64
+ *
65
+ * Usage:
66
+ * ```typescript
67
+ * @ApiImplementation()
68
+ * @injectable()
69
+ * export class AgentHandler { ... }
70
+ * ```
71
+ */
72
+ export declare function ApiImplementation(): ClassDecorator;
73
+ /**
74
+ * Helper function to check if a class is marked as an API implementation (designed-lib root).
75
+ * Server/library side only.
76
+ */
77
+ export declare function isApiImplementation(implClass: object): boolean;
51
78
  /**
52
79
  * SourceFile decorator to explicitly set the source filepath for a controller.
53
80
  * This is used by filter matching to determine which filters apply to the controller.
54
81
  *
55
- * If not specified, the system will use a heuristic based on class name.
82
+ * If not specified, the system will use a heuristic based on the controller's name.
56
83
  *
57
84
  * Usage:
58
85
  * @SourceFile('src/controllers/admin/UserController.ts')
59
86
  * @Controller()
60
- * export class UserController implements UserApi
87
+ * export class UserController { ... }
61
88
  *
62
89
  * @param filepath - The source filepath of the controller
63
90
  */
@@ -87,7 +114,7 @@ export declare function provideSingleton(): (target: any) => any;
87
114
  * import { SOME_API_TOKEN } from '@myorg/some-api';
88
115
  *
89
116
  * @provideSingletonAs(SOME_API_TOKEN)
90
- * export class SomeApiImpl implements SomeApi { ... }
117
+ * export class SomeApiImpl { ... }
91
118
  * ```
92
119
  */
93
120
  export declare function provideSingletonAs<T>(serviceIdentifier: ServiceIdentifier<T>): ClassDecorator;
package/src/decorators.js CHANGED
@@ -5,6 +5,8 @@ exports.Controller = Controller;
5
5
  exports.isController = isController;
6
6
  exports.NotController = NotController;
7
7
  exports.isNotController = isNotController;
8
+ exports.ApiImplementation = ApiImplementation;
9
+ exports.isApiImplementation = isApiImplementation;
8
10
  exports.SourceFile = SourceFile;
9
11
  exports.provideSingleton = provideSingleton;
10
12
  exports.provideSingletonAs = provideSingletonAs;
@@ -18,16 +20,16 @@ const binding_decorators_1 = require("@inversifyjs/binding-decorators");
18
20
  exports.ROUTING_METADATA_KEYS = {
19
21
  CONTROLLER: 'webpieces:controller',
20
22
  NOT_CONTROLLER: 'webpieces:not-controller',
23
+ API_IMPLEMENTATION: 'webpieces:api-implementation',
21
24
  SOURCE_FILEPATH: 'webpieces:source-filepath',
22
25
  };
23
26
  /**
24
- * @Controller decorator to mark a class as a controller.
25
- * This is a server-side only decorator.
27
+ * @Controller decorator marks a controller (server-side only).
26
28
  *
27
29
  * Usage:
28
30
  * ```typescript
29
31
  * @Controller()
30
- * export class SaveController implements SaveApi {
32
+ * export class SaveController {
31
33
  * // ...
32
34
  * }
33
35
  * ```
@@ -56,7 +58,7 @@ function isController(controllerClass) {
56
58
  * Usage:
57
59
  * ```typescript
58
60
  * @NotController()
59
- * export class Server2Simulator extends Server2Api { ... }
61
+ * export class Server2Simulator { ... }
60
62
  * ```
61
63
  */
62
64
  function NotController() {
@@ -71,16 +73,49 @@ function NotController() {
71
73
  function isNotController(controllerClass) {
72
74
  return Reflect.getMetadata(exports.ROUTING_METADATA_KEYS.NOT_CONTROLLER, controllerClass) === true;
73
75
  }
76
+ /**
77
+ * @ApiImplementation decorator — marks the top-of-DAG implementation class in a LIBRARY
78
+ * (a `role:designed-lib` project) whose DI design should be generated.
79
+ *
80
+ * It is the library-side analog of `@Controller`: where a server's design roots on its
81
+ * `@Controller` classes, a designed-lib's design roots on its `@ApiImplementation` classes.
82
+ * A `role:designed-lib` project is REQUIRED to have at least one such class — otherwise the
83
+ * DI-graph generator has no root and fails.
84
+ *
85
+ * Put it on the top implementation class a library exports and binds in its `ContainerModule`
86
+ * (e.g. the class an app injects to drive the library). Like `@Controller`, this is a pure
87
+ * marker read by the static DI-graph analyzer (by decorator name); it registers nothing at
88
+ * runtime on its own.
89
+ *
90
+ * Usage:
91
+ * ```typescript
92
+ * @ApiImplementation()
93
+ * @injectable()
94
+ * export class AgentHandler { ... }
95
+ * ```
96
+ */
97
+ function ApiImplementation() {
98
+ return (target) => {
99
+ Reflect.defineMetadata(exports.ROUTING_METADATA_KEYS.API_IMPLEMENTATION, true, target);
100
+ };
101
+ }
102
+ /**
103
+ * Helper function to check if a class is marked as an API implementation (designed-lib root).
104
+ * Server/library side only.
105
+ */
106
+ function isApiImplementation(implClass) {
107
+ return Reflect.getMetadata(exports.ROUTING_METADATA_KEYS.API_IMPLEMENTATION, implClass) === true;
108
+ }
74
109
  /**
75
110
  * SourceFile decorator to explicitly set the source filepath for a controller.
76
111
  * This is used by filter matching to determine which filters apply to the controller.
77
112
  *
78
- * If not specified, the system will use a heuristic based on class name.
113
+ * If not specified, the system will use a heuristic based on the controller's name.
79
114
  *
80
115
  * Usage:
81
116
  * @SourceFile('src/controllers/admin/UserController.ts')
82
117
  * @Controller()
83
- * export class UserController implements UserApi
118
+ * export class UserController { ... }
84
119
  *
85
120
  * @param filepath - The source filepath of the controller
86
121
  */
@@ -118,7 +153,7 @@ function provideSingleton() {
118
153
  * import { SOME_API_TOKEN } from '@myorg/some-api';
119
154
  *
120
155
  * @provideSingletonAs(SOME_API_TOKEN)
121
- * export class SomeApiImpl implements SomeApi { ... }
156
+ * export class SomeApiImpl { ... }
122
157
  * ```
123
158
  */
124
159
  function provideSingletonAs(serviceIdentifier) {
@@ -1 +1 @@
1
- {"version":3,"file":"decorators.js","sourceRoot":"","sources":["../../../../../packages/http/http-routing/src/decorators.ts"],"names":[],"mappings":";;;AA0BA,gCAIC;AAMD,oCAEC;AAiBD,sCAIC;AAMD,0CAEC;AAeD,gCAIC;AAiBD,4CAIC;AAcD,gDAEC;AAiBD,4CAIC;AAhJD,4BAA0B;AAC1B,wEAA0D;AAG1D;;;GAGG;AACU,QAAA,qBAAqB,GAAG;IACjC,UAAU,EAAE,sBAAsB;IAClC,cAAc,EAAE,0BAA0B;IAC1C,eAAe,EAAE,2BAA2B;CAC/C,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,SAAgB,UAAU;IACtB,OAAO,CAAC,MAAW,EAAE,EAAE;QACnB,OAAO,CAAC,cAAc,CAAC,6BAAqB,CAAC,UAAU,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;IAC3E,CAAC,CAAC;AACN,CAAC;AAED;;;GAGG;AACH,SAAgB,YAAY,CAAC,eAAoB;IAC7C,OAAO,OAAO,CAAC,WAAW,CAAC,6BAAqB,CAAC,UAAU,EAAE,eAAe,CAAC,KAAK,IAAI,CAAC;AAC3F,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,SAAgB,aAAa;IACzB,OAAO,CAAC,MAAc,EAAE,EAAE;QACtB,OAAO,CAAC,cAAc,CAAC,6BAAqB,CAAC,cAAc,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;IAC/E,CAAC,CAAC;AACN,CAAC;AAED;;;GAGG;AACH,SAAgB,eAAe,CAAC,eAAuB;IACnD,OAAO,OAAO,CAAC,WAAW,CAAC,6BAAqB,CAAC,cAAc,EAAE,eAAe,CAAC,KAAK,IAAI,CAAC;AAC/F,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,SAAgB,UAAU,CAAC,QAAgB;IACvC,OAAO,CAAC,MAAW,EAAE,EAAE;QACnB,OAAO,CAAC,cAAc,CAAC,6BAAqB,CAAC,eAAe,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC;IACpF,CAAC,CAAC;AACN,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,SAAgB,gBAAgB;IAC5B,OAAO,CAAC,MAAW,EAAE,EAAE;QACnB,OAAO,IAAA,4BAAO,EAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,gBAAgB,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC;IACtE,CAAC,CAAC;AACN,CAAC;AAED;;;;;;;;;;;GAWG;AACH,SAAgB,kBAAkB,CAAI,iBAAuC;IACzE,OAAO,IAAA,4BAAO,EAAC,iBAAiB,EAAE,CAAC,IAAiC,EAAE,EAAE,CAAC,IAAI,CAAC,gBAAgB,EAAE,CAAC,CAAC;AACtG,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,SAAgB,gBAAgB;IAC5B,OAAO,CAAC,MAAW,EAAE,EAAE;QACnB,OAAO,IAAA,4BAAO,EAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC;IACnC,CAAC,CAAC;AACN,CAAC","sourcesContent":["import 'reflect-metadata';\nimport { provide } from '@inversifyjs/binding-decorators';\nimport type { BindInWhenOnFluentSyntax, ServiceIdentifier } from 'inversify';\n\n/**\n * Metadata keys for server-side routing.\n * These are specific to the routing package (server-side only).\n */\nexport const ROUTING_METADATA_KEYS = {\n CONTROLLER: 'webpieces:controller',\n NOT_CONTROLLER: 'webpieces:not-controller',\n SOURCE_FILEPATH: 'webpieces:source-filepath',\n};\n\n/**\n * @Controller decorator to mark a class as a controller.\n * This is a server-side only decorator.\n *\n * Usage:\n * ```typescript\n * @Controller()\n * export class SaveController implements SaveApi {\n * // ...\n * }\n * ```\n */\nexport function Controller(): ClassDecorator {\n return (target: any) => {\n Reflect.defineMetadata(ROUTING_METADATA_KEYS.CONTROLLER, true, target);\n };\n}\n\n/**\n * Helper function to check if a class is a controller.\n * Server-side only.\n */\nexport function isController(controllerClass: any): boolean {\n return Reflect.getMetadata(ROUTING_METADATA_KEYS.CONTROLLER, controllerClass) === true;\n}\n\n/**\n * @NotController decorator — explicitly marks a class that implements/extends an `*Api` contract\n * as deliberately NOT a controller (e.g. a simulator, an in-process client, a test double).\n *\n * The `enforce-controller-naming` rule requires every class whose heritage ends in `*Api` to declare\n * its intent: either `@Controller` (then it must be named `{Something}Controller` and live in a\n * `{something}-controller.ts` file) OR `@NotController` (then it is exempt from those naming rules).\n * This is a pure marker — it registers no route and only records intent for the lint rule.\n *\n * Usage:\n * ```typescript\n * @NotController()\n * export class Server2Simulator extends Server2Api { ... }\n * ```\n */\nexport function NotController(): ClassDecorator {\n return (target: object) => {\n Reflect.defineMetadata(ROUTING_METADATA_KEYS.NOT_CONTROLLER, true, target);\n };\n}\n\n/**\n * Helper function to check if a class is explicitly marked as NOT a controller.\n * Server-side only.\n */\nexport function isNotController(controllerClass: object): boolean {\n return Reflect.getMetadata(ROUTING_METADATA_KEYS.NOT_CONTROLLER, controllerClass) === true;\n}\n\n/**\n * SourceFile decorator to explicitly set the source filepath for a controller.\n * This is used by filter matching to determine which filters apply to the controller.\n *\n * If not specified, the system will use a heuristic based on class name.\n *\n * Usage:\n * @SourceFile('src/controllers/admin/UserController.ts')\n * @Controller()\n * export class UserController implements UserApi\n *\n * @param filepath - The source filepath of the controller\n */\nexport function SourceFile(filepath: string): ClassDecorator {\n return (target: any) => {\n Reflect.defineMetadata(ROUTING_METADATA_KEYS.SOURCE_FILEPATH, filepath, target);\n };\n}\n\n/**\n * Provides a singleton-scoped dependency.\n * When called without arguments, the decorated class binds to itself.\n *\n * Server-side only - registers classes in the DI container.\n *\n * Usage:\n * ```typescript\n * @provideSingleton()\n * @Controller()\n * export class SaveController {\n * // ...\n * }\n * ```\n */\nexport function provideSingleton() {\n return (target: any) => {\n return provide(target, (bind) => bind.inSingletonScope())(target);\n };\n}\n\n/**\n * Provides a singleton-scoped dependency bound to a specific token (Symbol or abstract class).\n * Use this in libraries/apis-external/** to bind an impl to the Symbol defined in libraries/apis/**.\n *\n * Usage:\n * ```typescript\n * import { SOME_API_TOKEN } from '@myorg/some-api';\n *\n * @provideSingletonAs(SOME_API_TOKEN)\n * export class SomeApiImpl implements SomeApi { ... }\n * ```\n */\nexport function provideSingletonAs<T>(serviceIdentifier: ServiceIdentifier<T>): ClassDecorator {\n return provide(serviceIdentifier, (bind: BindInWhenOnFluentSyntax<T>) => bind.inSingletonScope());\n}\n\n/**\n * Provides a transient-scoped dependency (new instance every time).\n * When called without arguments, the decorated class binds to itself.\n *\n * Server-side only - registers classes in the DI container.\n *\n * Usage:\n * ```typescript\n * @provideTransient()\n * @Controller()\n * export class TransientController {\n * // ...\n * }\n * ```\n */\nexport function provideTransient() {\n return (target: any) => {\n return provide(target)(target);\n };\n}\n"]}
1
+ {"version":3,"file":"decorators.js","sourceRoot":"","sources":["../../../../../packages/http/http-routing/src/decorators.ts"],"names":[],"mappings":";;;AA0BA,gCAIC;AAMD,oCAEC;AAiBD,sCAIC;AAMD,0CAEC;AAuBD,8CAIC;AAMD,kDAEC;AAeD,gCAIC;AAiBD,4CAIC;AAcD,gDAEC;AAiBD,4CAIC;AAnLD,4BAA0B;AAC1B,wEAA0D;AAG1D;;;GAGG;AACU,QAAA,qBAAqB,GAAG;IACjC,UAAU,EAAE,sBAAsB;IAClC,cAAc,EAAE,0BAA0B;IAC1C,kBAAkB,EAAE,8BAA8B;IAClD,eAAe,EAAE,2BAA2B;CAC/C,CAAC;AAEF;;;;;;;;;;GAUG;AACH,SAAgB,UAAU;IACtB,OAAO,CAAC,MAAW,EAAE,EAAE;QACnB,OAAO,CAAC,cAAc,CAAC,6BAAqB,CAAC,UAAU,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;IAC3E,CAAC,CAAC;AACN,CAAC;AAED;;;GAGG;AACH,SAAgB,YAAY,CAAC,eAAoB;IAC7C,OAAO,OAAO,CAAC,WAAW,CAAC,6BAAqB,CAAC,UAAU,EAAE,eAAe,CAAC,KAAK,IAAI,CAAC;AAC3F,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,SAAgB,aAAa;IACzB,OAAO,CAAC,MAAc,EAAE,EAAE;QACtB,OAAO,CAAC,cAAc,CAAC,6BAAqB,CAAC,cAAc,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;IAC/E,CAAC,CAAC;AACN,CAAC;AAED;;;GAGG;AACH,SAAgB,eAAe,CAAC,eAAuB;IACnD,OAAO,OAAO,CAAC,WAAW,CAAC,6BAAqB,CAAC,cAAc,EAAE,eAAe,CAAC,KAAK,IAAI,CAAC;AAC/F,CAAC;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,SAAgB,iBAAiB;IAC7B,OAAO,CAAC,MAAc,EAAE,EAAE;QACtB,OAAO,CAAC,cAAc,CAAC,6BAAqB,CAAC,kBAAkB,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;IACnF,CAAC,CAAC;AACN,CAAC;AAED;;;GAGG;AACH,SAAgB,mBAAmB,CAAC,SAAiB;IACjD,OAAO,OAAO,CAAC,WAAW,CAAC,6BAAqB,CAAC,kBAAkB,EAAE,SAAS,CAAC,KAAK,IAAI,CAAC;AAC7F,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,SAAgB,UAAU,CAAC,QAAgB;IACvC,OAAO,CAAC,MAAW,EAAE,EAAE;QACnB,OAAO,CAAC,cAAc,CAAC,6BAAqB,CAAC,eAAe,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC;IACpF,CAAC,CAAC;AACN,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,SAAgB,gBAAgB;IAC5B,OAAO,CAAC,MAAW,EAAE,EAAE;QACnB,OAAO,IAAA,4BAAO,EAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,gBAAgB,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC;IACtE,CAAC,CAAC;AACN,CAAC;AAED;;;;;;;;;;;GAWG;AACH,SAAgB,kBAAkB,CAAI,iBAAuC;IACzE,OAAO,IAAA,4BAAO,EAAC,iBAAiB,EAAE,CAAC,IAAiC,EAAE,EAAE,CAAC,IAAI,CAAC,gBAAgB,EAAE,CAAC,CAAC;AACtG,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,SAAgB,gBAAgB;IAC5B,OAAO,CAAC,MAAW,EAAE,EAAE;QACnB,OAAO,IAAA,4BAAO,EAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC;IACnC,CAAC,CAAC;AACN,CAAC","sourcesContent":["import 'reflect-metadata';\nimport { provide } from '@inversifyjs/binding-decorators';\nimport type { BindInWhenOnFluentSyntax, ServiceIdentifier } from 'inversify';\n\n/**\n * Metadata keys for server-side routing.\n * These are specific to the routing package (server-side only).\n */\nexport const ROUTING_METADATA_KEYS = {\n CONTROLLER: 'webpieces:controller',\n NOT_CONTROLLER: 'webpieces:not-controller',\n API_IMPLEMENTATION: 'webpieces:api-implementation',\n SOURCE_FILEPATH: 'webpieces:source-filepath',\n};\n\n/**\n * @Controller decorator marks a controller (server-side only).\n *\n * Usage:\n * ```typescript\n * @Controller()\n * export class SaveController {\n * // ...\n * }\n * ```\n */\nexport function Controller(): ClassDecorator {\n return (target: any) => {\n Reflect.defineMetadata(ROUTING_METADATA_KEYS.CONTROLLER, true, target);\n };\n}\n\n/**\n * Helper function to check if a class is a controller.\n * Server-side only.\n */\nexport function isController(controllerClass: any): boolean {\n return Reflect.getMetadata(ROUTING_METADATA_KEYS.CONTROLLER, controllerClass) === true;\n}\n\n/**\n * @NotController decorator — explicitly marks a class that implements/extends an `*Api` contract\n * as deliberately NOT a controller (e.g. a simulator, an in-process client, a test double).\n *\n * The `enforce-controller-naming` rule requires every class whose heritage ends in `*Api` to declare\n * its intent: either `@Controller` (then it must be named `{Something}Controller` and live in a\n * `{something}-controller.ts` file) OR `@NotController` (then it is exempt from those naming rules).\n * This is a pure marker — it registers no route and only records intent for the lint rule.\n *\n * Usage:\n * ```typescript\n * @NotController()\n * export class Server2Simulator { ... }\n * ```\n */\nexport function NotController(): ClassDecorator {\n return (target: object) => {\n Reflect.defineMetadata(ROUTING_METADATA_KEYS.NOT_CONTROLLER, true, target);\n };\n}\n\n/**\n * Helper function to check if a class is explicitly marked as NOT a controller.\n * Server-side only.\n */\nexport function isNotController(controllerClass: object): boolean {\n return Reflect.getMetadata(ROUTING_METADATA_KEYS.NOT_CONTROLLER, controllerClass) === true;\n}\n\n/**\n * @ApiImplementation decorator — marks the top-of-DAG implementation class in a LIBRARY\n * (a `role:designed-lib` project) whose DI design should be generated.\n *\n * It is the library-side analog of `@Controller`: where a server's design roots on its\n * `@Controller` classes, a designed-lib's design roots on its `@ApiImplementation` classes.\n * A `role:designed-lib` project is REQUIRED to have at least one such class — otherwise the\n * DI-graph generator has no root and fails.\n *\n * Put it on the top implementation class a library exports and binds in its `ContainerModule`\n * (e.g. the class an app injects to drive the library). Like `@Controller`, this is a pure\n * marker read by the static DI-graph analyzer (by decorator name); it registers nothing at\n * runtime on its own.\n *\n * Usage:\n * ```typescript\n * @ApiImplementation()\n * @injectable()\n * export class AgentHandler { ... }\n * ```\n */\nexport function ApiImplementation(): ClassDecorator {\n return (target: object) => {\n Reflect.defineMetadata(ROUTING_METADATA_KEYS.API_IMPLEMENTATION, true, target);\n };\n}\n\n/**\n * Helper function to check if a class is marked as an API implementation (designed-lib root).\n * Server/library side only.\n */\nexport function isApiImplementation(implClass: object): boolean {\n return Reflect.getMetadata(ROUTING_METADATA_KEYS.API_IMPLEMENTATION, implClass) === true;\n}\n\n/**\n * SourceFile decorator to explicitly set the source filepath for a controller.\n * This is used by filter matching to determine which filters apply to the controller.\n *\n * If not specified, the system will use a heuristic based on the controller's name.\n *\n * Usage:\n * @SourceFile('src/controllers/admin/UserController.ts')\n * @Controller()\n * export class UserController { ... }\n *\n * @param filepath - The source filepath of the controller\n */\nexport function SourceFile(filepath: string): ClassDecorator {\n return (target: any) => {\n Reflect.defineMetadata(ROUTING_METADATA_KEYS.SOURCE_FILEPATH, filepath, target);\n };\n}\n\n/**\n * Provides a singleton-scoped dependency.\n * When called without arguments, the decorated class binds to itself.\n *\n * Server-side only - registers classes in the DI container.\n *\n * Usage:\n * ```typescript\n * @provideSingleton()\n * @Controller()\n * export class SaveController {\n * // ...\n * }\n * ```\n */\nexport function provideSingleton() {\n return (target: any) => {\n return provide(target, (bind) => bind.inSingletonScope())(target);\n };\n}\n\n/**\n * Provides a singleton-scoped dependency bound to a specific token (Symbol or abstract class).\n * Use this in libraries/apis-external/** to bind an impl to the Symbol defined in libraries/apis/**.\n *\n * Usage:\n * ```typescript\n * import { SOME_API_TOKEN } from '@myorg/some-api';\n *\n * @provideSingletonAs(SOME_API_TOKEN)\n * export class SomeApiImpl { ... }\n * ```\n */\nexport function provideSingletonAs<T>(serviceIdentifier: ServiceIdentifier<T>): ClassDecorator {\n return provide(serviceIdentifier, (bind: BindInWhenOnFluentSyntax<T>) => bind.inSingletonScope());\n}\n\n/**\n * Provides a transient-scoped dependency (new instance every time).\n * When called without arguments, the decorated class binds to itself.\n *\n * Server-side only - registers classes in the DI container.\n *\n * Usage:\n * ```typescript\n * @provideTransient()\n * @Controller()\n * export class TransientController {\n * // ...\n * }\n * ```\n */\nexport function provideTransient() {\n return (target: any) => {\n return provide(target)(target);\n };\n}\n"]}
package/src/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export { ApiPath, Endpoint, Authentication, AuthenticationConfig, getApiPath, getEndpoints, isApiPath, getAuthMeta, AuthMeta, RouteMetadata, METADATA_KEYS, ValidateImplementation, } from '@webpieces/http-api';
2
- export { Controller, isController, NotController, isNotController, provideSingleton, provideSingletonAs, provideTransient, ROUTING_METADATA_KEYS, } from './decorators';
2
+ export { Controller, isController, NotController, isNotController, ApiImplementation, isApiImplementation, provideSingleton, provideSingletonAs, provideTransient, ROUTING_METADATA_KEYS, } from './decorators';
3
3
  export { ApiRoutingFactory, ClassType } from './ApiRoutingFactory';
4
4
  export { WebAppMeta, WEBAPP_META_TOKEN, Routes, RouteBuilder, RouteDefinition, FilterDefinition, } from './WebAppMeta';
5
5
  export { MethodMeta } from './MethodMeta';
package/src/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.WEBPIECES_CONFIG_TOKEN = exports.WebpiecesConfig = exports.RequestContextReader = exports.FilterMatcher = exports.FilterWithMeta = exports.RouteHandlerWithMeta = exports.RouteBuilderImpl = exports.RouteHandler = exports.MethodMeta = exports.FilterDefinition = exports.RouteDefinition = exports.WEBAPP_META_TOKEN = exports.ApiRoutingFactory = exports.ROUTING_METADATA_KEYS = exports.provideTransient = exports.provideSingletonAs = exports.provideSingleton = exports.isNotController = exports.NotController = exports.isController = exports.Controller = exports.METADATA_KEYS = exports.RouteMetadata = exports.AuthMeta = exports.getAuthMeta = exports.isApiPath = exports.getEndpoints = exports.getApiPath = exports.AuthenticationConfig = exports.Authentication = exports.Endpoint = exports.ApiPath = void 0;
3
+ exports.WEBPIECES_CONFIG_TOKEN = exports.WebpiecesConfig = exports.RequestContextReader = exports.FilterMatcher = exports.FilterWithMeta = exports.RouteHandlerWithMeta = exports.RouteBuilderImpl = exports.RouteHandler = exports.MethodMeta = exports.FilterDefinition = exports.RouteDefinition = exports.WEBAPP_META_TOKEN = exports.ApiRoutingFactory = exports.ROUTING_METADATA_KEYS = exports.provideTransient = exports.provideSingletonAs = exports.provideSingleton = exports.isApiImplementation = exports.ApiImplementation = exports.isNotController = exports.NotController = exports.isController = exports.Controller = exports.METADATA_KEYS = exports.RouteMetadata = exports.AuthMeta = exports.getAuthMeta = exports.isApiPath = exports.getEndpoints = exports.getApiPath = exports.AuthenticationConfig = exports.Authentication = exports.Endpoint = exports.ApiPath = void 0;
4
4
  // Re-export API decorators from http-api for convenience
5
5
  var http_api_1 = require("@webpieces/http-api");
6
6
  Object.defineProperty(exports, "ApiPath", { enumerable: true, get: function () { return http_api_1.ApiPath; } });
@@ -20,6 +20,8 @@ Object.defineProperty(exports, "Controller", { enumerable: true, get: function (
20
20
  Object.defineProperty(exports, "isController", { enumerable: true, get: function () { return decorators_1.isController; } });
21
21
  Object.defineProperty(exports, "NotController", { enumerable: true, get: function () { return decorators_1.NotController; } });
22
22
  Object.defineProperty(exports, "isNotController", { enumerable: true, get: function () { return decorators_1.isNotController; } });
23
+ Object.defineProperty(exports, "ApiImplementation", { enumerable: true, get: function () { return decorators_1.ApiImplementation; } });
24
+ Object.defineProperty(exports, "isApiImplementation", { enumerable: true, get: function () { return decorators_1.isApiImplementation; } });
23
25
  Object.defineProperty(exports, "provideSingleton", { enumerable: true, get: function () { return decorators_1.provideSingleton; } });
24
26
  Object.defineProperty(exports, "provideSingletonAs", { enumerable: true, get: function () { return decorators_1.provideSingletonAs; } });
25
27
  Object.defineProperty(exports, "provideTransient", { enumerable: true, get: function () { return decorators_1.provideTransient; } });
package/src/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../packages/http/http-routing/src/index.ts"],"names":[],"mappings":";;;AAAA,yDAAyD;AACzD,gDAa6B;AAZzB,mGAAA,OAAO,OAAA;AACP,oGAAA,QAAQ,OAAA;AACR,0GAAA,cAAc,OAAA;AACd,gHAAA,oBAAoB,OAAA;AACpB,sGAAA,UAAU,OAAA;AACV,wGAAA,YAAY,OAAA;AACZ,qGAAA,SAAS,OAAA;AACT,uGAAA,WAAW,OAAA;AACX,oGAAA,QAAQ,OAAA;AACR,yGAAA,aAAa,OAAA;AACb,yGAAA,aAAa,OAAA;AAIjB,+CAA+C;AAC/C,2CASsB;AARlB,wGAAA,UAAU,OAAA;AACV,0GAAA,YAAY,OAAA;AACZ,2GAAA,aAAa,OAAA;AACb,6GAAA,eAAe,OAAA;AACf,8GAAA,gBAAgB,OAAA;AAChB,gHAAA,kBAAkB,OAAA;AAClB,8GAAA,gBAAgB,OAAA;AAChB,mHAAA,qBAAqB,OAAA;AAGzB,yDAAmE;AAA1D,sHAAA,iBAAiB,OAAA;AAE1B,4CAA4C;AAC5C,2CAOsB;AALlB,+GAAA,iBAAiB,OAAA;AAGjB,6GAAA,eAAe,OAAA;AACf,8GAAA,gBAAgB,OAAA;AAGpB,oCAAoC;AACpC,2CAA0C;AAAjC,wGAAA,UAAU,OAAA;AACnB,+CAA8C;AAArC,4GAAA,YAAY,OAAA;AAErB,+BAA+B;AAC/B,uDAK4B;AAJxB,oHAAA,gBAAgB,OAAA;AAChB,wHAAA,oBAAoB,OAAA;AACpB,kHAAA,cAAc,OAAA;AAIlB,kBAAkB;AAClB,iDAA4D;AAAnD,8GAAA,aAAa,OAAA;AAEtB,iCAAiC;AACjC,+DAA8D;AAArD,4HAAA,oBAAoB,OAAA;AAE7B,uBAAuB;AACvB,qDAA4E;AAAnE,kHAAA,eAAe,OAAA;AAAE,yHAAA,sBAAsB,OAAA","sourcesContent":["// Re-export API decorators from http-api for convenience\nexport {\n ApiPath,\n Endpoint,\n Authentication,\n AuthenticationConfig,\n getApiPath,\n getEndpoints,\n isApiPath,\n getAuthMeta,\n AuthMeta,\n RouteMetadata,\n METADATA_KEYS,\n ValidateImplementation,\n} from '@webpieces/http-api';\n\n// Server-side routing decorators and utilities\nexport {\n Controller,\n isController,\n NotController,\n isNotController,\n provideSingleton,\n provideSingletonAs,\n provideTransient,\n ROUTING_METADATA_KEYS,\n} from './decorators';\n\nexport { ApiRoutingFactory, ClassType } from './ApiRoutingFactory';\n\n// Core routing types (moved from core-meta)\nexport {\n WebAppMeta,\n WEBAPP_META_TOKEN,\n Routes,\n RouteBuilder,\n RouteDefinition,\n FilterDefinition,\n} from './WebAppMeta';\n\n// Method metadata and route handler\nexport { MethodMeta } from './MethodMeta';\nexport { RouteHandler } from './RouteHandler';\n\n// Route builder implementation\nexport {\n RouteBuilderImpl,\n RouteHandlerWithMeta,\n FilterWithMeta,\n ExpressRouteHandler,\n} from './RouteBuilderImpl';\n\n// Filter matching\nexport { FilterMatcher, HttpFilter } from './FilterMatcher';\n\n// Context readers (Node.js only)\nexport { RequestContextReader } from './RequestContextReader';\n\n// Server configuration\nexport { WebpiecesConfig, WEBPIECES_CONFIG_TOKEN } from './WebpiecesConfig';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../packages/http/http-routing/src/index.ts"],"names":[],"mappings":";;;AAAA,yDAAyD;AACzD,gDAa6B;AAZzB,mGAAA,OAAO,OAAA;AACP,oGAAA,QAAQ,OAAA;AACR,0GAAA,cAAc,OAAA;AACd,gHAAA,oBAAoB,OAAA;AACpB,sGAAA,UAAU,OAAA;AACV,wGAAA,YAAY,OAAA;AACZ,qGAAA,SAAS,OAAA;AACT,uGAAA,WAAW,OAAA;AACX,oGAAA,QAAQ,OAAA;AACR,yGAAA,aAAa,OAAA;AACb,yGAAA,aAAa,OAAA;AAIjB,+CAA+C;AAC/C,2CAWsB;AAVlB,wGAAA,UAAU,OAAA;AACV,0GAAA,YAAY,OAAA;AACZ,2GAAA,aAAa,OAAA;AACb,6GAAA,eAAe,OAAA;AACf,+GAAA,iBAAiB,OAAA;AACjB,iHAAA,mBAAmB,OAAA;AACnB,8GAAA,gBAAgB,OAAA;AAChB,gHAAA,kBAAkB,OAAA;AAClB,8GAAA,gBAAgB,OAAA;AAChB,mHAAA,qBAAqB,OAAA;AAGzB,yDAAmE;AAA1D,sHAAA,iBAAiB,OAAA;AAE1B,4CAA4C;AAC5C,2CAOsB;AALlB,+GAAA,iBAAiB,OAAA;AAGjB,6GAAA,eAAe,OAAA;AACf,8GAAA,gBAAgB,OAAA;AAGpB,oCAAoC;AACpC,2CAA0C;AAAjC,wGAAA,UAAU,OAAA;AACnB,+CAA8C;AAArC,4GAAA,YAAY,OAAA;AAErB,+BAA+B;AAC/B,uDAK4B;AAJxB,oHAAA,gBAAgB,OAAA;AAChB,wHAAA,oBAAoB,OAAA;AACpB,kHAAA,cAAc,OAAA;AAIlB,kBAAkB;AAClB,iDAA4D;AAAnD,8GAAA,aAAa,OAAA;AAEtB,iCAAiC;AACjC,+DAA8D;AAArD,4HAAA,oBAAoB,OAAA;AAE7B,uBAAuB;AACvB,qDAA4E;AAAnE,kHAAA,eAAe,OAAA;AAAE,yHAAA,sBAAsB,OAAA","sourcesContent":["// Re-export API decorators from http-api for convenience\nexport {\n ApiPath,\n Endpoint,\n Authentication,\n AuthenticationConfig,\n getApiPath,\n getEndpoints,\n isApiPath,\n getAuthMeta,\n AuthMeta,\n RouteMetadata,\n METADATA_KEYS,\n ValidateImplementation,\n} from '@webpieces/http-api';\n\n// Server-side routing decorators and utilities\nexport {\n Controller,\n isController,\n NotController,\n isNotController,\n ApiImplementation,\n isApiImplementation,\n provideSingleton,\n provideSingletonAs,\n provideTransient,\n ROUTING_METADATA_KEYS,\n} from './decorators';\n\nexport { ApiRoutingFactory, ClassType } from './ApiRoutingFactory';\n\n// Core routing types (moved from core-meta)\nexport {\n WebAppMeta,\n WEBAPP_META_TOKEN,\n Routes,\n RouteBuilder,\n RouteDefinition,\n FilterDefinition,\n} from './WebAppMeta';\n\n// Method metadata and route handler\nexport { MethodMeta } from './MethodMeta';\nexport { RouteHandler } from './RouteHandler';\n\n// Route builder implementation\nexport {\n RouteBuilderImpl,\n RouteHandlerWithMeta,\n FilterWithMeta,\n ExpressRouteHandler,\n} from './RouteBuilderImpl';\n\n// Filter matching\nexport { FilterMatcher, HttpFilter } from './FilterMatcher';\n\n// Context readers (Node.js only)\nexport { RequestContextReader } from './RequestContextReader';\n\n// Server configuration\nexport { WebpiecesConfig, WEBPIECES_CONFIG_TOKEN } from './WebpiecesConfig';\n"]}