@astrale-os/kernel-server 0.5.0-beta.2 → 0.5.0-beta.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (177) hide show
  1. package/dist/capture.d.ts +0 -1
  2. package/dist/capture.js +0 -1
  3. package/dist/cors/cors.d.ts +0 -1
  4. package/dist/cors/cors.js +0 -1
  5. package/dist/cors/index.d.ts +0 -1
  6. package/dist/cors/index.js +0 -1
  7. package/dist/cors/types.d.ts +0 -1
  8. package/dist/cors/types.js +0 -1
  9. package/dist/errors/availability.d.ts +0 -1
  10. package/dist/errors/availability.js +0 -1
  11. package/dist/errors/classify.d.ts +2 -3
  12. package/dist/errors/classify.js +4 -279
  13. package/dist/errors/index.d.ts +0 -1
  14. package/dist/errors/index.js +0 -1
  15. package/dist/errors/request-body.d.ts +0 -1
  16. package/dist/errors/request-body.js +0 -1
  17. package/dist/errors/response-body.d.ts +0 -1
  18. package/dist/errors/response-body.js +0 -1
  19. package/dist/index.d.ts +1 -2
  20. package/dist/index.js +0 -1
  21. package/dist/invocation/context.d.ts +2 -3
  22. package/dist/invocation/context.js +2 -3
  23. package/dist/invocation/identity.d.ts +9 -0
  24. package/dist/invocation/identity.js +11 -0
  25. package/dist/invocation/index.d.ts +2 -2
  26. package/dist/invocation/index.js +1 -1
  27. package/dist/invocation/publication-route.d.ts +5 -4
  28. package/dist/invocation/publication-route.js +8 -7
  29. package/dist/invocation/types.d.ts +33 -9
  30. package/dist/invocation/types.js +0 -1
  31. package/dist/issuer/exchange.d.ts +2 -3
  32. package/dist/issuer/exchange.js +13 -12
  33. package/dist/issuer/index.d.ts +0 -1
  34. package/dist/issuer/index.js +0 -1
  35. package/dist/issuer/routes.d.ts +0 -1
  36. package/dist/issuer/routes.js +14 -12
  37. package/dist/issuer/types.d.ts +2 -2
  38. package/dist/issuer/types.js +0 -1
  39. package/dist/lifecycle/active.d.ts +2 -1
  40. package/dist/lifecycle/active.js +5 -3
  41. package/dist/lifecycle/index.d.ts +0 -1
  42. package/dist/lifecycle/index.js +0 -1
  43. package/dist/publication/delivery/handler.d.ts +0 -1
  44. package/dist/publication/delivery/handler.js +2 -2
  45. package/dist/publication/delivery/index.d.ts +0 -1
  46. package/dist/publication/delivery/index.js +0 -1
  47. package/dist/publication/delivery/types.d.ts +1 -2
  48. package/dist/publication/delivery/types.js +0 -1
  49. package/dist/publication/index.d.ts +0 -1
  50. package/dist/publication/index.js +0 -1
  51. package/dist/publication/snapshot.d.ts +5 -3
  52. package/dist/publication/snapshot.js +14 -7
  53. package/dist/publication/table.d.ts +4 -0
  54. package/dist/publication/table.js +16 -0
  55. package/dist/publication/types.d.ts +5 -2
  56. package/dist/publication/types.js +0 -1
  57. package/dist/routes/index.d.ts +0 -1
  58. package/dist/routes/index.js +0 -1
  59. package/dist/routes/routes.d.ts +3 -3
  60. package/dist/routes/routes.js +91 -26
  61. package/dist/server.d.ts +0 -1
  62. package/dist/server.js +13 -7
  63. package/dist/transport/body.d.ts +0 -1
  64. package/dist/transport/body.js +0 -1
  65. package/dist/transport/codecs.d.ts +1 -2
  66. package/dist/transport/codecs.js +1 -2
  67. package/dist/transport/credential.d.ts +1 -2
  68. package/dist/transport/credential.js +1 -2
  69. package/dist/transport/http/handler.d.ts +2 -1
  70. package/dist/transport/http/handler.js +36 -33
  71. package/dist/transport/http/index.d.ts +0 -1
  72. package/dist/transport/http/index.js +0 -1
  73. package/dist/transport/http/render.d.ts +17 -13
  74. package/dist/transport/http/render.js +120 -41
  75. package/dist/transport/index.d.ts +0 -1
  76. package/dist/transport/index.js +0 -1
  77. package/dist/transport/router.d.ts +0 -1
  78. package/dist/transport/router.js +0 -1
  79. package/dist/transport/stream-error.d.ts +2 -3
  80. package/dist/transport/stream-error.js +3 -4
  81. package/dist/transport/types.d.ts +1 -2
  82. package/dist/transport/types.js +0 -1
  83. package/dist/transport/websocket/index.d.ts +0 -1
  84. package/dist/transport/websocket/index.js +0 -1
  85. package/dist/transport/websocket/session.d.ts +4 -3
  86. package/dist/transport/websocket/session.js +56 -39
  87. package/dist/transport/websocket/upgrade.d.ts +2 -1
  88. package/dist/transport/websocket/upgrade.js +2 -2
  89. package/dist/types.d.ts +6 -4
  90. package/dist/types.js +0 -1
  91. package/package.json +23 -13
  92. package/dist/capture.d.ts.map +0 -1
  93. package/dist/capture.js.map +0 -1
  94. package/dist/cors/cors.d.ts.map +0 -1
  95. package/dist/cors/cors.js.map +0 -1
  96. package/dist/cors/index.d.ts.map +0 -1
  97. package/dist/cors/index.js.map +0 -1
  98. package/dist/cors/types.d.ts.map +0 -1
  99. package/dist/cors/types.js.map +0 -1
  100. package/dist/errors/availability.d.ts.map +0 -1
  101. package/dist/errors/availability.js.map +0 -1
  102. package/dist/errors/classify.d.ts.map +0 -1
  103. package/dist/errors/classify.js.map +0 -1
  104. package/dist/errors/index.d.ts.map +0 -1
  105. package/dist/errors/index.js.map +0 -1
  106. package/dist/errors/request-body.d.ts.map +0 -1
  107. package/dist/errors/request-body.js.map +0 -1
  108. package/dist/errors/response-body.d.ts.map +0 -1
  109. package/dist/errors/response-body.js.map +0 -1
  110. package/dist/index.d.ts.map +0 -1
  111. package/dist/index.js.map +0 -1
  112. package/dist/invocation/context.d.ts.map +0 -1
  113. package/dist/invocation/context.js.map +0 -1
  114. package/dist/invocation/index.d.ts.map +0 -1
  115. package/dist/invocation/index.js.map +0 -1
  116. package/dist/invocation/publication-route.d.ts.map +0 -1
  117. package/dist/invocation/publication-route.js.map +0 -1
  118. package/dist/invocation/types.d.ts.map +0 -1
  119. package/dist/invocation/types.js.map +0 -1
  120. package/dist/issuer/exchange.d.ts.map +0 -1
  121. package/dist/issuer/exchange.js.map +0 -1
  122. package/dist/issuer/index.d.ts.map +0 -1
  123. package/dist/issuer/index.js.map +0 -1
  124. package/dist/issuer/routes.d.ts.map +0 -1
  125. package/dist/issuer/routes.js.map +0 -1
  126. package/dist/issuer/types.d.ts.map +0 -1
  127. package/dist/issuer/types.js.map +0 -1
  128. package/dist/lifecycle/active.d.ts.map +0 -1
  129. package/dist/lifecycle/active.js.map +0 -1
  130. package/dist/lifecycle/index.d.ts.map +0 -1
  131. package/dist/lifecycle/index.js.map +0 -1
  132. package/dist/publication/delivery/handler.d.ts.map +0 -1
  133. package/dist/publication/delivery/handler.js.map +0 -1
  134. package/dist/publication/delivery/index.d.ts.map +0 -1
  135. package/dist/publication/delivery/index.js.map +0 -1
  136. package/dist/publication/delivery/types.d.ts.map +0 -1
  137. package/dist/publication/delivery/types.js.map +0 -1
  138. package/dist/publication/index.d.ts.map +0 -1
  139. package/dist/publication/index.js.map +0 -1
  140. package/dist/publication/snapshot.d.ts.map +0 -1
  141. package/dist/publication/snapshot.js.map +0 -1
  142. package/dist/publication/types.d.ts.map +0 -1
  143. package/dist/publication/types.js.map +0 -1
  144. package/dist/routes/index.d.ts.map +0 -1
  145. package/dist/routes/index.js.map +0 -1
  146. package/dist/routes/routes.d.ts.map +0 -1
  147. package/dist/routes/routes.js.map +0 -1
  148. package/dist/server.d.ts.map +0 -1
  149. package/dist/server.js.map +0 -1
  150. package/dist/transport/body.d.ts.map +0 -1
  151. package/dist/transport/body.js.map +0 -1
  152. package/dist/transport/codecs.d.ts.map +0 -1
  153. package/dist/transport/codecs.js.map +0 -1
  154. package/dist/transport/credential.d.ts.map +0 -1
  155. package/dist/transport/credential.js.map +0 -1
  156. package/dist/transport/http/handler.d.ts.map +0 -1
  157. package/dist/transport/http/handler.js.map +0 -1
  158. package/dist/transport/http/index.d.ts.map +0 -1
  159. package/dist/transport/http/index.js.map +0 -1
  160. package/dist/transport/http/render.d.ts.map +0 -1
  161. package/dist/transport/http/render.js.map +0 -1
  162. package/dist/transport/index.d.ts.map +0 -1
  163. package/dist/transport/index.js.map +0 -1
  164. package/dist/transport/router.d.ts.map +0 -1
  165. package/dist/transport/router.js.map +0 -1
  166. package/dist/transport/stream-error.d.ts.map +0 -1
  167. package/dist/transport/stream-error.js.map +0 -1
  168. package/dist/transport/types.d.ts.map +0 -1
  169. package/dist/transport/types.js.map +0 -1
  170. package/dist/transport/websocket/index.d.ts.map +0 -1
  171. package/dist/transport/websocket/index.js.map +0 -1
  172. package/dist/transport/websocket/session.d.ts.map +0 -1
  173. package/dist/transport/websocket/session.js.map +0 -1
  174. package/dist/transport/websocket/upgrade.d.ts.map +0 -1
  175. package/dist/transport/websocket/upgrade.js.map +0 -1
  176. package/dist/types.d.ts.map +0 -1
  177. package/dist/types.js.map +0 -1
@@ -1,13 +1,20 @@
1
- import { codecs, errors, invocation as protocol, publication, routes, } from '@astrale-os/kernel-protocol';
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';
4
+ import { MEDIA_TYPE as PUBLICATION_MEDIA_TYPE, PATH as PUBLICATION_PATH, url as publicationUrl, } from '@astrale-os/kernel-protocol/publication/publication';
5
+ import { reference as publicationReference } from '@astrale-os/kernel-protocol/publication/reference';
6
+ import * as routes from '@astrale-os/kernel-protocol/routes';
2
7
  import { classifyError, RequestBodyInvalidError, RequestBodyTooLargeError, } from '../errors/index.js';
3
8
  import { invocationContext } from '../invocation/index.js';
4
9
  import { handleDelivery } from '../publication/delivery/index.js';
5
10
  import { readPreparedPublicationSnapshot, } from '../publication/index.js';
6
- import { interruptedStreamError, readBoundedBody } from '../transport/index.js';
7
- export function mountRoutes(app, source, deliveryProvider, handler, active, limits, cors, hostFor, reservations, externalIssuer) {
11
+ import { readBoundedBody } from '../transport/body.js';
12
+ import {} from '../transport/router.js';
13
+ import { interruptedStreamError } from '../transport/stream-error.js';
14
+ export function mountRoutes(app, source, deliveryProvider, handler, active, nextInvocation, limits, cors, hostFor, reservations, externalIssuer) {
8
15
  const publicationPath = externalIssuer === undefined
9
- ? publication.PATH
10
- : new URL(publication.url(externalIssuer)).pathname;
16
+ ? PUBLICATION_PATH
17
+ : new URL(publicationUrl(externalIssuer)).pathname;
11
18
  const externalOrigin = externalIssuer === undefined ? undefined : new URL(externalIssuer).origin;
12
19
  if (cors.enabled) {
13
20
  app.options(publicationPath, (context) => cors.preflight(context.req.raw, {
@@ -37,7 +44,7 @@ export function mountRoutes(app, source, deliveryProvider, handler, active, limi
37
44
  status: 200,
38
45
  headers: {
39
46
  ...responseCors,
40
- 'content-type': 'application/json',
47
+ 'content-type': PUBLICATION_MEDIA_TYPE,
41
48
  etag: quoteEtag(snapshot.publication.etag),
42
49
  'cache-control': 'public, max-age=0, must-revalidate, no-transform',
43
50
  },
@@ -89,7 +96,7 @@ export function mountRoutes(app, source, deliveryProvider, handler, active, limi
89
96
  },
90
97
  });
91
98
  }
92
- routing = routes.decodeRouting(request, publication.reference(snapshot.publication));
99
+ routing = routes.decodeRouting(request, publicationReference(snapshot.publication));
93
100
  }
94
101
  catch (cause) {
95
102
  if (cause instanceof routes.RouteError) {
@@ -97,9 +104,10 @@ export function mountRoutes(app, source, deliveryProvider, handler, active, limi
97
104
  }
98
105
  throw cause;
99
106
  }
100
- const route = routes.match(snapshot.routes, request);
107
+ const route = routes.match(snapshot.table, request);
101
108
  if (route === undefined)
102
109
  return context.notFound();
110
+ const assigned = nextInvocation();
103
111
  const operation = active.begin(limits.invocationTimeoutMs, request.signal);
104
112
  if (operation === undefined)
105
113
  return nativeError({
@@ -109,12 +117,7 @@ export function mountRoutes(app, source, deliveryProvider, handler, active, limi
109
117
  let handedOff = false;
110
118
  try {
111
119
  const body = await readBoundedBody(request, limits.maximumRequestBytes, operation.signal);
112
- const invocation = routes.decode(route, {
113
- url: request.url,
114
- method: request.method,
115
- headers: request.headers,
116
- body,
117
- });
120
+ const invocation = routes.decode(route, { url: request.url, method: request.method, headers: request.headers, body }, snapshot.domain, snapshot.table.publication);
118
121
  const idempotencyHeader = request.headers.get(protocol.HTTP_IDEMPOTENCY_KEY);
119
122
  const idempotencyKey = idempotencyHeader === null
120
123
  ? undefined
@@ -124,7 +127,7 @@ export function mountRoutes(app, source, deliveryProvider, handler, active, limi
124
127
  ...(invocation.credential === undefined ? {} : { credential: invocation.credential }),
125
128
  ...(routing === undefined ? {} : { via: routing }),
126
129
  publication: snapshot.snapshot,
127
- context: invocationContext(operation, active, hostFor(request), body, idempotencyKey),
130
+ context: invocationContext(assigned, operation, active, hostFor(request), body, idempotencyKey),
128
131
  }));
129
132
  if (result.kind === 'value') {
130
133
  return new Response(encodedBody(codecs.json.encode(result.value)), {
@@ -135,8 +138,13 @@ export function mountRoutes(app, source, deliveryProvider, handler, active, limi
135
138
  });
136
139
  }
137
140
  if (result.kind === 'binary') {
141
+ if (isStreamingBinary(result.value)) {
142
+ handedOff = true;
143
+ return streamingBinaryResponse(result.value, operation, cors, request);
144
+ }
138
145
  const applicationHeaders = applicationBinaryHeaders(result.value.headers);
139
146
  return new Response(toBody(result.value.body), {
147
+ status: result.value.status ?? 200,
140
148
  headers: {
141
149
  ...cors.response(request, [
142
150
  protocol.http.BINARY_HEADERS_FIELD,
@@ -194,6 +202,66 @@ export function mountRoutes(app, source, deliveryProvider, handler, active, limi
194
202
  }
195
203
  });
196
204
  }
205
+ function streamingBinaryResponse(binary, operation, cors, request) {
206
+ const iterator = binary.body[Symbol.asyncIterator]();
207
+ const applicationHeaders = applicationBinaryHeaders(binary.headers);
208
+ let terminal = false;
209
+ let stopping;
210
+ const stop = () => {
211
+ stopping ??= Promise.resolve().then(async () => {
212
+ if (terminal)
213
+ return;
214
+ terminal = true;
215
+ try {
216
+ await iterator.return?.();
217
+ }
218
+ finally {
219
+ operation.settle();
220
+ }
221
+ });
222
+ return stopping;
223
+ };
224
+ const body = new ReadableStream({
225
+ async pull(controller) {
226
+ if (terminal)
227
+ return;
228
+ try {
229
+ const next = await iterator.next();
230
+ if (terminal)
231
+ return;
232
+ if (next.done) {
233
+ terminal = true;
234
+ controller.close();
235
+ operation.settle();
236
+ return;
237
+ }
238
+ controller.enqueue(next.value);
239
+ }
240
+ catch (cause) {
241
+ terminal = true;
242
+ controller.error(cause);
243
+ operation.settle();
244
+ }
245
+ },
246
+ async cancel(reason) {
247
+ const message = typeof reason === 'string' ? reason : 'native binary response cancelled';
248
+ operation.cancel(message);
249
+ await stop();
250
+ },
251
+ });
252
+ operation.onCancel(stop);
253
+ return new Response(body, {
254
+ status: binary.status ?? 200,
255
+ headers: {
256
+ ...cors.response(request, Object.keys(applicationHeaders)),
257
+ ...applicationHeaders,
258
+ 'content-type': binary.mediaType,
259
+ },
260
+ });
261
+ }
262
+ function isStreamingBinary(input) {
263
+ return !(input.body instanceof Uint8Array);
264
+ }
197
265
  function publicationPreflight(cors, request, snapshot, externalOrigin) {
198
266
  if (sameRoute(request.url, snapshot.publication.schema.bundle.href, externalOrigin)) {
199
267
  return cors.preflight(request, { methods: ['GET'], headers: ['if-none-match'] });
@@ -208,7 +276,7 @@ function publicationPreflight(cors, request, snapshot, externalOrigin) {
208
276
  const requestedMethod = request.headers.get('access-control-request-method');
209
277
  const route = requestedMethod === null
210
278
  ? undefined
211
- : routes.match(snapshot.routes, { url: request.url, method: requestedMethod });
279
+ : routes.match(snapshot.table, { url: request.url, method: requestedMethod });
212
280
  return cors.preflight(request, route === undefined ? undefined : nativeCorsRoute(route, requestedMethod));
213
281
  }
214
282
  function nativeCorsRoute(entry, requestedMethod) {
@@ -218,16 +286,16 @@ function nativeCorsRoute(entry, requestedMethod) {
218
286
  routes.HTTP_ROUTE_ISSUER,
219
287
  protocol.HTTP_IDEMPOTENCY_KEY,
220
288
  ]);
221
- if (entry.route.body !== undefined)
289
+ if (entry.body !== undefined)
222
290
  headers.add('content-type');
223
291
  let allowAnyHeaders = false;
224
- for (const pick of Object.values(entry.route.headers ?? {})) {
292
+ for (const pick of Object.values(entry.headers ?? {})) {
225
293
  if (pick === '*')
226
294
  allowAnyHeaders = true;
227
295
  else
228
296
  headers.add(pick.toLowerCase());
229
297
  }
230
- const credential = entry.route.credential;
298
+ const credential = entry.credential;
231
299
  const sources = credential === undefined
232
300
  ? [{ in: 'header' }]
233
301
  : Array.isArray(credential)
@@ -238,9 +306,7 @@ function nativeCorsRoute(entry, requestedMethod) {
238
306
  headers.add((source.name ?? 'authorization').toLowerCase());
239
307
  }
240
308
  return Object.freeze({
241
- methods: Object.freeze([
242
- entry.route.method === '*' ? requestedMethod.toUpperCase() : entry.route.method,
243
- ]),
309
+ methods: Object.freeze([entry.method === '*' ? requestedMethod.toUpperCase() : entry.method]),
244
310
  headers: Object.freeze([...headers]),
245
311
  ...(allowAnyHeaders ? { allowAnyHeaders: true } : {}),
246
312
  });
@@ -269,9 +335,9 @@ function servingSnapshot(source, limits, request, reservations, externalIssuer)
269
335
  function conflictsWithServingRoutes(snapshot, serving) {
270
336
  for (const reservation of serving.reservations) {
271
337
  const href = `${serving.origin}${reservation.path}`;
272
- for (const entry of snapshot.routes) {
273
- if (reservation.methods.some((method) => entry.route.method === '*' || entry.route.method === method) &&
274
- routes.templatesOverlap(entry.route.href, href)) {
338
+ for (const entry of snapshot.table.entries) {
339
+ if (reservation.methods.some((method) => entry.method === '*' || entry.method === method) &&
340
+ routes.templatesOverlap(entry.href, href)) {
275
341
  return true;
276
342
  }
277
343
  }
@@ -445,4 +511,3 @@ function encodedBody(input) {
445
511
  function toBody(input) {
446
512
  return input.buffer.slice(input.byteOffset, input.byteOffset + input.byteLength);
447
513
  }
448
- //# sourceMappingURL=routes.js.map
package/dist/server.d.ts CHANGED
@@ -2,4 +2,3 @@ import type { Server, ServerConfig, ServerOptions, PreparedServer } from './type
2
2
  export declare function createServer(config: ServerConfig): Server;
3
3
  /** Validate all static transport configuration before a Host starts Runtime recovery/bootstrap. */
4
4
  export declare function prepareServer(options: ServerOptions): PreparedServer;
5
- //# sourceMappingURL=server.d.ts.map
package/dist/server.js CHANGED
@@ -1,11 +1,14 @@
1
- import { publication as protocolPublication } from '@astrale-os/kernel-protocol';
1
+ import { PATH as PUBLICATION_PATH, url as publicationUrl, } from '@astrale-os/kernel-protocol/publication/publication';
2
2
  import { captureMethod } from './capture.js';
3
3
  import { prepareCors } from './cors/index.js';
4
+ import { captureInvocationSource } from './invocation/index.js';
4
5
  import { capture as captureExchangeProvider } from './issuer/exchange.js';
5
6
  import { admitIssuer, issuerRouteReservations, mountIssuer } from './issuer/index.js';
6
7
  import { ActiveOperations } from './lifecycle/index.js';
7
8
  import { currentPublicationSnapshot, mountRoutes } from './routes/index.js';
8
- import { createHttpHandler, createServerRouter, handleWebSocketUpgrade } from './transport/index.js';
9
+ import { createHttpHandler } from './transport/http/handler.js';
10
+ import { createServerRouter } from './transport/router.js';
11
+ import { handleWebSocketUpgrade } from './transport/websocket/upgrade.js';
9
12
  export function createServer(config) {
10
13
  const { handler, ...options } = config;
11
14
  return prepareServer(options).create(handler);
@@ -27,6 +30,7 @@ function createPreparedServer(input, config) {
27
30
  const handleHttp = createHttpHandler({
28
31
  handler,
29
32
  active,
33
+ invocation: config.invocation,
30
34
  ...config.limits,
31
35
  cors: config.cors,
32
36
  websocket: config.websocket !== undefined,
@@ -46,6 +50,7 @@ function createPreparedServer(input, config) {
46
50
  adapter: config.websocket,
47
51
  handler,
48
52
  active,
53
+ invocation: config.invocation,
49
54
  ...config.limits,
50
55
  cors: config.cors,
51
56
  ...(config.publication === undefined
@@ -63,7 +68,7 @@ function createPreparedServer(input, config) {
63
68
  app.all(config.path, (context) => handleHttp(context.req.raw, hosts.get(context.req.raw)));
64
69
  if (config.health !== undefined) {
65
70
  app.get(config.health.path, (context) => {
66
- const ready = active.isAccepting && config.health.probe.check();
71
+ const ready = active.isAvailable && config.health.probe.check();
67
72
  return context.json({ status: ready ? 'ready' : 'not-ready' }, ready ? 200 : 503, {
68
73
  ...config.cors.response(context.req.raw),
69
74
  'cache-control': 'no-store',
@@ -77,7 +82,7 @@ function createPreparedServer(input, config) {
77
82
  mountIssuer(app, config.issuer, config.cors, active, config.limits.invocationTimeoutMs, config.tokenExchange);
78
83
  }
79
84
  if (config.publication !== undefined) {
80
- mountRoutes(app, config.publication, config.delivery, handler, active, config.limits, config.cors, (request) => hosts.get(request), config.routeReservations, externalIssuer);
85
+ mountRoutes(app, config.publication, config.delivery, handler, active, config.invocation, config.limits, config.cors, (request) => hosts.get(request), config.routeReservations, externalIssuer);
81
86
  }
82
87
  app.onError((_error, context) => new Response('{"error":"Internal server error."}', {
83
88
  status: 500,
@@ -126,6 +131,7 @@ function captureHandler(input) {
126
131
  return Object.freeze({ dispatch });
127
132
  }
128
133
  function admitOptions(config) {
134
+ const invocation = captureInvocationSource(config.invocation);
129
135
  const limits = admitLimits(config.limits);
130
136
  const path = admitRoute(config.path ?? '/', 'invocation path');
131
137
  const issuer = config.issuer === undefined ? undefined : admitIssuer(config.issuer);
@@ -173,6 +179,7 @@ function admitOptions(config) {
173
179
  }
174
180
  }
175
181
  return Object.freeze({
182
+ invocation,
176
183
  limits,
177
184
  path,
178
185
  cors: prepareCors(config.cors),
@@ -205,8 +212,8 @@ function routeReservations(invocationPath, healthPath, issuer, websocket, tokenE
205
212
  }
206
213
  function protocolPublicationPath(issuer) {
207
214
  if (issuer === undefined)
208
- return protocolPublication.PATH;
209
- return new URL(protocolPublication.url(issuer)).pathname;
215
+ return PUBLICATION_PATH;
216
+ return new URL(publicationUrl(issuer)).pathname;
210
217
  }
211
218
  function captureHealthProbe(probe) {
212
219
  const check = captureMethod(probe, 'check', 'Health probe is invalid.');
@@ -257,4 +264,3 @@ function admitRoute(path, label) {
257
264
  }
258
265
  return path;
259
266
  }
260
- //# sourceMappingURL=server.js.map
@@ -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
@@ -48,4 +48,3 @@ export async function readBoundedBody(request, maximumBytes, signal) {
48
48
  export function byteLength(input) {
49
49
  return typeof input === 'string' ? new TextEncoder().encode(input).byteLength : input.byteLength;
50
50
  }
51
- //# sourceMappingURL=body.js.map
@@ -1,5 +1,4 @@
1
- import { codecs } from '@astrale-os/kernel-protocol';
1
+ import * as codecs from '@astrale-os/kernel-protocol/codecs';
2
2
  export type LoadedCodec = codecs.Codec;
3
3
  /** Load the built-in Server representation set before pure Protocol binding selection. */
4
4
  export declare function loadCodecs(): Promise<readonly [codecs.Codec, codecs.Codec]>;
5
- //# sourceMappingURL=codecs.d.ts.map
@@ -1,6 +1,5 @@
1
- import { codecs } from '@astrale-os/kernel-protocol';
1
+ import * as codecs from '@astrale-os/kernel-protocol/codecs';
2
2
  /** Load the built-in Server representation set before pure Protocol binding selection. */
3
3
  export async function loadCodecs() {
4
4
  return Object.freeze([codecs.json, await codecs.loadMsgpack()]);
5
5
  }
6
- //# sourceMappingURL=codecs.js.map
@@ -1,4 +1,4 @@
1
- import { errors } from '@astrale-os/kernel-protocol';
1
+ import * as errors from '@astrale-os/kernel-protocol/errors';
2
2
  export type CredentialResult = {
3
3
  readonly ok: true;
4
4
  readonly credential: string | undefined;
@@ -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
@@ -1,4 +1,4 @@
1
- import { errors } from '@astrale-os/kernel-protocol';
1
+ import * as errors from '@astrale-os/kernel-protocol/errors';
2
2
  /** Resolve exactly zero or one untrusted credential channel without authenticating it. */
3
3
  export function resolveCredential(envelope, authorization) {
4
4
  if (envelope !== undefined && authorization !== null) {
@@ -26,4 +26,3 @@ function failure(message) {
26
26
  error: { code: errors.CODES.INVALID_REQUEST, message },
27
27
  };
28
28
  }
29
- //# sourceMappingURL=credential.js.map
@@ -1,10 +1,12 @@
1
1
  import type { CorsPolicy } from '../../cors/index.js';
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 ApplicationHost, type Handler } from '../../invocation/index.js';
5
6
  export interface HttpHandlerConfig {
6
7
  readonly handler: Handler;
7
8
  readonly active: ActiveOperations;
9
+ readonly invocation: NextInvocationId;
8
10
  readonly maximumRequestBytes: number;
9
11
  readonly maximumResponseBytes: number;
10
12
  readonly invocationTimeoutMs: number;
@@ -13,4 +15,3 @@ export interface HttpHandlerConfig {
13
15
  readonly currentPublication?: (request: Request) => PublicationSnapshot | undefined;
14
16
  }
15
17
  export declare function createHttpHandler(config: HttpHandlerConfig): (request: Request, host?: ApplicationHost) => Promise<Response>;
16
- //# sourceMappingURL=handler.d.ts.map
@@ -1,4 +1,6 @@
1
- import { codecs, errors, invocation as protocol } from '@astrale-os/kernel-protocol';
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
5
  import { invocationContext, publicationRouteDecision, } from '../../invocation/index.js';
4
6
  import { readBoundedBody } from '../body.js';
@@ -8,10 +10,6 @@ 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',
@@ -34,8 +32,13 @@ export function createHttpHandler(config) {
34
32
  headers: { ...cors(), allow: allow.join(', '), 'cache-control': 'no-store' },
35
33
  });
36
34
  }
37
- const operation = config.active.begin(config.invocationTimeoutMs, request.signal);
38
- if (operation === undefined) {
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) {
39
42
  return renderError(null, {
40
43
  code: errors.CODES.BACKEND_UNAVAILABLE,
41
44
  message: 'server is unavailable.',
@@ -63,19 +66,19 @@ export function createHttpHandler(config) {
63
66
  }
64
67
  let body;
65
68
  try {
66
- body = await readBoundedBody(request, config.maximumRequestBytes, operation.signal);
69
+ body = await readBoundedBody(request, config.maximumRequestBytes, active.signal);
67
70
  }
68
71
  catch (input) {
69
72
  const payload = input instanceof RequestBodyTooLargeError
70
73
  ? classifyError(input)
71
74
  : input instanceof RequestBodyInvalidError
72
75
  ? { code: errors.CODES.PARSE_ERROR, message: 'Request body is invalid.' }
73
- : operation.timedOut
76
+ : active.timedOut
74
77
  ? {
75
78
  code: errors.CODES.DEADLINE_EXCEEDED,
76
79
  message: 'Invocation deadline exceeded.',
77
80
  }
78
- : operation.signal.aborted
81
+ : active.signal.aborted
79
82
  ? { code: errors.CODES.CANCELLED, message: 'Invocation was cancelled.' }
80
83
  : undefined;
81
84
  if (payload === undefined)
@@ -93,69 +96,70 @@ export function createHttpHandler(config) {
93
96
  throw input;
94
97
  return renderError(null, { code: errors.CODES.PARSE_ERROR, message: 'Request body is invalid.' }, outgoing);
95
98
  }
96
- let invocation;
99
+ let envelope;
97
100
  try {
98
- invocation = protocol.decodeRequest(decoded);
101
+ envelope = protocol.decodeRequest(decoded);
99
102
  }
100
103
  catch (input) {
101
104
  return renderError(null, classifyError(input), outgoing);
102
105
  }
103
106
  const publication = config.currentPublication?.(request);
104
107
  if (config.currentPublication !== undefined && publication === undefined) {
105
- return renderError(invocation.id, {
108
+ return renderError(envelope.requestId, {
106
109
  code: errors.CODES.BACKEND_UNAVAILABLE,
107
110
  message: 'Publication is unavailable.',
108
111
  }, outgoing, { status: 503 });
109
112
  }
110
- if (invocation.routing?.kind === 'via') {
113
+ if (envelope.routing?.kind === 'via') {
111
114
  if (publication === undefined) {
112
- return renderError(invocation.id, {
115
+ return renderError(envelope.requestId, {
113
116
  code: errors.CODES.INVALID_REQUEST,
114
117
  message: 'Publication routing requires a Publication-backed destination.',
115
118
  }, outgoing);
116
119
  }
117
- const decision = publicationRouteDecision(publication.publication, invocation.routing.publication);
120
+ const decision = publicationRouteDecision(publication.publication, envelope.routing.publication);
118
121
  if (decision.kind === 'rejected') {
119
- return renderError(invocation.id, decision.error, outgoing);
122
+ return renderError(envelope.requestId, decision.error, outgoing);
120
123
  }
121
124
  }
122
- const credential = resolveCredential(invocation.credential, request.headers.get('authorization'));
125
+ const credential = resolveCredential(envelope.credential, request.headers.get('authorization'));
123
126
  if (!credential.ok) {
124
- return renderError(invocation.id, credential.error, outgoing);
127
+ return renderError(envelope.requestId, credential.error, outgoing);
125
128
  }
126
129
  const trace = protocol.http.decodeTraceHeaders(request.headers.get(protocol.http.TRACEPARENT_FIELD), request.headers.get(protocol.http.TRACESTATE_FIELD));
127
130
  try {
128
131
  const result = await config.handler.dispatch(Object.freeze({
129
- call: invocation.call,
132
+ call: envelope.call,
130
133
  ...(trace === undefined ? {} : { trace }),
131
134
  ...(credential.credential === undefined ? {} : { credential: credential.credential }),
132
- ...(invocation.delegate === undefined ? {} : { delegate: invocation.delegate }),
133
- ...(invocation.routing?.kind === 'via' ? { via: invocation.routing } : {}),
134
- ...(invocation.schema === undefined ? {} : { schema: invocation.schema }),
135
+ ...(envelope.delegate === undefined ? {} : { delegate: envelope.delegate }),
136
+ ...(envelope.routing?.kind === 'via' ? { via: envelope.routing } : {}),
137
+ ...(envelope.schema === undefined ? {} : { schema: envelope.schema }),
135
138
  ...(publication === undefined ? {} : { publication }),
136
- context: invocationContext(operation, config.active, host, undefined, invocation.idempotencyKey),
139
+ context: invocationContext(assigned, active, config.active, host, undefined, envelope.idempotencyKey),
137
140
  }));
138
141
  const response = renderHttpResult(result, {
139
- id: invocation.id,
142
+ requestId: envelope.requestId,
140
143
  codec: outgoing,
141
144
  cors,
142
- operation,
145
+ invocation: assigned,
146
+ active,
143
147
  maximumResponseBytes: config.maximumResponseBytes,
144
148
  });
145
149
  handedOff = result.kind === 'stream';
146
150
  return response;
147
151
  }
148
152
  catch (input) {
149
- if (operation.timedOut) {
150
- return renderError(invocation.id, {
153
+ if (active.timedOut) {
154
+ return renderError(envelope.requestId, {
151
155
  code: errors.CODES.DEADLINE_EXCEEDED,
152
156
  message: 'Invocation deadline exceeded.',
153
157
  }, outgoing, { status: 504 });
154
158
  }
155
- if (operation.signal.aborted) {
156
- return renderError(invocation.id, { code: errors.CODES.CANCELLED, message: 'Invocation was cancelled.' }, outgoing, { status: 408 });
159
+ if (active.signal.aborted) {
160
+ return renderError(envelope.requestId, { code: errors.CODES.CANCELLED, message: 'Invocation was cancelled.' }, outgoing, { status: 408 });
157
161
  }
158
- return renderError(invocation.id, classifyError(input), outgoing);
162
+ return renderError(envelope.requestId, classifyError(input), outgoing);
159
163
  }
160
164
  }
161
165
  catch (input) {
@@ -165,7 +169,7 @@ export function createHttpHandler(config) {
165
169
  }
166
170
  finally {
167
171
  if (!handedOff)
168
- operation.settle();
172
+ active.settle();
169
173
  }
170
174
  };
171
175
  }
@@ -174,4 +178,3 @@ function noStore(response) {
174
178
  headers.set('cache-control', 'no-store');
175
179
  return new Response(response.body, { status: response.status, headers });
176
180
  }
177
- //# 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,3 +1,2 @@
1
1
  export { createHttpHandler } from './handler.js';
2
2
  export { encodeEnvelope, renderBinary, renderHttpError, renderHttpResult, renderHttpStale, renderRedirect, } from './render.js';
3
- //# sourceMappingURL=index.js.map
@@ -1,11 +1,15 @@
1
- import { errors, invocation as protocol, type codecs } from '@astrale-os/kernel-protocol';
1
+ import type { BufferedBinaryResult, StreamingBinaryResult } from '@astrale-os/kernel-core/callable';
2
+ import type { Codec } from '@astrale-os/kernel-protocol/codecs';
3
+ import * as errors from '@astrale-os/kernel-protocol/errors';
4
+ import * as protocol from '@astrale-os/kernel-protocol/invocation';
2
5
  import type { Handler } from '../../invocation/index.js';
3
6
  import type { ActiveOperation } from '../../lifecycle/index.js';
4
7
  export interface RenderContext {
5
- readonly id: protocol.RequestId;
6
- readonly codec: codecs.Codec;
8
+ readonly requestId: protocol.RequestId;
9
+ readonly codec: Codec;
7
10
  readonly cors: CorsHeaders;
8
- readonly operation: ActiveOperation;
11
+ readonly invocation: protocol.InvocationId;
12
+ readonly active: ActiveOperation;
9
13
  readonly maximumResponseBytes: number;
10
14
  }
11
15
  export type CorsHeaders = (exposedHeaders?: readonly string[]) => Readonly<Record<string, string>>;
@@ -16,14 +20,14 @@ export interface ErrorRenderOptions {
16
20
  }
17
21
  type HandlerResult = Awaited<ReturnType<Handler['dispatch']>>;
18
22
  export declare function renderHttpResult(result: HandlerResult, context: RenderContext): Response;
19
- export declare function renderBinary(id: protocol.RequestId, binary: Extract<HandlerResult, {
20
- readonly kind: 'binary';
21
- }>['value']): protocol.BinaryResponse;
22
- export declare function renderRedirect(id: protocol.RequestId, redirect: Extract<HandlerResult, {
23
+ export declare function renderBinary(requestId: protocol.RequestId, invocation: protocol.InvocationId, binary: BufferedBinaryResult): protocol.BinaryResponse;
24
+ export declare function renderRedirect(requestId: protocol.RequestId, invocation: protocol.InvocationId, redirect: Extract<HandlerResult, {
23
25
  readonly kind: 'redirect';
24
- }>['redirect']): protocol.Redirect;
25
- export declare function renderHttpError(id: protocol.RequestId, error: errors.ErrorPayload, codec: codecs.Codec, cors: CorsHeaders, options?: ErrorRenderOptions): Response;
26
- export declare function renderHttpStale(id: protocol.RequestId, current: protocol.Stale['current'], codec: codecs.Codec, cors: CorsHeaders, maximumResponseBytes?: number): Response;
27
- export declare function encodeEnvelope(codec: codecs.Codec, input: unknown): string | Uint8Array;
26
+ }>['redirect']): protocol.RedirectResponse;
27
+ export declare function renderHttpError(requestId: protocol.RequestId, invocation: protocol.InvocationId, error: errors.ErrorPayload, codec: Codec, cors: CorsHeaders, options?: ErrorRenderOptions): Response;
28
+ export declare function renderHttpStale(requestId: protocol.RequestId, invocation: protocol.InvocationId, current: protocol.Stale['current'], codec: Codec, cors: CorsHeaders, maximumResponseBytes?: number): Response;
29
+ export declare function encodeEnvelope(codec: Codec, input: unknown): string | Uint8Array;
30
+ export declare function isStreamingBinary(input: Extract<HandlerResult, {
31
+ readonly kind: 'binary';
32
+ }>['value']): input is StreamingBinaryResult;
28
33
  export {};
29
- //# sourceMappingURL=render.d.ts.map