@astrale-os/kernel-server 0.5.0-beta.9 → 0.5.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/dist/capture.d.ts +0 -1
- package/dist/capture.js +0 -1
- package/dist/cors/cors.d.ts +0 -1
- package/dist/cors/cors.js +11 -4
- package/dist/cors/index.d.ts +0 -1
- package/dist/cors/index.js +0 -1
- package/dist/cors/types.d.ts +0 -1
- package/dist/cors/types.js +0 -1
- package/dist/errors/admission.d.ts +7 -0
- package/dist/errors/admission.js +22 -0
- package/dist/errors/availability.d.ts +0 -1
- package/dist/errors/availability.js +0 -1
- package/dist/errors/classify.d.ts +10 -1
- package/dist/errors/classify.js +25 -1
- package/dist/errors/index.d.ts +2 -2
- package/dist/errors/index.js +2 -2
- package/dist/errors/request-body.d.ts +0 -1
- package/dist/errors/request-body.js +0 -1
- package/dist/errors/response-body.d.ts +0 -1
- package/dist/errors/response-body.js +0 -1
- package/dist/index.d.ts +3 -4
- package/dist/index.js +2 -3
- package/dist/invocation/context.d.ts +2 -2
- package/dist/invocation/context.js +2 -2
- package/dist/invocation/identity.d.ts +0 -1
- package/dist/invocation/identity.js +0 -1
- package/dist/invocation/index.d.ts +1 -2
- package/dist/invocation/index.js +1 -2
- package/dist/invocation/release-route.d.ts +22 -0
- package/dist/invocation/release-route.js +32 -0
- package/dist/invocation/types.d.ts +9 -6
- package/dist/invocation/types.js +0 -1
- package/dist/issuer/exchange.d.ts +0 -1
- package/dist/issuer/exchange.js +20 -10
- package/dist/issuer/index.d.ts +0 -1
- package/dist/issuer/index.js +0 -1
- package/dist/issuer/routes.d.ts +0 -1
- package/dist/issuer/routes.js +57 -48
- package/dist/issuer/types.d.ts +5 -1
- package/dist/issuer/types.js +0 -1
- package/dist/lifecycle/active.d.ts +6 -2
- package/dist/lifecycle/active.js +55 -14
- package/dist/lifecycle/index.d.ts +0 -1
- package/dist/lifecycle/index.js +0 -1
- package/dist/release/delivery/handler.d.ts +9 -0
- package/dist/{publication → release}/delivery/handler.js +18 -13
- package/dist/release/delivery/index.d.ts +1 -0
- package/dist/release/delivery/index.js +1 -0
- package/dist/{publication → release}/delivery/types.d.ts +4 -5
- package/dist/release/delivery/types.js +1 -0
- package/dist/release/index.d.ts +3 -0
- package/dist/release/index.js +2 -0
- package/dist/release/served.d.ts +21 -0
- package/dist/release/served.js +10 -0
- package/dist/release/snapshot.d.ts +22 -0
- package/dist/release/snapshot.js +49 -0
- package/dist/release/table.d.ts +4 -0
- package/dist/release/table.js +11 -0
- package/dist/release/types.d.ts +23 -0
- package/dist/release/types.js +1 -0
- package/dist/routes/address.d.ts +2 -0
- package/dist/routes/address.js +6 -0
- package/dist/routes/binary.d.ts +9 -0
- package/dist/routes/binary.js +110 -0
- package/dist/routes/bundle.d.ts +5 -0
- package/dist/routes/bundle.js +50 -0
- package/dist/routes/csrf.d.ts +16 -0
- package/dist/routes/csrf.js +35 -0
- package/dist/routes/document.d.ts +6 -0
- package/dist/routes/document.js +57 -0
- package/dist/routes/index.d.ts +3 -2
- package/dist/routes/index.js +2 -2
- package/dist/routes/model.d.ts +15 -0
- package/dist/routes/model.js +1 -0
- package/dist/routes/native.d.ts +17 -0
- package/dist/routes/native.js +136 -0
- package/dist/routes/preflight.d.ts +4 -0
- package/dist/routes/preflight.js +55 -0
- package/dist/routes/response.d.ts +14 -0
- package/dist/routes/response.js +33 -0
- package/dist/routes/routes.d.ts +7 -24
- package/dist/routes/routes.js +24 -439
- package/dist/routes/snapshot.d.ts +13 -0
- package/dist/routes/snapshot.js +39 -0
- package/dist/routes/stream.d.ts +6 -0
- package/dist/routes/stream.js +122 -0
- package/dist/server.d.ts +0 -1
- package/dist/server.js +121 -53
- package/dist/transport/body.d.ts +0 -1
- package/dist/transport/body.js +0 -1
- package/dist/transport/codecs.d.ts +2 -3
- package/dist/transport/codecs.js +4 -4
- package/dist/transport/credential.d.ts +0 -1
- package/dist/transport/credential.js +0 -1
- package/dist/transport/http/binary-request.d.ts +11 -0
- package/dist/transport/http/binary-request.js +102 -0
- package/dist/transport/http/binary.d.ts +6 -0
- package/dist/transport/http/binary.js +35 -0
- package/dist/transport/http/byte-stream.d.ts +4 -0
- package/dist/transport/http/byte-stream.js +123 -0
- package/dist/transport/http/control.d.ts +12 -0
- package/dist/transport/http/control.js +24 -0
- package/dist/transport/http/handler.d.ts +8 -3
- package/dist/transport/http/handler.js +98 -45
- package/dist/transport/http/index.d.ts +3 -2
- package/dist/transport/http/index.js +2 -2
- package/dist/transport/http/model.d.ts +20 -0
- package/dist/transport/http/model.js +1 -0
- package/dist/transport/http/render.d.ts +3 -31
- package/dist/transport/http/render.js +25 -269
- package/dist/transport/http/response.d.ts +14 -0
- package/dist/transport/http/response.js +77 -0
- package/dist/transport/http/stream.d.ts +5 -0
- package/dist/transport/http/stream.js +134 -0
- package/dist/transport/index.d.ts +2 -2
- package/dist/transport/index.js +2 -2
- package/dist/transport/result.d.ts +13 -0
- package/dist/transport/result.js +35 -0
- package/dist/transport/router.d.ts +0 -1
- package/dist/transport/router.js +0 -1
- package/dist/transport/stream-error.d.ts +0 -1
- package/dist/transport/stream-error.js +0 -1
- package/dist/transport/types.d.ts +0 -1
- package/dist/transport/types.js +0 -1
- package/dist/transport/websocket/index.d.ts +0 -1
- package/dist/transport/websocket/index.js +0 -1
- package/dist/transport/websocket/session.d.ts +3 -3
- package/dist/transport/websocket/session.js +38 -30
- package/dist/transport/websocket/upgrade.d.ts +2 -3
- package/dist/transport/websocket/upgrade.js +7 -7
- package/dist/types.d.ts +43 -10
- package/dist/types.js +0 -1
- package/package.json +11 -22
- package/dist/capture.d.ts.map +0 -1
- package/dist/capture.js.map +0 -1
- package/dist/cors/cors.d.ts.map +0 -1
- package/dist/cors/cors.js.map +0 -1
- package/dist/cors/index.d.ts.map +0 -1
- package/dist/cors/index.js.map +0 -1
- package/dist/cors/types.d.ts.map +0 -1
- package/dist/cors/types.js.map +0 -1
- package/dist/errors/availability.d.ts.map +0 -1
- package/dist/errors/availability.js.map +0 -1
- package/dist/errors/classify.d.ts.map +0 -1
- package/dist/errors/classify.js.map +0 -1
- package/dist/errors/index.d.ts.map +0 -1
- package/dist/errors/index.js.map +0 -1
- package/dist/errors/request-body.d.ts.map +0 -1
- package/dist/errors/request-body.js.map +0 -1
- package/dist/errors/response-body.d.ts.map +0 -1
- package/dist/errors/response-body.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/invocation/context.d.ts.map +0 -1
- package/dist/invocation/context.js.map +0 -1
- package/dist/invocation/identity.d.ts.map +0 -1
- package/dist/invocation/identity.js.map +0 -1
- package/dist/invocation/index.d.ts.map +0 -1
- package/dist/invocation/index.js.map +0 -1
- package/dist/invocation/publication-route.d.ts +0 -14
- package/dist/invocation/publication-route.d.ts.map +0 -1
- package/dist/invocation/publication-route.js +0 -45
- package/dist/invocation/publication-route.js.map +0 -1
- package/dist/invocation/types.d.ts.map +0 -1
- package/dist/invocation/types.js.map +0 -1
- package/dist/issuer/exchange.d.ts.map +0 -1
- package/dist/issuer/exchange.js.map +0 -1
- package/dist/issuer/index.d.ts.map +0 -1
- package/dist/issuer/index.js.map +0 -1
- package/dist/issuer/routes.d.ts.map +0 -1
- package/dist/issuer/routes.js.map +0 -1
- package/dist/issuer/types.d.ts.map +0 -1
- package/dist/issuer/types.js.map +0 -1
- package/dist/lifecycle/active.d.ts.map +0 -1
- package/dist/lifecycle/active.js.map +0 -1
- package/dist/lifecycle/index.d.ts.map +0 -1
- package/dist/lifecycle/index.js.map +0 -1
- package/dist/publication/delivery/handler.d.ts +0 -10
- package/dist/publication/delivery/handler.d.ts.map +0 -1
- package/dist/publication/delivery/handler.js.map +0 -1
- package/dist/publication/delivery/index.d.ts +0 -3
- package/dist/publication/delivery/index.d.ts.map +0 -1
- package/dist/publication/delivery/index.js +0 -2
- package/dist/publication/delivery/index.js.map +0 -1
- package/dist/publication/delivery/types.d.ts.map +0 -1
- package/dist/publication/delivery/types.js +0 -2
- package/dist/publication/delivery/types.js.map +0 -1
- package/dist/publication/index.d.ts +0 -4
- package/dist/publication/index.d.ts.map +0 -1
- package/dist/publication/index.js +0 -3
- package/dist/publication/index.js.map +0 -1
- package/dist/publication/snapshot.d.ts +0 -17
- package/dist/publication/snapshot.d.ts.map +0 -1
- package/dist/publication/snapshot.js +0 -38
- package/dist/publication/snapshot.js.map +0 -1
- package/dist/publication/table.d.ts +0 -5
- package/dist/publication/table.d.ts.map +0 -1
- package/dist/publication/table.js +0 -17
- package/dist/publication/table.js.map +0 -1
- package/dist/publication/types.d.ts +0 -23
- package/dist/publication/types.d.ts.map +0 -1
- package/dist/publication/types.js +0 -2
- package/dist/publication/types.js.map +0 -1
- package/dist/routes/index.d.ts.map +0 -1
- package/dist/routes/index.js.map +0 -1
- package/dist/routes/routes.d.ts.map +0 -1
- package/dist/routes/routes.js.map +0 -1
- package/dist/server.d.ts.map +0 -1
- package/dist/server.js.map +0 -1
- package/dist/transport/body.d.ts.map +0 -1
- package/dist/transport/body.js.map +0 -1
- package/dist/transport/codecs.d.ts.map +0 -1
- package/dist/transport/codecs.js.map +0 -1
- package/dist/transport/credential.d.ts.map +0 -1
- package/dist/transport/credential.js.map +0 -1
- package/dist/transport/http/handler.d.ts.map +0 -1
- package/dist/transport/http/handler.js.map +0 -1
- package/dist/transport/http/index.d.ts.map +0 -1
- package/dist/transport/http/index.js.map +0 -1
- package/dist/transport/http/render.d.ts.map +0 -1
- package/dist/transport/http/render.js.map +0 -1
- package/dist/transport/index.d.ts.map +0 -1
- package/dist/transport/index.js.map +0 -1
- package/dist/transport/router.d.ts.map +0 -1
- package/dist/transport/router.js.map +0 -1
- package/dist/transport/stream-error.d.ts.map +0 -1
- package/dist/transport/stream-error.js.map +0 -1
- package/dist/transport/types.d.ts.map +0 -1
- package/dist/transport/types.js.map +0 -1
- package/dist/transport/websocket/index.d.ts.map +0 -1
- package/dist/transport/websocket/index.js.map +0 -1
- package/dist/transport/websocket/session.d.ts.map +0 -1
- package/dist/transport/websocket/session.js.map +0 -1
- package/dist/transport/websocket/upgrade.d.ts.map +0 -1
- package/dist/transport/websocket/upgrade.js.map +0 -1
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js.map +0 -1
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { json } from '@astrale-os/kernel-protocol/codecs';
|
|
2
|
+
import * as errors from '@astrale-os/kernel-protocol/errors';
|
|
3
|
+
import * as protocol from '@astrale-os/kernel-protocol/invocation';
|
|
4
|
+
import { deploymentRetiredBody, deploymentRetiredHeaders, HTTP_DEPLOYMENT_RETIRED, HTTP_DEPLOYMENT_RETIRED_STATUS, } from '@astrale-os/kernel-protocol/routes';
|
|
5
|
+
import { retryAfterHeaders } from '../../errors/index.js';
|
|
6
|
+
import { envelopeResponse, errorEnvelopeResponse, toBody } from './response.js';
|
|
7
|
+
/** Render a correlated error with its status, authentication challenge and retry delay. */
|
|
8
|
+
export function renderHttpError(requestId, invocation, error, codec, cors, options = {}) {
|
|
9
|
+
const status = options.status ?? errors.httpStatusOf(error);
|
|
10
|
+
const retry = retryAfterHeaders(error);
|
|
11
|
+
const extra = status === 401 ? { 'www-authenticate': 'Bearer realm="astrale-invocation"' } : retry;
|
|
12
|
+
return errorEnvelopeResponse(codec, { error, requestId, invocation }, { ...cors(Object.keys(retry)), ...extra }, status, options.negotiated ?? true, options.maximumResponseBytes);
|
|
13
|
+
}
|
|
14
|
+
/** Present stale routing as a bounded status-200 Invocation envelope. */
|
|
15
|
+
export function renderHttpStale(requestId, invocation, current, codec, cors, maximumResponseBytes) {
|
|
16
|
+
return envelopeResponse(codec, protocol.stale(requestId, invocation, current), cors(), 200, true, maximumResponseBytes);
|
|
17
|
+
}
|
|
18
|
+
/** Retirement controls always use JSON, regardless of the negotiated request codec. */
|
|
19
|
+
export function renderDeploymentRetired(deployment, release, cors) {
|
|
20
|
+
return new Response(toBody(json.encode(deploymentRetiredBody(deployment, release))), {
|
|
21
|
+
status: HTTP_DEPLOYMENT_RETIRED_STATUS,
|
|
22
|
+
headers: { ...cors([HTTP_DEPLOYMENT_RETIRED]), ...deploymentRetiredHeaders() },
|
|
23
|
+
});
|
|
24
|
+
}
|
|
@@ -1,18 +1,23 @@
|
|
|
1
1
|
import type { CorsPolicy } from '../../cors/index.js';
|
|
2
2
|
import type { NextInvocationId } from '../../invocation/index.js';
|
|
3
3
|
import type { ActiveOperations } from '../../lifecycle/index.js';
|
|
4
|
-
import type {
|
|
4
|
+
import type { RequestServing } from '../../release/served.js';
|
|
5
5
|
import { type ApplicationHost, type Handler } from '../../invocation/index.js';
|
|
6
6
|
export interface HttpHandlerConfig {
|
|
7
7
|
readonly handler: Handler;
|
|
8
8
|
readonly active: ActiveOperations;
|
|
9
9
|
readonly invocation: NextInvocationId;
|
|
10
10
|
readonly maximumRequestBytes: number;
|
|
11
|
+
readonly maximumBinaryRequestBytes: number;
|
|
11
12
|
readonly maximumResponseBytes: number;
|
|
12
13
|
readonly invocationTimeoutMs: number;
|
|
14
|
+
readonly binaryRequestTimeoutMs: number;
|
|
15
|
+
readonly binaryRequestIdleTimeoutMs?: number;
|
|
16
|
+
readonly binaryDownloadTarget?: string;
|
|
17
|
+
readonly binaryDownloadTimeoutMs?: number;
|
|
13
18
|
readonly cors: CorsPolicy;
|
|
14
19
|
readonly websocket: boolean;
|
|
15
|
-
|
|
20
|
+
/** Present exactly when the Server serves a Release. */
|
|
21
|
+
readonly serving?: (request: Request) => RequestServing;
|
|
16
22
|
}
|
|
17
23
|
export declare function createHttpHandler(config: HttpHandlerConfig): (request: Request, host?: ApplicationHost) => Promise<Response>;
|
|
18
|
-
//# sourceMappingURL=handler.d.ts.map
|
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
import * as codecs from '@astrale-os/kernel-protocol/codecs';
|
|
2
2
|
import * as errors from '@astrale-os/kernel-protocol/errors';
|
|
3
3
|
import * as protocol from '@astrale-os/kernel-protocol/invocation';
|
|
4
|
-
import { classifyError, RequestBodyInvalidError, RequestBodyTooLargeError, } from '../../errors/index.js';
|
|
5
|
-
import {
|
|
4
|
+
import { admissionRefusal, classifyError, classifyRequestError, RequestBodyInvalidError, RequestBodyTooLargeError, } from '../../errors/index.js';
|
|
5
|
+
import { admitVia, invocationContext, } from '../../invocation/index.js';
|
|
6
|
+
import { pinned } from '../../release/served.js';
|
|
6
7
|
import { readBoundedBody } from '../body.js';
|
|
7
8
|
import { loadCodecs } from '../codecs.js';
|
|
8
9
|
import { resolveCredential } from '../credential.js';
|
|
9
|
-
import {
|
|
10
|
+
import { isStreamingBinary } from '../result.js';
|
|
11
|
+
import { binaryRequestBody } from './binary-request.js';
|
|
12
|
+
import { renderDeploymentRetired, renderHttpError } from './control.js';
|
|
13
|
+
import { renderHttpResult } from './render.js';
|
|
10
14
|
export function createHttpHandler(config) {
|
|
11
15
|
return async (request, host) => {
|
|
12
16
|
const cors = (exposedHeaders) => config.cors.response(request, exposedHeaders);
|
|
@@ -21,6 +25,8 @@ export function createHttpHandler(config) {
|
|
|
21
25
|
headers: [
|
|
22
26
|
'authorization',
|
|
23
27
|
'content-type',
|
|
28
|
+
protocol.http.REQUEST_ENVELOPE_FIELD,
|
|
29
|
+
protocol.http.BINARY_LENGTH_FIELD,
|
|
24
30
|
protocol.http.TRACEPARENT_FIELD,
|
|
25
31
|
protocol.http.TRACESTATE_FIELD,
|
|
26
32
|
],
|
|
@@ -37,24 +43,34 @@ export function createHttpHandler(config) {
|
|
|
37
43
|
...options,
|
|
38
44
|
maximumResponseBytes: config.maximumResponseBytes,
|
|
39
45
|
});
|
|
40
|
-
const
|
|
46
|
+
const binaryRequest = request.headers.get('content-type')?.trim().toLowerCase() ===
|
|
47
|
+
protocol.http.BINARY_REQUEST_CONTENT_TYPE;
|
|
48
|
+
const active = config.active.begin(binaryRequest ? config.binaryRequestTimeoutMs : config.invocationTimeoutMs, request.signal);
|
|
41
49
|
if (active === undefined) {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
50
|
+
if (binaryRequest && request.body !== null && !request.body.locked) {
|
|
51
|
+
void request.body.cancel('binary request rejected').catch(() => undefined);
|
|
52
|
+
}
|
|
53
|
+
return renderError(null, admissionRefusal(config.active.isAccepting), codecs.json, {
|
|
54
|
+
status: 503,
|
|
55
|
+
negotiated: false,
|
|
56
|
+
});
|
|
46
57
|
}
|
|
47
58
|
let handedOff = false;
|
|
59
|
+
let binary;
|
|
48
60
|
try {
|
|
49
|
-
const supported =
|
|
61
|
+
const supported = loadCodecs();
|
|
50
62
|
const contentType = request.headers.get('content-type');
|
|
51
|
-
|
|
63
|
+
// No default representation: a body without a declared Astrale type is never decoded, so a
|
|
64
|
+
// browser cannot send an admissible invocation from another origin without a CORS preflight.
|
|
65
|
+
const incoming = binaryRequest
|
|
52
66
|
? codecs.json
|
|
53
67
|
: protocol.http.codecForContentType(contentType, supported);
|
|
54
68
|
if (incoming === undefined) {
|
|
55
69
|
return renderError(null, {
|
|
56
70
|
code: errors.CODES.UNSUPPORTED,
|
|
57
|
-
message:
|
|
71
|
+
message: contentType === null || contentType.trim() === ''
|
|
72
|
+
? 'Missing request Content-Type.'
|
|
73
|
+
: 'Unsupported request Content-Type.',
|
|
58
74
|
}, codecs.json, { status: 415, negotiated: false });
|
|
59
75
|
}
|
|
60
76
|
const outgoing = protocol.http.negotiateResponseCodec(request.headers.get('accept'), incoming, supported);
|
|
@@ -66,7 +82,15 @@ export function createHttpHandler(config) {
|
|
|
66
82
|
}
|
|
67
83
|
let body;
|
|
68
84
|
try {
|
|
69
|
-
|
|
85
|
+
if (binaryRequest)
|
|
86
|
+
binary = binaryRequestBody(request, config.maximumBinaryRequestBytes, active.signal, config.binaryRequestIdleTimeoutMs === undefined
|
|
87
|
+
? undefined
|
|
88
|
+
: {
|
|
89
|
+
timeoutMs: config.binaryRequestIdleTimeoutMs,
|
|
90
|
+
cancel: () => active.cancel('binary request idle timeout exceeded'),
|
|
91
|
+
});
|
|
92
|
+
else
|
|
93
|
+
body = await readBoundedBody(request, config.maximumRequestBytes, active.signal);
|
|
70
94
|
}
|
|
71
95
|
catch (input) {
|
|
72
96
|
const payload = input instanceof RequestBodyTooLargeError
|
|
@@ -87,37 +111,54 @@ export function createHttpHandler(config) {
|
|
|
87
111
|
status: input instanceof RequestBodyTooLargeError ? 413 : errors.httpStatusOf(payload),
|
|
88
112
|
});
|
|
89
113
|
}
|
|
90
|
-
let decoded;
|
|
91
|
-
try {
|
|
92
|
-
decoded = incoming.decode(body);
|
|
93
|
-
}
|
|
94
|
-
catch (input) {
|
|
95
|
-
if (!(input instanceof codecs.DecodeError))
|
|
96
|
-
throw input;
|
|
97
|
-
return renderError(null, { code: errors.CODES.PARSE_ERROR, message: 'Request body is invalid.' }, outgoing);
|
|
98
|
-
}
|
|
99
114
|
let envelope;
|
|
100
115
|
try {
|
|
101
|
-
|
|
116
|
+
if (binaryRequest) {
|
|
117
|
+
envelope = protocol.http.decodeBinaryRequestEnvelope(request.headers.get(protocol.http.REQUEST_ENVELOPE_FIELD));
|
|
118
|
+
if (envelope.idempotencyKey !== undefined) {
|
|
119
|
+
return renderError(envelope.requestId, {
|
|
120
|
+
code: errors.CODES.INVALID_REQUEST,
|
|
121
|
+
message: 'Binary requests forbid idempotencyKey.',
|
|
122
|
+
}, outgoing);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
let decoded;
|
|
127
|
+
try {
|
|
128
|
+
decoded = incoming.decode(body);
|
|
129
|
+
}
|
|
130
|
+
catch (input) {
|
|
131
|
+
if (!(input instanceof codecs.DecodeError))
|
|
132
|
+
throw input;
|
|
133
|
+
return renderError(null, { code: errors.CODES.PARSE_ERROR, message: 'Request body is invalid.' }, outgoing);
|
|
134
|
+
}
|
|
135
|
+
envelope = protocol.decodeRequest(decoded);
|
|
136
|
+
}
|
|
102
137
|
}
|
|
103
138
|
catch (input) {
|
|
104
139
|
return renderError(null, classifyError(input), outgoing);
|
|
105
140
|
}
|
|
106
|
-
|
|
107
|
-
|
|
141
|
+
if (!binaryRequest &&
|
|
142
|
+
config.binaryDownloadTarget !== undefined &&
|
|
143
|
+
protocol.targetPath(envelope.call.target) === config.binaryDownloadTarget) {
|
|
144
|
+
active.extend(config.binaryDownloadTimeoutMs);
|
|
145
|
+
}
|
|
146
|
+
if (active.signal.aborted) {
|
|
147
|
+
return renderError(envelope.requestId, classifyRequestError(active.signal.reason, active), outgoing);
|
|
148
|
+
}
|
|
149
|
+
const serving = config.serving?.(request);
|
|
150
|
+
const served = serving?.current();
|
|
151
|
+
if (serving !== undefined && served === undefined) {
|
|
108
152
|
return renderError(envelope.requestId, {
|
|
109
153
|
code: errors.CODES.BACKEND_UNAVAILABLE,
|
|
110
|
-
message: '
|
|
154
|
+
message: 'Release is unavailable.',
|
|
111
155
|
}, outgoing, { status: 503 });
|
|
112
156
|
}
|
|
113
157
|
if (envelope.routing?.kind === 'via') {
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
message: 'Publication routing requires a Publication-backed destination.',
|
|
118
|
-
}, outgoing);
|
|
158
|
+
const decision = admitVia(served, envelope.routing);
|
|
159
|
+
if (decision.kind === 'retired') {
|
|
160
|
+
return renderDeploymentRetired(serving.deployment(), decision.release, cors);
|
|
119
161
|
}
|
|
120
|
-
const decision = publicationRouteDecision(publication.publication, envelope.routing.publication);
|
|
121
162
|
if (decision.kind === 'rejected') {
|
|
122
163
|
return renderError(envelope.requestId, decision.error, outgoing);
|
|
123
164
|
}
|
|
@@ -135,9 +176,21 @@ export function createHttpHandler(config) {
|
|
|
135
176
|
...(envelope.delegate === undefined ? {} : { delegate: envelope.delegate }),
|
|
136
177
|
...(envelope.routing?.kind === 'via' ? { via: envelope.routing } : {}),
|
|
137
178
|
...(envelope.schema === undefined ? {} : { schema: envelope.schema }),
|
|
138
|
-
...(
|
|
139
|
-
|
|
179
|
+
...(envelope.maintenance === undefined ? {} : { maintenance: envelope.maintenance }),
|
|
180
|
+
...(served === undefined ? {} : pinned(served)),
|
|
181
|
+
context: invocationContext(assigned, active, config.active, host, undefined, envelope.idempotencyKey, binary),
|
|
140
182
|
}));
|
|
183
|
+
if (binary !== undefined && result.kind !== 'redirect' && result.kind !== 'miss') {
|
|
184
|
+
if (!binary.completed()) {
|
|
185
|
+
if (result.kind === 'stream') {
|
|
186
|
+
await result.stream.cancel('Binary request body was not fully consumed.');
|
|
187
|
+
}
|
|
188
|
+
else if (result.kind === 'binary' && isStreamingBinary(result.value)) {
|
|
189
|
+
await result.value.body[Symbol.asyncIterator]().return?.();
|
|
190
|
+
}
|
|
191
|
+
throw new Error('Binary Function returned before consuming its request body.');
|
|
192
|
+
}
|
|
193
|
+
}
|
|
141
194
|
const response = renderHttpResult(result, {
|
|
142
195
|
requestId: envelope.requestId,
|
|
143
196
|
codec: outgoing,
|
|
@@ -146,20 +199,12 @@ export function createHttpHandler(config) {
|
|
|
146
199
|
active,
|
|
147
200
|
maximumResponseBytes: config.maximumResponseBytes,
|
|
148
201
|
});
|
|
149
|
-
handedOff =
|
|
202
|
+
handedOff =
|
|
203
|
+
result.kind === 'stream' || (result.kind === 'binary' && isStreamingBinary(result.value));
|
|
150
204
|
return response;
|
|
151
205
|
}
|
|
152
206
|
catch (input) {
|
|
153
|
-
|
|
154
|
-
return renderError(envelope.requestId, {
|
|
155
|
-
code: errors.CODES.DEADLINE_EXCEEDED,
|
|
156
|
-
message: 'Invocation deadline exceeded.',
|
|
157
|
-
}, outgoing, { status: 504 });
|
|
158
|
-
}
|
|
159
|
-
if (active.signal.aborted) {
|
|
160
|
-
return renderError(envelope.requestId, { code: errors.CODES.CANCELLED, message: 'Invocation was cancelled.' }, outgoing, { status: 408 });
|
|
161
|
-
}
|
|
162
|
-
return renderError(envelope.requestId, classifyError(input), outgoing);
|
|
207
|
+
return renderError(envelope.requestId, classifyRequestError(input, active), outgoing);
|
|
163
208
|
}
|
|
164
209
|
}
|
|
165
210
|
catch (input) {
|
|
@@ -168,6 +213,15 @@ export function createHttpHandler(config) {
|
|
|
168
213
|
});
|
|
169
214
|
}
|
|
170
215
|
finally {
|
|
216
|
+
if (binary !== undefined) {
|
|
217
|
+
binary.cancel('binary invocation completed');
|
|
218
|
+
}
|
|
219
|
+
else if (binaryRequest &&
|
|
220
|
+
binary === undefined &&
|
|
221
|
+
request.body !== null &&
|
|
222
|
+
!request.body.locked) {
|
|
223
|
+
void request.body.cancel('binary request rejected').catch(() => undefined);
|
|
224
|
+
}
|
|
171
225
|
if (!handedOff)
|
|
172
226
|
active.settle();
|
|
173
227
|
}
|
|
@@ -178,4 +232,3 @@ function noStore(response) {
|
|
|
178
232
|
headers.set('cache-control', 'no-store');
|
|
179
233
|
return new Response(response.body, { status: response.status, headers });
|
|
180
234
|
}
|
|
181
|
-
//# sourceMappingURL=handler.js.map
|
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
export { createHttpHandler, type HttpHandlerConfig } from './handler.js';
|
|
2
|
-
export {
|
|
3
|
-
|
|
2
|
+
export { renderHttpResult } from './render.js';
|
|
3
|
+
export { renderHttpError, renderHttpStale } from './control.js';
|
|
4
|
+
export type { CorsHeaders, ErrorRenderOptions, RenderContext } from './model.js';
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export { createHttpHandler } from './handler.js';
|
|
2
|
-
export {
|
|
3
|
-
|
|
2
|
+
export { renderHttpResult } from './render.js';
|
|
3
|
+
export { renderHttpError, renderHttpStale } from './control.js';
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { Codec } from '@astrale-os/kernel-protocol/codecs';
|
|
2
|
+
import type * as protocol from '@astrale-os/kernel-protocol/invocation';
|
|
3
|
+
import type { ActiveOperation } from '../../lifecycle/index.js';
|
|
4
|
+
/** Correlation, binding and active lifetime retained while presenting one result. */
|
|
5
|
+
export interface RenderContext {
|
|
6
|
+
readonly requestId: protocol.RequestId;
|
|
7
|
+
readonly codec: Codec;
|
|
8
|
+
readonly cors: CorsHeaders;
|
|
9
|
+
readonly invocation: protocol.InvocationId;
|
|
10
|
+
readonly active: ActiveOperation;
|
|
11
|
+
readonly maximumResponseBytes: number;
|
|
12
|
+
}
|
|
13
|
+
/** Derive response headers with the transport fields exposed to the browser. */
|
|
14
|
+
export type CorsHeaders = (exposedHeaders?: readonly string[]) => Readonly<Record<string, string>>;
|
|
15
|
+
/** Bound and negotiate an error using the admitted request presentation. */
|
|
16
|
+
export interface ErrorRenderOptions {
|
|
17
|
+
readonly status?: number;
|
|
18
|
+
readonly negotiated?: boolean;
|
|
19
|
+
readonly maximumResponseBytes?: number;
|
|
20
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,32 +1,4 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
import type { Handler } from '../../invocation/index.js';
|
|
5
|
-
import type { ActiveOperation } from '../../lifecycle/index.js';
|
|
6
|
-
export interface RenderContext {
|
|
7
|
-
readonly requestId: protocol.RequestId;
|
|
8
|
-
readonly codec: Codec;
|
|
9
|
-
readonly cors: CorsHeaders;
|
|
10
|
-
readonly invocation: protocol.InvocationId;
|
|
11
|
-
readonly active: ActiveOperation;
|
|
12
|
-
readonly maximumResponseBytes: number;
|
|
13
|
-
}
|
|
14
|
-
export type CorsHeaders = (exposedHeaders?: readonly string[]) => Readonly<Record<string, string>>;
|
|
15
|
-
export interface ErrorRenderOptions {
|
|
16
|
-
readonly status?: number;
|
|
17
|
-
readonly negotiated?: boolean;
|
|
18
|
-
readonly maximumResponseBytes?: number;
|
|
19
|
-
}
|
|
20
|
-
type HandlerResult = Awaited<ReturnType<Handler['dispatch']>>;
|
|
1
|
+
import type { HandlerResult } from '../../invocation/index.js';
|
|
2
|
+
import type { RenderContext } from './model.js';
|
|
3
|
+
/** Render one admitted Handler result and retain only live producers in the active operation. */
|
|
21
4
|
export declare function renderHttpResult(result: HandlerResult, context: RenderContext): Response;
|
|
22
|
-
export declare function renderBinary(requestId: protocol.RequestId, invocation: protocol.InvocationId, binary: Extract<HandlerResult, {
|
|
23
|
-
readonly kind: 'binary';
|
|
24
|
-
}>['value']): protocol.BinaryResponse;
|
|
25
|
-
export declare function renderRedirect(requestId: protocol.RequestId, invocation: protocol.InvocationId, redirect: Extract<HandlerResult, {
|
|
26
|
-
readonly kind: 'redirect';
|
|
27
|
-
}>['redirect']): protocol.RedirectResponse;
|
|
28
|
-
export declare function renderHttpError(requestId: protocol.RequestId, invocation: protocol.InvocationId, error: errors.ErrorPayload, codec: Codec, cors: CorsHeaders, options?: ErrorRenderOptions): Response;
|
|
29
|
-
export declare function renderHttpStale(requestId: protocol.RequestId, invocation: protocol.InvocationId, current: protocol.Stale['current'], codec: Codec, cors: CorsHeaders, maximumResponseBytes?: number): Response;
|
|
30
|
-
export declare function encodeEnvelope(codec: Codec, input: unknown): string | Uint8Array;
|
|
31
|
-
export {};
|
|
32
|
-
//# sourceMappingURL=render.d.ts.map
|