@loutrejs/loutre 0.9.2 → 0.10.1

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 (145) hide show
  1. package/dist/adapters/aws-lambda.d.ts +1 -1
  2. package/dist/adapters/aws-lambda.js +8 -2
  3. package/dist/adapters/bun.d.ts +3 -2
  4. package/dist/adapters/bun.js +12 -6
  5. package/dist/adapters/cloudflare-workers.d.ts +1 -1
  6. package/dist/adapters/cloudflare-workers.js +2 -1
  7. package/dist/adapters/electron.d.ts +1 -1
  8. package/dist/adapters/electron.js +8 -51
  9. package/dist/adapters/server-transports.js +2 -2
  10. package/dist/adapters/websocket-native.js +4 -1
  11. package/dist/application/definition.d.ts +4 -7
  12. package/dist/application/definition.js +3 -1
  13. package/dist/application/kernel.d.ts +0 -2
  14. package/dist/application/kernel.js +1 -3
  15. package/dist/core/args.d.ts +1 -0
  16. package/dist/core/args.js +2 -1
  17. package/dist/core/env.d.ts +1 -0
  18. package/dist/core/env.js +2 -1
  19. package/dist/core/extension.d.ts +23 -13
  20. package/dist/core/extension.js +3 -1
  21. package/dist/core/generic-layer.d.ts +9 -2
  22. package/dist/core/generic-layer.js +2 -1
  23. package/dist/core/identity.d.ts +18 -0
  24. package/dist/core/identity.js +5 -0
  25. package/dist/core/index.d.ts +13 -5
  26. package/dist/core/index.js +7 -1
  27. package/dist/core/injection.d.ts +2 -1
  28. package/dist/core/instrumentation.d.ts +7 -5
  29. package/dist/core/lifecycle.d.ts +4 -0
  30. package/dist/core/logger-identity.d.ts +4 -0
  31. package/dist/core/logger-identity.js +9 -0
  32. package/dist/core/logger-internal.d.ts +5 -0
  33. package/dist/core/logger-internal.js +27 -0
  34. package/dist/core/logger-module.d.ts +5 -0
  35. package/dist/core/logger-module.js +8 -0
  36. package/dist/core/logger.d.ts +42 -0
  37. package/dist/core/logger.js +221 -0
  38. package/dist/core/model/context.d.ts +6 -3
  39. package/dist/core/model/context.js +17 -17
  40. package/dist/core/model/identity.d.ts +19 -0
  41. package/dist/core/model/identity.js +8 -0
  42. package/dist/core/model/lifecycle.d.ts +3 -2
  43. package/dist/core/model/lifecycle.js +7 -3
  44. package/dist/core/model/logger.d.ts +3 -0
  45. package/dist/core/model/logger.js +59 -0
  46. package/dist/core/model/modules.d.ts +4 -1
  47. package/dist/core/model/modules.js +6 -4
  48. package/dist/core/model/providers.d.ts +1 -1
  49. package/dist/core/model/providers.js +8 -8
  50. package/dist/core/model/types.d.ts +25 -18
  51. package/dist/core/model/validation.js +3 -2
  52. package/dist/core/model/visibility.js +7 -2
  53. package/dist/core/model.js +15 -7
  54. package/dist/core/module.d.ts +7 -7
  55. package/dist/core/module.js +0 -3
  56. package/dist/core/runtime-input.d.ts +2 -1
  57. package/dist/core/source-location.d.ts +14 -2
  58. package/dist/core/source-location.js +8 -3
  59. package/dist/core/token-internal.js +3 -1
  60. package/dist/core/token.d.ts +4 -2
  61. package/dist/core/token.js +3 -0
  62. package/dist/core/units.d.ts +22 -0
  63. package/dist/core/units.js +14 -0
  64. package/dist/devtools/capsule.d.ts +17 -13
  65. package/dist/devtools/capsule.js +14 -10
  66. package/dist/devtools/decoder.d.ts +15 -0
  67. package/dist/devtools/decoder.js +179 -0
  68. package/dist/devtools/identity-internal.d.ts +6 -0
  69. package/dist/devtools/identity-internal.js +5 -0
  70. package/dist/devtools/identity.d.ts +21 -0
  71. package/dist/devtools/identity.js +7 -0
  72. package/dist/devtools/index.d.ts +3 -0
  73. package/dist/devtools/index.js +2 -0
  74. package/dist/devtools/inspector.d.ts +18 -16
  75. package/dist/devtools/observer.d.ts +32 -28
  76. package/dist/devtools/runtime.js +34 -30
  77. package/dist/devtools/values.js +3 -5
  78. package/dist/generated/version.d.ts +1 -1
  79. package/dist/generated/version.js +1 -1
  80. package/dist/graph/model.d.ts +25 -14
  81. package/dist/http/auth.d.ts +4 -2
  82. package/dist/http/client.d.ts +6 -3
  83. package/dist/http/client.js +8 -9
  84. package/dist/http/cors-internal.d.ts +7 -5
  85. package/dist/http/cors-internal.js +8 -6
  86. package/dist/http/extension.d.ts +60 -21
  87. package/dist/http/extension.js +91 -20
  88. package/dist/http/identity.d.ts +20 -0
  89. package/dist/http/identity.js +10 -0
  90. package/dist/http/index.d.ts +6 -2
  91. package/dist/http/index.js +3 -1
  92. package/dist/http/openapi-identity.d.ts +9 -0
  93. package/dist/http/openapi-identity.js +4 -0
  94. package/dist/http/openapi.d.ts +1 -1
  95. package/dist/http/openapi.js +10 -7
  96. package/dist/http/path.d.ts +8 -5
  97. package/dist/http/route-validation.js +2 -1
  98. package/dist/http/runtime/request.d.ts +3 -2
  99. package/dist/http/runtime/request.js +1 -4
  100. package/dist/http/websocket-upgrade.d.ts +2 -0
  101. package/dist/http/websocket-upgrade.js +4 -0
  102. package/dist/internal/brand.d.ts +8 -0
  103. package/dist/internal/brand.js +1 -0
  104. package/dist/message-port/extension.d.ts +4 -2
  105. package/dist/message-port/extension.js +15 -8
  106. package/dist/message-port/identity.d.ts +9 -0
  107. package/dist/message-port/identity.js +16 -0
  108. package/dist/message-port/index.d.ts +2 -0
  109. package/dist/message-port/index.js +1 -0
  110. package/dist/message-port/transport.d.ts +4 -2
  111. package/dist/message-port/transport.js +6 -1
  112. package/dist/runtime/async-iterator-lifecycle.d.ts +2 -1
  113. package/dist/runtime/async-iterator-lifecycle.js +2 -1
  114. package/dist/runtime/capability.d.ts +6 -2
  115. package/dist/runtime/capability.js +3 -1
  116. package/dist/runtime/di.d.ts +1 -3
  117. package/dist/runtime/di.js +62 -35
  118. package/dist/runtime/error.d.ts +3 -1
  119. package/dist/runtime/index.d.ts +6 -2
  120. package/dist/runtime/index.js +3 -1
  121. package/dist/runtime/kernel.d.ts +0 -2
  122. package/dist/runtime/kernel.js +68 -30
  123. package/dist/runtime/logger-source.d.ts +4 -0
  124. package/dist/runtime/logger-source.js +47 -0
  125. package/dist/runtime/logger.d.ts +2 -38
  126. package/dist/runtime/logger.js +1 -209
  127. package/dist/runtime/node-capabilities.d.ts +1 -1
  128. package/dist/runtime/node-capabilities.js +2 -1
  129. package/dist/runtime/server-port.d.ts +5 -1
  130. package/dist/runtime/server-port.js +2 -1
  131. package/dist/runtime/shutdown-hooks.d.ts +1 -1
  132. package/dist/runtime/shutdown-hooks.js +5 -4
  133. package/dist/tasks/extension.d.ts +18 -16
  134. package/dist/tasks/extension.js +28 -23
  135. package/dist/tasks/identity.d.ts +9 -0
  136. package/dist/tasks/identity.js +4 -0
  137. package/dist/tasks/index.d.ts +1 -0
  138. package/dist/tasks/runtime/cron.d.ts +6 -2
  139. package/dist/tasks/runtime/cron.js +9 -0
  140. package/dist/websocket/extension.d.ts +19 -9
  141. package/dist/websocket/extension.js +103 -30
  142. package/dist/websocket/identity.d.ts +9 -0
  143. package/dist/websocket/identity.js +4 -0
  144. package/dist/websocket/index.d.ts +1 -0
  145. package/package.json +1 -1
@@ -1,34 +1,45 @@
1
+ import type { CapabilityId, ExtensionName } from '../core/identity.js';
2
+ import type { ModuleId } from '../core/model/identity.js';
1
3
  import { type ApplicationModel, type ApplicationModelEdge, type ApplicationModelNode, type Diagnostic, type SourceLocation } from '../core/index.js';
2
4
  export type JsonPrimitive = string | number | boolean | null;
3
5
  export type JsonValue = JsonPrimitive | {
4
6
  readonly [key: string]: JsonValue;
5
7
  } | readonly JsonValue[];
6
- export interface GraphNodeIR {
7
- readonly id: string;
8
- readonly kind: ApplicationModelNode['kind'];
8
+ interface GraphNodeBase {
9
9
  readonly name?: string;
10
- readonly module?: string;
10
+ readonly module?: ModuleId | 'application';
11
11
  readonly executionKind?: string;
12
- readonly capabilities?: readonly string[];
12
+ readonly capabilities?: readonly CapabilityId[];
13
13
  readonly extension?: {
14
- readonly name: string;
14
+ readonly name: ExtensionName;
15
15
  readonly hostNamespace?: string;
16
16
  readonly metadata?: JsonValue;
17
17
  };
18
18
  readonly attributes?: Readonly<Record<string, JsonValue>>;
19
19
  readonly source?: SourceLocation;
20
20
  }
21
- export interface GraphEdgeIR {
22
- readonly from: string;
23
- readonly to: string;
24
- readonly kind: ApplicationModelEdge['kind'];
25
- }
21
+ export type GraphNodeIR = {
22
+ [Kind in ApplicationModelNode['kind']]: GraphNodeBase & {
23
+ readonly kind: Kind;
24
+ readonly id: Extract<ApplicationModelNode, {
25
+ readonly kind: Kind;
26
+ }>['id'];
27
+ };
28
+ }[ApplicationModelNode['kind']];
29
+ export type GraphEdgeIR = ApplicationModelEdge;
26
30
  export interface ApplicationModelGraphIR {
27
31
  readonly nodes: readonly GraphNodeIR[];
28
32
  readonly edges: readonly GraphEdgeIR[];
29
33
  readonly diagnostics: readonly Diagnostic[];
30
- readonly modules: readonly GraphNodeIR[];
31
- readonly providers: readonly GraphNodeIR[];
32
- readonly executions: readonly GraphNodeIR[];
34
+ readonly modules: readonly Extract<GraphNodeIR, {
35
+ kind: 'module';
36
+ }>[];
37
+ readonly providers: readonly Extract<GraphNodeIR, {
38
+ kind: 'provider';
39
+ }>[];
40
+ readonly executions: readonly Extract<GraphNodeIR, {
41
+ kind: 'execution';
42
+ }>[];
33
43
  }
34
44
  export declare function projectApplicationModel(model: ApplicationModel): ApplicationModelGraphIR;
45
+ export {};
@@ -1,5 +1,7 @@
1
+ import type { Brand, Descriptor } from '../internal/brand.js';
2
+ export type BearerCredential = Brand<string, 'http.bearer-credential'>;
1
3
  import type { HttpExecutionResult, HttpMiddleware, HttpMiddlewareContext } from './extension.js';
2
- export interface BasicAuthCredentials {
4
+ export interface BasicAuthCredentials extends Descriptor<'basic-auth-credentials'> {
3
5
  readonly username: string;
4
6
  readonly password: string;
5
7
  }
@@ -39,7 +41,7 @@ export interface BearerAuthDefinition<TContribution extends object, TResponse ex
39
41
  readonly factory: () => BearerAuthRuntime<TContribution, TResponse, TUnauthorizedBody>;
40
42
  }
41
43
  export interface BearerAuthRuntime<TContribution extends object, TResponse extends string, TUnauthorizedBody> {
42
- authenticate(token: string): TContribution | null | undefined | Promise<TContribution | null | undefined>;
44
+ authenticate(token: BearerCredential): TContribution | null | undefined | Promise<TContribution | null | undefined>;
43
45
  unauthorized(): HttpAuthenticationFailure<TResponse, TUnauthorizedBody> | Response;
44
46
  }
45
47
  export declare function bearerAuth<const TContribution extends object, const TResponse extends string, TUnauthorizedBody>(definition: BearerAuthDefinition<TContribution, TResponse, TUnauthorizedBody>): HttpMiddleware<TContribution, HttpMiddlewareContext, AuthenticationShortCircuit<TResponse, TUnauthorizedBody>>;
@@ -1,9 +1,10 @@
1
+ import { type RequestPathname, type HttpMethod } from './identity.js';
1
2
  import { type SchemaInput, type SchemaOutput, type StandardSchemaV1 } from '../core/index.js';
2
3
  import type { HttpContract, HttpExecutionResponseDefinition, HttpExecutionRouteDefinition, HttpHeaders } from './extension.js';
3
4
  import { type PathParamNames } from './path.js';
4
5
  export interface HttpClientTransportRequest {
5
- readonly method: string;
6
- readonly path: string;
6
+ readonly method: HttpMethod;
7
+ readonly path: RequestPathname;
7
8
  readonly query?: unknown;
8
9
  readonly headers?: unknown;
9
10
  readonly body?: unknown;
@@ -50,7 +51,9 @@ export type HttpClientResponse<TDefinition extends HttpExecutionRouteDefinition>
50
51
  }[keyof TDefinition['responses'] & string];
51
52
  type HttpClientMethod<TDefinition extends HttpExecutionRouteDefinition> = keyof HttpClientRequest<TDefinition> extends never ? () => Promise<HttpClientResponse<TDefinition>> : (request: HttpClientRequest<TDefinition>) => Promise<HttpClientResponse<TDefinition>>;
52
53
  export type HttpClient<TContract extends HttpContract> = {
53
- readonly [TName in keyof TContract['routes']]: HttpClientMethod<TContract['routes'][TName]>;
54
+ readonly [TName in keyof TContract['routes'] as TContract['routes'][TName] extends {
55
+ readonly raw: true;
56
+ } ? never : TName]: HttpClientMethod<Extract<TContract['routes'][TName], HttpExecutionRouteDefinition>>;
54
57
  };
55
58
  export declare class HttpClientResponseError extends Error {
56
59
  readonly status: number;
@@ -1,3 +1,4 @@
1
+ import { normalizeMediaType, normalizeHttpMethod, httpBaseUrl, requestPathname, } from './identity.js';
1
2
  import { SchemaValidationError, validateSchema, } from '../core/index.js';
2
3
  import { parseHttpPath } from './path.js';
3
4
  import { match } from 'ts-pattern';
@@ -18,9 +19,11 @@ export class HttpClientResponseError extends Error {
18
19
  export function createHttpClient(contract, transport) {
19
20
  const client = {};
20
21
  for (const [procedureName, definition] of Object.entries(contract.routes)) {
22
+ if (definition.raw === true)
23
+ continue;
21
24
  client[procedureName] = async (request = {}) => {
22
25
  const response = await transport({
23
- method: definition.method,
26
+ method: normalizeHttpMethod(definition.method),
24
27
  path: interpolatePath(definition.path, request.params),
25
28
  ...(request.query === undefined ? {} : { query: request.query }),
26
29
  ...(request.headers === undefined ? {} : { headers: request.headers }),
@@ -34,8 +37,8 @@ export function createHttpClient(contract, transport) {
34
37
  function interpolatePath(path, params) {
35
38
  const segments = parseHttpPath(path);
36
39
  if (segments.length === 0)
37
- return '/';
38
- return `/${segments
40
+ return requestPathname('/');
41
+ return requestPathname(`/${segments
39
42
  .map((segment) => {
40
43
  if (segment.kind === 'static')
41
44
  return segment.value;
@@ -45,7 +48,7 @@ function interpolatePath(path, params) {
45
48
  }
46
49
  return encodeURIComponent(String(value));
47
50
  })
48
- .join('/')}`;
51
+ .join('/')}`);
49
52
  }
50
53
  async function decodeResponse(procedure, definition, response) {
51
54
  const target = describeHttpTarget(definition, procedure);
@@ -128,7 +131,7 @@ function isAsyncIterable(value) {
128
131
  export function fetchHttpTransport(options) {
129
132
  const fetchImplementation = options.fetch ?? globalThis.fetch;
130
133
  return async (request) => {
131
- const url = new URL(request.path, options.baseUrl);
134
+ const url = new URL(request.path, httpBaseUrl(options.baseUrl));
132
135
  appendQuery(url.searchParams, request.query);
133
136
  const headers = new Headers(options.headers);
134
137
  appendHeaders(headers, request.headers);
@@ -223,10 +226,6 @@ async function decodeFetchBody(response) {
223
226
  }
224
227
  return response.text();
225
228
  }
226
- function normalizeMediaType(value) {
227
- const mediaType = value?.split(';', 1)[0]?.trim().toLowerCase();
228
- return mediaType || undefined;
229
- }
230
229
  async function* decodeServerSentEvents(stream) {
231
230
  const reader = stream.getReader();
232
231
  const decoder = new TextDecoder();
@@ -1,3 +1,5 @@
1
+ import { type HttpMethod, type HttpHeaderName, type CorsOriginValue } from './identity.js';
2
+ import { type DurationSeconds } from '../core/units.js';
1
3
  export type CorsOrigin = string | readonly string[] | ((origin: string) => boolean | Promise<boolean>);
2
4
  export interface CorsPolicyOptions {
3
5
  readonly origin?: CorsOrigin;
@@ -12,16 +14,16 @@ export type CorsPolicy = Readonly<{
12
14
  readonly kind: 'wildcard';
13
15
  } | {
14
16
  readonly kind: 'exact';
15
- readonly origins: ReadonlySet<string>;
17
+ readonly origins: ReadonlySet<CorsOriginValue>;
16
18
  } | {
17
19
  readonly kind: 'predicate';
18
20
  readonly predicate: (origin: string) => boolean | Promise<boolean>;
19
21
  };
20
- allowMethods: readonly string[] | undefined;
21
- allowHeaders: readonly string[] | undefined;
22
- exposeHeaders: readonly string[];
22
+ allowMethods: readonly HttpMethod[] | undefined;
23
+ allowHeaders: readonly HttpHeaderName[] | undefined;
24
+ exposeHeaders: readonly HttpHeaderName[];
23
25
  credentials: boolean;
24
- maxAge: number | undefined;
26
+ maxAge: DurationSeconds | undefined;
25
27
  }>;
26
28
  export declare function normalizeCorsPolicy(options: CorsPolicyOptions): CorsPolicy;
27
29
  export declare function registerCorsPolicy(middleware: object, policy: CorsPolicy): void;
@@ -1,3 +1,5 @@
1
+ import { normalizeHttpMethod, httpHeaderName, corsOriginValue, } from './identity.js';
2
+ import { seconds } from '../core/units.js';
1
3
  const policies = new WeakMap();
2
4
  const httpToken = /^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/;
3
5
  export function normalizeCorsPolicy(options) {
@@ -6,11 +8,11 @@ export function normalizeCorsPolicy(options) {
6
8
  origin: normalizeOrigin(options.origin ?? '*', credentials),
7
9
  allowMethods: options.allowMethods === undefined
8
10
  ? undefined
9
- : normalizeTokens(options.allowMethods, 'allowMethods', true),
11
+ : normalizeTokens(options.allowMethods, 'allowMethods', true).map(normalizeHttpMethod),
10
12
  allowHeaders: options.allowHeaders === undefined
11
13
  ? undefined
12
- : normalizeTokens(options.allowHeaders, 'allowHeaders', false),
13
- exposeHeaders: normalizeTokens(options.exposeHeaders ?? [], 'exposeHeaders', false),
14
+ : normalizeTokens(options.allowHeaders, 'allowHeaders', false).map(httpHeaderName),
15
+ exposeHeaders: normalizeTokens(options.exposeHeaders ?? [], 'exposeHeaders', false).map(httpHeaderName),
14
16
  credentials,
15
17
  maxAge: normalizeMaxAge(options.maxAge),
16
18
  });
@@ -89,7 +91,7 @@ async function applyOrigin(headers, policy, origin) {
89
91
  }
90
92
  appendVary(headers, 'Origin');
91
93
  const allowed = policy.origin.kind === 'exact'
92
- ? policy.origin.origins.has(origin)
94
+ ? policy.origin.origins.has(corsOriginValue(origin))
93
95
  : await policy.origin.predicate(origin);
94
96
  if (allowed)
95
97
  headers.set('access-control-allow-origin', origin);
@@ -115,7 +117,7 @@ function normalizeOrigin(origin, credentials) {
115
117
  }
116
118
  return Object.freeze({
117
119
  kind: 'exact',
118
- origins: new Set(origins),
120
+ origins: new Set(origins.map(corsOriginValue)),
119
121
  });
120
122
  }
121
123
  function containsControlCharacter(value) {
@@ -141,7 +143,7 @@ function normalizeMaxAge(maxAge) {
141
143
  if (!Number.isSafeInteger(maxAge) || maxAge < 0) {
142
144
  throw new TypeError('CORS maxAge must be a non-negative safe integer');
143
145
  }
144
- return maxAge;
146
+ return seconds(maxAge);
145
147
  }
146
148
  function appendVary(headers, value) {
147
149
  const current = headers.get('vary');
@@ -1,6 +1,10 @@
1
- import { type ExecutionDefinition, type ExecutionContextView, type ExecutionExtension, type ExecutionExtensionDrainContext, type GenericLayer, type RuntimeCapabilityBinding, type SchemaInput, type SchemaOutput, type StandardSchemaV1, type SourceLocation, type Type } from '../core/index.js';
2
- import { type HttpPathSegment, type PathParamNames } from './path.js';
1
+ import type { Descriptor } from '../internal/brand.js';
2
+ import { type HttpMethod, type HttpPathTemplate, type HttpDispatchKey, type HttpProcedureName, type HttpResponseStatus } from './identity.js';
3
+ import type { ParsedHttpPath } from './path.js';
4
+ import { type LayerState, type ExecutionDefinition, type ExecutionContextView, type ExecutionExtension, type ExecutionExtensionDrainContext, type GenericLayer, type RuntimeCapabilityBinding, type SchemaInput, type SchemaOutput, type StandardSchemaV1, type SourceLocation, type Type } from '../core/index.js';
5
+ import { type PathParamNames } from './path.js';
3
6
  import type { HttpRequestHeadDefinition } from './request-head.js';
7
+ import { isWebSocketUpgrade } from './websocket-upgrade.js';
4
8
  export interface HttpServerDriver {
5
9
  readonly runtime: string;
6
10
  }
@@ -43,6 +47,7 @@ export interface HttpValidationMiddleware<TPart extends HttpValidationPart = Htt
43
47
  readonly part: TPart;
44
48
  }
45
49
  export interface HttpExecutionRouteDefinition {
50
+ readonly raw?: false;
46
51
  readonly method: string;
47
52
  readonly path: string;
48
53
  readonly summary?: string;
@@ -63,7 +68,21 @@ export interface HttpContractBranchDefinition {
63
68
  readonly middlewares?: readonly AnyHttpMiddleware[];
64
69
  readonly routes: HttpContractRouteTree;
65
70
  }
66
- export type HttpContractNodeDefinition = HttpExecutionRouteDefinition | HttpContractBranchDefinition;
71
+ export type HttpContractNodeDefinition = HttpExecutionRouteDefinition | HttpContractRawRouteDefinition | HttpContractBranchDefinition;
72
+ export type HttpContractRouteDefinition = HttpExecutionRouteDefinition | HttpContractRawRouteDefinition;
73
+ export interface HttpContractRawRouteDefinition {
74
+ readonly raw: true;
75
+ readonly method: string;
76
+ readonly path: string;
77
+ readonly middlewares?: readonly AnyHttpMiddleware[];
78
+ readonly request?: never;
79
+ readonly responses?: never;
80
+ }
81
+ declare const httpContractRawRouteBrand: unique symbol;
82
+ export interface HttpContractRawRoute extends HttpContractRawRouteDefinition {
83
+ readonly [httpContractRawRouteBrand]: true;
84
+ }
85
+ export declare function isHttpRawContractRoute(value: unknown): value is HttpContractRawRoute;
67
86
  export type HttpContractRouteTree = Readonly<Record<string, HttpContractNodeDefinition>>;
68
87
  declare const httpMiddlewareShortCircuit: unique symbol;
69
88
  export type HttpMiddleware<TContribution extends object = object, TContext extends object = HttpMiddlewareContext, TShortCircuit extends HttpExecutionResult = never> = GenericLayer<TContext, TContribution, HttpMiddlewareOutcome> & {
@@ -91,10 +110,11 @@ type BranchResponses<TBranch extends HttpContractBranchDefinition> = TBranch ext
91
110
  type BranchMiddlewares<TBranch extends HttpContractBranchDefinition> = TBranch extends {
92
111
  readonly middlewares: infer TMiddlewares extends readonly AnyHttpMiddleware[];
93
112
  } ? TMiddlewares : readonly [];
94
- type ResolveHttpRoute<TRoute extends HttpExecutionRouteDefinition, TPathPrefix extends string, TResponses extends Readonly<Record<string, HttpExecutionResponseDefinition>>, TMiddlewares extends readonly HttpRouteMiddleware[]> = Omit<TRoute, 'path' | 'responses' | 'middlewares'> & {
113
+ type ResolveHttpRoute<TRoute extends HttpContractRouteDefinition, TPathPrefix extends string, TResponses extends Readonly<Record<string, HttpExecutionResponseDefinition>>, TMiddlewares extends readonly HttpRouteMiddleware[]> = Omit<TRoute, 'path' | 'responses' | 'middlewares'> & {
95
114
  readonly path: JoinHttpPath<TPathPrefix, TRoute['path']>;
115
+ } & (TRoute extends HttpContractRawRouteDefinition ? Omit<HttpContractRawRoute, keyof HttpContractRawRouteDefinition> : {
96
116
  readonly responses: TResponses & TRoute['responses'];
97
- } & (readonly [
117
+ }) & (readonly [
98
118
  ...TMiddlewares,
99
119
  ...(TRoute extends {
100
120
  readonly middlewares: infer TRouteMiddlewares extends readonly HttpRouteMiddleware[];
@@ -107,15 +127,15 @@ type ResolveHttpRoute<TRoute extends HttpExecutionRouteDefinition, TPathPrefix e
107
127
  } ? TRouteMiddlewares : readonly [])
108
128
  ];
109
129
  });
110
- type ResolveHttpNode<TName extends string, TNode extends HttpContractNodeDefinition, TPathPrefix extends string, TResponses extends Readonly<Record<string, HttpExecutionResponseDefinition>>, TMiddlewares extends readonly HttpRouteMiddleware[]> = TNode extends HttpExecutionRouteDefinition ? Readonly<Record<TName, ResolveHttpRoute<TNode, TPathPrefix, TResponses, TMiddlewares>>> : TNode extends HttpContractBranchDefinition ? ResolveHttpRouteTree<TNode['routes'], JoinHttpPath<TPathPrefix, BranchPath<TNode>>, TResponses & BranchResponses<TNode>, readonly [...TMiddlewares, ...BranchMiddlewares<TNode>]> : never;
130
+ type ResolveHttpNode<TName extends string, TNode extends HttpContractNodeDefinition, TPathPrefix extends string, TResponses extends Readonly<Record<string, HttpExecutionResponseDefinition>>, TMiddlewares extends readonly HttpRouteMiddleware[]> = TNode extends HttpContractRouteDefinition ? Readonly<Record<TName, ResolveHttpRoute<TNode, TPathPrefix, TResponses, TMiddlewares>>> : TNode extends HttpContractBranchDefinition ? ResolveHttpRouteTree<TNode['routes'], JoinHttpPath<TPathPrefix, BranchPath<TNode>>, TResponses & BranchResponses<TNode>, readonly [...TMiddlewares, ...BranchMiddlewares<TNode>]> : never;
111
131
  type ResolveHttpRouteTree<TTree extends HttpContractRouteTree, TPathPrefix extends string = '', TResponses extends Readonly<Record<string, HttpExecutionResponseDefinition>> = {}, TMiddlewares extends readonly HttpRouteMiddleware[] = readonly []> = UnionToIntersection<{
112
132
  [TName in keyof TTree & string]: ResolveHttpNode<TName, TTree[TName], TPathPrefix, TResponses, TMiddlewares>;
113
133
  }[keyof TTree & string]>;
114
134
  export type ResolvedHttpContractRoutes<TTree extends HttpContractRouteTree> = ResolveHttpRouteTree<TTree> extends infer TRoutes ? {
115
- readonly [TName in keyof TRoutes]: Extract<TRoutes[TName], HttpExecutionRouteDefinition>;
135
+ readonly [TName in keyof TRoutes]: Extract<TRoutes[TName], HttpContractRouteDefinition>;
116
136
  } : never;
117
137
  type HasResponseNameCollision<TLeft extends Readonly<Record<string, HttpExecutionResponseDefinition>>, TRight extends Readonly<Record<string, HttpExecutionResponseDefinition>>> = Extract<keyof TLeft, keyof TRight> extends never ? false : true;
118
- type IsHttpContractNodeInheritanceValid<TNode extends HttpContractNodeDefinition, TResponses extends Readonly<Record<string, HttpExecutionResponseDefinition>>> = TNode extends HttpExecutionRouteDefinition ? HasResponseNameCollision<TResponses, TNode['responses']> extends true ? false : true : TNode extends HttpContractBranchDefinition ? HasResponseNameCollision<TResponses, BranchResponses<TNode>> extends true ? false : IsHttpContractTreeInheritanceValid<TNode['routes'], TResponses & BranchResponses<TNode>> : false;
138
+ type IsHttpContractNodeInheritanceValid<TNode extends HttpContractNodeDefinition, TResponses extends Readonly<Record<string, HttpExecutionResponseDefinition>>> = TNode extends HttpContractRawRouteDefinition ? keyof TResponses extends never ? true : false : TNode extends HttpExecutionRouteDefinition ? HasResponseNameCollision<TResponses, TNode['responses']> extends true ? false : true : TNode extends HttpContractBranchDefinition ? HasResponseNameCollision<TResponses, BranchResponses<TNode>> extends true ? false : IsHttpContractTreeInheritanceValid<TNode['routes'], TResponses & BranchResponses<TNode>> : false;
119
139
  type IsHttpContractTreeInheritanceValid<TTree extends HttpContractRouteTree, TResponses extends Readonly<Record<string, HttpExecutionResponseDefinition>> = {}> = string extends keyof TTree ? true : false extends {
120
140
  [TName in keyof TTree]: IsHttpContractNodeInheritanceValid<TTree[TName], TResponses>;
121
141
  }[keyof TTree] ? false : true;
@@ -123,7 +143,7 @@ type HttpMiddlewareState<TRoute extends HttpExecutionRouteDefinition> = TRoute e
123
143
  readonly middlewares: infer TMiddlewares extends readonly HttpRouteMiddleware[];
124
144
  } ? UnionToIntersection<MiddlewareContribution<TMiddlewares[number]>> : {};
125
145
  declare const httpContractBrand: unique symbol;
126
- export interface HttpContract<TRoutes extends Readonly<Record<string, HttpExecutionRouteDefinition>> = Readonly<Record<string, HttpExecutionRouteDefinition>>> {
146
+ export interface HttpContract<TRoutes extends Readonly<Record<string, HttpContractRouteDefinition>> = Readonly<Record<string, HttpContractRouteDefinition>>> {
127
147
  readonly kind: 'http-contract';
128
148
  readonly routes: TRoutes;
129
149
  readonly [httpContractBrand]: true;
@@ -193,7 +213,7 @@ export type HttpExecutionContext<TRoute extends HttpExecutionRouteDefinition = H
193
213
  readonly state: Readonly<HttpMiddlewareState<TRoute>>;
194
214
  };
195
215
  export type HttpHandlers<TContract extends HttpContract> = {
196
- readonly [TName in keyof TContract['routes']]: (context: HttpExecutionContext<TContract['routes'][TName]>) => DeclaredHttpResults<TContract['routes'][TName]> | Promise<DeclaredHttpResults<TContract['routes'][TName]>>;
216
+ readonly [TName in keyof TContract['routes'] as TContract['routes'][TName] extends HttpContractRawRouteDefinition ? never : TName]: (context: HttpExecutionContext<Extract<TContract['routes'][TName], HttpExecutionRouteDefinition>>) => DeclaredHttpResults<Extract<TContract['routes'][TName], HttpExecutionRouteDefinition>> | Promise<DeclaredHttpResults<Extract<TContract['routes'][TName], HttpExecutionRouteDefinition>>>;
197
217
  };
198
218
  export interface HttpImplementationDefinition<TContract extends HttpContract = HttpContract> {
199
219
  readonly name: string;
@@ -212,7 +232,7 @@ export interface HttpRawExecutionContext<TState = Readonly<Record<string, unknow
212
232
  readonly state: Readonly<TState>;
213
233
  readonly execution: ExecutionContextView;
214
234
  }
215
- type RawMiddlewareState<TMiddlewares extends readonly AnyHttpMiddleware[]> = UnionToIntersection<MiddlewareContribution<TMiddlewares[number]>> & object;
235
+ type RawMiddlewareState<TMiddlewares extends readonly AnyHttpMiddleware[]> = LayerState<TMiddlewares>;
216
236
  export interface HttpRawDefinition<TMiddlewares extends readonly AnyHttpMiddleware[] = readonly AnyHttpMiddleware[]> {
217
237
  readonly name?: string;
218
238
  readonly route: HttpRawRouteDefinition & {
@@ -222,21 +242,35 @@ export interface HttpRawDefinition<TMiddlewares extends readonly AnyHttpMiddlewa
222
242
  }
223
243
  export type HttpRawExecutionDefinition = HttpRawDefinition & ExecutionDefinition<typeof httpExecutionExtension>;
224
244
  export declare function defineHttpRaw<const TMiddlewares extends readonly AnyHttpMiddleware[] = readonly []>(definition: HttpRawDefinition<TMiddlewares>): HttpRawDefinition<TMiddlewares> & ExecutionDefinition<typeof httpExecutionExtension>;
245
+ export type CompiledHttpResponseDefinition = HttpExecutionResponseDefinition & Descriptor<'http-response'> & {
246
+ readonly status: HttpResponseStatus;
247
+ };
248
+ type CompiledHttpRouteDefinition = Omit<HttpExecutionRouteDefinition, 'responses'> & {
249
+ readonly responses: Readonly<Record<string, CompiledHttpResponseDefinition>>;
250
+ };
225
251
  interface CompiledHttpRoute {
226
- readonly name: string;
227
- readonly method: string;
228
- readonly path: string;
229
- readonly segments: readonly HttpPathSegment[];
230
- readonly dispatch: string;
231
- readonly definition: HttpExecutionRouteDefinition;
252
+ readonly name: HttpProcedureName;
253
+ readonly method: HttpMethod | '*';
254
+ readonly path: HttpPathTemplate;
255
+ readonly segments: ParsedHttpPath;
256
+ readonly dispatch: HttpDispatchKey;
257
+ readonly definition: CompiledHttpRouteDefinition;
232
258
  readonly middlewares: readonly AnyHttpMiddleware[];
233
259
  readonly source?: SourceLocation;
234
260
  readonly raw?: boolean;
235
261
  readonly protocol?: string;
236
262
  }
263
+ interface RuntimeHttpContext {
264
+ readonly input: HttpMiddlewareContext['input'];
265
+ readonly response: ReturnType<typeof createHttpResponseHelpers>;
266
+ readonly signal: AbortSignal;
267
+ readonly state: Readonly<Record<string, unknown>>;
268
+ readonly request?: Request;
269
+ readonly execution?: ExecutionContextView;
270
+ }
237
271
  interface CompiledHttpExecution {
238
272
  readonly routes: readonly CompiledHttpRoute[];
239
- readonly factory: () => Record<string, (context: HttpExecutionContext) => HttpMiddlewareOutcome | Promise<HttpMiddlewareOutcome>>;
273
+ readonly factory: () => Record<string, (context: RuntimeHttpContext) => HttpMiddlewareOutcome | Promise<HttpMiddlewareOutcome>>;
240
274
  }
241
275
  export interface HttpExtensionRuntime {
242
276
  fetch(request: Request): Promise<Response>;
@@ -323,8 +357,8 @@ type HttpRouteConstraint<TRoute extends HttpExecutionRouteDefinition> = (AreResp
323
357
  } : unknown) & (AreMiddlewareShortCircuitsCompatible<TRoute> extends true ? unknown : {
324
358
  readonly middlewares: never;
325
359
  });
326
- type HttpContractConstraint<TRoutes extends Readonly<Record<string, HttpExecutionRouteDefinition>>> = {
327
- readonly [TName in keyof TRoutes]: HttpRouteConstraint<TRoutes[TName]>;
360
+ type HttpContractConstraint<TRoutes extends Readonly<Record<string, HttpContractRouteDefinition>>> = {
361
+ readonly [TName in keyof TRoutes]: TRoutes[TName] extends HttpContractRawRouteDefinition ? unknown : HttpRouteConstraint<Extract<TRoutes[TName], HttpExecutionRouteDefinition>>;
328
362
  };
329
363
  type ErrorOf<TDefinition> = TDefinition extends HttpErrorMatcher<infer TError> ? TError : never;
330
364
  export declare function httpError<TDefinition extends HttpErrorMatcher<{
@@ -354,6 +388,7 @@ export declare const validate: Readonly<{
354
388
  }>;
355
389
  }>;
356
390
  export declare const executionHttp: Readonly<{
391
+ isWebSocketUpgrade: typeof isWebSocketUpgrade;
357
392
  raw: typeof defineHttpRaw;
358
393
  contract: typeof defineHttpContract;
359
394
  implementation: typeof defineHttpImplementation;
@@ -365,11 +400,15 @@ export declare const executionHttp: Readonly<{
365
400
  }>;
366
401
  }>;
367
402
  error: typeof httpError;
368
- extension: ExecutionExtension<(HttpImplementationDefinition<HttpContract<Readonly<Record<string, HttpExecutionRouteDefinition>>>> | HttpRawDefinition<readonly AnyHttpMiddleware[]>) & ExecutionDefinition<import("../core/extension.js").AnyExecutionExtension>, CompiledHttpExecution, "http", HttpHostApi, HttpExtensionRuntime> & {
403
+ extension: ExecutionExtension<(HttpImplementationDefinition<HttpContract<Readonly<Record<string, HttpContractRouteDefinition>>>> | HttpRawDefinition<readonly AnyHttpMiddleware[]>) & ExecutionDefinition<import("../core/extension.js").AnyExecutionExtension>, CompiledHttpExecution, "http", HttpHostApi, HttpExtensionRuntime> & {
369
404
  readonly [httpExecutionExtensionIdentity]: true;
370
405
  };
371
406
  serverCapability: import("../core/extension.js").RuntimeCapability<HttpServerDriver>;
372
407
  bindServer: typeof bindHttpServer;
373
408
  }>;
374
409
  export declare function withHttpFrameworkHeaders(result: HttpExecutionResult, headers: HttpHeaders): HttpExecutionResult;
410
+ declare function createHttpResponseHelpers(responses: HttpExecutionRouteDefinition['responses']): Readonly<Record<string, (value?: {
411
+ readonly body?: unknown;
412
+ readonly headers?: HttpHeaders;
413
+ }) => HttpExecutionResult>>;
375
414
  export {};