@astrale-os/kernel-server 0.5.0-beta.7 → 0.5.0-beta.71
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 +8 -1
- package/dist/errors/classify.js +15 -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 +8 -4
- package/dist/index.js +7 -3
- package/dist/invocation/context.d.ts +3 -3
- package/dist/invocation/context.js +2 -2
- package/dist/invocation/identity.d.ts +1 -2
- package/dist/invocation/identity.js +1 -2
- package/dist/invocation/index.d.ts +1 -2
- package/dist/invocation/index.js +1 -2
- package/dist/invocation/legacy/index.d.ts +20 -0
- package/dist/invocation/legacy/index.js +20 -0
- package/dist/invocation/{publication-route.d.ts → legacy/publication-route.d.ts} +7 -5
- package/dist/invocation/{publication-route.js → legacy/publication-route.js} +7 -13
- package/dist/invocation/release-route.d.ts +26 -0
- package/dist/invocation/release-route.js +55 -0
- package/dist/invocation/types.d.ts +20 -7
- 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 +33 -5
- package/dist/issuer/types.d.ts +5 -1
- package/dist/issuer/types.js +0 -1
- package/dist/lifecycle/active.d.ts +4 -1
- package/dist/lifecycle/active.js +48 -11
- package/dist/lifecycle/index.d.ts +0 -1
- package/dist/lifecycle/index.js +0 -1
- package/dist/release/delivery/handler.d.ts +13 -0
- package/dist/{publication → release}/delivery/handler.js +42 -15
- package/dist/{publication → release}/delivery/index.d.ts +0 -1
- package/dist/{publication → release}/delivery/index.js +0 -1
- package/dist/release/delivery/types.d.ts +21 -0
- 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/legacy/delivery.d.ts +18 -0
- package/dist/release/legacy/delivery.js +2 -0
- package/dist/release/legacy/index.d.ts +39 -0
- package/dist/release/legacy/index.js +38 -0
- package/dist/release/legacy/snapshot.d.ts +26 -0
- package/dist/release/legacy/snapshot.js +55 -0
- package/dist/release/legacy/table.d.ts +5 -0
- package/dist/{publication → release/legacy}/table.js +5 -6
- package/dist/release/legacy/types.d.ts +31 -0
- package/dist/release/legacy/types.js +1 -0
- package/dist/release/served.d.ts +30 -0
- package/dist/release/served.js +14 -0
- package/dist/release/snapshot.d.ts +26 -0
- package/dist/release/snapshot.js +54 -0
- package/dist/release/table.d.ts +4 -0
- package/dist/release/table.js +11 -0
- package/dist/release/types.d.ts +33 -0
- package/dist/release/types.js +1 -0
- package/dist/routes/index.d.ts +1 -2
- package/dist/routes/index.js +1 -2
- package/dist/routes/routes.d.ts +9 -7
- package/dist/routes/routes.js +314 -123
- package/dist/server.d.ts +0 -1
- package/dist/server.js +110 -48
- 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/handler.d.ts +8 -3
- package/dist/transport/http/handler.js +95 -45
- package/dist/transport/http/index.d.ts +0 -1
- package/dist/transport/http/index.js +0 -1
- package/dist/transport/http/render.d.ts +9 -4
- package/dist/transport/http/render.js +150 -5
- 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 +0 -1
- package/dist/transport/stream-error.js +0 -1
- 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 +3 -3
- package/dist/transport/websocket/session.js +30 -30
- package/dist/transport/websocket/upgrade.d.ts +2 -3
- package/dist/transport/websocket/upgrade.js +7 -7
- package/dist/types.d.ts +32 -6
- package/dist/types.js +0 -1
- package/package.json +12 -15
- 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.map +0 -1
- 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.map +0 -1
- package/dist/publication/delivery/index.js.map +0 -1
- package/dist/publication/delivery/types.d.ts +0 -12
- 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 -16
- package/dist/publication/snapshot.d.ts.map +0 -1
- package/dist/publication/snapshot.js +0 -39
- package/dist/publication/snapshot.js.map +0 -1
- package/dist/publication/table.d.ts +0 -4
- package/dist/publication/table.d.ts.map +0 -1
- 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/publication/validator.d.ts +0 -4
- package/dist/publication/validator.d.ts.map +0 -1
- package/dist/publication/validator.js +0 -17
- package/dist/publication/validator.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
package/dist/server.js
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { accept as acceptIssuer } from '@astrale-os/kernel-core/auth/issuer';
|
|
2
|
+
import { Path } from '@astrale-os/kernel-core/path';
|
|
3
|
+
import { PATH as RELEASE_PATH, url as releaseUrl } from '@astrale-os/kernel-protocol/release';
|
|
4
|
+
import { PATH as PUBLICATION_PATH, url as publicationUrl, } from '@astrale-os/kernel-protocol/release/legacy';
|
|
2
5
|
import { captureMethod } from './capture.js';
|
|
3
6
|
import { prepareCors } from './cors/index.js';
|
|
4
7
|
import { captureInvocationSource } from './invocation/index.js';
|
|
5
8
|
import { capture as captureExchangeProvider } from './issuer/exchange.js';
|
|
6
9
|
import { admitIssuer, issuerRouteReservations, mountIssuer } from './issuer/index.js';
|
|
7
10
|
import { ActiveOperations } from './lifecycle/index.js';
|
|
8
|
-
import {
|
|
11
|
+
import { currentServed, mountRoutes } from './routes/index.js';
|
|
9
12
|
import { createHttpHandler } from './transport/http/handler.js';
|
|
10
13
|
import { createServerRouter } from './transport/router.js';
|
|
11
14
|
import { handleWebSocketUpgrade } from './transport/websocket/upgrade.js';
|
|
@@ -26,7 +29,23 @@ function createPreparedServer(input, config) {
|
|
|
26
29
|
const app = createServerRouter();
|
|
27
30
|
const hosts = new WeakMap();
|
|
28
31
|
const externalIssuer = config.issuer?.issuer;
|
|
29
|
-
const externalOrigin =
|
|
32
|
+
const externalOrigin = config.publicOrigin ??
|
|
33
|
+
(externalIssuer === undefined ? undefined : new URL(externalIssuer).origin);
|
|
34
|
+
const source = config.serving;
|
|
35
|
+
const serving = source === undefined
|
|
36
|
+
? undefined
|
|
37
|
+
: (request) => {
|
|
38
|
+
const origin = externalOrigin ?? new URL(request.url).origin;
|
|
39
|
+
return Object.freeze({
|
|
40
|
+
kind: source.kind,
|
|
41
|
+
current: () => currentServed(source, config.limits, {
|
|
42
|
+
origin,
|
|
43
|
+
...(externalIssuer === undefined ? {} : { issuer: externalIssuer }),
|
|
44
|
+
reservations: config.routeReservations,
|
|
45
|
+
}),
|
|
46
|
+
deployment: () => acceptIssuer(origin),
|
|
47
|
+
});
|
|
48
|
+
};
|
|
30
49
|
const handleHttp = createHttpHandler({
|
|
31
50
|
handler,
|
|
32
51
|
active,
|
|
@@ -34,15 +53,7 @@ function createPreparedServer(input, config) {
|
|
|
34
53
|
...config.limits,
|
|
35
54
|
cors: config.cors,
|
|
36
55
|
websocket: config.websocket !== undefined,
|
|
37
|
-
...(
|
|
38
|
-
? {}
|
|
39
|
-
: {
|
|
40
|
-
currentPublication: (request) => currentPublicationSnapshot(config.publication, config.limits, {
|
|
41
|
-
origin: externalOrigin ?? new URL(request.url).origin,
|
|
42
|
-
...(externalIssuer === undefined ? {} : { issuer: externalIssuer }),
|
|
43
|
-
reservations: config.routeReservations,
|
|
44
|
-
})?.snapshot,
|
|
45
|
-
}),
|
|
56
|
+
...(serving === undefined ? {} : { serving }),
|
|
46
57
|
});
|
|
47
58
|
if (config.websocket !== undefined) {
|
|
48
59
|
app.get(config.path, (context) => handleWebSocketUpgrade({
|
|
@@ -53,22 +64,14 @@ function createPreparedServer(input, config) {
|
|
|
53
64
|
invocation: config.invocation,
|
|
54
65
|
...config.limits,
|
|
55
66
|
cors: config.cors,
|
|
56
|
-
...(
|
|
57
|
-
? {}
|
|
58
|
-
: {
|
|
59
|
-
currentPublication: () => currentPublicationSnapshot(config.publication, config.limits, {
|
|
60
|
-
origin: externalOrigin ?? new URL(context.req.raw.url).origin,
|
|
61
|
-
...(externalIssuer === undefined ? {} : { issuer: externalIssuer }),
|
|
62
|
-
reservations: config.routeReservations,
|
|
63
|
-
})?.snapshot,
|
|
64
|
-
}),
|
|
67
|
+
...(serving === undefined ? {} : { serving: serving(context.req.raw) }),
|
|
65
68
|
host: hosts.get(context.req.raw),
|
|
66
69
|
}));
|
|
67
70
|
}
|
|
68
71
|
app.all(config.path, (context) => handleHttp(context.req.raw, hosts.get(context.req.raw)));
|
|
69
72
|
if (config.health !== undefined) {
|
|
70
73
|
app.get(config.health.path, (context) => {
|
|
71
|
-
const ready = active.
|
|
74
|
+
const ready = active.isAvailable && config.health.probe.check();
|
|
72
75
|
return context.json({ status: ready ? 'ready' : 'not-ready' }, ready ? 200 : 503, {
|
|
73
76
|
...config.cors.response(context.req.raw),
|
|
74
77
|
'cache-control': 'no-store',
|
|
@@ -81,8 +84,8 @@ function createPreparedServer(input, config) {
|
|
|
81
84
|
if (config.issuer !== undefined) {
|
|
82
85
|
mountIssuer(app, config.issuer, config.cors, active, config.limits.invocationTimeoutMs, config.tokenExchange);
|
|
83
86
|
}
|
|
84
|
-
if (config.
|
|
85
|
-
mountRoutes(app, config.
|
|
87
|
+
if (config.serving !== undefined) {
|
|
88
|
+
mountRoutes(app, config.serving, config.delivery, handler, active, config.invocation, config.limits, config.cors, (request) => hosts.get(request), config.routeReservations, externalIssuer, externalOrigin);
|
|
86
89
|
}
|
|
87
90
|
app.onError((_error, context) => new Response('{"error":"Internal server error."}', {
|
|
88
91
|
status: 500,
|
|
@@ -131,6 +134,7 @@ function captureHandler(input) {
|
|
|
131
134
|
return Object.freeze({ dispatch });
|
|
132
135
|
}
|
|
133
136
|
function admitOptions(config) {
|
|
137
|
+
const publicOrigin = config.publicOrigin === undefined ? undefined : admitPublicOrigin(config.publicOrigin);
|
|
134
138
|
const invocation = captureInvocationSource(config.invocation);
|
|
135
139
|
const limits = admitLimits(config.limits);
|
|
136
140
|
const path = admitRoute(config.path ?? '/', 'invocation path');
|
|
@@ -146,23 +150,31 @@ function admitOptions(config) {
|
|
|
146
150
|
probe: captureHealthProbe(config.health.probe),
|
|
147
151
|
});
|
|
148
152
|
const websocket = config.websocket === undefined ? undefined : captureWebSocket(config.websocket);
|
|
149
|
-
|
|
153
|
+
if (config.release !== undefined && config.publication !== undefined) {
|
|
154
|
+
throw new TypeError('Server options take at most one of release and publication.');
|
|
155
|
+
}
|
|
156
|
+
const serving = config.release !== undefined
|
|
157
|
+
? Object.freeze({ kind: 'release', source: captureReleaseSource(config.release) })
|
|
158
|
+
: config.publication !== undefined
|
|
159
|
+
? Object.freeze({
|
|
160
|
+
kind: 'publication',
|
|
161
|
+
source: capturePublicationSource(config.publication),
|
|
162
|
+
})
|
|
163
|
+
: undefined;
|
|
150
164
|
const delivery = config.delivery === undefined ? undefined : captureDeliveryProvider(config.delivery);
|
|
151
|
-
if (delivery !== undefined &&
|
|
152
|
-
throw new TypeError('
|
|
165
|
+
if (delivery !== undefined && serving === undefined) {
|
|
166
|
+
throw new TypeError('Delivery requires a release or Publication source.');
|
|
153
167
|
}
|
|
154
|
-
const
|
|
155
|
-
? undefined
|
|
156
|
-
: issuer === undefined
|
|
157
|
-
? protocolPublicationPath()
|
|
158
|
-
: protocolPublicationPath(issuer.issuer);
|
|
168
|
+
const documentPaths = serving === undefined ? [] : servedDocumentPaths(serving.kind, issuer?.issuer);
|
|
159
169
|
if (health?.path === path)
|
|
160
170
|
throw new TypeError('Health and invocation paths must be distinct.');
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
171
|
+
for (const { name, path: documentPath } of documentPaths) {
|
|
172
|
+
if (documentPath === path) {
|
|
173
|
+
throw new TypeError(`${name} and invocation paths must be distinct.`);
|
|
174
|
+
}
|
|
175
|
+
if (health !== undefined && documentPath === health.path) {
|
|
176
|
+
throw new TypeError(`Health and ${name} paths must be distinct.`);
|
|
177
|
+
}
|
|
166
178
|
}
|
|
167
179
|
if (issuer !== undefined) {
|
|
168
180
|
const issuerReservations = issuerRouteReservations(issuer, tokenExchange !== undefined);
|
|
@@ -180,19 +192,20 @@ function admitOptions(config) {
|
|
|
180
192
|
}
|
|
181
193
|
return Object.freeze({
|
|
182
194
|
invocation,
|
|
195
|
+
...(publicOrigin === undefined ? {} : { publicOrigin }),
|
|
183
196
|
limits,
|
|
184
197
|
path,
|
|
185
198
|
cors: prepareCors(config.cors),
|
|
186
199
|
...(health === undefined ? {} : { health }),
|
|
187
200
|
...(issuer === undefined ? {} : { issuer }),
|
|
188
201
|
...(tokenExchange === undefined ? {} : { tokenExchange }),
|
|
189
|
-
...(
|
|
202
|
+
...(serving === undefined ? {} : { serving }),
|
|
190
203
|
...(delivery === undefined ? {} : { delivery }),
|
|
191
|
-
routeReservations: routeReservations(path, health?.path, issuer, websocket !== undefined, tokenExchange !== undefined,
|
|
204
|
+
routeReservations: routeReservations(path, health?.path, issuer, websocket !== undefined, tokenExchange !== undefined, documentPaths.map(({ path: documentPath }) => documentPath)),
|
|
192
205
|
...(websocket === undefined ? {} : { websocket }),
|
|
193
206
|
});
|
|
194
207
|
}
|
|
195
|
-
function routeReservations(invocationPath, healthPath, issuer, websocket, tokenExchange,
|
|
208
|
+
function routeReservations(invocationPath, healthPath, issuer, websocket, tokenExchange, documentPaths) {
|
|
196
209
|
const reservations = [
|
|
197
210
|
Object.freeze({
|
|
198
211
|
path: invocationPath,
|
|
@@ -205,15 +218,23 @@ function routeReservations(invocationPath, healthPath, issuer, websocket, tokenE
|
|
|
205
218
|
if (issuer !== undefined) {
|
|
206
219
|
reservations.push(...issuerRouteReservations(issuer, tokenExchange));
|
|
207
220
|
}
|
|
208
|
-
|
|
209
|
-
reservations.push(Object.freeze({ path:
|
|
221
|
+
for (const documentPath of documentPaths) {
|
|
222
|
+
reservations.push(Object.freeze({ path: documentPath, methods: Object.freeze(['GET']) }));
|
|
210
223
|
}
|
|
211
224
|
return Object.freeze(reservations);
|
|
212
225
|
}
|
|
213
|
-
function
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
226
|
+
function servedDocumentPaths(kind, issuer) {
|
|
227
|
+
const publication = {
|
|
228
|
+
name: 'Publication',
|
|
229
|
+
path: issuer === undefined ? PUBLICATION_PATH : new URL(publicationUrl(issuer)).pathname,
|
|
230
|
+
};
|
|
231
|
+
if (kind === 'publication')
|
|
232
|
+
return [publication];
|
|
233
|
+
const release = {
|
|
234
|
+
name: 'Release',
|
|
235
|
+
path: issuer === undefined ? RELEASE_PATH : new URL(releaseUrl(issuer)).pathname,
|
|
236
|
+
};
|
|
237
|
+
return [release, publication];
|
|
217
238
|
}
|
|
218
239
|
function captureHealthProbe(probe) {
|
|
219
240
|
const check = captureMethod(probe, 'check', 'Health probe is invalid.');
|
|
@@ -223,12 +244,16 @@ function captureWebSocket(adapter) {
|
|
|
223
244
|
const upgrade = captureMethod(adapter, 'upgrade', 'WebSocket adapter is invalid.');
|
|
224
245
|
return Object.freeze({ upgrade });
|
|
225
246
|
}
|
|
247
|
+
function captureReleaseSource(input) {
|
|
248
|
+
const current = captureMethod(input, 'current', 'Release source is invalid.');
|
|
249
|
+
return Object.freeze({ current });
|
|
250
|
+
}
|
|
226
251
|
function capturePublicationSource(input) {
|
|
227
252
|
const current = captureMethod(input, 'current', 'Publication source is invalid.');
|
|
228
253
|
return Object.freeze({ current });
|
|
229
254
|
}
|
|
230
255
|
function captureDeliveryProvider(input) {
|
|
231
|
-
const create = captureMethod(input, 'create', '
|
|
256
|
+
const create = captureMethod(input, 'create', 'Delivery provider is invalid.');
|
|
232
257
|
return Object.freeze({ create });
|
|
233
258
|
}
|
|
234
259
|
function admitLimits(limits) {
|
|
@@ -241,16 +266,42 @@ function admitLimits(limits) {
|
|
|
241
266
|
if (limits.invocationTimeoutMs > 2_147_483_647) {
|
|
242
267
|
throw new TypeError('invocationTimeoutMs exceeds the platform timer range.');
|
|
243
268
|
}
|
|
269
|
+
if ((limits.binaryDownloadTarget === undefined) !==
|
|
270
|
+
(limits.binaryDownloadTimeoutMs === undefined)) {
|
|
271
|
+
throw new TypeError('binaryDownloadTarget and binaryDownloadTimeoutMs must be configured together.');
|
|
272
|
+
}
|
|
273
|
+
const binaryDownloadTarget = limits.binaryDownloadTarget === undefined
|
|
274
|
+
? undefined
|
|
275
|
+
: Path.parse(limits.binaryDownloadTarget).raw;
|
|
276
|
+
const binaryDownloadTimeoutMs = limits.binaryDownloadTimeoutMs === undefined
|
|
277
|
+
? undefined
|
|
278
|
+
: admitTimerLimit(limits.binaryDownloadTimeoutMs, 'binaryDownloadTimeoutMs');
|
|
244
279
|
return Object.freeze({
|
|
245
280
|
maximumRequestBytes: limits.maximumRequestBytes,
|
|
281
|
+
maximumBinaryRequestBytes: admitOptionalLimit(limits.maximumBinaryRequestBytes, limits.maximumRequestBytes, 'maximumBinaryRequestBytes'),
|
|
246
282
|
maximumResponseBytes: admitOptionalLimit(limits.maximumResponseBytes, 16 * 1024 * 1024, 'maximumResponseBytes'),
|
|
247
283
|
maximumConcurrentOperations: admitOptionalLimit(limits.maximumConcurrentOperations, 1_024, 'maximumConcurrentOperations'),
|
|
248
284
|
maximumPublicationBytes: admitOptionalLimit(limits.maximumPublicationBytes, limits.maximumRequestBytes, 'maximumPublicationBytes'),
|
|
249
285
|
maximumBundleBytes: admitOptionalLimit(limits.maximumBundleBytes, 16 * 1024 * 1024, 'maximumBundleBytes'),
|
|
250
286
|
maximumDeliveryBytes: admitOptionalLimit(limits.maximumDeliveryBytes, limits.maximumRequestBytes, 'maximumDeliveryBytes'),
|
|
251
287
|
invocationTimeoutMs: limits.invocationTimeoutMs,
|
|
288
|
+
binaryRequestTimeoutMs: admitTimerLimit(limits.binaryRequestTimeoutMs ?? limits.invocationTimeoutMs, 'binaryRequestTimeoutMs'),
|
|
289
|
+
...(limits.binaryRequestIdleTimeoutMs === undefined
|
|
290
|
+
? {}
|
|
291
|
+
: {
|
|
292
|
+
binaryRequestIdleTimeoutMs: admitTimerLimit(limits.binaryRequestIdleTimeoutMs, 'binaryRequestIdleTimeoutMs'),
|
|
293
|
+
}),
|
|
294
|
+
...(binaryDownloadTarget === undefined
|
|
295
|
+
? {}
|
|
296
|
+
: { binaryDownloadTarget, binaryDownloadTimeoutMs }),
|
|
252
297
|
});
|
|
253
298
|
}
|
|
299
|
+
function admitTimerLimit(input, label) {
|
|
300
|
+
if (!Number.isSafeInteger(input) || input <= 0 || input > 2_147_483_647) {
|
|
301
|
+
throw new TypeError(`${label} must be a positive platform timer duration.`);
|
|
302
|
+
}
|
|
303
|
+
return input;
|
|
304
|
+
}
|
|
254
305
|
function admitOptionalLimit(input, fallback, label) {
|
|
255
306
|
const value = input ?? fallback;
|
|
256
307
|
if (!Number.isSafeInteger(value) || value <= 0) {
|
|
@@ -264,4 +315,15 @@ function admitRoute(path, label) {
|
|
|
264
315
|
}
|
|
265
316
|
return path;
|
|
266
317
|
}
|
|
267
|
-
|
|
318
|
+
function admitPublicOrigin(input) {
|
|
319
|
+
const url = new URL(input);
|
|
320
|
+
if (!['http:', 'https:'].includes(url.protocol) ||
|
|
321
|
+
url.username !== '' ||
|
|
322
|
+
url.password !== '' ||
|
|
323
|
+
url.pathname !== '/' ||
|
|
324
|
+
url.search !== '' ||
|
|
325
|
+
url.hash !== '') {
|
|
326
|
+
throw new TypeError('Server publicOrigin must be an HTTP(S) origin.');
|
|
327
|
+
}
|
|
328
|
+
return url.origin;
|
|
329
|
+
}
|
package/dist/transport/body.d.ts
CHANGED
|
@@ -2,4 +2,3 @@ export { RequestBodyInvalidError, RequestBodyTooLargeError } from '../errors/ind
|
|
|
2
2
|
/** Read a request body while enforcing the limit before retaining excess bytes. */
|
|
3
3
|
export declare function readBoundedBody(request: Request, maximumBytes: number, signal: AbortSignal): Promise<Uint8Array>;
|
|
4
4
|
export declare function byteLength(input: string | Uint8Array): number;
|
|
5
|
-
//# sourceMappingURL=body.d.ts.map
|
package/dist/transport/body.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import * as codecs from '@astrale-os/kernel-protocol/codecs';
|
|
2
2
|
export type LoadedCodec = codecs.Codec;
|
|
3
|
-
/**
|
|
4
|
-
export declare function loadCodecs():
|
|
5
|
-
//# sourceMappingURL=codecs.d.ts.map
|
|
3
|
+
/** The built-in Server representation set before pure Protocol binding selection. */
|
|
4
|
+
export declare function loadCodecs(): readonly [codecs.Codec];
|
package/dist/transport/codecs.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as codecs from '@astrale-os/kernel-protocol/codecs';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
const SUPPORTED = Object.freeze([codecs.json]);
|
|
3
|
+
/** The built-in Server representation set before pure Protocol binding selection. */
|
|
4
|
+
export function loadCodecs() {
|
|
5
|
+
return SUPPORTED;
|
|
5
6
|
}
|
|
6
|
-
//# sourceMappingURL=codecs.js.map
|
|
@@ -8,4 +8,3 @@ export type CredentialResult = {
|
|
|
8
8
|
};
|
|
9
9
|
/** Resolve exactly zero or one untrusted credential channel without authenticating it. */
|
|
10
10
|
export declare function resolveCredential(envelope: string | undefined, authorization: string | null): CredentialResult;
|
|
11
|
-
//# sourceMappingURL=credential.d.ts.map
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type BinaryRequestBody } from '@astrale-os/kernel-core/callable';
|
|
2
|
+
interface IdleBudget {
|
|
3
|
+
readonly timeoutMs: number;
|
|
4
|
+
readonly cancel: () => void;
|
|
5
|
+
}
|
|
6
|
+
/** Admit a declared length before dispatch and expose one counted, non-buffering body. */
|
|
7
|
+
export declare function binaryRequestBody(request: Request, maximumBytes: number, signal: AbortSignal, idle?: IdleBudget): BinaryRequestBody & {
|
|
8
|
+
readonly completed: () => boolean;
|
|
9
|
+
readonly cancel: (reason: unknown) => void;
|
|
10
|
+
};
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { BinaryBodyLengthError } from '@astrale-os/kernel-core/callable';
|
|
2
|
+
import * as protocol from '@astrale-os/kernel-protocol/invocation';
|
|
3
|
+
import { RequestBodyInvalidError, RequestBodyTooLargeError } from '../../errors/index.js';
|
|
4
|
+
/** Admit a declared length before dispatch and expose one counted, non-buffering body. */
|
|
5
|
+
export function binaryRequestBody(request, maximumBytes, signal, idle) {
|
|
6
|
+
const declared = request.headers.get(protocol.http.BINARY_LENGTH_FIELD);
|
|
7
|
+
if (declared === null || !/^(?:0|[1-9][0-9]*)$/u.test(declared)) {
|
|
8
|
+
throw new RequestBodyInvalidError('Binary request length is required and must be exact.');
|
|
9
|
+
}
|
|
10
|
+
const length = Number(declared);
|
|
11
|
+
if (!Number.isSafeInteger(length)) {
|
|
12
|
+
throw new RequestBodyInvalidError('Binary request length is invalid.');
|
|
13
|
+
}
|
|
14
|
+
const contentLength = request.headers.get('content-length');
|
|
15
|
+
if (contentLength !== null && contentLength !== declared) {
|
|
16
|
+
throw new RequestBodyInvalidError('Binary request length differs from Content-Length.');
|
|
17
|
+
}
|
|
18
|
+
if (length > maximumBytes)
|
|
19
|
+
throw new RequestBodyTooLargeError(maximumBytes);
|
|
20
|
+
if (request.body === null) {
|
|
21
|
+
if (length !== 0)
|
|
22
|
+
throw new RequestBodyInvalidError('Binary request body is missing.');
|
|
23
|
+
return Object.freeze({
|
|
24
|
+
body: new ReadableStream({ start: (controller) => controller.close() }),
|
|
25
|
+
length,
|
|
26
|
+
completed: () => true,
|
|
27
|
+
cancel: () => undefined,
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
const reader = request.body.getReader();
|
|
31
|
+
let size = 0;
|
|
32
|
+
let finished = false;
|
|
33
|
+
let completed = false;
|
|
34
|
+
let idleTimer;
|
|
35
|
+
const clearIdle = () => {
|
|
36
|
+
if (idleTimer !== undefined)
|
|
37
|
+
clearTimeout(idleTimer);
|
|
38
|
+
idleTimer = undefined;
|
|
39
|
+
};
|
|
40
|
+
const release = () => {
|
|
41
|
+
if (finished)
|
|
42
|
+
return;
|
|
43
|
+
finished = true;
|
|
44
|
+
clearIdle();
|
|
45
|
+
signal.removeEventListener('abort', abort);
|
|
46
|
+
reader.releaseLock();
|
|
47
|
+
};
|
|
48
|
+
const cancelSource = (reason) => {
|
|
49
|
+
if (finished)
|
|
50
|
+
return;
|
|
51
|
+
clearIdle();
|
|
52
|
+
void reader.cancel(reason).then(release, release);
|
|
53
|
+
};
|
|
54
|
+
const abort = () => cancelSource(signal.reason);
|
|
55
|
+
signal.addEventListener('abort', abort, { once: true });
|
|
56
|
+
if (signal.aborted)
|
|
57
|
+
abort();
|
|
58
|
+
const startIdle = () => {
|
|
59
|
+
if (idle !== undefined && idleTimer === undefined) {
|
|
60
|
+
idleTimer = setTimeout(idle.cancel, idle.timeoutMs);
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
const body = new ReadableStream({
|
|
64
|
+
async pull(controller) {
|
|
65
|
+
try {
|
|
66
|
+
if (signal.aborted)
|
|
67
|
+
throw signal.reason;
|
|
68
|
+
startIdle();
|
|
69
|
+
const next = await reader.read();
|
|
70
|
+
if (signal.aborted)
|
|
71
|
+
throw signal.reason;
|
|
72
|
+
if (next.done) {
|
|
73
|
+
if (size !== length)
|
|
74
|
+
throw new BinaryBodyLengthError();
|
|
75
|
+
completed = true;
|
|
76
|
+
release();
|
|
77
|
+
controller.close();
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
if (!(next.value instanceof Uint8Array)) {
|
|
81
|
+
throw new RequestBodyInvalidError('Binary request yielded a non-byte chunk.');
|
|
82
|
+
}
|
|
83
|
+
size += next.value.byteLength;
|
|
84
|
+
if (size > length)
|
|
85
|
+
throw new BinaryBodyLengthError();
|
|
86
|
+
if (next.value.byteLength > 0)
|
|
87
|
+
clearIdle();
|
|
88
|
+
controller.enqueue(next.value);
|
|
89
|
+
}
|
|
90
|
+
catch (cause) {
|
|
91
|
+
cancelSource(cause);
|
|
92
|
+
release();
|
|
93
|
+
controller.error(cause);
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
cancel(reason) {
|
|
97
|
+
cancelSource(reason);
|
|
98
|
+
release();
|
|
99
|
+
},
|
|
100
|
+
}, { highWaterMark: 0 });
|
|
101
|
+
return Object.freeze({ body, length, completed: () => completed, cancel: cancelSource });
|
|
102
|
+
}
|
|
@@ -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 or a Publication. */
|
|
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
|