@fluojs/http 1.0.0-beta.2 → 1.0.0-beta.3

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.
Files changed (59) hide show
  1. package/dist/adapter.d.ts +31 -0
  2. package/dist/adapter.d.ts.map +1 -1
  3. package/dist/adapter.js +37 -0
  4. package/dist/adapters/binding.d.ts +6 -0
  5. package/dist/adapters/binding.d.ts.map +1 -1
  6. package/dist/adapters/binding.js +8 -0
  7. package/dist/adapters/dto-validation-adapter.d.ts +3 -0
  8. package/dist/adapters/dto-validation-adapter.d.ts.map +1 -1
  9. package/dist/adapters/dto-validation-adapter.js +3 -0
  10. package/dist/dispatch/dispatch-content-negotiation.d.ts +17 -0
  11. package/dist/dispatch/dispatch-content-negotiation.d.ts.map +1 -1
  12. package/dist/dispatch/dispatch-content-negotiation.js +21 -0
  13. package/dist/dispatch/dispatch-error-policy.d.ts +8 -0
  14. package/dist/dispatch/dispatch-error-policy.d.ts.map +1 -1
  15. package/dist/dispatch/dispatch-error-policy.js +9 -0
  16. package/dist/dispatch/dispatch-handler-policy.d.ts +8 -0
  17. package/dist/dispatch/dispatch-handler-policy.d.ts.map +1 -1
  18. package/dist/dispatch/dispatch-handler-policy.js +9 -0
  19. package/dist/dispatch/dispatch-response-policy.d.ts +10 -0
  20. package/dist/dispatch/dispatch-response-policy.d.ts.map +1 -1
  21. package/dist/dispatch/dispatch-response-policy.js +11 -0
  22. package/dist/dispatch/dispatch-routing-policy.d.ts +13 -0
  23. package/dist/dispatch/dispatch-routing-policy.d.ts.map +1 -1
  24. package/dist/dispatch/dispatch-routing-policy.js +14 -0
  25. package/dist/dispatch/dispatcher.d.ts.map +1 -1
  26. package/dist/dispatch/dispatcher.js +55 -16
  27. package/dist/errors.d.ts +3 -0
  28. package/dist/errors.d.ts.map +1 -1
  29. package/dist/errors.js +4 -0
  30. package/dist/guards.d.ts +7 -0
  31. package/dist/guards.d.ts.map +1 -1
  32. package/dist/guards.js +11 -0
  33. package/dist/input-error-detail.d.ts +9 -0
  34. package/dist/input-error-detail.d.ts.map +1 -1
  35. package/dist/input-error-detail.js +10 -0
  36. package/dist/interceptors.d.ts +8 -0
  37. package/dist/interceptors.d.ts.map +1 -1
  38. package/dist/interceptors.js +14 -1
  39. package/dist/mapping.d.ts +7 -0
  40. package/dist/mapping.d.ts.map +1 -1
  41. package/dist/mapping.js +93 -11
  42. package/dist/middleware/correlation.d.ts +5 -0
  43. package/dist/middleware/correlation.d.ts.map +1 -1
  44. package/dist/middleware/correlation.js +6 -0
  45. package/dist/middleware/cors.d.ts +9 -0
  46. package/dist/middleware/cors.d.ts.map +1 -1
  47. package/dist/middleware/cors.js +11 -0
  48. package/dist/middleware/middleware.d.ts +34 -0
  49. package/dist/middleware/middleware.d.ts.map +1 -1
  50. package/dist/middleware/middleware.js +47 -0
  51. package/dist/middleware/security-headers.d.ts +9 -0
  52. package/dist/middleware/security-headers.d.ts.map +1 -1
  53. package/dist/middleware/security-headers.js +11 -0
  54. package/dist/route-path.d.ts +41 -0
  55. package/dist/route-path.d.ts.map +1 -1
  56. package/dist/route-path.js +50 -0
  57. package/dist/types.d.ts +5 -0
  58. package/dist/types.d.ts.map +1 -1
  59. package/package.json +3 -3
@@ -1,3 +1,13 @@
1
+ /**
2
+ * Describes the input error detail contract.
3
+ */
4
+
5
+ /**
6
+ * To input error detail.
7
+ *
8
+ * @param detail The detail.
9
+ * @returns The to input error detail result.
10
+ */
1
11
  export function toInputErrorDetail(detail) {
2
12
  return {
3
13
  code: detail.code,
@@ -1,3 +1,11 @@
1
1
  import type { InterceptorContext, InterceptorLike } from './types.js';
2
+ /**
3
+ * Run interceptor chain.
4
+ *
5
+ * @param definitions The definitions.
6
+ * @param context The context.
7
+ * @param terminal The terminal.
8
+ * @returns The run interceptor chain result.
9
+ */
2
10
  export declare function runInterceptorChain(definitions: InterceptorLike[], context: InterceptorContext, terminal: () => Promise<unknown>): Promise<unknown>;
3
11
  //# sourceMappingURL=interceptors.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"interceptors.d.ts","sourceRoot":"","sources":["../src/interceptors.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAGV,kBAAkB,EAClB,eAAe,EAEhB,MAAM,YAAY,CAAC;AAiBpB,wBAAsB,mBAAmB,CACvC,WAAW,EAAE,eAAe,EAAE,EAC9B,OAAO,EAAE,kBAAkB,EAC3B,QAAQ,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,GAC/B,OAAO,CAAC,OAAO,CAAC,CAelB"}
1
+ {"version":3,"file":"interceptors.d.ts","sourceRoot":"","sources":["../src/interceptors.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAGV,kBAAkB,EAClB,eAAe,EAEhB,MAAM,YAAY,CAAC;AAiBpB;;;;;;;GAOG;AACH,wBAAsB,mBAAmB,CACvC,WAAW,EAAE,eAAe,EAAE,EAC9B,OAAO,EAAE,kBAAkB,EAC3B,QAAQ,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,GAC/B,OAAO,CAAC,OAAO,CAAC,CAoBlB"}
@@ -7,11 +7,24 @@ async function resolveInterceptor(definition, requestContext) {
7
7
  }
8
8
  return requestContext.container.resolve(definition);
9
9
  }
10
+
11
+ /**
12
+ * Run interceptor chain.
13
+ *
14
+ * @param definitions The definitions.
15
+ * @param context The context.
16
+ * @param terminal The terminal.
17
+ * @returns The run interceptor chain result.
18
+ */
10
19
  export async function runInterceptorChain(definitions, context, terminal) {
20
+ if (definitions.length === 0) {
21
+ return terminal();
22
+ }
11
23
  let next = {
12
24
  handle: terminal
13
25
  };
14
- for (const definition of [...definitions].reverse()) {
26
+ for (let index = definitions.length - 1; index >= 0; index -= 1) {
27
+ const definition = definitions[index];
15
28
  const interceptor = await resolveInterceptor(definition, context.requestContext);
16
29
  const previous = next;
17
30
  next = {
package/dist/mapping.d.ts CHANGED
@@ -2,6 +2,13 @@ import type { HandlerMapping, HandlerSource, VersioningOptions } from './types.j
2
2
  interface CreateHandlerMappingOptions {
3
3
  versioning?: VersioningOptions;
4
4
  }
5
+ /**
6
+ * Create handler mapping.
7
+ *
8
+ * @param sources The sources.
9
+ * @param options The options.
10
+ * @returns The create handler mapping result.
11
+ */
5
12
  export declare function createHandlerMapping(sources: HandlerSource[], options?: CreateHandlerMappingOptions): HandlerMapping;
6
13
  export {};
7
14
  //# sourceMappingURL=mapping.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"mapping.d.ts","sourceRoot":"","sources":["../src/mapping.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAIV,cAAc,EAEd,aAAa,EAIb,iBAAiB,EAClB,MAAM,YAAY,CAAC;AAOpB,UAAU,2BAA2B;IACnC,UAAU,CAAC,EAAE,iBAAiB,CAAC;CAChC;AAmQD,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,aAAa,EAAE,EAAE,OAAO,CAAC,EAAE,2BAA2B,GAAG,cAAc,CA0DpH"}
1
+ {"version":3,"file":"mapping.d.ts","sourceRoot":"","sources":["../src/mapping.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAIV,cAAc,EAEd,aAAa,EAIb,iBAAiB,EAClB,MAAM,YAAY,CAAC;AAOpB,UAAU,2BAA2B;IACnC,UAAU,CAAC,EAAE,iBAAiB,CAAC;CAChC;AA6VD;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,aAAa,EAAE,EAAE,OAAO,CAAC,EAAE,2BAA2B,GAAG,cAAc,CAuEpH"}
package/dist/mapping.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { getControllerMetadata, getRouteMetadata } from '@fluojs/core/internal';
2
2
  import { getRouteProducesMetadata } from './decorators.js';
3
3
  import { RouteConflictError } from './errors.js';
4
- import { extractRoutePathParams, matchRoutePath, normalizeRoutePath, parseRoutePath } from './route-path.js';
4
+ import { extractRoutePathParams, normalizeRoutePath, parseRoutePath } from './route-path.js';
5
5
  import { VersioningType } from './types.js';
6
6
  function joinPaths(basePath, routePath) {
7
7
  return normalizeRoutePath(`${basePath}/${routePath}`);
@@ -116,19 +116,32 @@ function matchesRouteVersion(descriptor, requestVersion) {
116
116
  function getControllerMethodNames(controllerToken) {
117
117
  return Object.getOwnPropertyNames(controllerToken.prototype).filter(propertyKey => propertyKey !== 'constructor');
118
118
  }
119
- function splitIncomingPathSegments(path) {
120
- return normalizeRoutePath(path).split('/').filter(Boolean);
121
- }
122
119
  function buildDescriptorIndex(descriptors) {
123
- const index = new Map();
120
+ const staticIndex = new Map();
121
+ const paramIndex = new Map();
124
122
  for (const descriptor of descriptors) {
125
123
  const method = descriptor.route.method;
126
124
  const segments = parseRoutePath(descriptor.route.path, `Registered ${descriptor.route.method} route path`);
125
+ if (segments.every(segment => segment.kind === 'literal')) {
126
+ let methodMap = staticIndex.get(method);
127
+ if (!methodMap) {
128
+ methodMap = new Map();
129
+ staticIndex.set(method, methodMap);
130
+ }
131
+ const path = descriptor.route.path;
132
+ const bucket = methodMap.get(path);
133
+ if (bucket) {
134
+ bucket.push(descriptor);
135
+ } else {
136
+ methodMap.set(path, [descriptor]);
137
+ }
138
+ continue;
139
+ }
127
140
  const segmentCount = segments.length;
128
- let methodMap = index.get(method);
141
+ let methodMap = paramIndex.get(method);
129
142
  if (!methodMap) {
130
143
  methodMap = new Map();
131
- index.set(method, methodMap);
144
+ paramIndex.set(method, methodMap);
132
145
  }
133
146
  let bucket = methodMap.get(segmentCount);
134
147
  if (!bucket) {
@@ -140,7 +153,61 @@ function buildDescriptorIndex(descriptors) {
140
153
  segments
141
154
  });
142
155
  }
143
- return index;
156
+ return {
157
+ param: paramIndex,
158
+ static: staticIndex
159
+ };
160
+ }
161
+ function findStaticMatch(descriptorBuckets, requestVersion, versioning) {
162
+ let firstUnversionedMatch;
163
+ for (const descriptors of descriptorBuckets) {
164
+ if (!descriptors || descriptors.length === 0) {
165
+ continue;
166
+ }
167
+ for (const descriptor of descriptors) {
168
+ if (versioning.type === VersioningType.URI) {
169
+ return {
170
+ descriptor,
171
+ params: {}
172
+ };
173
+ }
174
+ if (matchesRouteVersion(descriptor, requestVersion)) {
175
+ return {
176
+ descriptor,
177
+ params: {}
178
+ };
179
+ }
180
+ if (descriptor.route.version === undefined && !firstUnversionedMatch) {
181
+ firstUnversionedMatch = {
182
+ descriptor,
183
+ params: {}
184
+ };
185
+ }
186
+ }
187
+ }
188
+ return firstUnversionedMatch;
189
+ }
190
+ function matchParameterizedRoute(candidate, incomingSegments) {
191
+ const {
192
+ segments
193
+ } = candidate;
194
+ if (segments.length !== incomingSegments.length) {
195
+ return undefined;
196
+ }
197
+ for (let index = 0; index < segments.length; index += 1) {
198
+ const segment = segments[index];
199
+ if (segment.kind === 'literal' && segment.value !== incomingSegments[index]) {
200
+ return undefined;
201
+ }
202
+ }
203
+ const params = {};
204
+ for (let index = 0; index < segments.length; index += 1) {
205
+ const segment = segments[index];
206
+ if (segment.kind === 'param') {
207
+ params[segment.name] = incomingSegments[index];
208
+ }
209
+ }
210
+ return params;
144
211
  }
145
212
  function createHandlerDescriptors(source, versioning) {
146
213
  const controllerMetadata = getControllerMetadata(source.controllerToken) ?? {
@@ -194,6 +261,14 @@ function buildDescriptorList(sources, versioning) {
194
261
  }
195
262
  return descriptors;
196
263
  }
264
+
265
+ /**
266
+ * Create handler mapping.
267
+ *
268
+ * @param sources The sources.
269
+ * @param options The options.
270
+ * @returns The create handler mapping result.
271
+ */
197
272
  export function createHandlerMapping(sources, options) {
198
273
  const versioning = resolveVersioning(options);
199
274
  const descriptors = buildDescriptorList(sources, versioning);
@@ -203,11 +278,18 @@ export function createHandlerMapping(sources, options) {
203
278
  match(request) {
204
279
  const method = request.method.toUpperCase();
205
280
  const requestVersion = versioning.type === VersioningType.URI ? undefined : resolveRequestVersion(request, versioning);
206
- const incomingSegments = splitIncomingPathSegments(request.path);
207
- const candidates = [...(descriptorIndex.get(method)?.get(incomingSegments.length) ?? []), ...(descriptorIndex.get('ALL')?.get(incomingSegments.length) ?? [])];
281
+ const normalizedPath = normalizeRoutePath(request.path);
282
+ const methodStaticDescriptors = descriptorIndex.static.get(method)?.get(normalizedPath);
283
+ const allStaticDescriptors = descriptorIndex.static.get('ALL')?.get(normalizedPath);
284
+ const directStaticMatch = findStaticMatch([methodStaticDescriptors, allStaticDescriptors], requestVersion, versioning);
285
+ if (directStaticMatch) {
286
+ return directStaticMatch;
287
+ }
288
+ const incomingSegments = normalizedPath.split('/').filter(Boolean);
289
+ const candidates = [...(descriptorIndex.param.get(method)?.get(incomingSegments.length) ?? []), ...(descriptorIndex.param.get('ALL')?.get(incomingSegments.length) ?? [])];
208
290
  let firstUnversionedMatch;
209
291
  for (const candidate of candidates) {
210
- const params = matchRoutePath(candidate.segments, incomingSegments);
292
+ const params = matchParameterizedRoute(candidate, incomingSegments);
211
293
  if (!params) {
212
294
  continue;
213
295
  }
@@ -1,3 +1,8 @@
1
1
  import type { Middleware } from '../types.js';
2
+ /**
3
+ * Create correlation middleware.
4
+ *
5
+ * @returns The create correlation middleware result.
6
+ */
2
7
  export declare function createCorrelationMiddleware(): Middleware;
3
8
  //# sourceMappingURL=correlation.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"correlation.d.ts","sourceRoot":"","sources":["../../src/middleware/correlation.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAY9C,wBAAgB,2BAA2B,IAAI,UAAU,CAYxD"}
1
+ {"version":3,"file":"correlation.d.ts","sourceRoot":"","sources":["../../src/middleware/correlation.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAY9C;;;;GAIG;AACH,wBAAgB,2BAA2B,IAAI,UAAU,CAYxD"}
@@ -6,6 +6,12 @@ function resolveInboundRequestId(headers) {
6
6
  const value = Array.isArray(requestId) ? requestId[0] : requestId;
7
7
  return value ?? randomUUID();
8
8
  }
9
+
10
+ /**
11
+ * Create correlation middleware.
12
+ *
13
+ * @returns The create correlation middleware result.
14
+ */
9
15
  export function createCorrelationMiddleware() {
10
16
  return {
11
17
  async handle(context, next) {
@@ -1,4 +1,7 @@
1
1
  import type { Middleware } from '../types.js';
2
+ /**
3
+ * Describes the cors options contract.
4
+ */
2
5
  export interface CorsOptions {
3
6
  allowCredentials?: boolean;
4
7
  allowHeaders?: string[];
@@ -7,5 +10,11 @@ export interface CorsOptions {
7
10
  exposeHeaders?: string[];
8
11
  maxAge?: number;
9
12
  }
13
+ /**
14
+ * Create cors middleware.
15
+ *
16
+ * @param options The options.
17
+ * @returns The create cors middleware result.
18
+ */
10
19
  export declare function createCorsMiddleware(options?: CorsOptions): Middleware;
11
20
  //# sourceMappingURL=cors.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"cors.d.ts","sourceRoot":"","sources":["../../src/middleware/cors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9C,MAAM,WAAW,WAAW;IAC1B,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,CAAC,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,KAAK,MAAM,GAAG,SAAS,CAAC,CAAC;IACvF,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AA4BD,wBAAgB,oBAAoB,CAAC,OAAO,GAAE,WAAgB,GAAG,UAAU,CA0D1E"}
1
+ {"version":3,"file":"cors.d.ts","sourceRoot":"","sources":["../../src/middleware/cors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9C;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,CAAC,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,KAAK,MAAM,GAAG,SAAS,CAAC,CAAC;IACvF,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AA4BD;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,GAAE,WAAgB,GAAG,UAAU,CA0D1E"}
@@ -1,3 +1,7 @@
1
+ /**
2
+ * Describes the cors options contract.
3
+ */
4
+
1
5
  function resolveOrigin(options, requestOrigin) {
2
6
  if (typeof options.allowOrigin === 'function') {
3
7
  return options.allowOrigin(requestOrigin);
@@ -15,6 +19,13 @@ function setHeaderIfValue(response, name, value) {
15
19
  response.setHeader(name, value);
16
20
  }
17
21
  }
22
+
23
+ /**
24
+ * Create cors middleware.
25
+ *
26
+ * @param options The options.
27
+ * @returns The create cors middleware result.
28
+ */
18
29
  export function createCorsMiddleware(options = {}) {
19
30
  if (options.allowCredentials === true) {
20
31
  if (options.allowOrigin === '*' || options.allowOrigin === undefined) {
@@ -1,8 +1,42 @@
1
1
  import type { Constructor } from '@fluojs/core';
2
2
  import type { Middleware, MiddlewareContext, MiddlewareLike, MiddlewareRouteConfig, Next } from '../types.js';
3
+ /**
4
+ * Is middleware route config.
5
+ *
6
+ * @param value The value.
7
+ * @returns The is middleware route config result.
8
+ */
3
9
  export declare function isMiddlewareRouteConfig(value: MiddlewareLike): value is MiddlewareRouteConfig;
10
+ /**
11
+ * Normalize route pattern.
12
+ *
13
+ * @param path The path.
14
+ * @returns The normalize route pattern result.
15
+ */
4
16
  export declare function normalizeRoutePattern(path: string): string;
17
+ /**
18
+ * Match route pattern.
19
+ *
20
+ * @param pattern The pattern.
21
+ * @param path The path.
22
+ * @returns The match route pattern result.
23
+ */
5
24
  export declare function matchRoutePattern(pattern: string, path: string): boolean;
25
+ /**
26
+ * For routes.
27
+ *
28
+ * @param middlewareClass The middleware class.
29
+ * @param routes The routes.
30
+ * @returns The for routes result.
31
+ */
6
32
  export declare function forRoutes<T extends Constructor<Middleware>>(middlewareClass: T, ...routes: string[]): MiddlewareRouteConfig;
33
+ /**
34
+ * Run middleware chain.
35
+ *
36
+ * @param definitions The definitions.
37
+ * @param context The context.
38
+ * @param terminal The terminal.
39
+ * @returns The run middleware chain result.
40
+ */
7
41
  export declare function runMiddlewareChain(definitions: MiddlewareLike[], context: MiddlewareContext, terminal: Next): Promise<void>;
8
42
  //# sourceMappingURL=middleware.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../../src/middleware/middleware.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAS,MAAM,cAAc,CAAC;AAGvD,OAAO,KAAK,EAAE,UAAU,EAAE,iBAAiB,EAAE,cAAc,EAAE,qBAAqB,EAAE,IAAI,EAAkB,MAAM,aAAa,CAAC;AAM9H,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,cAAc,GAAG,KAAK,IAAI,qBAAqB,CAE7F;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAM1D;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAUxE;AAED,wBAAgB,SAAS,CAAC,CAAC,SAAS,WAAW,CAAC,UAAU,CAAC,EACzD,eAAe,EAAE,CAAC,EAClB,GAAG,MAAM,EAAE,MAAM,EAAE,GAClB,qBAAqB,CAEvB;AA2CD,wBAAsB,kBAAkB,CACtC,WAAW,EAAE,cAAc,EAAE,EAC7B,OAAO,EAAE,iBAAiB,EAC1B,QAAQ,EAAE,IAAI,GACb,OAAO,CAAC,IAAI,CAAC,CAUf"}
1
+ {"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../../src/middleware/middleware.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAS,MAAM,cAAc,CAAC;AAGvD,OAAO,KAAK,EAAE,UAAU,EAAE,iBAAiB,EAAE,cAAc,EAAE,qBAAqB,EAAE,IAAI,EAAkB,MAAM,aAAa,CAAC;AAM9H;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,cAAc,GAAG,KAAK,IAAI,qBAAqB,CAE7F;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAM1D;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAUxE;AAED;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,CAAC,SAAS,WAAW,CAAC,UAAU,CAAC,EACzD,eAAe,EAAE,CAAC,EAClB,GAAG,MAAM,EAAE,MAAM,EAAE,GAClB,qBAAqB,CAEvB;AA2CD;;;;;;;GAOG;AACH,wBAAsB,kBAAkB,CACtC,WAAW,EAAE,cAAc,EAAE,EAC7B,OAAO,EAAE,iBAAiB,EAC1B,QAAQ,EAAE,IAAI,GACb,OAAO,CAAC,IAAI,CAAC,CAqBf"}
@@ -2,15 +2,37 @@ import { normalizeRoutePath } from '../route-path.js';
2
2
  function isMiddleware(value) {
3
3
  return typeof value === 'object' && value !== null && 'handle' in value;
4
4
  }
5
+
6
+ /**
7
+ * Is middleware route config.
8
+ *
9
+ * @param value The value.
10
+ * @returns The is middleware route config result.
11
+ */
5
12
  export function isMiddlewareRouteConfig(value) {
6
13
  return typeof value === 'object' && value !== null && 'middleware' in value && 'routes' in value;
7
14
  }
15
+
16
+ /**
17
+ * Normalize route pattern.
18
+ *
19
+ * @param path The path.
20
+ * @returns The normalize route pattern result.
21
+ */
8
22
  export function normalizeRoutePattern(path) {
9
23
  if (path.endsWith('/*')) {
10
24
  return `${normalizeRoutePattern(path.slice(0, -2))}/*`;
11
25
  }
12
26
  return normalizeRoutePath(path);
13
27
  }
28
+
29
+ /**
30
+ * Match route pattern.
31
+ *
32
+ * @param pattern The pattern.
33
+ * @param path The path.
34
+ * @returns The match route pattern result.
35
+ */
14
36
  export function matchRoutePattern(pattern, path) {
15
37
  const normalizedPath = normalizeRoutePattern(path);
16
38
  const normalizedPattern = normalizeRoutePattern(pattern);
@@ -20,6 +42,14 @@ export function matchRoutePattern(pattern, path) {
20
42
  }
21
43
  return normalizedPath === normalizedPattern;
22
44
  }
45
+
46
+ /**
47
+ * For routes.
48
+ *
49
+ * @param middlewareClass The middleware class.
50
+ * @param routes The routes.
51
+ * @returns The for routes result.
52
+ */
23
53
  export function forRoutes(middlewareClass, ...routes) {
24
54
  return {
25
55
  middleware: middlewareClass,
@@ -55,8 +85,25 @@ function deferNext(next) {
55
85
  await next();
56
86
  };
57
87
  }
88
+
89
+ /**
90
+ * Run middleware chain.
91
+ *
92
+ * @param definitions The definitions.
93
+ * @param context The context.
94
+ * @param terminal The terminal.
95
+ * @returns The run middleware chain result.
96
+ */
58
97
  export async function runMiddlewareChain(definitions, context, terminal) {
98
+ if (definitions.length === 0) {
99
+ await terminal();
100
+ return;
101
+ }
59
102
  const middlewareChain = await resolveActiveMiddlewareDefinitions(definitions, context);
103
+ if (middlewareChain.length === 0) {
104
+ await terminal();
105
+ return;
106
+ }
60
107
  const composed = middlewareChain.reduceRight((next, middleware) => deferNext(async () => {
61
108
  await middleware.handle(context, next);
62
109
  }), deferNext(terminal));
@@ -1,4 +1,7 @@
1
1
  import type { Middleware } from '../types.js';
2
+ /**
3
+ * Describes the security headers options contract.
4
+ */
2
5
  export interface SecurityHeadersOptions {
3
6
  contentSecurityPolicy?: string | false;
4
7
  crossOriginOpenerPolicy?: string | false;
@@ -8,5 +11,11 @@ export interface SecurityHeadersOptions {
8
11
  xFrameOptions?: string | false;
9
12
  xXssProtection?: string | false;
10
13
  }
14
+ /**
15
+ * Create security headers middleware.
16
+ *
17
+ * @param options The options.
18
+ * @returns The create security headers middleware result.
19
+ */
11
20
  export declare function createSecurityHeadersMiddleware(options?: SecurityHeadersOptions): Middleware;
12
21
  //# sourceMappingURL=security-headers.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"security-headers.d.ts","sourceRoot":"","sources":["../../src/middleware/security-headers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9C,MAAM,WAAW,sBAAsB;IACrC,qBAAqB,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IACvC,uBAAuB,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IACzC,cAAc,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IAChC,uBAAuB,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IACzC,mBAAmB,CAAC,EAAE,KAAK,CAAC;IAC5B,aAAa,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IAC/B,cAAc,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;CACjC;AAYD,wBAAgB,+BAA+B,CAAC,OAAO,GAAE,sBAA2B,GAAG,UAAU,CA6ChG"}
1
+ {"version":3,"file":"security-headers.d.ts","sourceRoot":"","sources":["../../src/middleware/security-headers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9C;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,qBAAqB,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IACvC,uBAAuB,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IACzC,cAAc,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IAChC,uBAAuB,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IACzC,mBAAmB,CAAC,EAAE,KAAK,CAAC;IAC5B,aAAa,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IAC/B,cAAc,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;CACjC;AAYD;;;;;GAKG;AACH,wBAAgB,+BAA+B,CAAC,OAAO,GAAE,sBAA2B,GAAG,UAAU,CA6ChG"}
@@ -1,3 +1,7 @@
1
+ /**
2
+ * Describes the security headers options contract.
3
+ */
4
+
1
5
  const DEFAULTS = {
2
6
  contentSecurityPolicy: "default-src 'self'",
3
7
  crossOriginOpenerPolicy: 'same-origin',
@@ -7,6 +11,13 @@ const DEFAULTS = {
7
11
  xFrameOptions: 'SAMEORIGIN',
8
12
  xXssProtection: '0'
9
13
  };
14
+
15
+ /**
16
+ * Create security headers middleware.
17
+ *
18
+ * @param options The options.
19
+ * @returns The create security headers middleware result.
20
+ */
10
21
  export function createSecurityHeadersMiddleware(options = {}) {
11
22
  const csp = 'contentSecurityPolicy' in options ? options.contentSecurityPolicy : DEFAULTS.contentSecurityPolicy;
12
23
  const coop = 'crossOriginOpenerPolicy' in options ? options.crossOriginOpenerPolicy : DEFAULTS.crossOriginOpenerPolicy;
@@ -1,15 +1,56 @@
1
+ /**
2
+ * Describes the route path literal segment contract.
3
+ */
1
4
  export interface RoutePathLiteralSegment {
2
5
  kind: 'literal';
3
6
  value: string;
4
7
  }
8
+ /**
9
+ * Describes the route path param segment contract.
10
+ */
5
11
  export interface RoutePathParamSegment {
6
12
  kind: 'param';
7
13
  name: string;
8
14
  }
15
+ /**
16
+ * Defines the route path segment type.
17
+ */
9
18
  export type RoutePathSegment = RoutePathLiteralSegment | RoutePathParamSegment;
19
+ /**
20
+ * Normalize route path.
21
+ *
22
+ * @param path The path.
23
+ * @returns The normalize route path result.
24
+ */
10
25
  export declare function normalizeRoutePath(path: string): string;
26
+ /**
27
+ * Parse route path.
28
+ *
29
+ * @param path The path.
30
+ * @param label The label.
31
+ * @returns The parse route path result.
32
+ */
11
33
  export declare function parseRoutePath(path: string, label?: string): RoutePathSegment[];
34
+ /**
35
+ * Validate route path.
36
+ *
37
+ * @param path The path.
38
+ * @param label The label.
39
+ */
12
40
  export declare function validateRoutePath(path: string, label?: string): void;
41
+ /**
42
+ * Extract route path params.
43
+ *
44
+ * @param path The path.
45
+ * @returns The extract route path params result.
46
+ */
13
47
  export declare function extractRoutePathParams(path: string): string[];
48
+ /**
49
+ * Match route path.
50
+ *
51
+ * @param registeredSegments The registered segments.
52
+ * @param incomingSegments The incoming segments.
53
+ * @returns The match route path result.
54
+ */
14
55
  export declare function matchRoutePath(registeredSegments: readonly RoutePathSegment[], incomingSegments: readonly string[]): Readonly<Record<string, string>> | undefined;
15
56
  //# sourceMappingURL=route-path.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"route-path.d.ts","sourceRoot":"","sources":["../src/route-path.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,SAAS,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,OAAO,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,MAAM,gBAAgB,GAAG,uBAAuB,GAAG,qBAAqB,CAAC;AAsD/E,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAKvD;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,gBAAgB,EAAE,CAK/E;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAEpE;AAED,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAE7D;AAED,wBAAgB,cAAc,CAC5B,kBAAkB,EAAE,SAAS,gBAAgB,EAAE,EAC/C,gBAAgB,EAAE,SAAS,MAAM,EAAE,GAClC,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GAAG,SAAS,CAqB9C"}
1
+ {"version":3,"file":"route-path.d.ts","sourceRoot":"","sources":["../src/route-path.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,SAAS,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,OAAO,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG,uBAAuB,GAAG,qBAAqB,CAAC;AAsD/E;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAKvD;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,gBAAgB,EAAE,CAK/E;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAEpE;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAE7D;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAC5B,kBAAkB,EAAE,SAAS,gBAAgB,EAAE,EAC/C,gBAAgB,EAAE,SAAS,MAAM,EAAE,GAClC,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GAAG,SAAS,CAqB9C"}
@@ -1,4 +1,17 @@
1
1
  import { InvalidRoutePathError } from './errors.js';
2
+
3
+ /**
4
+ * Describes the route path literal segment contract.
5
+ */
6
+
7
+ /**
8
+ * Describes the route path param segment contract.
9
+ */
10
+
11
+ /**
12
+ * Defines the route path segment type.
13
+ */
14
+
2
15
  const routeParamNamePattern = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
3
16
  const unsupportedLiteralTokenPattern = /[*?+()[\]{}\\]/;
4
17
  const supportedRouteSyntaxDescription = 'Only literal segments and full-segment ":param" placeholders are supported.';
@@ -34,22 +47,59 @@ function parseRoutePathSegment(segment, path, label) {
34
47
  value: segment
35
48
  };
36
49
  }
50
+
51
+ /**
52
+ * Normalize route path.
53
+ *
54
+ * @param path The path.
55
+ * @returns The normalize route path result.
56
+ */
37
57
  export function normalizeRoutePath(path) {
38
58
  const segments = path.split('/').filter(Boolean);
39
59
  const normalized = `/${segments.join('/')}`;
40
60
  return normalized === '' ? '/' : normalized;
41
61
  }
62
+
63
+ /**
64
+ * Parse route path.
65
+ *
66
+ * @param path The path.
67
+ * @param label The label.
68
+ * @returns The parse route path result.
69
+ */
42
70
  export function parseRoutePath(path, label) {
43
71
  const normalizedPath = normalizeRoutePath(path);
44
72
  const segments = normalizedPath.split('/').filter(Boolean);
45
73
  return segments.map(segment => parseRoutePathSegment(segment, path, label));
46
74
  }
75
+
76
+ /**
77
+ * Validate route path.
78
+ *
79
+ * @param path The path.
80
+ * @param label The label.
81
+ */
47
82
  export function validateRoutePath(path, label) {
48
83
  void parseRoutePath(path, label);
49
84
  }
85
+
86
+ /**
87
+ * Extract route path params.
88
+ *
89
+ * @param path The path.
90
+ * @returns The extract route path params result.
91
+ */
50
92
  export function extractRoutePathParams(path) {
51
93
  return parseRoutePath(path).flatMap(segment => segment.kind === 'param' ? [segment.name] : []);
52
94
  }
95
+
96
+ /**
97
+ * Match route path.
98
+ *
99
+ * @param registeredSegments The registered segments.
100
+ * @param incomingSegments The incoming segments.
101
+ * @returns The match route path result.
102
+ */
53
103
  export function matchRoutePath(registeredSegments, incomingSegments) {
54
104
  if (registeredSegments.length !== incomingSegments.length) {
55
105
  return undefined;
package/dist/types.d.ts CHANGED
@@ -182,6 +182,11 @@ export type VersioningOptions = {
182
182
  /** Runtime dispatcher that executes the full HTTP request lifecycle. */
183
183
  export interface Dispatcher {
184
184
  dispatch(request: FrameworkRequest, response: FrameworkResponse): Promise<void>;
185
+ /**
186
+ * Returns the mapped route descriptors known to this dispatcher when the
187
+ * implementation can expose them without changing dispatch behavior.
188
+ */
189
+ describeRoutes?(): readonly HandlerDescriptor[];
185
190
  }
186
191
  /** Logger seam used by the dispatcher for non-fatal internal failure reporting. */
187
192
  export interface DispatcherLogger {