@travetto/web 6.0.2 → 7.0.0-rc.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
  <!-- Please modify https://github.com/travetto/travetto/tree/main/module/web/DOC.tsx and execute "npx trv doc" to rebuild -->
3
3
  # Web API
4
4
 
5
- ## Declarative support creating for Web Applications
5
+ ## Declarative support for creating Web Applications
6
6
 
7
7
  **Install: @travetto/web**
8
8
  ```bash
@@ -13,9 +13,9 @@ npm install @travetto/web
13
13
  yarn add @travetto/web
14
14
  ```
15
15
 
16
- The module provides a declarative API for creating and describing a Web application. Since the framework is declarative, decorators are used to configure almost everything. The general layout of an application is a collection of [@Controller](https://github.com/travetto/travetto/tree/main/module/web/src/decorator/controller.ts#L9)s that employ some combination of [WebInterceptor](https://github.com/travetto/travetto/tree/main/module/web/src/types/interceptor.ts#L15)s to help manage which functionality is executed before the [Endpoint](https://github.com/travetto/travetto/tree/main/module/web/src/decorator/endpoint.ts#L14) code, within the [@Controller](https://github.com/travetto/travetto/tree/main/module/web/src/decorator/controller.ts#L9). This module will look at:
16
+ The module provides a declarative API for creating and describing a Web application. Since the framework is declarative, decorators are used to configure almost everything. The general layout of an application is a collection of [@Controller](https://github.com/travetto/travetto/tree/main/module/web/src/decorator/controller.ts#L11)s that employ some combination of [WebInterceptor](https://github.com/travetto/travetto/tree/main/module/web/src/types/interceptor.ts#L15)s to help manage which functionality is executed before the [Endpoint](https://github.com/travetto/travetto/tree/main/module/web/src/decorator/endpoint.ts#L14) code, within the [@Controller](https://github.com/travetto/travetto/tree/main/module/web/src/decorator/controller.ts#L11). This module will look at:
17
17
  * Request/Response Pattern
18
- * Defining a [@Controller](https://github.com/travetto/travetto/tree/main/module/web/src/decorator/controller.ts#L9)
18
+ * Defining a [@Controller](https://github.com/travetto/travetto/tree/main/module/web/src/decorator/controller.ts#L11)
19
19
  * Defining an [Endpoint](https://github.com/travetto/travetto/tree/main/module/web/src/decorator/endpoint.ts#L14)
20
20
  * Using a [WebInterceptor](https://github.com/travetto/travetto/tree/main/module/web/src/types/interceptor.ts#L15)
21
21
  * Creating a Custom [WebInterceptor](https://github.com/travetto/travetto/tree/main/module/web/src/types/interceptor.ts#L15)
@@ -91,7 +91,7 @@ export class WebResponse<B = unknown> extends BaseWebMessage<B, WebResponseConte
91
91
  These objects do not represent the underlying sockets provided by various http servers, but in fact are simple wrappers that track the flow through the call stack of the various [WebInterceptor](https://github.com/travetto/travetto/tree/main/module/web/src/types/interceptor.ts#L15)s and the [Endpoint](https://github.com/travetto/travetto/tree/main/module/web/src/decorator/endpoint.ts#L14) handler. One of the biggest departures here, is that the response is not an entity that is passed around from call-site to call-site, but is is solely a return-value. This doesn't mean the return value has to be static and pre-allocated, on the contrary streams are still supported. The difference here is that the streams/asynchronous values will be consumed until the response is sent back to the user. The [CompressInterceptor](https://github.com/travetto/travetto/tree/main/module/web/src/interceptor/compress.ts#L44) is a good reference for transforming a [WebResponse](https://github.com/travetto/travetto/tree/main/module/web/src/types/response.ts#L3) that can either be a stream or a fixed value.
92
92
 
93
93
  ## Defining a Controller
94
- To start, we must define a [@Controller](https://github.com/travetto/travetto/tree/main/module/web/src/decorator/controller.ts#L9), which is only allowed on classes. Controllers can be configured with:
94
+ To start, we must define a [@Controller](https://github.com/travetto/travetto/tree/main/module/web/src/decorator/controller.ts#L11), which is only allowed on classes. Controllers can be configured with:
95
95
  * `path` - The required context path the controller will operate atop
96
96
  * `title` - The definition of the controller
97
97
  * `description` - High level description fo the controller
@@ -114,13 +114,13 @@ class SimpleController {
114
114
  Once the controller is declared, each method of the controller is a candidate for being an endpoint. By design, everything is asynchronous, and so async/await is natively supported.
115
115
 
116
116
  The most common pattern is to register HTTP-driven endpoints. The HTTP methods that are currently supported:
117
- * [@Get](https://github.com/travetto/travetto/tree/main/module/web/src/decorator/endpoint.ts#L42)
118
- * [@Post](https://github.com/travetto/travetto/tree/main/module/web/src/decorator/endpoint.ts#L49)
119
- * [@Put](https://github.com/travetto/travetto/tree/main/module/web/src/decorator/endpoint.ts#L56)
117
+ * [@Get](https://github.com/travetto/travetto/tree/main/module/web/src/decorator/endpoint.ts#L41)
118
+ * [@Post](https://github.com/travetto/travetto/tree/main/module/web/src/decorator/endpoint.ts#L48)
119
+ * [@Put](https://github.com/travetto/travetto/tree/main/module/web/src/decorator/endpoint.ts#L55)
120
120
  * [@Delete](https://github.com/travetto/travetto/tree/main/module/web/src/decorator/endpoint.ts#L69)
121
- * [@Patch](https://github.com/travetto/travetto/tree/main/module/web/src/decorator/endpoint.ts#L63)
122
- * [@Head](https://github.com/travetto/travetto/tree/main/module/web/src/decorator/endpoint.ts#L75)
123
- * [@Options](https://github.com/travetto/travetto/tree/main/module/web/src/decorator/endpoint.ts#L81)
121
+ * [@Patch](https://github.com/travetto/travetto/tree/main/module/web/src/decorator/endpoint.ts#L62)
122
+ * [@Head](https://github.com/travetto/travetto/tree/main/module/web/src/decorator/endpoint.ts#L76)
123
+ * [@Options](https://github.com/travetto/travetto/tree/main/module/web/src/decorator/endpoint.ts#L83)
124
124
 
125
125
  Similar to the Controller, each endpoint decorator handles the following config:
126
126
  * `title` - The definition of the endpoint
@@ -155,12 +155,12 @@ class SimpleController {
155
155
 
156
156
  ### Parameters
157
157
  Endpoints can be configured to describe and enforce parameter behavior. Request parameters can be defined in five areas:
158
- * [@PathParam](https://github.com/travetto/travetto/tree/main/module/web/src/decorator/param.ts#L37) - Path params
159
- * [@QueryParam](https://github.com/travetto/travetto/tree/main/module/web/src/decorator/param.ts#L43) - Query params - can be either a single value or bind to a whole object
160
- * [@Body](https://github.com/travetto/travetto/tree/main/module/web/src/decorator/param.ts#L55) - Request body
161
- * [@HeaderParam](https://github.com/travetto/travetto/tree/main/module/web/src/decorator/param.ts#L49) - Header values
158
+ * [@PathParam](https://github.com/travetto/travetto/tree/main/module/web/src/decorator/param.ts#L38) - Path params
159
+ * [@QueryParam](https://github.com/travetto/travetto/tree/main/module/web/src/decorator/param.ts#L45) - Query params - can be either a single value or bind to a whole object
160
+ * [@Body](https://github.com/travetto/travetto/tree/main/module/web/src/decorator/param.ts#L59) - Request body
161
+ * [@HeaderParam](https://github.com/travetto/travetto/tree/main/module/web/src/decorator/param.ts#L52) - Header values
162
162
 
163
- Each [@Param](https://github.com/travetto/travetto/tree/main/module/web/src/decorator/param.ts#L24) can be configured to indicate:
163
+ Each [@Param](https://github.com/travetto/travetto/tree/main/module/web/src/decorator/param.ts#L16) can be configured to indicate:
164
164
  * `name` - Name of param, field name, defaults to handler parameter name if necessary
165
165
  * `description` - Description of param, pulled from [JSDoc](http://usejsdoc.org/about-getting-started.html), or defaults to name if empty
166
166
  * `required?` - Is the field required?, defaults to whether or not the parameter itself is optional
@@ -223,7 +223,7 @@ export class Simple {
223
223
  ```
224
224
 
225
225
  ### ContextParam
226
- In addition to endpoint parameters (i.e. user-provided inputs), there may also be a desire to access indirect contextual information. Specifically you may need access to the entire [WebRequest](https://github.com/travetto/travetto/tree/main/module/web/src/types/request.ts#L11). These are able to be injected using the [@ContextParam](https://github.com/travetto/travetto/tree/main/module/web/src/decorator/param.ts#L61) on a class-level field from the [WebAsyncContext](https://github.com/travetto/travetto/tree/main/module/web/src/context.ts#L11). These are not exposed as endpoint parameters as they cannot be provided when making RPC invocations.
226
+ In addition to endpoint parameters (i.e. user-provided inputs), there may also be a desire to access indirect contextual information. Specifically you may need access to the entire [WebRequest](https://github.com/travetto/travetto/tree/main/module/web/src/types/request.ts#L11). These are able to be injected using the [@ContextParam](https://github.com/travetto/travetto/tree/main/module/web/src/decorator/param.ts#L66) on a class-level field from the [WebAsyncContext](https://github.com/travetto/travetto/tree/main/module/web/src/context.ts#L11). These are not exposed as endpoint parameters as they cannot be provided when making RPC invocations.
227
227
 
228
228
  **Code: Example ContextParam usage**
229
229
  ```typescript
@@ -251,12 +251,12 @@ class ContextController {
251
251
  }
252
252
  ```
253
253
 
254
- **Note**: When referencing the [@ContextParam](https://github.com/travetto/travetto/tree/main/module/web/src/decorator/param.ts#L61) values, the contract for idempotency needs to be carefully inspected, if expected. You can see in the example above that the [CacheControl](https://github.com/travetto/travetto/tree/main/module/web/src/decorator/common.ts#L48) decorator is used to ensure that the response is not cached.
254
+ **Note**: When referencing the [@ContextParam](https://github.com/travetto/travetto/tree/main/module/web/src/decorator/param.ts#L66) values, the contract for idempotency needs to be carefully inspected, if expected. You can see in the example above that the [@CacheControl](https://github.com/travetto/travetto/tree/main/module/web/src/decorator/common.ts#L45) decorator is used to ensure that the response is not cached.
255
255
 
256
256
  ### Validating Inputs
257
257
  The module provides high level access for [Schema](https://github.com/travetto/travetto/tree/main/module/schema#readme "Data type registry for runtime validation, reflection and binding.") support, via decorators, for validating and typing request inputs.
258
258
 
259
- By default, all endpoint parameters are validated for type, and any additional constraints added (required, vs optional, minlength, etc). Each parameter location ([@PathParam](https://github.com/travetto/travetto/tree/main/module/web/src/decorator/param.ts#L37), [@Body](https://github.com/travetto/travetto/tree/main/module/web/src/decorator/param.ts#L55), [@QueryParam](https://github.com/travetto/travetto/tree/main/module/web/src/decorator/param.ts#L43), [@HeaderParam](https://github.com/travetto/travetto/tree/main/module/web/src/decorator/param.ts#L49)) primarily provides a source to bind the endpoint arguments from. Once bound, the module will validate that the provided arguments are in fact valid. All validation will occur before the endpoint is ever executed, ensuring a strong contract.
259
+ By default, all endpoint parameters are validated for type, and any additional constraints added (required, vs optional, minlength, etc). Each parameter location ([@PathParam](https://github.com/travetto/travetto/tree/main/module/web/src/decorator/param.ts#L38), [@Body](https://github.com/travetto/travetto/tree/main/module/web/src/decorator/param.ts#L59), [@QueryParam](https://github.com/travetto/travetto/tree/main/module/web/src/decorator/param.ts#L45), [@HeaderParam](https://github.com/travetto/travetto/tree/main/module/web/src/decorator/param.ts#L52)) primarily provides a source to bind the endpoint arguments from. Once bound, the module will validate that the provided arguments are in fact valid. All validation will occur before the endpoint is ever executed, ensuring a strong contract.
260
260
 
261
261
  **Code: Using Body for POST requests**
262
262
  ```typescript
@@ -617,7 +617,7 @@ export class CorsConfig {
617
617
  ```
618
618
 
619
619
  #### CacheControlInterceptor
620
- [CacheControlInterceptor](https://github.com/travetto/travetto/tree/main/module/web/src/interceptor/cache-control.ts#L23) by default, enforces whatever caching policy is established on a given endpoint using the [CacheControl](https://github.com/travetto/travetto/tree/main/module/web/src/decorator/common.ts#L48) decorator. Additionally, the interceptor retains knowledge if it is running on a private endpoint, or not. If the endpoint is deemed private it affects the caching header accordingly. If the endpoint directly returns a `Cache-Control` header, that takes precedence and all other logic is ignored.
620
+ [CacheControlInterceptor](https://github.com/travetto/travetto/tree/main/module/web/src/interceptor/cache-control.ts#L23) by default, enforces whatever caching policy is established on a given endpoint using the [@CacheControl](https://github.com/travetto/travetto/tree/main/module/web/src/decorator/common.ts#L45) decorator. Additionally, the interceptor retains knowledge if it is running on a private endpoint, or not. If the endpoint is deemed private it affects the caching header accordingly. If the endpoint directly returns a `Cache-Control` header, that takes precedence and all other logic is ignored.
621
621
 
622
622
  This can be managed by setting `web.cache.applies: <boolean>` in your config.
623
623
 
@@ -675,11 +675,11 @@ export class AlowDenyController {
675
675
  ```
676
676
 
677
677
  The resolution logic is as follows:
678
- * Check the resolved [Endpoint](https://github.com/travetto/travetto/tree/main/module/web/src/decorator/endpoint.ts#L14)/[@Controller](https://github.com/travetto/travetto/tree/main/module/web/src/decorator/controller.ts#L9) overrides to see if an interceptor is explicitly allowed or disallowed
678
+ * Check the resolved [Endpoint](https://github.com/travetto/travetto/tree/main/module/web/src/decorator/endpoint.ts#L14)/[@Controller](https://github.com/travetto/travetto/tree/main/module/web/src/decorator/controller.ts#L11) overrides to see if an interceptor is explicitly allowed or disallowed
679
679
  * Default to `applies()` logic for all available interceptors
680
680
 
681
681
  ## Creating a Custom WebInterceptor
682
- Additionally it may be desirable to create a custom interceptor. Interceptors can be registered with the [Dependency Injection](https://github.com/travetto/travetto/tree/main/module/di#readme "Dependency registration/management and injection support.") by implementing the [WebInterceptor](https://github.com/travetto/travetto/tree/main/module/web/src/types/interceptor.ts#L15) interface and adding an [@Injectable](https://github.com/travetto/travetto/tree/main/module/di/src/decorator.ts#L29) decorator. A simple logging interceptor:
682
+ Additionally it may be desirable to create a custom interceptor. Interceptors can be registered with the [Dependency Injection](https://github.com/travetto/travetto/tree/main/module/di#readme "Dependency registration/management and injection support.") by implementing the [WebInterceptor](https://github.com/travetto/travetto/tree/main/module/web/src/types/interceptor.ts#L15) interface and adding an [@Injectable](https://github.com/travetto/travetto/tree/main/module/di/src/decorator.ts#L15) decorator. A simple logging interceptor:
683
683
 
684
684
  **Code: Defining a new Interceptor**
685
685
  ```typescript
@@ -735,7 +735,7 @@ export class SimpleAuthInterceptor implements WebInterceptor {
735
735
  ```
736
736
 
737
737
  ## Cookie Support
738
- Cookies are a unique element, within the framework, as they sit on the request and response flows. Ideally we would separate these out, but given the support for key rotation, there is a scenario in which reading a cookie on the request, will result in a cookie needing to be written on the response. Because of this, cookies are treated as being outside the normal [WebRequest](https://github.com/travetto/travetto/tree/main/module/web/src/types/request.ts#L11) activity, and is exposed as the [@ContextParam](https://github.com/travetto/travetto/tree/main/module/web/src/decorator/param.ts#L61) [CookieJar](https://github.com/travetto/travetto/tree/main/module/web/src/util/cookie.ts#L12). The [CookieJar](https://github.com/travetto/travetto/tree/main/module/web/src/util/cookie.ts#L12) has a fairly basic contract:
738
+ Cookies are a unique element, within the framework, as they sit on the request and response flows. Ideally we would separate these out, but given the support for key rotation, there is a scenario in which reading a cookie on the request, will result in a cookie needing to be written on the response. Because of this, cookies are treated as being outside the normal [WebRequest](https://github.com/travetto/travetto/tree/main/module/web/src/types/request.ts#L11) activity, and is exposed as the [@ContextParam](https://github.com/travetto/travetto/tree/main/module/web/src/decorator/param.ts#L66) [CookieJar](https://github.com/travetto/travetto/tree/main/module/web/src/util/cookie.ts#L12). The [CookieJar](https://github.com/travetto/travetto/tree/main/module/web/src/util/cookie.ts#L12) has a fairly basic contract:
739
739
 
740
740
  **Code: CookieJar contract**
741
741
  ```typescript
package/__index__.ts CHANGED
@@ -19,7 +19,8 @@ export * from './src/decorator/controller.ts';
19
19
  export * from './src/decorator/param.ts';
20
20
  export * from './src/decorator/endpoint.ts';
21
21
 
22
- export * from './src/registry/controller.ts';
22
+ export * from './src/registry/registry-index.ts';
23
+ export * from './src/registry/registry-adapter.ts';
23
24
  export * from './src/registry/visitor.ts';
24
25
  export * from './src/registry/types.ts';
25
26
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@travetto/web",
3
- "version": "6.0.2",
4
- "description": "Declarative support creating for Web Applications",
3
+ "version": "7.0.0-rc.0",
4
+ "description": "Declarative support for creating Web Applications",
5
5
  "keywords": [
6
6
  "web",
7
7
  "decorators",
@@ -25,18 +25,18 @@
25
25
  "directory": "module/web"
26
26
  },
27
27
  "dependencies": {
28
- "@travetto/config": "^6.0.0",
29
- "@travetto/context": "^6.0.0",
30
- "@travetto/di": "^6.0.0",
31
- "@travetto/registry": "^6.0.0",
32
- "@travetto/runtime": "^6.0.0",
33
- "@travetto/schema": "^6.0.0",
28
+ "@travetto/config": "^7.0.0-rc.0",
29
+ "@travetto/context": "^7.0.0-rc.0",
30
+ "@travetto/di": "^7.0.0-rc.0",
31
+ "@travetto/registry": "^7.0.0-rc.0",
32
+ "@travetto/runtime": "^7.0.0-rc.0",
33
+ "@travetto/schema": "^7.0.0-rc.0",
34
34
  "find-my-way": "^9.3.0"
35
35
  },
36
36
  "peerDependencies": {
37
- "@travetto/cli": "^6.0.0",
38
- "@travetto/test": "^6.0.1",
39
- "@travetto/transformer": "^6.0.0"
37
+ "@travetto/cli": "^7.0.0-rc.0",
38
+ "@travetto/test": "^7.0.0-rc.0",
39
+ "@travetto/transformer": "^7.0.0-rc.0"
40
40
  },
41
41
  "peerDependenciesMeta": {
42
42
  "@travetto/transformer": {
@@ -1,20 +1,21 @@
1
- import { DependencyRegistry } from '@travetto/di';
1
+ import { DependencyRegistryIndex } from '@travetto/di';
2
2
  import { Runtime } from '@travetto/runtime';
3
+ import { IsPrivate } from '@travetto/schema';
3
4
 
4
5
  import { Controller } from '../decorator/controller.ts';
5
- import { ConditionalRegister, ConfigureInterceptor, Undocumented } from '../decorator/common.ts';
6
+ import { ConditionalRegister, ConfigureInterceptor } from '../decorator/common.ts';
6
7
  import { Get, Options } from '../decorator/endpoint.ts';
7
8
  import { WebConfig } from '../config.ts';
8
9
  import { LoggingInterceptor, } from '../interceptor/logging.ts';
9
10
 
10
- @Undocumented()
11
+ @IsPrivate()
11
12
  @Controller('/')
12
13
  @ConfigureInterceptor(LoggingInterceptor, { applies: false })
13
14
  export class GlobalHandler {
14
15
 
15
16
  @Get('')
16
17
  @ConditionalRegister(async () => {
17
- const config = await DependencyRegistry.getInstance(WebConfig);
18
+ const config = await DependencyRegistryIndex.getInstance(WebConfig);
18
19
  return config.defaultMessage;
19
20
  })
20
21
  message(): { module: string, version: string, env?: string } {
@@ -1,34 +1,29 @@
1
- import { asConstructable, castTo, Class, TimeSpan, TimeUtil } from '@travetto/runtime';
1
+ import { Class, ClassInstance, getClass, RetainPrimitiveFields, TimeSpan, TimeUtil } from '@travetto/runtime';
2
2
 
3
- import { ControllerRegistry } from '../registry/controller.ts';
4
- import { EndpointConfig, ControllerConfig, DescribableConfig, EndpointDecorator, EndpointFunctionDescriptor } from '../registry/types.ts';
3
+ import { ControllerRegistryIndex } from '../registry/registry-index.ts';
4
+ import { EndpointConfig, ControllerConfig, EndpointDecorator, EndpointFunctionDescriptor } from '../registry/types.ts';
5
5
  import { AcceptInterceptor } from '../interceptor/accept.ts';
6
6
  import { WebInterceptor } from '../types/interceptor.ts';
7
7
 
8
+ function isClass(target: unknown, property: unknown,): target is Class<unknown> {
9
+ return !property;
10
+ }
11
+
8
12
  function register(config: Partial<EndpointConfig | ControllerConfig>): EndpointDecorator {
9
- return function <T>(target: T | Class<T>, property?: string, descriptor?: EndpointFunctionDescriptor) {
10
- if (descriptor) {
11
- return ControllerRegistry.registerPendingEndpoint(asConstructable(target).constructor, descriptor, config);
13
+ return function <T>(instanceOrCls: ClassInstance | Class<T>, property?: string | symbol, _?: EndpointFunctionDescriptor) {
14
+ const adapter = ControllerRegistryIndex.getForRegister(getClass(instanceOrCls));
15
+ if (isClass(instanceOrCls, property)) {
16
+ adapter.register(config);
12
17
  } else {
13
- return ControllerRegistry.registerPending(castTo(target), config);
18
+ adapter.registerEndpoint(property!, config);
14
19
  }
15
20
  };
16
21
  }
17
22
 
18
- /**
19
- * Decorator used to add description metadata to a class or method
20
- * @param desc The describe config
21
- */
22
- export function Describe(desc: DescribableConfig): EndpointDecorator { return register(desc); }
23
-
24
- /**
25
- * Marks a class/endpoint as being undocumented
26
- */
27
- export function Undocumented(): EndpointDecorator { return register({ documented: false }); }
28
-
29
23
  /**
30
24
  * Set response headers on success
31
25
  * @param headers The response headers to set
26
+ * @kind decorator
32
27
  */
33
28
  export function SetHeaders(headers: EndpointConfig['responseHeaders']): EndpointDecorator {
34
29
  return register({ responseHeaders: headers });
@@ -36,6 +31,7 @@ export function SetHeaders(headers: EndpointConfig['responseHeaders']): Endpoint
36
31
 
37
32
  /**
38
33
  * Specifies content type for response
34
+ * @kind decorator
39
35
  */
40
36
  export function Produces(mime: string): EndpointDecorator { return SetHeaders({ 'Content-Type': mime }); }
41
37
 
@@ -44,6 +40,7 @@ type CacheControlInput = { cacheableAge?: number | TimeSpan, isPrivate?: boolean
44
40
  /**
45
41
  * Set the max-age of a response based on the config
46
42
  * @param value The value for the duration
43
+ * @kind decorator
47
44
  */
48
45
  export function CacheControl(input: TimeSpan | number | CacheControlInput, extra?: Omit<CacheControlInput, 'cacheableAge'>): EndpointDecorator {
49
46
  if (typeof input === 'string' || typeof input === 'number') {
@@ -61,9 +58,10 @@ export function CacheControl(input: TimeSpan | number | CacheControlInput, extra
61
58
  /**
62
59
  * Define an endpoint to support specific input types
63
60
  * @param types The list of mime types to allow/deny
61
+ * @kind decorator
64
62
  */
65
63
  export function Accepts(types: [string, ...string[]]): EndpointDecorator {
66
- return ControllerRegistry.createInterceptorConfigDecorator(
64
+ return ControllerRegistryIndex.createInterceptorConfigDecorator(
67
65
  AcceptInterceptor,
68
66
  { types, applies: true },
69
67
  { responseHeaders: { accepts: types.join(', ') } }
@@ -72,12 +70,18 @@ export function Accepts(types: [string, ...string[]]): EndpointDecorator {
72
70
 
73
71
  /**
74
72
  * Allows for configuring interceptor-level support at an endpoint or controller level
73
+ * @kind decorator
75
74
  */
76
- export const ConfigureInterceptor =
77
- ControllerRegistry.createInterceptorConfigDecorator.bind(ControllerRegistry);
75
+ export const ConfigureInterceptor = <T extends WebInterceptor>(
76
+ cls: Class<T>,
77
+ cfg: Partial<RetainPrimitiveFields<T['config']>>,
78
+ extra?: Partial<EndpointConfig & ControllerConfig>
79
+ ): EndpointDecorator =>
80
+ ControllerRegistryIndex.createInterceptorConfigDecorator(cls, cfg, extra);
78
81
 
79
82
  /**
80
83
  * Specifies if endpoint should be conditional
84
+ * @kind decorator
81
85
  */
82
86
  export function ConditionalRegister(handler: () => (boolean | Promise<boolean>)): EndpointDecorator {
83
87
  return register({ conditional: handler });
@@ -85,6 +89,7 @@ export function ConditionalRegister(handler: () => (boolean | Promise<boolean>))
85
89
 
86
90
  /**
87
91
  * Registers an interceptor exclusion filter
92
+ * @kind decorator
88
93
  */
89
94
  export function ExcludeInterceptors(interceptorExclude: (val: WebInterceptor) => boolean): EndpointDecorator {
90
95
  return register({ interceptorExclude });
@@ -1,13 +1,16 @@
1
1
  import { Class } from '@travetto/runtime';
2
- import { ControllerRegistry } from '../registry/controller.ts';
2
+ import { DependencyRegistryIndex } from '@travetto/di';
3
+
4
+ import { ControllerRegistryIndex } from '../registry/registry-index.ts';
3
5
 
4
6
  /**
5
7
  * Decorator to register a new web controller
6
- * @augments `@travetto/di:Injectable`
7
- * @augments `@travetto/web:Controller`
8
+ * @augments `@travetto/schema:Schema`
9
+ * @kind decorator
8
10
  */
9
11
  export function Controller(path: string) {
10
- return function <T>(target: Class<T>): void {
11
- ControllerRegistry.registerPending(target, { basePath: path, class: target, });
12
+ return function <T>(cls: Class<T>): void {
13
+ ControllerRegistryIndex.getForRegister(cls).register({ basePath: path, class: cls, });
14
+ DependencyRegistryIndex.getForRegister(cls).registerClass();
12
15
  };
13
16
  }
@@ -1,10 +1,10 @@
1
- import { asConstructable } from '@travetto/runtime';
1
+ import { ClassInstance, getClass } from '@travetto/runtime';
2
2
 
3
- import { ControllerRegistry } from '../registry/controller.ts';
4
- import { EndpointConfig, EndpointFunctionDescriptor, EndpointIOType } from '../registry/types.ts';
3
+ import { EndpointConfig, EndpointFunctionDescriptor } from '../registry/types.ts';
5
4
  import { HTTP_METHODS, HttpMethod } from '../types/core.ts';
5
+ import { ControllerRegistryIndex } from '../registry/registry-index.ts';
6
6
 
7
- type EndpointFunctionDecorator = <T>(target: T, prop: symbol | string, descriptor: EndpointFunctionDescriptor) => EndpointFunctionDescriptor;
7
+ type EndpointFunctionDecorator = <T>(instance: T, property: symbol | string, descriptor: EndpointFunctionDescriptor) => EndpointFunctionDescriptor;
8
8
 
9
9
  type EndpointDecConfig = Partial<EndpointConfig> & { path: string };
10
10
 
@@ -12,11 +12,9 @@ type EndpointDecConfig = Partial<EndpointConfig> & { path: string };
12
12
  * Generic Endpoint Decorator
13
13
  */
14
14
  export function Endpoint(config: EndpointDecConfig): EndpointFunctionDecorator {
15
- return function <T>(target: T, prop: symbol | string, descriptor: EndpointFunctionDescriptor): EndpointFunctionDescriptor {
16
- const result = ControllerRegistry.registerPendingEndpoint(
17
- asConstructable(target).constructor, descriptor, config
18
- );
19
- return result;
15
+ return function (instance: ClassInstance, property: symbol | string, descriptor: EndpointFunctionDescriptor): EndpointFunctionDescriptor {
16
+ ControllerRegistryIndex.getForRegister(getClass(instance)).registerEndpoint(property, { methodName: property }, config);
17
+ return descriptor;
20
18
  };
21
19
  }
22
20
 
@@ -37,65 +35,49 @@ function HttpEndpoint(method: HttpMethod, path: string): EndpointFunctionDecorat
37
35
  /**
38
36
  * Registers GET requests
39
37
  * @param path The endpoint path for the request
40
- * @augments `@travetto/web:Endpoint`
38
+ * @augments `@travetto/schema:Method`
39
+ * @kind decorator
41
40
  */
42
41
  export function Get(path = '/'): EndpointFunctionDecorator { return HttpEndpoint('GET', path); }
43
42
  /**
44
43
  * Registers POST requests
45
44
  * @param path The endpoint path for the request
46
- * @augments `@travetto/web:HttpRequestBody`
47
- * @augments `@travetto/web:Endpoint`
45
+ * @augments `@travetto/schema:Method`
46
+ * @kind decorator
48
47
  */
49
48
  export function Post(path = '/'): EndpointFunctionDecorator { return HttpEndpoint('POST', path); }
50
49
  /**
51
50
  * Registers PUT requests
52
51
  * @param path The endpoint path for the request
53
- * @augments `@travetto/web:HttpRequestBody`
54
- * @augments `@travetto/web:Endpoint`
52
+ * @augments `@travetto/schema:Method`
53
+ * @kind decorator
55
54
  */
56
55
  export function Put(path = '/'): EndpointFunctionDecorator { return HttpEndpoint('PUT', path); }
57
56
  /**
58
57
  * Registers PATCH requests
59
58
  * @param path The endpoint path for the request
60
- * @augments `@travetto/web:HttpRequestBody`
61
- * @augments `@travetto/web:Endpoint`
59
+ * @augments `@travetto/schema:Method`
60
+ * @kind decorator
62
61
  */
63
62
  export function Patch(path = '/'): EndpointFunctionDecorator { return HttpEndpoint('PATCH', path); }
64
63
  /**
65
64
  * Registers DELETE requests
66
65
  * @param path The endpoint path for the request
67
- * @augments `@travetto/web:Endpoint`
66
+ * @augments `@travetto/schema:Method`
67
+ * @kind decorator
68
68
  */
69
69
  export function Delete(path = '/'): EndpointFunctionDecorator { return HttpEndpoint('DELETE', path); }
70
70
  /**
71
71
  * Registers HEAD requests
72
72
  * @param path The endpoint path for the request
73
- * @augments `@travetto/web:Endpoint`
73
+ * @augments `@travetto/schema:Method`
74
+ * @kind decorator
74
75
  */
75
76
  export function Head(path = '/'): EndpointFunctionDecorator { return HttpEndpoint('HEAD', path); }
76
77
  /**
77
78
  * Registers OPTIONS requests
78
79
  * @param path The endpoint path for the request
79
- * @augments `@travetto/web:Endpoint`
80
+ * @augments `@travetto/schema:Method`
81
+ * @kind decorator
80
82
  */
81
83
  export function Options(path = '/'): EndpointFunctionDecorator { return HttpEndpoint('OPTIONS', path); }
82
-
83
- /**
84
- * Defines the response type of the endpoint
85
- * @param responseType The desired response mime type
86
- */
87
- export function ResponseType(responseType: EndpointIOType): EndpointFunctionDecorator {
88
- return function <T>(target: T, property: string | symbol, descriptor: EndpointFunctionDescriptor) {
89
- return ControllerRegistry.registerPendingEndpoint(asConstructable(target).constructor, descriptor, { responseType });
90
- };
91
- }
92
-
93
- /**
94
- * Defines the supported request body type
95
- * @param requestType The type of the request body
96
- */
97
- export function RequestType(requestType: EndpointIOType): EndpointFunctionDecorator {
98
- return function <T>(target: T, property: string | symbol, descriptor: EndpointFunctionDescriptor) {
99
- return ControllerRegistry.registerPendingEndpoint(asConstructable(target).constructor, descriptor, { requestType });
100
- };
101
- }
@@ -1,64 +1,71 @@
1
- import { asConstructable, Class, ClassInstance } from '@travetto/runtime';
1
+ import { ClassInstance, getClass } from '@travetto/runtime';
2
+ import { SchemaRegistryIndex } from '@travetto/schema';
2
3
 
3
- import { ControllerRegistry } from '../registry/controller.ts';
4
- import { EndpointParamConfig } from '../registry/types.ts';
4
+ import { ControllerRegistryIndex } from '../registry/registry-index.ts';
5
+ import { EndpointParameterConfig, EndpointParamLocation } from '../registry/types.ts';
5
6
 
6
- type ParamDecorator = (target: ClassInstance, propertyKey: string | symbol, idx: number) => void;
7
-
8
- /**
9
- * Get the param configuration
10
- * @param location The location of the parameter
11
- * @param extra Any additional configuration for the param config
12
- */
13
- export const paramConfig = (location: EndpointParamConfig['location'], extra: string | Partial<EndpointParamConfig>): EndpointParamConfig => ({
14
- location,
15
- ...((typeof extra === 'string' ? { name: extra } : extra))
16
- });
7
+ type ParamDecorator = (instance: ClassInstance, property: string | symbol, idx: number) => void;
17
8
 
18
9
  /**
19
10
  * Define a parameter
20
11
  * @param location The location of the parameter
21
12
  * @param extra Any extra configuration for the param
22
- * @augments `@travetto/web:Param`
13
+ * @augments `@travetto/schema:Input`
14
+ * @kind decorator
23
15
  */
24
- export function Param(location: EndpointParamConfig['location'], extra: string | Partial<EndpointParamConfig>): ParamDecorator {
25
- const param = paramConfig(location, extra);
26
- return (target: ClassInstance, propertyKey: string | symbol, idx: number): void => {
27
- const handler = target.constructor.prototype[propertyKey];
28
- ControllerRegistry.registerEndpointParameter(target.constructor, handler, param, idx);
16
+ export function Param(location: EndpointParamLocation, extra: string | Partial<EndpointParameterConfig>): ParamDecorator {
17
+ return (instance: ClassInstance, property: string | symbol, idx: number): void => {
18
+ const name = typeof extra === 'string' ? extra : extra.name;
19
+ const config = typeof extra === 'string' ? {} : extra;
20
+
21
+ // Set name as needed
22
+ if (name) {
23
+ SchemaRegistryIndex.getForRegister(getClass(instance)).registerParameter(property, idx, { name });
24
+ }
25
+
26
+ ControllerRegistryIndex.getForRegister(getClass(instance)).registerEndpointParameter(property, idx, {
27
+ index: idx, location, ...config
28
+ });
29
29
  };
30
30
  }
31
31
 
32
32
  /**
33
33
  * Define a Path param
34
34
  * @param param The param configuration or name
35
- * @augments `@travetto/web:Param`
35
+ * @augments `@travetto/schema:Input`
36
+ * @kind decorator
36
37
  */
37
- export function PathParam(param: string | Partial<EndpointParamConfig> = {}): ParamDecorator { return Param('path', param); }
38
+ export function PathParam(param: string | Partial<EndpointParameterConfig> = {}): ParamDecorator { return Param('path', param); }
38
39
  /**
39
40
  * Define a Query param
40
41
  * @param param The param configuration or name
41
- * @augments `@travetto/web:Param`
42
+ * @augments `@travetto/schema:Input`
43
+ * @kind decorator
42
44
  */
43
- export function QueryParam(param: string | Partial<EndpointParamConfig> = {}): ParamDecorator { return Param('query', param); }
45
+ export function QueryParam(param: string | Partial<EndpointParameterConfig> = {}): ParamDecorator { return Param('query', param); }
44
46
  /**
45
47
  * Define a Header param
46
48
  * @param param The param configuration or name
47
- * @augments `@travetto/web:Param`
49
+ * @augments `@travetto/schema:Input`
50
+ * @kind decorator
48
51
  */
49
- export function HeaderParam(param: string | Partial<EndpointParamConfig> = {}): ParamDecorator { return Param('header', param); }
52
+ export function HeaderParam(param: string | Partial<EndpointParameterConfig> = {}): ParamDecorator { return Param('header', param); }
50
53
  /**
51
54
  * Define a body param as an input
52
55
  * @param param The param configuration
53
- * @augments `@travetto/web:Param`
56
+ * @augments `@travetto/schema:Input`
57
+ * @kind decorator
54
58
  */
55
- export function Body(param: Partial<EndpointParamConfig> = {}): ParamDecorator { return Param('body', param); }
59
+ export function Body(param: Partial<EndpointParameterConfig> = {}): ParamDecorator { return Param('body', param); }
56
60
 
57
61
  /**
58
62
  * A contextual field as provided by the WebAsyncContext
59
- * @augments `@travetto/web:ContextParam`
63
+ * @augments `@travetto/schema:Field`
64
+ * @kind decorator
60
65
  */
61
- export function ContextParam(config?: { target: Class }) {
62
- return (inst: unknown, field: string): void =>
63
- ControllerRegistry.registerControllerContextParam(asConstructable(inst).constructor, field, config!.target);
66
+ export function ContextParam() {
67
+ return (instance: ClassInstance, property: string | symbol): void => {
68
+ ControllerRegistryIndex.getForRegister(getClass(instance)).register({ contextParams: { [property]: true } });
69
+ ControllerRegistryIndex.bindContextParamsOnPostConstruct(getClass(instance));
70
+ };
64
71
  }
@@ -1,4 +1,4 @@
1
- import { Injectable, Inject, DependencyRegistry } from '@travetto/di';
1
+ import { Injectable, Inject, DependencyRegistryIndex } from '@travetto/di';
2
2
  import { Config } from '@travetto/config';
3
3
  import { toConcrete } from '@travetto/runtime';
4
4
  import { Ignore } from '@travetto/schema';
@@ -66,7 +66,7 @@ export class BodyInterceptor implements WebInterceptor<WebBodyConfig> {
66
66
 
67
67
  async postConstruct(): Promise<void> {
68
68
  // Load all the parser types
69
- const instances = await DependencyRegistry.getCandidateInstances(toConcrete<BodyContentParser>());
69
+ const instances = await DependencyRegistryIndex.getInstances(toConcrete<BodyContentParser>());
70
70
  for (const instance of instances) {
71
71
  this.parsers[instance.type] = instance;
72
72
  }
@@ -96,8 +96,8 @@ export class BodyInterceptor implements WebInterceptor<WebBodyConfig> {
96
96
  return next();
97
97
  }
98
98
 
99
- const [baseType,] = contentType.value.split('/');
100
- const parserType = config.parsingTypes[contentType.value] ?? config.parsingTypes[baseType];
99
+ const [baseMimeType,] = contentType.value.split('/');
100
+ const parserType = config.parsingTypes[contentType.value] ?? config.parsingTypes[baseMimeType];
101
101
  if (!parserType) {
102
102
  return next();
103
103
  }