@loutrejs/loutre 0.5.0 → 0.7.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 +63 -32
- package/dist/adapters/aws-lambda.d.ts +5 -3
- package/dist/adapters/aws-lambda.js +53 -23
- package/dist/adapters/bun.d.ts +7 -4
- package/dist/adapters/bun.js +52 -42
- package/dist/adapters/cloudflare-workers.d.ts +5 -3
- package/dist/adapters/cloudflare-workers.js +23 -28
- package/dist/adapters/deno.d.ts +7 -4
- package/dist/adapters/deno.js +94 -57
- package/dist/adapters/electron.d.ts +13 -5
- package/dist/adapters/electron.js +76 -28
- package/dist/application/definition.d.ts +31 -0
- package/dist/application/definition.js +16 -0
- package/dist/application/index.d.ts +4 -63
- package/dist/application/index.js +2 -11
- package/dist/application/kernel-internal.d.ts +2 -0
- package/dist/application/kernel-internal.js +10 -0
- package/dist/application/kernel.d.ts +22 -0
- package/dist/application/kernel.js +65 -0
- package/dist/core/diagnostic.d.ts +9 -0
- package/dist/core/diagnostic.js +9 -0
- package/dist/core/extension.d.ts +118 -0
- package/dist/core/extension.js +73 -0
- package/dist/core/generic-layer.d.ts +26 -0
- package/dist/core/generic-layer.js +116 -0
- package/dist/core/index.d.ts +32 -15
- package/dist/core/index.js +15 -15
- package/dist/core/injection.d.ts +4 -13
- package/dist/core/injection.js +63 -0
- package/dist/core/instrumentation.d.ts +36 -0
- package/dist/core/model/context.d.ts +18 -0
- package/dist/core/model/context.js +34 -0
- package/dist/core/model/lifecycle.d.ts +5 -0
- package/dist/core/model/lifecycle.js +44 -0
- package/dist/core/model/modules.d.ts +2 -0
- package/dist/core/model/modules.js +101 -0
- package/dist/core/model/providers.d.ts +4 -0
- package/dist/core/model/providers.js +74 -0
- package/dist/core/model/snapshot.d.ts +6 -0
- package/dist/core/model/snapshot.js +31 -0
- package/dist/core/model/types.d.ts +78 -0
- package/dist/core/model/types.js +1 -0
- package/dist/core/model/validation.d.ts +4 -0
- package/dist/core/model/validation.js +40 -0
- package/dist/core/model/visibility.d.ts +4 -0
- package/dist/core/model/visibility.js +20 -0
- package/dist/core/model.d.ts +10 -0
- package/dist/core/model.js +346 -0
- package/dist/core/module.d.ts +8 -13
- package/dist/core/source-location.d.ts +8 -0
- package/dist/core/source-location.js +31 -0
- package/dist/core/token-internal.d.ts +3 -0
- package/dist/core/token-internal.js +4 -0
- package/dist/core/type.d.ts +7 -0
- package/dist/core/type.js +4 -0
- package/dist/devtools/capsule.d.ts +51 -0
- package/dist/devtools/capsule.js +245 -0
- package/dist/devtools/index.d.ts +11 -0
- package/dist/devtools/index.js +6 -0
- package/dist/devtools/inspector.d.ts +57 -0
- package/dist/devtools/inspector.js +1 -0
- package/dist/devtools/module.d.ts +18 -0
- package/dist/devtools/module.js +26 -0
- package/dist/devtools/observer.d.ts +77 -0
- package/dist/devtools/observer.js +10 -0
- package/dist/devtools/protocol.d.ts +1 -0
- package/dist/devtools/protocol.js +1 -0
- package/dist/devtools/provider-instrumentation.d.ts +14 -0
- package/dist/devtools/provider-instrumentation.js +117 -0
- package/dist/devtools/runtime.d.ts +20 -0
- package/dist/devtools/runtime.js +519 -0
- package/dist/devtools/values.d.ts +35 -0
- package/dist/devtools/values.js +175 -0
- package/dist/generated/version.d.ts +1 -1
- package/dist/generated/version.js +1 -1
- package/dist/graph/index.d.ts +2 -3
- package/dist/graph/index.js +1 -3
- package/dist/graph/model.d.ts +34 -0
- package/dist/graph/model.js +127 -0
- package/dist/http/auth.d.ts +46 -0
- package/dist/http/auth.js +96 -0
- package/dist/http/client.d.ts +28 -31
- package/dist/http/client.js +58 -44
- package/dist/http/cors-internal.d.ts +29 -0
- package/dist/http/cors-internal.js +160 -0
- package/dist/http/cors.d.ts +5 -8
- package/dist/http/cors.js +7 -165
- package/dist/http/extension.d.ts +348 -0
- package/dist/http/extension.js +1061 -0
- package/dist/http/index.d.ts +9 -7
- package/dist/http/index.js +5 -7
- package/dist/{application → http}/openapi.d.ts +12 -3
- package/dist/{application → http}/openapi.js +164 -102
- package/dist/http/path.d.ts +1 -42
- package/dist/http/path.js +1 -2
- package/dist/http/runtime/request.d.ts +17 -0
- package/dist/http/runtime/request.js +109 -0
- package/dist/http/runtime/response.d.ts +18 -0
- package/dist/http/runtime/response.js +108 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +2 -0
- package/dist/message-port/extension.d.ts +66 -0
- package/dist/message-port/extension.js +411 -0
- package/dist/message-port/index.d.ts +4 -73
- package/dist/message-port/index.js +2 -189
- package/dist/message-port/transport.d.ts +11 -0
- package/dist/message-port/transport.js +45 -0
- package/dist/runtime/async-iterator-lifecycle.d.ts +12 -0
- package/dist/runtime/async-iterator-lifecycle.js +95 -0
- package/dist/runtime/capability.d.ts +11 -11
- package/dist/runtime/capability.js +3 -3
- package/dist/runtime/di.d.ts +5 -21
- package/dist/runtime/di.js +22 -289
- package/dist/runtime/execution-tracker.d.ts +8 -0
- package/dist/runtime/execution-tracker.js +54 -0
- package/dist/runtime/index.d.ts +15 -9
- package/dist/runtime/index.js +9 -9
- package/dist/runtime/ingress-gate.d.ts +7 -0
- package/dist/runtime/ingress-gate.js +33 -0
- package/dist/runtime/kernel.d.ts +25 -0
- package/dist/runtime/kernel.js +447 -0
- package/dist/runtime/logger.d.ts +2 -0
- package/dist/runtime/logger.js +2 -0
- package/dist/runtime/node-capabilities.d.ts +1 -1
- package/dist/runtime/node-capabilities.js +1 -1
- package/dist/runtime/server-port.d.ts +2 -0
- package/dist/runtime/server-port.js +11 -0
- package/dist/tasks/extension.d.ts +144 -0
- package/dist/tasks/extension.js +525 -0
- package/dist/tasks/index.d.ts +2 -0
- package/dist/tasks/index.js +1 -0
- package/dist/tasks/runtime/cron.d.ts +6 -0
- package/dist/tasks/runtime/cron.js +89 -0
- package/dist/websocket/errors.d.ts +9 -0
- package/dist/websocket/errors.js +18 -0
- package/dist/websocket/extension.d.ts +154 -0
- package/dist/websocket/extension.js +533 -0
- package/dist/websocket/index.d.ts +3 -0
- package/dist/websocket/index.js +2 -0
- package/package.json +16 -16
- package/dist/application/binding.d.ts +0 -33
- package/dist/application/binding.js +0 -295
- package/dist/application/host.d.ts +0 -8
- package/dist/application/host.js +0 -14
- package/dist/application/queue.d.ts +0 -3
- package/dist/application/queue.js +0 -4
- package/dist/application/scheduler.d.ts +0 -2
- package/dist/application/scheduler.js +0 -45
- package/dist/core/context-key.d.ts +0 -16
- package/dist/core/context-key.js +0 -17
- package/dist/core/contract-internal.d.ts +0 -22
- package/dist/core/contract-internal.js +0 -61
- package/dist/core/contract.d.ts +0 -96
- package/dist/core/contract.js +0 -88
- package/dist/core/execution.d.ts +0 -78
- package/dist/core/execution.js +0 -61
- package/dist/core/implementation.d.ts +0 -44
- package/dist/core/implementation.js +0 -35
- package/dist/core/layer.d.ts +0 -137
- package/dist/core/layer.js +0 -81
- package/dist/graph/compiler.d.ts +0 -4
- package/dist/graph/compiler.js +0 -228
- package/dist/graph/graph.d.ts +0 -18
- package/dist/graph/graph.js +0 -1118
- package/dist/graph/ir.d.ts +0 -175
- package/dist/http/application.d.ts +0 -18
- package/dist/http/application.js +0 -515
- package/dist/http/basic-auth.d.ts +0 -37
- package/dist/http/basic-auth.js +0 -67
- package/dist/http/definitions.d.ts +0 -363
- package/dist/http/definitions.js +0 -310
- package/dist/http/hosted-protocol.d.ts +0 -4
- package/dist/http/hosted-protocol.js +0 -4
- package/dist/http/internal.d.ts +0 -8
- package/dist/http/internal.js +0 -1
- package/dist/http/params.d.ts +0 -2
- package/dist/http/params.js +0 -19
- package/dist/http/request-body.d.ts +0 -4
- package/dist/http/request-body.js +0 -6
- package/dist/http/validate.d.ts +0 -20
- package/dist/http/validate.js +0 -6
- package/dist/message-port/environment.d.ts +0 -2
- package/dist/message-port/environment.js +0 -4
- package/dist/runtime/application.d.ts +0 -38
- package/dist/runtime/application.js +0 -339
- package/dist/runtime/pipeline.d.ts +0 -11
- package/dist/runtime/pipeline.js +0 -161
- /package/dist/{graph/ir.js → core/instrumentation.js} +0 -0
package/dist/http/index.d.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
export
|
|
2
|
-
export
|
|
3
|
-
export
|
|
1
|
+
export { createHttpClient, fetchHttpTransport, HttpClientResponseError, } from './client.js';
|
|
2
|
+
export type { FetchHttpTransportOptions, HttpClient, HttpClientRequest, HttpClientResponse, HttpClientTransport, HttpClientTransportRequest, HttpClientTransportResponse, } from './client.js';
|
|
3
|
+
export { cors } from './cors.js';
|
|
4
4
|
export type { CorsLayerDescriptor, CorsOptions, CorsOrigin } from './cors.js';
|
|
5
|
-
export
|
|
6
|
-
export {
|
|
7
|
-
export
|
|
8
|
-
export {
|
|
5
|
+
export { basicAuth, bearerAuth } from './auth.js';
|
|
6
|
+
export type { BasicAuthContext, BasicAuthCredentials, BasicAuthDefinition, BasicAuthUnauthorized, BasicAuthRuntime, BearerAuthContext, BearerAuthDefinition, BearerAuthRuntime, BearerAuthUnauthorized, HttpAuthenticationFailure, } from './auth.js';
|
|
7
|
+
export { bindHttpServer, defineHttpContract, defineHttpImplementation, defineHttpMiddleware, httpError, executionHttp as http, httpExecutionExtension, HTTP_SERVER, validate, } from './extension.js';
|
|
8
|
+
export type { HttpContract, HttpContractBranchDefinition, HttpContractNodeDefinition, HttpContractRouteTree, HttpExecutionContext, HttpExecutionDefinition, HttpExecutionRequestDefinition, HttpExecutionResponseDefinition, HttpExecutionResult, HttpExecutionRouteDefinition, HttpErrorMapping, HttpErrorMatcher, HttpExtensionRuntime, HttpHandlers, HttpHeaderValue, HttpHeaders, HttpHostApi, HttpImplementationDefinition, HttpMiddleware, HttpMiddlewareContext, HttpResponseHeadersDefinition, HttpResponseResult, HttpResponseHeadersWithDefaults, HttpServerDriver, HttpValidationMiddleware, HttpValidationPart, ResolvedHttpContractRoutes, } from './extension.js';
|
|
9
|
+
export { compareHttpPathSpecificity, HttpPathDecodeError, matchHttpPath, normalizeHttpPath, parseHttpPath, } from './path.js';
|
|
10
|
+
export type { HttpPathSegment, PathParamNames } from './path.js';
|
package/dist/http/index.js
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
export
|
|
2
|
-
export
|
|
3
|
-
export
|
|
4
|
-
export
|
|
5
|
-
export {
|
|
6
|
-
export * from './request-body.js';
|
|
7
|
-
export { validate } from './validate.js';
|
|
1
|
+
export { createHttpClient, fetchHttpTransport, HttpClientResponseError, } from './client.js';
|
|
2
|
+
export { cors } from './cors.js';
|
|
3
|
+
export { basicAuth, bearerAuth } from './auth.js';
|
|
4
|
+
export { bindHttpServer, defineHttpContract, defineHttpImplementation, defineHttpMiddleware, httpError, executionHttp as http, httpExecutionExtension, HTTP_SERVER, validate, } from './extension.js';
|
|
5
|
+
export { compareHttpPathSpecificity, HttpPathDecodeError, matchHttpPath, normalizeHttpPath, parseHttpPath, } from './path.js';
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type ApplicationModel } from '../core/index.js';
|
|
2
|
+
import { type HttpExecutionResponseDefinition, type HttpExecutionRouteDefinition } from './extension.js';
|
|
2
3
|
export interface OpenApiInfo {
|
|
3
4
|
readonly title: string;
|
|
4
5
|
readonly version: string;
|
|
@@ -20,7 +21,6 @@ export interface GenerateOpenApiOptions {
|
|
|
20
21
|
}
|
|
21
22
|
export interface OpenApiDocument {
|
|
22
23
|
readonly openapi: '3.2.0';
|
|
23
|
-
readonly jsonSchemaDialect: 'https://json-schema.org/draft/2020-12/schema';
|
|
24
24
|
readonly info: OpenApiInfo;
|
|
25
25
|
readonly servers?: readonly OpenApiServer[];
|
|
26
26
|
readonly paths: Readonly<Record<string, OpenApiPathItem>>;
|
|
@@ -30,5 +30,14 @@ export interface OpenApiDocument {
|
|
|
30
30
|
}
|
|
31
31
|
type JsonSchema = Record<string, unknown>;
|
|
32
32
|
type OpenApiPathItem = Record<string, unknown>;
|
|
33
|
-
|
|
33
|
+
type OpenApiResponseDefinition = HttpExecutionResponseDefinition;
|
|
34
|
+
export interface HttpOperationTarget {
|
|
35
|
+
readonly definition: Omit<HttpExecutionRouteDefinition, 'responses'> & {
|
|
36
|
+
readonly responses: Readonly<Record<string, OpenApiResponseDefinition>>;
|
|
37
|
+
};
|
|
38
|
+
readonly procedure: string;
|
|
39
|
+
}
|
|
40
|
+
export declare function generateOpenApi(source: ApplicationModel | {
|
|
41
|
+
readonly model: ApplicationModel;
|
|
42
|
+
}, options: GenerateOpenApiOptions): OpenApiDocument;
|
|
34
43
|
export {};
|
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
import { supportsJsonSchema, } from '../core/index.js';
|
|
2
|
-
import {
|
|
3
|
-
import { assertValidCompilation, compileApplication } from '../graph/index.js';
|
|
4
|
-
import { httpRequestBodyContentType, httpRequestBodySchema, } from '../http/index.js';
|
|
1
|
+
import { supportsJsonSchema, assertValidApplicationModel, } from '../core/index.js';
|
|
2
|
+
import { httpExecutionExtension, } from './extension.js';
|
|
5
3
|
const FIXED_METHODS = new Set([
|
|
6
4
|
'get',
|
|
7
5
|
'put',
|
|
@@ -13,40 +11,29 @@ const FIXED_METHODS = new Set([
|
|
|
13
11
|
'trace',
|
|
14
12
|
'query',
|
|
15
13
|
]);
|
|
16
|
-
export function generateOpenApi(
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
...(application.arguments === undefined
|
|
20
|
-
? {}
|
|
21
|
-
: { arguments: application.arguments }),
|
|
22
|
-
tasks: application.tasks,
|
|
23
|
-
triggers: application.triggers,
|
|
24
|
-
}));
|
|
14
|
+
export function generateOpenApi(source, options) {
|
|
15
|
+
const model = 'model' in source ? source.model : source;
|
|
16
|
+
assertValidApplicationModel(model);
|
|
25
17
|
const registry = new SchemaRegistry();
|
|
26
18
|
const paths = {};
|
|
27
19
|
const operationIds = new Set();
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
};
|
|
41
|
-
const operation = createOperation(target, registry, operationIds, options.operationId);
|
|
42
|
-
attachOperation(paths, typed.definition, operation);
|
|
43
|
-
}
|
|
20
|
+
const http = model.extensions.get(httpExecutionExtension);
|
|
21
|
+
for (const execution of http?.executions ?? []) {
|
|
22
|
+
for (const route of execution.compiled.routes) {
|
|
23
|
+
const target = {
|
|
24
|
+
procedure: route.name,
|
|
25
|
+
definition: {
|
|
26
|
+
...route.definition,
|
|
27
|
+
method: route.method,
|
|
28
|
+
path: route.path,
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
attachOperation(paths, target.definition, createOperation(target, registry, operationIds, options.operationId));
|
|
44
32
|
}
|
|
45
33
|
}
|
|
46
34
|
const schemas = registry.components();
|
|
47
35
|
return {
|
|
48
36
|
openapi: '3.2.0',
|
|
49
|
-
jsonSchemaDialect: 'https://json-schema.org/draft/2020-12/schema',
|
|
50
37
|
info: options.info,
|
|
51
38
|
...(options.servers === undefined ? {} : { servers: options.servers }),
|
|
52
39
|
paths,
|
|
@@ -83,6 +70,7 @@ function createOperation(target, registry, operationIds, resolveOperationId) {
|
|
|
83
70
|
}
|
|
84
71
|
if (request?.query) {
|
|
85
72
|
parameters.push({
|
|
73
|
+
name: 'query',
|
|
86
74
|
in: 'querystring',
|
|
87
75
|
content: {
|
|
88
76
|
'application/x-www-form-urlencoded': {
|
|
@@ -95,7 +83,7 @@ function createOperation(target, registry, operationIds, resolveOperationId) {
|
|
|
95
83
|
parameters.push(...headerParameters(request.headers, registry, target, 'RequestHeaders_Input'));
|
|
96
84
|
}
|
|
97
85
|
const requestBody = request?.body
|
|
98
|
-
? createRequestBody(request.body, registry, target)
|
|
86
|
+
? createRequestBody(request.body, request.headers, registry, target)
|
|
99
87
|
: undefined;
|
|
100
88
|
return {
|
|
101
89
|
...(definition.tags === undefined ? {} : { tags: definition.tags }),
|
|
@@ -114,21 +102,62 @@ function createOperation(target, registry, operationIds, resolveOperationId) {
|
|
|
114
102
|
: { deprecated: definition.deprecated }),
|
|
115
103
|
};
|
|
116
104
|
}
|
|
117
|
-
function createRequestBody(body, registry, target) {
|
|
118
|
-
const
|
|
105
|
+
function createRequestBody(body, headers, registry, target) {
|
|
106
|
+
const mediaTypes = requestBodyMediaTypes(headers, registry, target);
|
|
107
|
+
const schema = registry.reference(body, 'input', componentName(target, 'RequestBody_Input'));
|
|
119
108
|
return {
|
|
120
|
-
content: {
|
|
121
|
-
[contentType]: {
|
|
122
|
-
schema: registry.reference(httpRequestBodySchema(body), 'input', componentName(target, 'RequestBody_Input')),
|
|
123
|
-
},
|
|
124
|
-
},
|
|
109
|
+
content: Object.fromEntries(mediaTypes.map((mediaType) => [mediaType, { schema }])),
|
|
125
110
|
};
|
|
126
111
|
}
|
|
112
|
+
function requestBodyMediaTypes(headers, registry, target) {
|
|
113
|
+
if (!headers) {
|
|
114
|
+
throw openApiError('LUTRE_OPENAPI_CONTENT_TYPE_001', `${describeTarget(target)} request body requires a request headers schema with content-type.`);
|
|
115
|
+
}
|
|
116
|
+
const materialized = registry.materialize(headers, 'input', componentName(target, 'RequestHeaders_Input'));
|
|
117
|
+
const properties = objectProperties(materialized.schema, 'LUTRE_OPENAPI_HEADER_SCHEMA_001', `${describeTarget(target)} request headers`);
|
|
118
|
+
const contentType = properties['content-type'];
|
|
119
|
+
if (!contentType) {
|
|
120
|
+
throw openApiError('LUTRE_OPENAPI_CONTENT_TYPE_001', `${describeTarget(target)} request headers must declare content-type.`);
|
|
121
|
+
}
|
|
122
|
+
const values = finiteStringValues(contentType);
|
|
123
|
+
if (!values || values.length === 0) {
|
|
124
|
+
throw openApiError('LUTRE_OPENAPI_CONTENT_TYPE_002', `${describeTarget(target)} request content-type must resolve to a finite set of string literals.`);
|
|
125
|
+
}
|
|
126
|
+
return [...new Set(values)];
|
|
127
|
+
}
|
|
128
|
+
function finiteStringValues(schema) {
|
|
129
|
+
if (typeof schema.const === 'string')
|
|
130
|
+
return [schema.const];
|
|
131
|
+
if (Array.isArray(schema.enum)) {
|
|
132
|
+
return schema.enum.every((value) => typeof value === 'string')
|
|
133
|
+
? schema.enum
|
|
134
|
+
: undefined;
|
|
135
|
+
}
|
|
136
|
+
for (const keyword of ['anyOf', 'oneOf']) {
|
|
137
|
+
const alternatives = schema[keyword];
|
|
138
|
+
if (!Array.isArray(alternatives))
|
|
139
|
+
continue;
|
|
140
|
+
const values = [];
|
|
141
|
+
for (const alternative of alternatives) {
|
|
142
|
+
if (typeof alternative !== 'object' ||
|
|
143
|
+
alternative === null ||
|
|
144
|
+
Array.isArray(alternative)) {
|
|
145
|
+
return undefined;
|
|
146
|
+
}
|
|
147
|
+
const nested = finiteStringValues(alternative);
|
|
148
|
+
if (!nested)
|
|
149
|
+
return undefined;
|
|
150
|
+
values.push(...nested);
|
|
151
|
+
}
|
|
152
|
+
return values;
|
|
153
|
+
}
|
|
154
|
+
return undefined;
|
|
155
|
+
}
|
|
127
156
|
function createResponses(target, registry) {
|
|
128
157
|
const grouped = new Map();
|
|
129
|
-
for (const [
|
|
158
|
+
for (const [name, response] of Object.entries(target.definition.responses)) {
|
|
130
159
|
const current = grouped.get(response.status) ?? [];
|
|
131
|
-
current.push({
|
|
160
|
+
current.push({ name, response });
|
|
132
161
|
grouped.set(response.status, current);
|
|
133
162
|
}
|
|
134
163
|
return Object.fromEntries([...grouped.entries()]
|
|
@@ -143,50 +172,64 @@ function createResponse(target, entries, registry) {
|
|
|
143
172
|
if (streamKinds.size > 1) {
|
|
144
173
|
throw openApiError('LUTRE_OPENAPI_RESPONSE_STREAM_001', `${describeTarget(target)} declares streaming and non-streaming responses with the same status.`);
|
|
145
174
|
}
|
|
146
|
-
const schemas = entries
|
|
175
|
+
const schemas = entries
|
|
176
|
+
.filter(({ response }) => response.body !== undefined)
|
|
177
|
+
.map(({ name, response }) => registry.reference(response.body, 'output', componentName(target, `Response_${name}_Output`)));
|
|
147
178
|
const payloadSchema = schemas.length === 1 ? schemas[0] : { oneOf: schemas };
|
|
148
179
|
const streaming = entries[0]?.response.stream === 'server';
|
|
149
180
|
const headers = mergeResponseHeaders(entries, registry, target);
|
|
150
181
|
const descriptions = [
|
|
151
|
-
...new Set(entries.map(({
|
|
182
|
+
...new Set(entries.map(({ name, response }) => response.description ?? name)),
|
|
152
183
|
];
|
|
153
184
|
return {
|
|
154
185
|
description: descriptions.join(' / '),
|
|
155
186
|
...(headers === undefined ? {} : { headers }),
|
|
156
|
-
|
|
157
|
-
? {
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
187
|
+
...(schemas.length === 0
|
|
188
|
+
? {}
|
|
189
|
+
: {
|
|
190
|
+
content: streaming
|
|
191
|
+
? {
|
|
192
|
+
'text/event-stream': {
|
|
193
|
+
itemSchema: {
|
|
194
|
+
type: 'object',
|
|
195
|
+
required: ['data'],
|
|
196
|
+
properties: {
|
|
197
|
+
data: {
|
|
198
|
+
type: 'string',
|
|
199
|
+
contentMediaType: 'application/json',
|
|
200
|
+
contentSchema: payloadSchema,
|
|
201
|
+
},
|
|
202
|
+
},
|
|
167
203
|
},
|
|
168
204
|
},
|
|
205
|
+
}
|
|
206
|
+
: {
|
|
207
|
+
'application/json': {
|
|
208
|
+
schema: payloadSchema,
|
|
209
|
+
},
|
|
169
210
|
},
|
|
170
|
-
|
|
171
|
-
}
|
|
172
|
-
: {
|
|
173
|
-
'application/json': {
|
|
174
|
-
schema: payloadSchema,
|
|
175
|
-
},
|
|
176
|
-
},
|
|
211
|
+
}),
|
|
177
212
|
};
|
|
178
213
|
}
|
|
179
214
|
function mergeResponseHeaders(entries, registry, target) {
|
|
180
215
|
const result = new Map();
|
|
181
|
-
for (const {
|
|
182
|
-
|
|
216
|
+
for (const { name, response } of entries) {
|
|
217
|
+
for (const [headerName, value] of Object.entries(responseHeadersDefaults(response.headers) ?? {})) {
|
|
218
|
+
if (value === undefined)
|
|
219
|
+
continue;
|
|
220
|
+
const current = result.get(headerName) ?? [];
|
|
221
|
+
current.push(responseHeaderDefaultSchema(value));
|
|
222
|
+
result.set(headerName, current);
|
|
223
|
+
}
|
|
224
|
+
const headerSchema = responseHeadersSchema(response.headers);
|
|
225
|
+
if (!headerSchema)
|
|
183
226
|
continue;
|
|
184
|
-
const materialized = registry.materialize(
|
|
227
|
+
const materialized = registry.materialize(headerSchema, 'output', componentName(target, `Response_${name}_Headers_Output`));
|
|
185
228
|
const properties = objectProperties(materialized.schema, 'LUTRE_OPENAPI_HEADER_SCHEMA_001', `${describeTarget(target)} response headers`);
|
|
186
|
-
for (const [
|
|
187
|
-
const current = result.get(
|
|
229
|
+
for (const [headerName, schema] of Object.entries(properties)) {
|
|
230
|
+
const current = result.get(headerName) ?? [];
|
|
188
231
|
current.push(schema);
|
|
189
|
-
result.set(
|
|
232
|
+
result.set(headerName, current);
|
|
190
233
|
}
|
|
191
234
|
}
|
|
192
235
|
if (result.size === 0)
|
|
@@ -200,13 +243,47 @@ function mergeResponseHeaders(entries, registry, target) {
|
|
|
200
243
|
},
|
|
201
244
|
]));
|
|
202
245
|
}
|
|
246
|
+
function responseHeadersSchema(headers) {
|
|
247
|
+
if (isStandardSchema(headers))
|
|
248
|
+
return headers;
|
|
249
|
+
if (isResponseHeadersWithDefaults(headers))
|
|
250
|
+
return headers.schema;
|
|
251
|
+
return undefined;
|
|
252
|
+
}
|
|
253
|
+
function responseHeadersDefaults(headers) {
|
|
254
|
+
if (headers === undefined || isStandardSchema(headers))
|
|
255
|
+
return undefined;
|
|
256
|
+
if (isResponseHeadersWithDefaults(headers))
|
|
257
|
+
return headers.defaults;
|
|
258
|
+
return headers;
|
|
259
|
+
}
|
|
260
|
+
function isStandardSchema(value) {
|
|
261
|
+
return typeof value === 'object' && value !== null && '~standard' in value;
|
|
262
|
+
}
|
|
263
|
+
function isResponseHeadersWithDefaults(value) {
|
|
264
|
+
return (typeof value === 'object' &&
|
|
265
|
+
value !== null &&
|
|
266
|
+
'schema' in value &&
|
|
267
|
+
isStandardSchema(value.schema));
|
|
268
|
+
}
|
|
269
|
+
function responseHeaderDefaultSchema(value) {
|
|
270
|
+
if (typeof value === 'string')
|
|
271
|
+
return { type: 'string', const: value };
|
|
272
|
+
return {
|
|
273
|
+
type: 'array',
|
|
274
|
+
items: { type: 'string' },
|
|
275
|
+
const: [...value],
|
|
276
|
+
};
|
|
277
|
+
}
|
|
203
278
|
function headerParameters(schema, registry, target, suffix) {
|
|
204
279
|
const materialized = registry.materialize(schema, 'input', componentName(target, suffix));
|
|
205
280
|
const properties = objectProperties(materialized.schema, 'LUTRE_OPENAPI_HEADER_SCHEMA_001', `${describeTarget(target)} request headers`);
|
|
206
281
|
const required = new Set(Array.isArray(materialized.schema.required)
|
|
207
282
|
? materialized.schema.required.filter((value) => typeof value === 'string')
|
|
208
283
|
: []);
|
|
209
|
-
return Object.entries(properties)
|
|
284
|
+
return Object.entries(properties)
|
|
285
|
+
.filter(([name]) => name.toLowerCase() !== 'content-type')
|
|
286
|
+
.map(([name, propertySchema]) => ({
|
|
210
287
|
name,
|
|
211
288
|
in: 'header',
|
|
212
289
|
required: required.has(name),
|
|
@@ -241,20 +318,27 @@ function attachOperation(paths, definition, operation) {
|
|
|
241
318
|
}
|
|
242
319
|
additional[methodName] = operation;
|
|
243
320
|
}
|
|
244
|
-
function
|
|
245
|
-
const
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
if (
|
|
249
|
-
return;
|
|
250
|
-
|
|
251
|
-
for (const
|
|
252
|
-
|
|
253
|
-
|
|
321
|
+
function rebaseLocalDefinitions(schema, schemaComponentName) {
|
|
322
|
+
const visit = (value) => {
|
|
323
|
+
if (Array.isArray(value))
|
|
324
|
+
return value.map(visit);
|
|
325
|
+
if (typeof value !== 'object' || value === null)
|
|
326
|
+
return value;
|
|
327
|
+
const result = {};
|
|
328
|
+
for (const [key, child] of Object.entries(value)) {
|
|
329
|
+
if (key === '$ref' &&
|
|
330
|
+
typeof child === 'string' &&
|
|
331
|
+
child.startsWith('#/$defs/')) {
|
|
332
|
+
result[key] =
|
|
333
|
+
`#/components/schemas/${escapeJsonPointer(schemaComponentName)}/$defs/${child.slice('#/$defs/'.length)}`;
|
|
334
|
+
}
|
|
335
|
+
else {
|
|
336
|
+
result[key] = visit(child);
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
return result;
|
|
254
340
|
};
|
|
255
|
-
|
|
256
|
-
visit(root);
|
|
257
|
-
return result;
|
|
341
|
+
return visit(schema);
|
|
258
342
|
}
|
|
259
343
|
class SchemaRegistry {
|
|
260
344
|
bySchema = new Map();
|
|
@@ -295,28 +379,6 @@ class SchemaRegistry {
|
|
|
295
379
|
return this.schemas;
|
|
296
380
|
}
|
|
297
381
|
}
|
|
298
|
-
function rebaseLocalDefinitions(schema, schemaComponentName) {
|
|
299
|
-
const visit = (value) => {
|
|
300
|
-
if (Array.isArray(value))
|
|
301
|
-
return value.map(visit);
|
|
302
|
-
if (typeof value !== 'object' || value === null)
|
|
303
|
-
return value;
|
|
304
|
-
const result = {};
|
|
305
|
-
for (const [key, child] of Object.entries(value)) {
|
|
306
|
-
if (key === '$ref' &&
|
|
307
|
-
typeof child === 'string' &&
|
|
308
|
-
child.startsWith('#/$defs/')) {
|
|
309
|
-
result[key] =
|
|
310
|
-
`#/components/schemas/${escapeJsonPointer(schemaComponentName)}/$defs/${child.slice('#/$defs/'.length)}`;
|
|
311
|
-
}
|
|
312
|
-
else {
|
|
313
|
-
result[key] = visit(child);
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
return result;
|
|
317
|
-
};
|
|
318
|
-
return visit(schema);
|
|
319
|
-
}
|
|
320
382
|
function componentName(target, suffix) {
|
|
321
383
|
return sanitizeComponentName(`${target.definition.method} ${target.definition.path} ${target.procedure} ${suffix}`);
|
|
322
384
|
}
|
package/dist/http/path.d.ts
CHANGED
|
@@ -1,44 +1,3 @@
|
|
|
1
|
-
type AsciiLowercase = 'a' | 'b' | 'c' | 'd' | 'e' | 'f' | 'g' | 'h' | 'i' | 'j' | 'k' | 'l' | 'm' | 'n' | 'o' | 'p' | 'q' | 'r' | 's' | 't' | 'u' | 'v' | 'w' | 'x' | 'y' | 'z';
|
|
2
|
-
type AsciiLetter = AsciiLowercase | Uppercase<AsciiLowercase>;
|
|
3
|
-
type AsciiDigit = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9';
|
|
4
|
-
type ParamNameStart = AsciiLetter | '_';
|
|
5
|
-
type ParamNameContinuation = ParamNameStart | AsciiDigit;
|
|
6
|
-
type HttpMethodTokenCharacter = AsciiLetter | AsciiDigit | '!' | '#' | '$' | '%' | '&' | "'" | '*' | '+' | '-' | '.' | '^' | '_' | '`' | '|' | '~';
|
|
7
|
-
type IsHttpMethodTokenRest<TMethod extends string> = TMethod extends '' ? true : TMethod extends `${HttpMethodTokenCharacter}${infer TRest}` ? IsHttpMethodTokenRest<TRest> : false;
|
|
8
|
-
export type IsValidHttpMethod<TMethod extends string> = string extends TMethod ? false : TMethod extends `${HttpMethodTokenCharacter}${infer TRest}` ? IsHttpMethodTokenRest<TRest> : false;
|
|
9
|
-
type IsParamNameRest<TName extends string> = TName extends '' ? true : TName extends `${ParamNameContinuation}${infer TRest}` ? IsParamNameRest<TRest> : false;
|
|
10
|
-
type IsParamName<TName extends string> = TName extends `${ParamNameStart}${infer TRest}` ? IsParamNameRest<TRest> : false;
|
|
11
|
-
type IsStaticSegment<TSegment extends string> = TSegment extends '' ? false : TSegment extends `${string}{${string}` | `${string}}${string}` ? false : TSegment extends `${string}?${string}` | `${string}#${string}` ? false : true;
|
|
12
|
-
type ValidatePathSegments<TSegments extends string, TSeen extends string = never> = TSegments extends `${infer THead}/${infer TTail}` ? ValidatePathSegment<THead, TSeen> extends infer TResult ? TResult extends {
|
|
13
|
-
readonly valid: true;
|
|
14
|
-
readonly seen: infer TNext extends string;
|
|
15
|
-
} ? ValidatePathSegments<TTail, TNext> : false : false : ValidatePathSegment<TSegments, TSeen> extends {
|
|
16
|
-
readonly valid: true;
|
|
17
|
-
} ? true : false;
|
|
18
|
-
type ValidatePathSegment<TSegment extends string, TSeen extends string> = TSegment extends `{${infer TName}}` ? IsParamName<TName> extends true ? TName extends TSeen ? {
|
|
19
|
-
readonly valid: false;
|
|
20
|
-
} : {
|
|
21
|
-
readonly valid: true;
|
|
22
|
-
readonly seen: TSeen | TName;
|
|
23
|
-
} : {
|
|
24
|
-
readonly valid: false;
|
|
25
|
-
} : IsStaticSegment<TSegment> extends true ? {
|
|
26
|
-
readonly valid: true;
|
|
27
|
-
readonly seen: TSeen;
|
|
28
|
-
} : {
|
|
29
|
-
readonly valid: false;
|
|
30
|
-
};
|
|
31
|
-
export type IsValidHttpPath<TPath extends string> = string extends TPath ? false : TPath extends '/' ? true : TPath extends `/${infer TSegments}` ? ValidatePathSegments<TSegments> : false;
|
|
32
|
-
type PathParamNamesFromSegments<TSegments extends string> = TSegments extends `${infer THead}/${infer TTail}` ? PathParamName<THead> | PathParamNamesFromSegments<TTail> : PathParamName<TSegments>;
|
|
33
|
-
type PathParamName<TSegment extends string> = TSegment extends `{${infer TName}}` ? TName : never;
|
|
34
|
-
export type PathParamNames<TPath extends string> = TPath extends `/${infer TSegments}` ? PathParamNamesFromSegments<TSegments> : never;
|
|
35
|
-
export type RawPathParams<TPath extends string> = Readonly<{
|
|
36
|
-
[TName in PathParamNames<TPath>]: string;
|
|
37
|
-
}>;
|
|
38
|
-
type NormalizeHttpPathSegments<TSegments extends string> = TSegments extends `${infer THead}/${infer TTail}` ? `${NormalizeHttpPathSegment<THead>}/${NormalizeHttpPathSegments<TTail>}` : NormalizeHttpPathSegment<TSegments>;
|
|
39
|
-
type NormalizeHttpPathSegment<TSegment extends string> = TSegment extends `{${string}}` ? '{}' : TSegment;
|
|
40
|
-
export type NormalizeHttpPath<TPath extends string> = TPath extends '/' ? '/' : string extends TPath ? string : TPath extends `/${infer TSegments}` ? `/${NormalizeHttpPathSegments<TSegments>}` : never;
|
|
41
|
-
export type HttpDispatchKey<TMethod extends string, TPath extends string> = `http:${Uppercase<TMethod>}:${NormalizeHttpPath<TPath>}`;
|
|
42
1
|
export type HttpPathSegment = {
|
|
43
2
|
readonly kind: 'static';
|
|
44
3
|
readonly value: string;
|
|
@@ -46,6 +5,7 @@ export type HttpPathSegment = {
|
|
|
46
5
|
readonly kind: 'param';
|
|
47
6
|
readonly name: string;
|
|
48
7
|
};
|
|
8
|
+
export type PathParamNames<TPath extends string> = TPath extends `${string}{${infer TName}}${infer TRest}` ? TName | PathParamNames<TRest> : never;
|
|
49
9
|
export declare function assertValidHttpMethod(method: string): void;
|
|
50
10
|
export declare function parseHttpPath(path: string): readonly HttpPathSegment[];
|
|
51
11
|
export declare function normalizeHttpPath(segments: readonly HttpPathSegment[]): string;
|
|
@@ -56,4 +16,3 @@ export declare class HttpPathDecodeError extends Error {
|
|
|
56
16
|
readonly cause: unknown;
|
|
57
17
|
constructor(cause: unknown);
|
|
58
18
|
}
|
|
59
|
-
export {};
|
package/dist/http/path.js
CHANGED
|
@@ -56,8 +56,7 @@ export function matchHttpPath(segments, pathname) {
|
|
|
56
56
|
if (requestSegments.length !== segments.length)
|
|
57
57
|
return undefined;
|
|
58
58
|
const params = {};
|
|
59
|
-
for (
|
|
60
|
-
const routeSegment = segments[index];
|
|
59
|
+
for (const [index, routeSegment] of segments.entries()) {
|
|
61
60
|
const requestSegment = requestSegments[index];
|
|
62
61
|
if (routeSegment.kind === 'static') {
|
|
63
62
|
if (routeSegment.value !== requestSegment)
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type StandardSchemaV1 } from '../../core/index.js';
|
|
2
|
+
export declare function decodeQuery(searchParams: URLSearchParams): Readonly<Record<string, string | string[]>>;
|
|
3
|
+
export declare function validateRequestHeaders(schema: StandardSchemaV1, bodyDeclared: boolean, headers: Headers): Promise<unknown>;
|
|
4
|
+
export declare function validatedContentType(headers: unknown): string;
|
|
5
|
+
export declare function decodeBody(request: Request, contentType: string): Promise<unknown>;
|
|
6
|
+
export declare class HttpInputDecodeError extends Error {
|
|
7
|
+
readonly cause: unknown;
|
|
8
|
+
constructor(cause: unknown);
|
|
9
|
+
}
|
|
10
|
+
export declare class HttpInputValidationError extends Error {
|
|
11
|
+
readonly cause: unknown;
|
|
12
|
+
constructor(cause: unknown);
|
|
13
|
+
}
|
|
14
|
+
export declare class HttpUnsupportedMediaTypeError extends Error {
|
|
15
|
+
readonly mediaType: string | undefined;
|
|
16
|
+
constructor(mediaType: string | undefined);
|
|
17
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { SchemaValidationError, validateSchema, } from '../../core/index.js';
|
|
2
|
+
export function decodeQuery(searchParams) {
|
|
3
|
+
const query = {};
|
|
4
|
+
for (const [key, value] of searchParams) {
|
|
5
|
+
const current = query[key];
|
|
6
|
+
query[key] =
|
|
7
|
+
current === undefined
|
|
8
|
+
? value
|
|
9
|
+
: Array.isArray(current)
|
|
10
|
+
? [...current, value]
|
|
11
|
+
: [current, value];
|
|
12
|
+
}
|
|
13
|
+
return query;
|
|
14
|
+
}
|
|
15
|
+
export async function validateRequestHeaders(schema, bodyDeclared, headers) {
|
|
16
|
+
try {
|
|
17
|
+
return await validateSchema(schema, requestHeadersForValidation(headers));
|
|
18
|
+
}
|
|
19
|
+
catch (error) {
|
|
20
|
+
if (bodyDeclared &&
|
|
21
|
+
error instanceof SchemaValidationError &&
|
|
22
|
+
hasContentTypeIssue(error)) {
|
|
23
|
+
throw new HttpUnsupportedMediaTypeError(normalizeMediaType(headers.get('content-type')));
|
|
24
|
+
}
|
|
25
|
+
throw error;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
export function validatedContentType(headers) {
|
|
29
|
+
if (typeof headers !== 'object' || headers === null) {
|
|
30
|
+
throw new TypeError('HTTP body requires validated request headers');
|
|
31
|
+
}
|
|
32
|
+
const contentType = headers['content-type'];
|
|
33
|
+
if (typeof contentType !== 'string' || contentType.length === 0) {
|
|
34
|
+
throw new TypeError('HTTP body requires request.headers content-type to resolve to a string');
|
|
35
|
+
}
|
|
36
|
+
return contentType;
|
|
37
|
+
}
|
|
38
|
+
export async function decodeBody(request, contentType) {
|
|
39
|
+
const mediaType = normalizeMediaType(contentType);
|
|
40
|
+
if (mediaType === 'application/json' || mediaType.endsWith('+json')) {
|
|
41
|
+
try {
|
|
42
|
+
return await request.json();
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
throw new HttpInputDecodeError(error);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
if (mediaType === 'multipart/form-data') {
|
|
49
|
+
try {
|
|
50
|
+
return await request.formData();
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
throw new HttpInputDecodeError(error);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
if (mediaType.startsWith('text/')) {
|
|
57
|
+
try {
|
|
58
|
+
return await request.text();
|
|
59
|
+
}
|
|
60
|
+
catch (error) {
|
|
61
|
+
throw new HttpInputDecodeError(error);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return request.body;
|
|
65
|
+
}
|
|
66
|
+
function requestHeadersForValidation(headers) {
|
|
67
|
+
const decoded = Object.fromEntries(headers.entries());
|
|
68
|
+
const contentType = normalizeMediaType(headers.get('content-type'));
|
|
69
|
+
if (contentType)
|
|
70
|
+
decoded['content-type'] = contentType;
|
|
71
|
+
return decoded;
|
|
72
|
+
}
|
|
73
|
+
function hasContentTypeIssue(error) {
|
|
74
|
+
return error.issues.some((issue) => {
|
|
75
|
+
const first = issue.path?.[0];
|
|
76
|
+
const key = typeof first === 'object' && first !== null && 'key' in first
|
|
77
|
+
? first.key
|
|
78
|
+
: first;
|
|
79
|
+
return key === 'content-type';
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
function normalizeMediaType(value) {
|
|
83
|
+
const normalized = value?.split(';', 1)[0]?.trim().toLowerCase();
|
|
84
|
+
return normalized ? normalized : undefined;
|
|
85
|
+
}
|
|
86
|
+
export class HttpInputDecodeError extends Error {
|
|
87
|
+
cause;
|
|
88
|
+
constructor(cause) {
|
|
89
|
+
super('HTTP request body decode failed', { cause });
|
|
90
|
+
this.cause = cause;
|
|
91
|
+
this.name = 'HttpInputDecodeError';
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
export class HttpInputValidationError extends Error {
|
|
95
|
+
cause;
|
|
96
|
+
constructor(cause) {
|
|
97
|
+
super('HTTP request body validation failed', { cause });
|
|
98
|
+
this.cause = cause;
|
|
99
|
+
this.name = 'HttpInputValidationError';
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
export class HttpUnsupportedMediaTypeError extends Error {
|
|
103
|
+
mediaType;
|
|
104
|
+
constructor(mediaType) {
|
|
105
|
+
super('HTTP request content type is unsupported by the Contract');
|
|
106
|
+
this.mediaType = mediaType;
|
|
107
|
+
this.name = 'HttpUnsupportedMediaTypeError';
|
|
108
|
+
}
|
|
109
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type StandardSchemaV1 } from '../../core/index.js';
|
|
2
|
+
type HttpHeaderValue = string | readonly string[];
|
|
3
|
+
type HttpHeaders = Readonly<Record<string, HttpHeaderValue | undefined>>;
|
|
4
|
+
interface HttpResponseHeadersWithDefaults {
|
|
5
|
+
readonly schema: StandardSchemaV1;
|
|
6
|
+
readonly defaults: HttpHeaders;
|
|
7
|
+
}
|
|
8
|
+
type HttpResponseHeadersDefinition = StandardSchemaV1 | HttpHeaders | HttpResponseHeadersWithDefaults;
|
|
9
|
+
export declare function validateResponseHeaders(schema: StandardSchemaV1 | undefined, headers: HttpHeaders | undefined): Promise<HttpHeaders | undefined>;
|
|
10
|
+
export declare function responseHeadersSchema(headers: HttpResponseHeadersDefinition | undefined): StandardSchemaV1 | undefined;
|
|
11
|
+
export declare function responseHeadersDefaults(headers: HttpResponseHeadersDefinition | undefined): HttpHeaders | undefined;
|
|
12
|
+
export declare function isStandardSchema(value: unknown): value is StandardSchemaV1;
|
|
13
|
+
export declare function isResponseHeadersWithDefaults(value: unknown): value is HttpResponseHeadersWithDefaults;
|
|
14
|
+
export declare function mergeResponseHeaders(defaults: HttpHeaders | undefined, dynamic: HttpHeaders | undefined): Headers;
|
|
15
|
+
export declare function applyResponseHeaders(headers: Headers, source: HttpHeaders | undefined): void;
|
|
16
|
+
export declare function applyFrameworkHeadersToResponse(response: Response, source: Headers | undefined): Response;
|
|
17
|
+
export declare function applyFrameworkResponseHeaders(headers: Headers, source: HttpHeaders | undefined): void;
|
|
18
|
+
export {};
|