@astrale-os/kernel-server 0.5.0-beta.1 → 0.5.0-beta.10
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 +0 -1
- 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/availability.d.ts +3 -4
- package/dist/errors/availability.js +4 -5
- package/dist/errors/classify.d.ts +2 -3
- package/dist/errors/classify.js +4 -217
- package/dist/errors/index.d.ts +1 -2
- package/dist/errors/index.js +1 -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 -3
- package/dist/index.js +2 -2
- package/dist/invocation/context.d.ts +2 -3
- package/dist/invocation/context.js +2 -4
- package/dist/invocation/identity.d.ts +9 -0
- package/dist/invocation/identity.js +11 -0
- package/dist/invocation/index.d.ts +3 -2
- package/dist/invocation/index.js +2 -1
- package/dist/invocation/publication-route.d.ts +13 -0
- package/dist/invocation/publication-route.js +44 -0
- package/dist/invocation/types.d.ts +38 -10
- package/dist/invocation/types.js +0 -1
- package/dist/issuer/exchange.d.ts +12 -0
- package/dist/issuer/exchange.js +136 -0
- package/dist/issuer/index.d.ts +1 -1
- package/dist/issuer/index.js +0 -1
- package/dist/issuer/routes.d.ts +3 -3
- package/dist/issuer/routes.js +25 -14
- package/dist/issuer/types.d.ts +2 -2
- package/dist/issuer/types.js +0 -1
- package/dist/lifecycle/active.d.ts +0 -1
- package/dist/lifecycle/active.js +0 -1
- package/dist/lifecycle/index.d.ts +0 -1
- package/dist/lifecycle/index.js +0 -1
- package/dist/publication/delivery/handler.d.ts +9 -0
- package/dist/{installation → publication/delivery}/handler.js +29 -28
- package/dist/publication/delivery/index.d.ts +2 -0
- package/dist/publication/delivery/index.js +1 -0
- package/dist/publication/delivery/types.d.ts +11 -0
- package/dist/publication/delivery/types.js +1 -0
- package/dist/publication/index.d.ts +1 -1
- package/dist/publication/index.js +1 -1
- package/dist/publication/snapshot.d.ts +5 -3
- package/dist/publication/snapshot.js +14 -7
- package/dist/publication/table.d.ts +4 -0
- package/dist/publication/table.js +16 -0
- package/dist/publication/types.d.ts +5 -2
- package/dist/publication/types.js +0 -1
- package/dist/routes/index.d.ts +0 -1
- package/dist/routes/index.js +0 -1
- package/dist/routes/routes.d.ts +6 -5
- package/dist/routes/routes.js +51 -41
- package/dist/server.d.ts +0 -1
- package/dist/server.js +56 -16
- package/dist/transport/body.d.ts +0 -1
- package/dist/transport/body.js +0 -1
- package/dist/transport/codecs.d.ts +1 -2
- package/dist/transport/codecs.js +1 -2
- package/dist/transport/credential.d.ts +1 -2
- package/dist/transport/credential.js +1 -2
- package/dist/transport/http/handler.d.ts +2 -1
- package/dist/transport/http/handler.js +47 -37
- package/dist/transport/http/index.d.ts +0 -1
- package/dist/transport/http/index.js +0 -1
- package/dist/transport/http/render.d.ts +13 -11
- package/dist/transport/http/render.js +50 -39
- package/dist/transport/index.d.ts +0 -1
- package/dist/transport/index.js +0 -1
- package/dist/transport/router.d.ts +0 -1
- package/dist/transport/router.js +0 -1
- package/dist/transport/stream-error.d.ts +2 -3
- package/dist/transport/stream-error.js +3 -4
- package/dist/transport/types.d.ts +1 -2
- 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 +4 -3
- package/dist/transport/websocket/session.js +46 -39
- package/dist/transport/websocket/upgrade.d.ts +2 -1
- package/dist/transport/websocket/upgrade.js +2 -2
- package/dist/types.d.ts +13 -10
- package/dist/types.js +0 -1
- package/package.json +23 -11
- 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/installation/handler.d.ts +0 -10
- package/dist/installation/handler.d.ts.map +0 -1
- package/dist/installation/handler.js.map +0 -1
- package/dist/installation/index.d.ts +0 -3
- package/dist/installation/index.d.ts.map +0 -1
- package/dist/installation/index.js +0 -2
- package/dist/installation/index.js.map +0 -1
- package/dist/installation/types.d.ts +0 -12
- package/dist/installation/types.d.ts.map +0 -1
- package/dist/installation/types.js +0 -2
- package/dist/installation/types.js.map +0 -1
- package/dist/invocation/context.d.ts.map +0 -1
- package/dist/invocation/context.js.map +0 -1
- package/dist/invocation/index.d.ts.map +0 -1
- package/dist/invocation/index.js.map +0 -1
- package/dist/invocation/types.d.ts.map +0 -1
- package/dist/invocation/types.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/index.d.ts.map +0 -1
- package/dist/publication/index.js.map +0 -1
- package/dist/publication/snapshot.d.ts.map +0 -1
- package/dist/publication/snapshot.js.map +0 -1
- package/dist/publication/types.d.ts.map +0 -1
- 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
|
@@ -1,17 +1,15 @@
|
|
|
1
|
-
import
|
|
1
|
+
import * as codecs 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';
|
|
2
4
|
import { classifyError, RequestBodyInvalidError, RequestBodyTooLargeError, } from '../../errors/index.js';
|
|
3
|
-
import { invocationContext } from '../../invocation/index.js';
|
|
5
|
+
import { invocationContext, publicationRouteDecision, } from '../../invocation/index.js';
|
|
4
6
|
import { readBoundedBody } from '../body.js';
|
|
5
7
|
import { loadCodecs } from '../codecs.js';
|
|
6
8
|
import { resolveCredential } from '../credential.js';
|
|
7
|
-
import { renderHttpError, renderHttpResult
|
|
9
|
+
import { renderHttpError, renderHttpResult } from './render.js';
|
|
8
10
|
export function createHttpHandler(config) {
|
|
9
11
|
return async (request, host) => {
|
|
10
12
|
const cors = (exposedHeaders) => config.cors.response(request, exposedHeaders);
|
|
11
|
-
const renderError = (id, error, codec, options = {}) => renderHttpError(id, error, codec, cors, {
|
|
12
|
-
...options,
|
|
13
|
-
maximumResponseBytes: config.maximumResponseBytes,
|
|
14
|
-
});
|
|
15
13
|
const allow = [
|
|
16
14
|
...(config.websocket ? ['GET'] : []),
|
|
17
15
|
'POST',
|
|
@@ -20,7 +18,12 @@ export function createHttpHandler(config) {
|
|
|
20
18
|
if (request.method === 'OPTIONS' && config.cors.enabled) {
|
|
21
19
|
return noStore(config.cors.preflight(request, {
|
|
22
20
|
methods: ['POST'],
|
|
23
|
-
headers: [
|
|
21
|
+
headers: [
|
|
22
|
+
'authorization',
|
|
23
|
+
'content-type',
|
|
24
|
+
protocol.http.TRACEPARENT_FIELD,
|
|
25
|
+
protocol.http.TRACESTATE_FIELD,
|
|
26
|
+
],
|
|
24
27
|
}));
|
|
25
28
|
}
|
|
26
29
|
if (request.method !== 'POST') {
|
|
@@ -29,8 +32,13 @@ export function createHttpHandler(config) {
|
|
|
29
32
|
headers: { ...cors(), allow: allow.join(', '), 'cache-control': 'no-store' },
|
|
30
33
|
});
|
|
31
34
|
}
|
|
32
|
-
const
|
|
33
|
-
|
|
35
|
+
const assigned = config.invocation();
|
|
36
|
+
const renderError = (requestId, error, codec, options = {}) => renderHttpError(requestId, assigned, error, codec, cors, {
|
|
37
|
+
...options,
|
|
38
|
+
maximumResponseBytes: config.maximumResponseBytes,
|
|
39
|
+
});
|
|
40
|
+
const active = config.active.begin(config.invocationTimeoutMs, request.signal);
|
|
41
|
+
if (active === undefined) {
|
|
34
42
|
return renderError(null, {
|
|
35
43
|
code: errors.CODES.BACKEND_UNAVAILABLE,
|
|
36
44
|
message: 'server is unavailable.',
|
|
@@ -58,19 +66,19 @@ export function createHttpHandler(config) {
|
|
|
58
66
|
}
|
|
59
67
|
let body;
|
|
60
68
|
try {
|
|
61
|
-
body = await readBoundedBody(request, config.maximumRequestBytes,
|
|
69
|
+
body = await readBoundedBody(request, config.maximumRequestBytes, active.signal);
|
|
62
70
|
}
|
|
63
71
|
catch (input) {
|
|
64
72
|
const payload = input instanceof RequestBodyTooLargeError
|
|
65
73
|
? classifyError(input)
|
|
66
74
|
: input instanceof RequestBodyInvalidError
|
|
67
75
|
? { code: errors.CODES.PARSE_ERROR, message: 'Request body is invalid.' }
|
|
68
|
-
:
|
|
76
|
+
: active.timedOut
|
|
69
77
|
? {
|
|
70
78
|
code: errors.CODES.DEADLINE_EXCEEDED,
|
|
71
79
|
message: 'Invocation deadline exceeded.',
|
|
72
80
|
}
|
|
73
|
-
:
|
|
81
|
+
: active.signal.aborted
|
|
74
82
|
? { code: errors.CODES.CANCELLED, message: 'Invocation was cancelled.' }
|
|
75
83
|
: undefined;
|
|
76
84
|
if (payload === undefined)
|
|
@@ -88,67 +96,70 @@ export function createHttpHandler(config) {
|
|
|
88
96
|
throw input;
|
|
89
97
|
return renderError(null, { code: errors.CODES.PARSE_ERROR, message: 'Request body is invalid.' }, outgoing);
|
|
90
98
|
}
|
|
91
|
-
let
|
|
99
|
+
let envelope;
|
|
92
100
|
try {
|
|
93
|
-
|
|
101
|
+
envelope = protocol.decodeRequest(decoded);
|
|
94
102
|
}
|
|
95
103
|
catch (input) {
|
|
96
104
|
return renderError(null, classifyError(input), outgoing);
|
|
97
105
|
}
|
|
98
106
|
const publication = config.currentPublication?.(request);
|
|
99
107
|
if (config.currentPublication !== undefined && publication === undefined) {
|
|
100
|
-
return renderError(
|
|
108
|
+
return renderError(envelope.requestId, {
|
|
101
109
|
code: errors.CODES.BACKEND_UNAVAILABLE,
|
|
102
110
|
message: 'Publication is unavailable.',
|
|
103
111
|
}, outgoing, { status: 503 });
|
|
104
112
|
}
|
|
105
|
-
if (
|
|
113
|
+
if (envelope.routing?.kind === 'via') {
|
|
106
114
|
if (publication === undefined) {
|
|
107
|
-
return renderError(
|
|
115
|
+
return renderError(envelope.requestId, {
|
|
108
116
|
code: errors.CODES.INVALID_REQUEST,
|
|
109
117
|
message: 'Publication routing requires a Publication-backed destination.',
|
|
110
118
|
}, outgoing);
|
|
111
119
|
}
|
|
112
|
-
|
|
113
|
-
|
|
120
|
+
const decision = publicationRouteDecision(publication.publication, envelope.routing.publication);
|
|
121
|
+
if (decision.kind === 'rejected') {
|
|
122
|
+
return renderError(envelope.requestId, decision.error, outgoing);
|
|
114
123
|
}
|
|
115
124
|
}
|
|
116
|
-
const credential = resolveCredential(
|
|
125
|
+
const credential = resolveCredential(envelope.credential, request.headers.get('authorization'));
|
|
117
126
|
if (!credential.ok) {
|
|
118
|
-
return renderError(
|
|
127
|
+
return renderError(envelope.requestId, credential.error, outgoing);
|
|
119
128
|
}
|
|
129
|
+
const trace = protocol.http.decodeTraceHeaders(request.headers.get(protocol.http.TRACEPARENT_FIELD), request.headers.get(protocol.http.TRACESTATE_FIELD));
|
|
120
130
|
try {
|
|
121
131
|
const result = await config.handler.dispatch(Object.freeze({
|
|
122
|
-
call:
|
|
132
|
+
call: envelope.call,
|
|
133
|
+
...(trace === undefined ? {} : { trace }),
|
|
123
134
|
...(credential.credential === undefined ? {} : { credential: credential.credential }),
|
|
124
|
-
...(
|
|
125
|
-
...(
|
|
135
|
+
...(envelope.delegate === undefined ? {} : { delegate: envelope.delegate }),
|
|
136
|
+
...(envelope.routing?.kind === 'via' ? { via: envelope.routing } : {}),
|
|
137
|
+
...(envelope.schema === undefined ? {} : { schema: envelope.schema }),
|
|
126
138
|
...(publication === undefined ? {} : { publication }),
|
|
127
|
-
context: invocationContext(
|
|
128
|
-
? { staleEtag: invocation.routing.stale }
|
|
129
|
-
: undefined),
|
|
139
|
+
context: invocationContext(assigned, active, config.active, host, undefined, envelope.idempotencyKey),
|
|
130
140
|
}));
|
|
131
141
|
const response = renderHttpResult(result, {
|
|
132
|
-
|
|
142
|
+
requestId: envelope.requestId,
|
|
133
143
|
codec: outgoing,
|
|
134
144
|
cors,
|
|
135
|
-
|
|
145
|
+
invocation: assigned,
|
|
146
|
+
active,
|
|
136
147
|
maximumResponseBytes: config.maximumResponseBytes,
|
|
137
148
|
});
|
|
138
149
|
handedOff = result.kind === 'stream';
|
|
139
150
|
return response;
|
|
140
151
|
}
|
|
141
152
|
catch (input) {
|
|
142
|
-
if (
|
|
143
|
-
return renderError(
|
|
153
|
+
if (active.timedOut) {
|
|
154
|
+
return renderError(envelope.requestId, {
|
|
144
155
|
code: errors.CODES.DEADLINE_EXCEEDED,
|
|
145
156
|
message: 'Invocation deadline exceeded.',
|
|
146
157
|
}, outgoing, { status: 504 });
|
|
147
158
|
}
|
|
148
|
-
if (
|
|
149
|
-
return renderError(
|
|
159
|
+
if (active.signal.aborted) {
|
|
160
|
+
return renderError(envelope.requestId, { code: errors.CODES.CANCELLED, message: 'Invocation was cancelled.' }, outgoing, { status: 408 });
|
|
150
161
|
}
|
|
151
|
-
return renderError(
|
|
162
|
+
return renderError(envelope.requestId, classifyError(input), outgoing);
|
|
152
163
|
}
|
|
153
164
|
}
|
|
154
165
|
catch (input) {
|
|
@@ -158,7 +169,7 @@ export function createHttpHandler(config) {
|
|
|
158
169
|
}
|
|
159
170
|
finally {
|
|
160
171
|
if (!handedOff)
|
|
161
|
-
|
|
172
|
+
active.settle();
|
|
162
173
|
}
|
|
163
174
|
};
|
|
164
175
|
}
|
|
@@ -167,4 +178,3 @@ function noStore(response) {
|
|
|
167
178
|
headers.set('cache-control', 'no-store');
|
|
168
179
|
return new Response(response.body, { status: response.status, headers });
|
|
169
180
|
}
|
|
170
|
-
//# sourceMappingURL=handler.js.map
|
|
@@ -1,3 +1,2 @@
|
|
|
1
1
|
export { createHttpHandler, type HttpHandlerConfig } from './handler.js';
|
|
2
2
|
export { encodeEnvelope, renderBinary, renderHttpError, renderHttpResult, renderHttpStale, renderRedirect, type CorsHeaders, type ErrorRenderOptions, type RenderContext, } from './render.js';
|
|
3
|
-
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1,11 +1,14 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { Codec } 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';
|
|
2
4
|
import type { Handler } from '../../invocation/index.js';
|
|
3
5
|
import type { ActiveOperation } from '../../lifecycle/index.js';
|
|
4
6
|
export interface RenderContext {
|
|
5
|
-
readonly
|
|
6
|
-
readonly codec:
|
|
7
|
+
readonly requestId: protocol.RequestId;
|
|
8
|
+
readonly codec: Codec;
|
|
7
9
|
readonly cors: CorsHeaders;
|
|
8
|
-
readonly
|
|
10
|
+
readonly invocation: protocol.InvocationId;
|
|
11
|
+
readonly active: ActiveOperation;
|
|
9
12
|
readonly maximumResponseBytes: number;
|
|
10
13
|
}
|
|
11
14
|
export type CorsHeaders = (exposedHeaders?: readonly string[]) => Readonly<Record<string, string>>;
|
|
@@ -16,14 +19,13 @@ export interface ErrorRenderOptions {
|
|
|
16
19
|
}
|
|
17
20
|
type HandlerResult = Awaited<ReturnType<Handler['dispatch']>>;
|
|
18
21
|
export declare function renderHttpResult(result: HandlerResult, context: RenderContext): Response;
|
|
19
|
-
export declare function renderBinary(
|
|
22
|
+
export declare function renderBinary(requestId: protocol.RequestId, invocation: protocol.InvocationId, binary: Extract<HandlerResult, {
|
|
20
23
|
readonly kind: 'binary';
|
|
21
24
|
}>['value']): protocol.BinaryResponse;
|
|
22
|
-
export declare function renderRedirect(
|
|
25
|
+
export declare function renderRedirect(requestId: protocol.RequestId, invocation: protocol.InvocationId, redirect: Extract<HandlerResult, {
|
|
23
26
|
readonly kind: 'redirect';
|
|
24
|
-
}>['redirect']): protocol.
|
|
25
|
-
export declare function renderHttpError(
|
|
26
|
-
export declare function renderHttpStale(
|
|
27
|
-
export declare function encodeEnvelope(codec:
|
|
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;
|
|
28
31
|
export {};
|
|
29
|
-
//# sourceMappingURL=render.d.ts.map
|
|
@@ -1,55 +1,64 @@
|
|
|
1
|
-
import
|
|
1
|
+
import * as errors from '@astrale-os/kernel-protocol/errors';
|
|
2
|
+
import * as protocol from '@astrale-os/kernel-protocol/invocation';
|
|
3
|
+
import { HTTP_ROUTE_MISS, HTTP_ROUTE_STALE } from '@astrale-os/kernel-protocol/routes/routing';
|
|
2
4
|
import { classifyError } from '../../errors/index.js';
|
|
3
5
|
import { ResponseBodyTooLargeError } from '../../errors/index.js';
|
|
4
6
|
import { interruptedStreamError } from '../stream-error.js';
|
|
5
7
|
export function renderHttpResult(result, context) {
|
|
6
8
|
switch (result.kind) {
|
|
7
9
|
case 'value':
|
|
8
|
-
return settled(context.
|
|
10
|
+
return settled(context.active, envelopeResponse(context.codec, {
|
|
11
|
+
result: result.value,
|
|
12
|
+
requestId: context.requestId,
|
|
13
|
+
invocation: context.invocation,
|
|
14
|
+
}, context.cors(), 200, true, context.maximumResponseBytes));
|
|
9
15
|
case 'redirect': {
|
|
10
|
-
const response = renderRedirect(context.
|
|
11
|
-
return settled(context.
|
|
16
|
+
const response = renderRedirect(context.requestId, context.invocation, result.redirect);
|
|
17
|
+
return settled(context.active, envelopeResponse(context.codec, response, context.cors(), 200, true, context.maximumResponseBytes));
|
|
12
18
|
}
|
|
13
19
|
case 'miss':
|
|
14
|
-
return settled(context.
|
|
20
|
+
return settled(context.active, envelopeResponse(context.codec, protocol.miss(context.requestId, context.invocation), context.cors(), 200, true, context.maximumResponseBytes));
|
|
15
21
|
case 'binary': {
|
|
16
|
-
const binary = renderBinary(context.
|
|
17
|
-
return settled(context.
|
|
22
|
+
const binary = renderBinary(context.requestId, context.invocation, result.value);
|
|
23
|
+
return settled(context.active, binaryHttpResponse(binary, context.cors, context.maximumResponseBytes));
|
|
18
24
|
}
|
|
19
25
|
case 'stream':
|
|
20
26
|
return streamHttpResponse(result.stream, context);
|
|
21
27
|
}
|
|
22
28
|
}
|
|
23
|
-
export function renderBinary(
|
|
24
|
-
|
|
25
|
-
const
|
|
26
|
-
return
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
}
|
|
29
|
+
export function renderBinary(requestId, invocation, binary) {
|
|
30
|
+
const reserved = Object.keys(binary.headers ?? {}).find((name) => {
|
|
31
|
+
const normalized = name.toLowerCase();
|
|
32
|
+
return (normalized === protocol.http.INVOCATION_FIELD ||
|
|
33
|
+
normalized === HTTP_ROUTE_STALE ||
|
|
34
|
+
normalized === HTTP_ROUTE_MISS);
|
|
35
|
+
});
|
|
36
|
+
if (reserved !== undefined)
|
|
37
|
+
throw new TypeError(`${reserved} is reserved by Protocol.`);
|
|
30
38
|
return protocol.decodeBinaryResponse({
|
|
31
39
|
kind: 'binary',
|
|
32
|
-
|
|
40
|
+
requestId,
|
|
41
|
+
invocation,
|
|
33
42
|
body: binary.body,
|
|
34
43
|
mediaType: binary.mediaType,
|
|
35
44
|
...(binary.headers === undefined ? {} : { headers: binary.headers }),
|
|
36
45
|
});
|
|
37
46
|
}
|
|
38
|
-
export function renderRedirect(
|
|
39
|
-
return protocol.
|
|
47
|
+
export function renderRedirect(requestId, invocation, redirect) {
|
|
48
|
+
return protocol.decodeRedirectResponse({
|
|
40
49
|
kind: 'redirect',
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
50
|
+
requestId,
|
|
51
|
+
invocation,
|
|
52
|
+
redirect,
|
|
44
53
|
});
|
|
45
54
|
}
|
|
46
|
-
export function renderHttpError(
|
|
55
|
+
export function renderHttpError(requestId, invocation, error, codec, cors, options = {}) {
|
|
47
56
|
const status = options.status ?? errors.httpStatusOf(error);
|
|
48
57
|
const extra = status === 401 ? { 'www-authenticate': 'Bearer realm="astrale-invocation"' } : {};
|
|
49
|
-
return errorEnvelopeResponse(codec, { error,
|
|
58
|
+
return errorEnvelopeResponse(codec, { error, requestId, invocation }, { ...cors(), ...extra }, status, options.negotiated ?? true, options.maximumResponseBytes);
|
|
50
59
|
}
|
|
51
|
-
export function renderHttpStale(
|
|
52
|
-
return envelopeResponse(codec, protocol.stale(
|
|
60
|
+
export function renderHttpStale(requestId, invocation, current, codec, cors, maximumResponseBytes) {
|
|
61
|
+
return envelopeResponse(codec, protocol.stale(requestId, invocation, current), cors(), 200, true, maximumResponseBytes);
|
|
53
62
|
}
|
|
54
63
|
export function encodeEnvelope(codec, input) {
|
|
55
64
|
return codec.encode(input);
|
|
@@ -69,6 +78,7 @@ function binaryHttpResponse(binary, cors, maximumResponseBytes) {
|
|
|
69
78
|
const applicationHeaders = Object.keys(binary.headers ?? {}).filter((name) => protocol.http.isApplicationBinaryHeader(name));
|
|
70
79
|
const headers = new Headers(cors([
|
|
71
80
|
protocol.http.REQUEST_ID_FIELD,
|
|
81
|
+
protocol.http.INVOCATION_FIELD,
|
|
72
82
|
protocol.http.BINARY_HEADERS_FIELD,
|
|
73
83
|
...applicationHeaders,
|
|
74
84
|
]));
|
|
@@ -78,14 +88,15 @@ function binaryHttpResponse(binary, cors, maximumResponseBytes) {
|
|
|
78
88
|
}
|
|
79
89
|
headers.set('content-type', binary.mediaType);
|
|
80
90
|
headers.set(protocol.http.BINARY_HEADERS_FIELD, protocol.http.encodeBinaryHeaderNames(binary.headers));
|
|
81
|
-
headers.set(protocol.http.REQUEST_ID_FIELD, String(binary.
|
|
91
|
+
headers.set(protocol.http.REQUEST_ID_FIELD, String(binary.requestId));
|
|
92
|
+
headers.set(protocol.http.INVOCATION_FIELD, protocol.http.encodeInvocationId(binary.invocation));
|
|
82
93
|
headers.set('cache-control', 'no-store');
|
|
83
94
|
appendVary(headers, 'accept');
|
|
84
95
|
return new Response(toBody(binary.body), { status: 200, headers });
|
|
85
96
|
}
|
|
86
97
|
function streamHttpResponse(stream, context) {
|
|
87
98
|
const iterator = stream[Symbol.asyncIterator]();
|
|
88
|
-
const startFrame = encodeBoundedStreamFrame(context.codec, { kind: 'stream.start',
|
|
99
|
+
const startFrame = encodeBoundedStreamFrame(context.codec, { kind: 'stream.start', requestId: context.requestId, invocation: context.invocation }, context.maximumResponseBytes);
|
|
89
100
|
let count = 0;
|
|
90
101
|
let terminal = false;
|
|
91
102
|
let controller;
|
|
@@ -121,7 +132,7 @@ function streamHttpResponse(stream, context) {
|
|
|
121
132
|
]);
|
|
122
133
|
}
|
|
123
134
|
finally {
|
|
124
|
-
context.
|
|
135
|
+
context.active.settle();
|
|
125
136
|
}
|
|
126
137
|
}
|
|
127
138
|
const body = new ReadableStream({
|
|
@@ -140,16 +151,16 @@ function streamHttpResponse(stream, context) {
|
|
|
140
151
|
terminal = true;
|
|
141
152
|
output.enqueue(encodeBoundedStreamFrame(context.codec, {
|
|
142
153
|
kind: 'stream.end',
|
|
143
|
-
|
|
154
|
+
requestId: context.requestId,
|
|
144
155
|
count,
|
|
145
156
|
}, context.maximumResponseBytes));
|
|
146
157
|
output.close();
|
|
147
|
-
context.
|
|
158
|
+
context.active.settle();
|
|
148
159
|
return;
|
|
149
160
|
}
|
|
150
161
|
const frame = protocol.decodeStreamFrame({
|
|
151
162
|
kind: 'stream.item',
|
|
152
|
-
|
|
163
|
+
requestId: context.requestId,
|
|
153
164
|
index: count,
|
|
154
165
|
value: next.value,
|
|
155
166
|
});
|
|
@@ -160,11 +171,11 @@ function streamHttpResponse(stream, context) {
|
|
|
160
171
|
if (terminal)
|
|
161
172
|
return;
|
|
162
173
|
terminal = true;
|
|
163
|
-
if (!context.
|
|
174
|
+
if (!context.active.signal.aborted) {
|
|
164
175
|
try {
|
|
165
176
|
output.enqueue(encodeBoundedStreamFrame(context.codec, {
|
|
166
177
|
kind: 'stream.error',
|
|
167
|
-
|
|
178
|
+
requestId: context.requestId,
|
|
168
179
|
error: classifyError(input),
|
|
169
180
|
}, context.maximumResponseBytes));
|
|
170
181
|
}
|
|
@@ -177,16 +188,16 @@ function streamHttpResponse(stream, context) {
|
|
|
177
188
|
Promise.resolve().then(() => stream.cancel('stream failed')),
|
|
178
189
|
Promise.resolve().then(() => iterator.return?.()),
|
|
179
190
|
]);
|
|
180
|
-
context.
|
|
191
|
+
context.active.settle();
|
|
181
192
|
}
|
|
182
193
|
},
|
|
183
194
|
async cancel(reason) {
|
|
184
195
|
const message = typeof reason === 'string' ? reason : 'response consumer cancelled';
|
|
185
|
-
context.
|
|
196
|
+
context.active.cancel(message);
|
|
186
197
|
await stop(message);
|
|
187
198
|
},
|
|
188
199
|
});
|
|
189
|
-
context.
|
|
200
|
+
context.active.onCancel(stop);
|
|
190
201
|
return new Response(body, {
|
|
191
202
|
status: 200,
|
|
192
203
|
headers: {
|
|
@@ -213,7 +224,8 @@ function errorEnvelopeResponse(codec, response, cors, status, negotiated, maximu
|
|
|
213
224
|
if (!(error instanceof ResponseBodyTooLargeError))
|
|
214
225
|
throw error;
|
|
215
226
|
const fallback = {
|
|
216
|
-
|
|
227
|
+
requestId: response.requestId,
|
|
228
|
+
invocation: response.invocation,
|
|
217
229
|
error: {
|
|
218
230
|
code: errors.CODES.LIMIT_EXCEEDED,
|
|
219
231
|
message: 'Response body exceeds the configured limit.',
|
|
@@ -264,8 +276,8 @@ function mergeVary(headers, value) {
|
|
|
264
276
|
function cancellationFrame(context) {
|
|
265
277
|
return {
|
|
266
278
|
kind: 'stream.error',
|
|
267
|
-
|
|
268
|
-
error: interruptedStreamError(context.
|
|
279
|
+
requestId: context.requestId,
|
|
280
|
+
error: interruptedStreamError(context.active.timedOut),
|
|
269
281
|
};
|
|
270
282
|
}
|
|
271
283
|
function toBody(input) {
|
|
@@ -274,4 +286,3 @@ function toBody(input) {
|
|
|
274
286
|
const copy = new Uint8Array(input);
|
|
275
287
|
return copy.buffer;
|
|
276
288
|
}
|
|
277
|
-
//# sourceMappingURL=render.js.map
|
|
@@ -7,4 +7,3 @@ export { interruptedStreamError } from './stream-error.js';
|
|
|
7
7
|
export { createServerRouter, type ServerRouter } from './router.js';
|
|
8
8
|
export { createWebSocketSession, handleWebSocketUpgrade, type WebSocketHandlerConfig, type WebSocketSessionConfig, } from './websocket/index.js';
|
|
9
9
|
export type { Application, WebSocketAdapter, WebSocketHandlers, WebSocketLike, WebSocketUpgradeOptions, } from './types.js';
|
|
10
|
-
//# sourceMappingURL=index.d.ts.map
|
package/dist/transport/index.js
CHANGED
|
@@ -6,4 +6,3 @@ export { encodeEnvelope, renderBinary, renderHttpError, renderHttpResult, render
|
|
|
6
6
|
export { interruptedStreamError } from './stream-error.js';
|
|
7
7
|
export { createServerRouter } from './router.js';
|
|
8
8
|
export { createWebSocketSession, handleWebSocketUpgrade, } from './websocket/index.js';
|
|
9
|
-
//# sourceMappingURL=index.js.map
|
package/dist/transport/router.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { ErrorPayload } from '@astrale-os/kernel-protocol/errors';
|
|
2
2
|
/** A transport cancellation after stream.start necessarily follows the Function effect boundary. */
|
|
3
|
-
export declare function interruptedStreamError(timedOut: boolean):
|
|
4
|
-
//# sourceMappingURL=stream-error.d.ts.map
|
|
3
|
+
export declare function interruptedStreamError(timedOut: boolean): ErrorPayload;
|
|
@@ -1,14 +1,13 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { CODES } from '@astrale-os/kernel-protocol/errors';
|
|
2
2
|
/** A transport cancellation after stream.start necessarily follows the Function effect boundary. */
|
|
3
3
|
export function interruptedStreamError(timedOut) {
|
|
4
4
|
return timedOut
|
|
5
5
|
? {
|
|
6
|
-
code:
|
|
6
|
+
code: CODES.OUTCOME_UNKNOWN,
|
|
7
7
|
message: 'Invocation deadline elapsed after the Function stream began; outcome is unknown.',
|
|
8
8
|
}
|
|
9
9
|
: {
|
|
10
|
-
code:
|
|
10
|
+
code: CODES.OUTCOME_UNKNOWN,
|
|
11
11
|
message: 'Function stream was cancelled after execution began; outcome is unknown.',
|
|
12
12
|
};
|
|
13
13
|
}
|
|
14
|
-
//# sourceMappingURL=stream-error.js.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import type * as protocol from '@astrale-os/kernel-protocol/invocation';
|
|
2
2
|
import type { ApplicationHost } from '../invocation/index.js';
|
|
3
3
|
/** Portable Fetch application; framework and listener APIs are adapter-owned. */
|
|
4
4
|
export interface Application {
|
|
@@ -26,4 +26,3 @@ export interface WebSocketUpgradeOptions {
|
|
|
26
26
|
export interface WebSocketAdapter {
|
|
27
27
|
upgrade(request: Request, options: WebSocketUpgradeOptions): Response | Promise<Response>;
|
|
28
28
|
}
|
|
29
|
-
//# sourceMappingURL=types.d.ts.map
|
package/dist/transport/types.js
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { Codec } from '@astrale-os/kernel-protocol/codecs';
|
|
2
|
+
import type { NextInvocationId } from '../../invocation/index.js';
|
|
2
3
|
import type { ActiveOperations } from '../../lifecycle/index.js';
|
|
3
4
|
import type { PublicationSnapshot } from '../../publication/index.js';
|
|
4
5
|
import type { WebSocketHandlers } from '../types.js';
|
|
5
6
|
import { type ApplicationHost, type Handler } from '../../invocation/index.js';
|
|
6
7
|
export interface WebSocketSessionConfig {
|
|
7
|
-
readonly codec:
|
|
8
|
+
readonly codec: Codec;
|
|
8
9
|
readonly authorization: string | null;
|
|
9
10
|
readonly handler: Handler;
|
|
10
11
|
readonly active: ActiveOperations;
|
|
12
|
+
readonly invocation: NextInvocationId;
|
|
11
13
|
readonly maximumRequestBytes: number;
|
|
12
14
|
readonly maximumResponseBytes: number;
|
|
13
15
|
readonly invocationTimeoutMs: number;
|
|
@@ -16,4 +18,3 @@ export interface WebSocketSessionConfig {
|
|
|
16
18
|
}
|
|
17
19
|
/** Build one socket-pinned transport session. */
|
|
18
20
|
export declare function createWebSocketSession(config: WebSocketSessionConfig): WebSocketHandlers;
|
|
19
|
-
//# sourceMappingURL=session.d.ts.map
|