@astrale-os/kernel-server 0.5.0-beta.7 → 0.5.0-beta.70

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 (215) 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 +11 -4
  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/admission.d.ts +7 -0
  10. package/dist/errors/admission.js +22 -0
  11. package/dist/errors/availability.d.ts +0 -1
  12. package/dist/errors/availability.js +0 -1
  13. package/dist/errors/classify.d.ts +8 -1
  14. package/dist/errors/classify.js +15 -1
  15. package/dist/errors/index.d.ts +2 -2
  16. package/dist/errors/index.js +2 -2
  17. package/dist/errors/request-body.d.ts +0 -1
  18. package/dist/errors/request-body.js +0 -1
  19. package/dist/errors/response-body.d.ts +0 -1
  20. package/dist/errors/response-body.js +0 -1
  21. package/dist/index.d.ts +8 -4
  22. package/dist/index.js +7 -3
  23. package/dist/invocation/context.d.ts +3 -3
  24. package/dist/invocation/context.js +2 -2
  25. package/dist/invocation/identity.d.ts +1 -2
  26. package/dist/invocation/identity.js +1 -2
  27. package/dist/invocation/index.d.ts +1 -2
  28. package/dist/invocation/index.js +1 -2
  29. package/dist/invocation/legacy/index.d.ts +20 -0
  30. package/dist/invocation/legacy/index.js +20 -0
  31. package/dist/invocation/{publication-route.d.ts → legacy/publication-route.d.ts} +7 -5
  32. package/dist/invocation/{publication-route.js → legacy/publication-route.js} +7 -13
  33. package/dist/invocation/release-route.d.ts +26 -0
  34. package/dist/invocation/release-route.js +55 -0
  35. package/dist/invocation/types.d.ts +20 -7
  36. package/dist/invocation/types.js +0 -1
  37. package/dist/issuer/exchange.d.ts +0 -1
  38. package/dist/issuer/exchange.js +20 -10
  39. package/dist/issuer/index.d.ts +0 -1
  40. package/dist/issuer/index.js +0 -1
  41. package/dist/issuer/routes.d.ts +0 -1
  42. package/dist/issuer/routes.js +33 -5
  43. package/dist/issuer/types.d.ts +5 -1
  44. package/dist/issuer/types.js +0 -1
  45. package/dist/lifecycle/active.d.ts +4 -1
  46. package/dist/lifecycle/active.js +48 -11
  47. package/dist/lifecycle/index.d.ts +0 -1
  48. package/dist/lifecycle/index.js +0 -1
  49. package/dist/release/delivery/handler.d.ts +13 -0
  50. package/dist/{publication → release}/delivery/handler.js +42 -15
  51. package/dist/{publication → release}/delivery/index.d.ts +0 -1
  52. package/dist/{publication → release}/delivery/index.js +0 -1
  53. package/dist/release/delivery/types.d.ts +21 -0
  54. package/dist/release/delivery/types.js +1 -0
  55. package/dist/release/index.d.ts +3 -0
  56. package/dist/release/index.js +2 -0
  57. package/dist/release/legacy/delivery.d.ts +18 -0
  58. package/dist/release/legacy/delivery.js +2 -0
  59. package/dist/release/legacy/index.d.ts +39 -0
  60. package/dist/release/legacy/index.js +38 -0
  61. package/dist/release/legacy/snapshot.d.ts +26 -0
  62. package/dist/release/legacy/snapshot.js +55 -0
  63. package/dist/release/legacy/table.d.ts +5 -0
  64. package/dist/{publication → release/legacy}/table.js +5 -6
  65. package/dist/release/legacy/types.d.ts +31 -0
  66. package/dist/release/legacy/types.js +1 -0
  67. package/dist/release/served.d.ts +30 -0
  68. package/dist/release/served.js +14 -0
  69. package/dist/release/snapshot.d.ts +26 -0
  70. package/dist/release/snapshot.js +54 -0
  71. package/dist/release/table.d.ts +4 -0
  72. package/dist/release/table.js +11 -0
  73. package/dist/release/types.d.ts +33 -0
  74. package/dist/release/types.js +1 -0
  75. package/dist/routes/index.d.ts +1 -2
  76. package/dist/routes/index.js +1 -2
  77. package/dist/routes/routes.d.ts +9 -7
  78. package/dist/routes/routes.js +256 -123
  79. package/dist/server.d.ts +0 -1
  80. package/dist/server.js +110 -48
  81. package/dist/transport/body.d.ts +0 -1
  82. package/dist/transport/body.js +0 -1
  83. package/dist/transport/codecs.d.ts +2 -3
  84. package/dist/transport/codecs.js +4 -4
  85. package/dist/transport/credential.d.ts +0 -1
  86. package/dist/transport/credential.js +0 -1
  87. package/dist/transport/http/binary-request.d.ts +11 -0
  88. package/dist/transport/http/binary-request.js +102 -0
  89. package/dist/transport/http/handler.d.ts +8 -3
  90. package/dist/transport/http/handler.js +95 -45
  91. package/dist/transport/http/index.d.ts +0 -1
  92. package/dist/transport/http/index.js +0 -1
  93. package/dist/transport/http/render.d.ts +9 -4
  94. package/dist/transport/http/render.js +150 -5
  95. package/dist/transport/index.d.ts +0 -1
  96. package/dist/transport/index.js +0 -1
  97. package/dist/transport/router.d.ts +0 -1
  98. package/dist/transport/router.js +0 -1
  99. package/dist/transport/stream-error.d.ts +0 -1
  100. package/dist/transport/stream-error.js +0 -1
  101. package/dist/transport/types.d.ts +1 -2
  102. package/dist/transport/types.js +0 -1
  103. package/dist/transport/websocket/index.d.ts +0 -1
  104. package/dist/transport/websocket/index.js +0 -1
  105. package/dist/transport/websocket/session.d.ts +3 -3
  106. package/dist/transport/websocket/session.js +30 -30
  107. package/dist/transport/websocket/upgrade.d.ts +2 -3
  108. package/dist/transport/websocket/upgrade.js +7 -7
  109. package/dist/types.d.ts +32 -6
  110. package/dist/types.js +0 -1
  111. package/package.json +12 -15
  112. package/dist/capture.d.ts.map +0 -1
  113. package/dist/capture.js.map +0 -1
  114. package/dist/cors/cors.d.ts.map +0 -1
  115. package/dist/cors/cors.js.map +0 -1
  116. package/dist/cors/index.d.ts.map +0 -1
  117. package/dist/cors/index.js.map +0 -1
  118. package/dist/cors/types.d.ts.map +0 -1
  119. package/dist/cors/types.js.map +0 -1
  120. package/dist/errors/availability.d.ts.map +0 -1
  121. package/dist/errors/availability.js.map +0 -1
  122. package/dist/errors/classify.d.ts.map +0 -1
  123. package/dist/errors/classify.js.map +0 -1
  124. package/dist/errors/index.d.ts.map +0 -1
  125. package/dist/errors/index.js.map +0 -1
  126. package/dist/errors/request-body.d.ts.map +0 -1
  127. package/dist/errors/request-body.js.map +0 -1
  128. package/dist/errors/response-body.d.ts.map +0 -1
  129. package/dist/errors/response-body.js.map +0 -1
  130. package/dist/index.d.ts.map +0 -1
  131. package/dist/index.js.map +0 -1
  132. package/dist/invocation/context.d.ts.map +0 -1
  133. package/dist/invocation/context.js.map +0 -1
  134. package/dist/invocation/identity.d.ts.map +0 -1
  135. package/dist/invocation/identity.js.map +0 -1
  136. package/dist/invocation/index.d.ts.map +0 -1
  137. package/dist/invocation/index.js.map +0 -1
  138. package/dist/invocation/publication-route.d.ts.map +0 -1
  139. package/dist/invocation/publication-route.js.map +0 -1
  140. package/dist/invocation/types.d.ts.map +0 -1
  141. package/dist/invocation/types.js.map +0 -1
  142. package/dist/issuer/exchange.d.ts.map +0 -1
  143. package/dist/issuer/exchange.js.map +0 -1
  144. package/dist/issuer/index.d.ts.map +0 -1
  145. package/dist/issuer/index.js.map +0 -1
  146. package/dist/issuer/routes.d.ts.map +0 -1
  147. package/dist/issuer/routes.js.map +0 -1
  148. package/dist/issuer/types.d.ts.map +0 -1
  149. package/dist/issuer/types.js.map +0 -1
  150. package/dist/lifecycle/active.d.ts.map +0 -1
  151. package/dist/lifecycle/active.js.map +0 -1
  152. package/dist/lifecycle/index.d.ts.map +0 -1
  153. package/dist/lifecycle/index.js.map +0 -1
  154. package/dist/publication/delivery/handler.d.ts +0 -10
  155. package/dist/publication/delivery/handler.d.ts.map +0 -1
  156. package/dist/publication/delivery/handler.js.map +0 -1
  157. package/dist/publication/delivery/index.d.ts.map +0 -1
  158. package/dist/publication/delivery/index.js.map +0 -1
  159. package/dist/publication/delivery/types.d.ts +0 -12
  160. package/dist/publication/delivery/types.d.ts.map +0 -1
  161. package/dist/publication/delivery/types.js +0 -2
  162. package/dist/publication/delivery/types.js.map +0 -1
  163. package/dist/publication/index.d.ts +0 -4
  164. package/dist/publication/index.d.ts.map +0 -1
  165. package/dist/publication/index.js +0 -3
  166. package/dist/publication/index.js.map +0 -1
  167. package/dist/publication/snapshot.d.ts +0 -16
  168. package/dist/publication/snapshot.d.ts.map +0 -1
  169. package/dist/publication/snapshot.js +0 -39
  170. package/dist/publication/snapshot.js.map +0 -1
  171. package/dist/publication/table.d.ts +0 -4
  172. package/dist/publication/table.d.ts.map +0 -1
  173. package/dist/publication/table.js.map +0 -1
  174. package/dist/publication/types.d.ts +0 -23
  175. package/dist/publication/types.d.ts.map +0 -1
  176. package/dist/publication/types.js +0 -2
  177. package/dist/publication/types.js.map +0 -1
  178. package/dist/publication/validator.d.ts +0 -4
  179. package/dist/publication/validator.d.ts.map +0 -1
  180. package/dist/publication/validator.js +0 -17
  181. package/dist/publication/validator.js.map +0 -1
  182. package/dist/routes/index.d.ts.map +0 -1
  183. package/dist/routes/index.js.map +0 -1
  184. package/dist/routes/routes.d.ts.map +0 -1
  185. package/dist/routes/routes.js.map +0 -1
  186. package/dist/server.d.ts.map +0 -1
  187. package/dist/server.js.map +0 -1
  188. package/dist/transport/body.d.ts.map +0 -1
  189. package/dist/transport/body.js.map +0 -1
  190. package/dist/transport/codecs.d.ts.map +0 -1
  191. package/dist/transport/codecs.js.map +0 -1
  192. package/dist/transport/credential.d.ts.map +0 -1
  193. package/dist/transport/credential.js.map +0 -1
  194. package/dist/transport/http/handler.d.ts.map +0 -1
  195. package/dist/transport/http/handler.js.map +0 -1
  196. package/dist/transport/http/index.d.ts.map +0 -1
  197. package/dist/transport/http/index.js.map +0 -1
  198. package/dist/transport/http/render.d.ts.map +0 -1
  199. package/dist/transport/http/render.js.map +0 -1
  200. package/dist/transport/index.d.ts.map +0 -1
  201. package/dist/transport/index.js.map +0 -1
  202. package/dist/transport/router.d.ts.map +0 -1
  203. package/dist/transport/router.js.map +0 -1
  204. package/dist/transport/stream-error.d.ts.map +0 -1
  205. package/dist/transport/stream-error.js.map +0 -1
  206. package/dist/transport/types.d.ts.map +0 -1
  207. package/dist/transport/types.js.map +0 -1
  208. package/dist/transport/websocket/index.d.ts.map +0 -1
  209. package/dist/transport/websocket/index.js.map +0 -1
  210. package/dist/transport/websocket/session.d.ts.map +0 -1
  211. package/dist/transport/websocket/session.js.map +0 -1
  212. package/dist/transport/websocket/upgrade.d.ts.map +0 -1
  213. package/dist/transport/websocket/upgrade.js.map +0 -1
  214. package/dist/types.d.ts.map +0 -1
  215. package/dist/types.js.map +0 -1
package/dist/server.js CHANGED
@@ -1,11 +1,14 @@
1
- import { PATH as PUBLICATION_PATH, url as publicationUrl, } from '@astrale-os/kernel-protocol/publication/publication';
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 { currentPublicationSnapshot, mountRoutes } from './routes/index.js';
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 = externalIssuer === undefined ? undefined : new URL(externalIssuer).origin;
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
- ...(config.publication === undefined
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
- ...(config.publication === undefined
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.isAccepting && config.health.probe.check();
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.publication !== undefined) {
85
- mountRoutes(app, config.publication, config.delivery, handler, active, config.invocation, config.limits, config.cors, (request) => hosts.get(request), config.routeReservations, externalIssuer);
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
- const publication = config.publication === undefined ? undefined : capturePublicationSource(config.publication);
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 && publication === undefined) {
152
- throw new TypeError('Publication Delivery requires a Publication source.');
165
+ if (delivery !== undefined && serving === undefined) {
166
+ throw new TypeError('Delivery requires a release or Publication source.');
153
167
  }
154
- const publicationPath = publication === undefined
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
- if (publicationPath === path) {
162
- throw new TypeError('Publication and invocation paths must be distinct.');
163
- }
164
- if (health !== undefined && publicationPath === health.path) {
165
- throw new TypeError('Health and Publication paths must be distinct.');
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
- ...(publication === undefined ? {} : { publication }),
202
+ ...(serving === undefined ? {} : { serving }),
190
203
  ...(delivery === undefined ? {} : { delivery }),
191
- routeReservations: routeReservations(path, health?.path, issuer, websocket !== undefined, tokenExchange !== undefined, publicationPath),
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, publicationPath) {
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
- if (publicationPath !== undefined) {
209
- reservations.push(Object.freeze({ path: publicationPath, methods: Object.freeze(['GET']) }));
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 protocolPublicationPath(issuer) {
214
- if (issuer === undefined)
215
- return PUBLICATION_PATH;
216
- return new URL(publicationUrl(issuer)).pathname;
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', 'Publication Delivery provider is invalid.');
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
- //# sourceMappingURL=server.js.map
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
+ }
@@ -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
1
  import * as codecs from '@astrale-os/kernel-protocol/codecs';
2
2
  export type LoadedCodec = codecs.Codec;
3
- /** Load the built-in Server representation set before pure Protocol binding selection. */
4
- export declare function loadCodecs(): Promise<readonly [codecs.Codec, codecs.Codec]>;
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];
@@ -1,6 +1,6 @@
1
1
  import * as codecs from '@astrale-os/kernel-protocol/codecs';
2
- /** Load the built-in Server representation set before pure Protocol binding selection. */
3
- export async function loadCodecs() {
4
- return Object.freeze([codecs.json, await codecs.loadMsgpack()]);
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
@@ -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
@@ -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 { PublicationSnapshot } from '../../publication/index.js';
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
- readonly currentPublication?: (request: Request) => PublicationSnapshot | undefined;
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