@astrale-os/kernel-server 0.5.0-beta.9 → 1.0.0-beta.1

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 (237) 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 +3 -4
  22. package/dist/index.js +2 -3
  23. package/dist/invocation/context.d.ts +2 -2
  24. package/dist/invocation/context.js +2 -2
  25. package/dist/invocation/identity.d.ts +0 -1
  26. package/dist/invocation/identity.js +0 -1
  27. package/dist/invocation/index.d.ts +1 -2
  28. package/dist/invocation/index.js +1 -2
  29. package/dist/invocation/release-route.d.ts +22 -0
  30. package/dist/invocation/release-route.js +32 -0
  31. package/dist/invocation/types.d.ts +7 -6
  32. package/dist/invocation/types.js +0 -1
  33. package/dist/issuer/exchange.d.ts +0 -1
  34. package/dist/issuer/exchange.js +20 -10
  35. package/dist/issuer/index.d.ts +0 -1
  36. package/dist/issuer/index.js +0 -1
  37. package/dist/issuer/routes.d.ts +0 -1
  38. package/dist/issuer/routes.js +57 -48
  39. package/dist/issuer/types.d.ts +5 -1
  40. package/dist/issuer/types.js +0 -1
  41. package/dist/lifecycle/active.d.ts +4 -1
  42. package/dist/lifecycle/active.js +48 -11
  43. package/dist/lifecycle/index.d.ts +0 -1
  44. package/dist/lifecycle/index.js +0 -1
  45. package/dist/release/delivery/handler.d.ts +9 -0
  46. package/dist/{publication → release}/delivery/handler.js +18 -13
  47. package/dist/release/delivery/index.d.ts +1 -0
  48. package/dist/release/delivery/index.js +1 -0
  49. package/dist/{publication → release}/delivery/types.d.ts +4 -5
  50. package/dist/release/delivery/types.js +1 -0
  51. package/dist/release/index.d.ts +3 -0
  52. package/dist/release/index.js +2 -0
  53. package/dist/release/served.d.ts +21 -0
  54. package/dist/release/served.js +10 -0
  55. package/dist/release/snapshot.d.ts +22 -0
  56. package/dist/release/snapshot.js +49 -0
  57. package/dist/release/table.d.ts +4 -0
  58. package/dist/release/table.js +11 -0
  59. package/dist/release/types.d.ts +23 -0
  60. package/dist/release/types.js +1 -0
  61. package/dist/routes/address.d.ts +2 -0
  62. package/dist/routes/address.js +6 -0
  63. package/dist/routes/binary.d.ts +9 -0
  64. package/dist/routes/binary.js +110 -0
  65. package/dist/routes/bundle.d.ts +5 -0
  66. package/dist/routes/bundle.js +50 -0
  67. package/dist/routes/csrf.d.ts +16 -0
  68. package/dist/routes/csrf.js +35 -0
  69. package/dist/routes/document.d.ts +6 -0
  70. package/dist/routes/document.js +57 -0
  71. package/dist/routes/index.d.ts +3 -2
  72. package/dist/routes/index.js +2 -2
  73. package/dist/routes/model.d.ts +15 -0
  74. package/dist/routes/model.js +1 -0
  75. package/dist/routes/native.d.ts +17 -0
  76. package/dist/routes/native.js +126 -0
  77. package/dist/routes/preflight.d.ts +4 -0
  78. package/dist/routes/preflight.js +55 -0
  79. package/dist/routes/response.d.ts +14 -0
  80. package/dist/routes/response.js +33 -0
  81. package/dist/routes/routes.d.ts +7 -24
  82. package/dist/routes/routes.js +24 -439
  83. package/dist/routes/snapshot.d.ts +13 -0
  84. package/dist/routes/snapshot.js +39 -0
  85. package/dist/routes/stream.d.ts +6 -0
  86. package/dist/routes/stream.js +122 -0
  87. package/dist/server.d.ts +0 -1
  88. package/dist/server.js +95 -51
  89. package/dist/transport/body.d.ts +0 -1
  90. package/dist/transport/body.js +0 -1
  91. package/dist/transport/codecs.d.ts +2 -3
  92. package/dist/transport/codecs.js +4 -4
  93. package/dist/transport/credential.d.ts +0 -1
  94. package/dist/transport/credential.js +0 -1
  95. package/dist/transport/http/binary-request.d.ts +11 -0
  96. package/dist/transport/http/binary-request.js +102 -0
  97. package/dist/transport/http/binary.d.ts +6 -0
  98. package/dist/transport/http/binary.js +35 -0
  99. package/dist/transport/http/byte-stream.d.ts +4 -0
  100. package/dist/transport/http/byte-stream.js +123 -0
  101. package/dist/transport/http/control.d.ts +12 -0
  102. package/dist/transport/http/control.js +24 -0
  103. package/dist/transport/http/handler.d.ts +8 -3
  104. package/dist/transport/http/handler.js +97 -45
  105. package/dist/transport/http/index.d.ts +3 -2
  106. package/dist/transport/http/index.js +2 -2
  107. package/dist/transport/http/model.d.ts +20 -0
  108. package/dist/transport/http/model.js +1 -0
  109. package/dist/transport/http/render.d.ts +3 -31
  110. package/dist/transport/http/render.js +18 -269
  111. package/dist/transport/http/response.d.ts +14 -0
  112. package/dist/transport/http/response.js +77 -0
  113. package/dist/transport/http/stream.d.ts +5 -0
  114. package/dist/transport/http/stream.js +134 -0
  115. package/dist/transport/index.d.ts +2 -2
  116. package/dist/transport/index.js +2 -2
  117. package/dist/transport/result.d.ts +13 -0
  118. package/dist/transport/result.js +35 -0
  119. package/dist/transport/router.d.ts +0 -1
  120. package/dist/transport/router.js +0 -1
  121. package/dist/transport/stream-error.d.ts +0 -1
  122. package/dist/transport/stream-error.js +0 -1
  123. package/dist/transport/types.d.ts +0 -1
  124. package/dist/transport/types.js +0 -1
  125. package/dist/transport/websocket/index.d.ts +0 -1
  126. package/dist/transport/websocket/index.js +0 -1
  127. package/dist/transport/websocket/session.d.ts +3 -3
  128. package/dist/transport/websocket/session.js +30 -30
  129. package/dist/transport/websocket/upgrade.d.ts +2 -3
  130. package/dist/transport/websocket/upgrade.js +7 -7
  131. package/dist/types.d.ts +33 -10
  132. package/dist/types.js +0 -1
  133. package/package.json +11 -22
  134. package/dist/capture.d.ts.map +0 -1
  135. package/dist/capture.js.map +0 -1
  136. package/dist/cors/cors.d.ts.map +0 -1
  137. package/dist/cors/cors.js.map +0 -1
  138. package/dist/cors/index.d.ts.map +0 -1
  139. package/dist/cors/index.js.map +0 -1
  140. package/dist/cors/types.d.ts.map +0 -1
  141. package/dist/cors/types.js.map +0 -1
  142. package/dist/errors/availability.d.ts.map +0 -1
  143. package/dist/errors/availability.js.map +0 -1
  144. package/dist/errors/classify.d.ts.map +0 -1
  145. package/dist/errors/classify.js.map +0 -1
  146. package/dist/errors/index.d.ts.map +0 -1
  147. package/dist/errors/index.js.map +0 -1
  148. package/dist/errors/request-body.d.ts.map +0 -1
  149. package/dist/errors/request-body.js.map +0 -1
  150. package/dist/errors/response-body.d.ts.map +0 -1
  151. package/dist/errors/response-body.js.map +0 -1
  152. package/dist/index.d.ts.map +0 -1
  153. package/dist/index.js.map +0 -1
  154. package/dist/invocation/context.d.ts.map +0 -1
  155. package/dist/invocation/context.js.map +0 -1
  156. package/dist/invocation/identity.d.ts.map +0 -1
  157. package/dist/invocation/identity.js.map +0 -1
  158. package/dist/invocation/index.d.ts.map +0 -1
  159. package/dist/invocation/index.js.map +0 -1
  160. package/dist/invocation/publication-route.d.ts +0 -14
  161. package/dist/invocation/publication-route.d.ts.map +0 -1
  162. package/dist/invocation/publication-route.js +0 -45
  163. package/dist/invocation/publication-route.js.map +0 -1
  164. package/dist/invocation/types.d.ts.map +0 -1
  165. package/dist/invocation/types.js.map +0 -1
  166. package/dist/issuer/exchange.d.ts.map +0 -1
  167. package/dist/issuer/exchange.js.map +0 -1
  168. package/dist/issuer/index.d.ts.map +0 -1
  169. package/dist/issuer/index.js.map +0 -1
  170. package/dist/issuer/routes.d.ts.map +0 -1
  171. package/dist/issuer/routes.js.map +0 -1
  172. package/dist/issuer/types.d.ts.map +0 -1
  173. package/dist/issuer/types.js.map +0 -1
  174. package/dist/lifecycle/active.d.ts.map +0 -1
  175. package/dist/lifecycle/active.js.map +0 -1
  176. package/dist/lifecycle/index.d.ts.map +0 -1
  177. package/dist/lifecycle/index.js.map +0 -1
  178. package/dist/publication/delivery/handler.d.ts +0 -10
  179. package/dist/publication/delivery/handler.d.ts.map +0 -1
  180. package/dist/publication/delivery/handler.js.map +0 -1
  181. package/dist/publication/delivery/index.d.ts +0 -3
  182. package/dist/publication/delivery/index.d.ts.map +0 -1
  183. package/dist/publication/delivery/index.js +0 -2
  184. package/dist/publication/delivery/index.js.map +0 -1
  185. package/dist/publication/delivery/types.d.ts.map +0 -1
  186. package/dist/publication/delivery/types.js +0 -2
  187. package/dist/publication/delivery/types.js.map +0 -1
  188. package/dist/publication/index.d.ts +0 -4
  189. package/dist/publication/index.d.ts.map +0 -1
  190. package/dist/publication/index.js +0 -3
  191. package/dist/publication/index.js.map +0 -1
  192. package/dist/publication/snapshot.d.ts +0 -17
  193. package/dist/publication/snapshot.d.ts.map +0 -1
  194. package/dist/publication/snapshot.js +0 -38
  195. package/dist/publication/snapshot.js.map +0 -1
  196. package/dist/publication/table.d.ts +0 -5
  197. package/dist/publication/table.d.ts.map +0 -1
  198. package/dist/publication/table.js +0 -17
  199. package/dist/publication/table.js.map +0 -1
  200. package/dist/publication/types.d.ts +0 -23
  201. package/dist/publication/types.d.ts.map +0 -1
  202. package/dist/publication/types.js +0 -2
  203. package/dist/publication/types.js.map +0 -1
  204. package/dist/routes/index.d.ts.map +0 -1
  205. package/dist/routes/index.js.map +0 -1
  206. package/dist/routes/routes.d.ts.map +0 -1
  207. package/dist/routes/routes.js.map +0 -1
  208. package/dist/server.d.ts.map +0 -1
  209. package/dist/server.js.map +0 -1
  210. package/dist/transport/body.d.ts.map +0 -1
  211. package/dist/transport/body.js.map +0 -1
  212. package/dist/transport/codecs.d.ts.map +0 -1
  213. package/dist/transport/codecs.js.map +0 -1
  214. package/dist/transport/credential.d.ts.map +0 -1
  215. package/dist/transport/credential.js.map +0 -1
  216. package/dist/transport/http/handler.d.ts.map +0 -1
  217. package/dist/transport/http/handler.js.map +0 -1
  218. package/dist/transport/http/index.d.ts.map +0 -1
  219. package/dist/transport/http/index.js.map +0 -1
  220. package/dist/transport/http/render.d.ts.map +0 -1
  221. package/dist/transport/http/render.js.map +0 -1
  222. package/dist/transport/index.d.ts.map +0 -1
  223. package/dist/transport/index.js.map +0 -1
  224. package/dist/transport/router.d.ts.map +0 -1
  225. package/dist/transport/router.js.map +0 -1
  226. package/dist/transport/stream-error.d.ts.map +0 -1
  227. package/dist/transport/stream-error.js.map +0 -1
  228. package/dist/transport/types.d.ts.map +0 -1
  229. package/dist/transport/types.js.map +0 -1
  230. package/dist/transport/websocket/index.d.ts.map +0 -1
  231. package/dist/transport/websocket/index.js.map +0 -1
  232. package/dist/transport/websocket/session.d.ts.map +0 -1
  233. package/dist/transport/websocket/session.js.map +0 -1
  234. package/dist/transport/websocket/upgrade.d.ts.map +0 -1
  235. package/dist/transport/websocket/upgrade.js.map +0 -1
  236. package/dist/types.d.ts.map +0 -1
  237. package/dist/types.js.map +0 -1
@@ -0,0 +1,77 @@
1
+ import * as errors from '@astrale-os/kernel-protocol/errors';
2
+ import { ResponseBodyTooLargeError } from '../../errors/index.js';
3
+ /** Encode a bounded envelope with its binding content type and cache policy. */
4
+ export function envelopeResponse(codec, input, cors, status = 200, negotiated = true, maximumResponseBytes) {
5
+ const encoded = codec.encode(input);
6
+ requireResponseBound(encoded, maximumResponseBytes);
7
+ const headers = bindingHeaders(cors, negotiated);
8
+ headers.set('content-type', codec.contentType);
9
+ return new Response(toBody(encoded), {
10
+ status,
11
+ headers,
12
+ });
13
+ }
14
+ function bindingHeaders(input, negotiated) {
15
+ const headers = new Headers(input);
16
+ headers.set('cache-control', 'no-store');
17
+ if (negotiated)
18
+ appendVary(headers, 'accept');
19
+ return headers;
20
+ }
21
+ /** Bound an error, falling back to a correlated limit refusal or an empty response. */
22
+ export function errorEnvelopeResponse(codec, response, cors, status, negotiated, maximumResponseBytes) {
23
+ try {
24
+ return envelopeResponse(codec, response, cors, status, negotiated, maximumResponseBytes);
25
+ }
26
+ catch (error) {
27
+ if (!(error instanceof ResponseBodyTooLargeError))
28
+ throw error;
29
+ const fallback = {
30
+ requestId: response.requestId,
31
+ invocation: response.invocation,
32
+ error: {
33
+ code: errors.CODES.LIMIT_EXCEEDED,
34
+ message: 'Response body exceeds the configured limit.',
35
+ },
36
+ };
37
+ try {
38
+ return envelopeResponse(codec, fallback, cors, errors.httpStatusOf(fallback.error), negotiated, maximumResponseBytes);
39
+ }
40
+ catch (fallbackError) {
41
+ if (!(fallbackError instanceof ResponseBodyTooLargeError))
42
+ throw fallbackError;
43
+ return new Response(null, {
44
+ status: 500,
45
+ headers: bindingHeaders(cors, negotiated),
46
+ });
47
+ }
48
+ }
49
+ }
50
+ /** Enforce the configured byte budget before a buffered response is handed off. */
51
+ export function requireResponseBound(input, maximumResponseBytes) {
52
+ if (maximumResponseBytes === undefined)
53
+ return;
54
+ const bytes = typeof input === 'string' ? new TextEncoder().encode(input).byteLength : input.byteLength;
55
+ if (bytes > maximumResponseBytes)
56
+ throw new ResponseBodyTooLargeError(maximumResponseBytes);
57
+ }
58
+ /** Retain existing Vary fields while declaring another response selector. */
59
+ export function appendVary(headers, value) {
60
+ headers.set('vary', mergeVary(Object.fromEntries(headers), value));
61
+ }
62
+ /** Merge one case-insensitive selector into the response Vary field. */
63
+ export function mergeVary(headers, value) {
64
+ const names = new Set((headers.vary ?? '')
65
+ .split(',')
66
+ .map((name) => name.trim().toLowerCase())
67
+ .filter(Boolean));
68
+ names.add(value.toLowerCase());
69
+ return [...names].join(', ');
70
+ }
71
+ /** Detach encoded bytes for Fetch while retaining encoded text as text. */
72
+ export function toBody(input) {
73
+ if (typeof input === 'string')
74
+ return input;
75
+ const copy = new Uint8Array(input);
76
+ return copy.buffer;
77
+ }
@@ -0,0 +1,5 @@
1
+ import type { RenderContext } from './model.js';
2
+ /** Frame ordered Invocation items and retain cleanup until the producer settles. */
3
+ export declare function streamHttpResponse(stream: AsyncIterable<unknown> & {
4
+ cancel(reason?: string): Promise<void>;
5
+ }, context: RenderContext): Response;
@@ -0,0 +1,134 @@
1
+ import * as protocol from '@astrale-os/kernel-protocol/invocation';
2
+ import { classifyError, ResponseBodyTooLargeError } from '../../errors/index.js';
3
+ import { interruptedStreamError } from '../stream-error.js';
4
+ import { mergeVary } from './response.js';
5
+ /** Frame ordered Invocation items and retain cleanup until the producer settles. */
6
+ export function streamHttpResponse(stream, context) {
7
+ const iterator = stream[Symbol.asyncIterator]();
8
+ const startFrame = encodeBoundedStreamFrame(context.codec, { kind: 'stream.start', requestId: context.requestId, invocation: context.invocation }, context.maximumResponseBytes);
9
+ let count = 0;
10
+ let terminal = false;
11
+ let controller;
12
+ let stopping;
13
+ const stop = (reason) => {
14
+ stopping ??= stopStream(reason);
15
+ return stopping;
16
+ };
17
+ async function stopStream(reason) {
18
+ if (terminal)
19
+ return;
20
+ terminal = true;
21
+ // End the wire response immediately. Producer cleanup remains part of the active operation,
22
+ // but an uncooperative producer must not leave the client waiting for a terminal frame.
23
+ if (controller !== undefined) {
24
+ try {
25
+ controller.enqueue(encodeBoundedStreamFrame(context.codec, cancellationFrame(context), context.maximumResponseBytes));
26
+ }
27
+ catch {
28
+ // The transport consumer may already have disconnected.
29
+ }
30
+ try {
31
+ controller.close();
32
+ }
33
+ catch {
34
+ // The stream may already be closed or cancelled by the consumer.
35
+ }
36
+ }
37
+ try {
38
+ await Promise.allSettled([
39
+ Promise.resolve().then(() => stream.cancel(reason)),
40
+ Promise.resolve().then(() => iterator.return?.()),
41
+ ]);
42
+ }
43
+ finally {
44
+ context.active.settle();
45
+ }
46
+ }
47
+ const body = new ReadableStream({
48
+ start(output) {
49
+ controller = output;
50
+ output.enqueue(startFrame);
51
+ },
52
+ async pull(output) {
53
+ if (terminal)
54
+ return;
55
+ try {
56
+ const next = await iterator.next();
57
+ if (terminal)
58
+ return;
59
+ if (next.done) {
60
+ terminal = true;
61
+ output.enqueue(encodeBoundedStreamFrame(context.codec, {
62
+ kind: 'stream.end',
63
+ requestId: context.requestId,
64
+ count,
65
+ }, context.maximumResponseBytes));
66
+ output.close();
67
+ context.active.settle();
68
+ return;
69
+ }
70
+ const frame = protocol.decodeStreamFrame({
71
+ kind: 'stream.item',
72
+ requestId: context.requestId,
73
+ index: count,
74
+ value: next.value,
75
+ });
76
+ output.enqueue(encodeBoundedStreamFrame(context.codec, frame, context.maximumResponseBytes));
77
+ count += 1;
78
+ }
79
+ catch (input) {
80
+ if (terminal)
81
+ return;
82
+ terminal = true;
83
+ if (!context.active.signal.aborted) {
84
+ try {
85
+ output.enqueue(encodeBoundedStreamFrame(context.codec, {
86
+ kind: 'stream.error',
87
+ requestId: context.requestId,
88
+ error: classifyError(input),
89
+ }, context.maximumResponseBytes));
90
+ }
91
+ catch {
92
+ // No valid terminal frame can be formed; closing is the only remaining signal.
93
+ }
94
+ }
95
+ output.close();
96
+ await Promise.allSettled([
97
+ Promise.resolve().then(() => stream.cancel('stream failed')),
98
+ Promise.resolve().then(() => iterator.return?.()),
99
+ ]);
100
+ context.active.settle();
101
+ }
102
+ },
103
+ async cancel(reason) {
104
+ const message = typeof reason === 'string' ? reason : 'response consumer cancelled';
105
+ context.active.cancel(message);
106
+ await stop(message);
107
+ },
108
+ });
109
+ context.active.onCancel(stop);
110
+ return new Response(body, {
111
+ status: 200,
112
+ headers: {
113
+ ...context.cors([protocol.http.STREAM_FRAMING_FIELD]),
114
+ 'cache-control': 'no-store',
115
+ 'content-type': context.codec.contentType,
116
+ vary: mergeVary(context.cors(), 'accept'),
117
+ [protocol.http.STREAM_FRAMING_FIELD]: protocol.http.LENGTH_PREFIX_V1,
118
+ },
119
+ });
120
+ }
121
+ function encodeBoundedStreamFrame(codec, frame, maximumResponseBytes) {
122
+ const encoded = protocol.http.encodeStreamFrame(codec, frame);
123
+ if (encoded.byteLength - 4 > maximumResponseBytes) {
124
+ throw new ResponseBodyTooLargeError(maximumResponseBytes);
125
+ }
126
+ return encoded;
127
+ }
128
+ function cancellationFrame(context) {
129
+ return {
130
+ kind: 'stream.error',
131
+ requestId: context.requestId,
132
+ error: interruptedStreamError(context.active.timedOut),
133
+ };
134
+ }
@@ -1,10 +1,10 @@
1
+ export { renderBinary, renderRedirect } from './result.js';
1
2
  export { byteLength, readBoundedBody } from './body.js';
2
3
  export { loadCodecs, type LoadedCodec } from './codecs.js';
3
4
  export { resolveCredential, type CredentialResult } from './credential.js';
4
5
  export { createHttpHandler, type HttpHandlerConfig } from './http/index.js';
5
- export { encodeEnvelope, renderBinary, renderHttpError, renderHttpResult, renderHttpStale, renderRedirect, type CorsHeaders, type ErrorRenderOptions, type RenderContext, } from './http/index.js';
6
+ export { renderHttpError, renderHttpResult, renderHttpStale, type CorsHeaders, type ErrorRenderOptions, type RenderContext, } from './http/index.js';
6
7
  export { interruptedStreamError } from './stream-error.js';
7
8
  export { createServerRouter, type ServerRouter } from './router.js';
8
9
  export { createWebSocketSession, handleWebSocketUpgrade, type WebSocketHandlerConfig, type WebSocketSessionConfig, } from './websocket/index.js';
9
10
  export type { Application, WebSocketAdapter, WebSocketHandlers, WebSocketLike, WebSocketUpgradeOptions, } from './types.js';
10
- //# sourceMappingURL=index.d.ts.map
@@ -1,9 +1,9 @@
1
+ export { renderBinary, renderRedirect } from './result.js';
1
2
  export { byteLength, readBoundedBody } from './body.js';
2
3
  export { loadCodecs } from './codecs.js';
3
4
  export { resolveCredential } from './credential.js';
4
5
  export { createHttpHandler } from './http/index.js';
5
- export { encodeEnvelope, renderBinary, renderHttpError, renderHttpResult, renderHttpStale, renderRedirect, } from './http/index.js';
6
+ export { renderHttpError, renderHttpResult, renderHttpStale, } from './http/index.js';
6
7
  export { interruptedStreamError } from './stream-error.js';
7
8
  export { createServerRouter } from './router.js';
8
9
  export { createWebSocketSession, handleWebSocketUpgrade, } from './websocket/index.js';
9
- //# sourceMappingURL=index.js.map
@@ -0,0 +1,13 @@
1
+ import type { BufferedBinaryResult, StreamingBinaryResult } from '@astrale-os/kernel-core/callable';
2
+ import * as protocol from '@astrale-os/kernel-protocol/invocation';
3
+ import type { HandlerResult } from '../invocation/index.js';
4
+ /** Admit one buffered binary result into the shared Invocation envelope. */
5
+ export declare function renderBinary(requestId: protocol.RequestId, invocation: protocol.InvocationId, binary: BufferedBinaryResult): protocol.BinaryResponse;
6
+ /** Admit a semantic redirect without selecting an HTTP or WebSocket binding. */
7
+ export declare function renderRedirect(requestId: protocol.RequestId, invocation: protocol.InvocationId, redirect: Extract<HandlerResult, {
8
+ readonly kind: 'redirect';
9
+ }>['redirect']): protocol.RedirectResponse;
10
+ /** Identify a binary producer whose lifetime stays with its transport. */
11
+ export declare function isStreamingBinary(input: Extract<HandlerResult, {
12
+ readonly kind: 'binary';
13
+ }>['value']): input is StreamingBinaryResult;
@@ -0,0 +1,35 @@
1
+ import * as protocol from '@astrale-os/kernel-protocol/invocation';
2
+ import { HTTP_ROUTE_MISS, HTTP_ROUTE_STALE } from '@astrale-os/kernel-protocol/routes';
3
+ /** Admit one buffered binary result into the shared Invocation envelope. */
4
+ export function renderBinary(requestId, invocation, binary) {
5
+ const reserved = Object.keys(binary.headers ?? {}).find((name) => {
6
+ const normalized = name.toLowerCase();
7
+ return (normalized === protocol.http.INVOCATION_FIELD ||
8
+ normalized === HTTP_ROUTE_STALE ||
9
+ normalized === HTTP_ROUTE_MISS);
10
+ });
11
+ if (reserved !== undefined)
12
+ throw new TypeError(`${reserved} is reserved by Protocol.`);
13
+ return protocol.decodeBinaryResponse({
14
+ kind: 'binary',
15
+ requestId,
16
+ invocation,
17
+ body: binary.body,
18
+ mediaType: binary.mediaType,
19
+ status: binary.status ?? 200,
20
+ ...(binary.headers === undefined ? {} : { headers: binary.headers }),
21
+ });
22
+ }
23
+ /** Admit a semantic redirect without selecting an HTTP or WebSocket binding. */
24
+ export function renderRedirect(requestId, invocation, redirect) {
25
+ return protocol.decodeRedirectResponse({
26
+ kind: 'redirect',
27
+ requestId,
28
+ invocation,
29
+ redirect,
30
+ });
31
+ }
32
+ /** Identify a binary producer whose lifetime stays with its transport. */
33
+ export function isStreamingBinary(input) {
34
+ return !(input.body instanceof Uint8Array);
35
+ }
@@ -2,4 +2,3 @@ import { type Hono as HonoType } from 'hono';
2
2
  /** Private Web-standard router capability shared by Server route-owning children. */
3
3
  export type ServerRouter = HonoType;
4
4
  export declare function createServerRouter(): ServerRouter;
5
- //# sourceMappingURL=router.d.ts.map
@@ -2,4 +2,3 @@ import { Hono } from 'hono';
2
2
  export function createServerRouter() {
3
3
  return new Hono();
4
4
  }
5
- //# sourceMappingURL=router.js.map
@@ -1,4 +1,3 @@
1
1
  import type { ErrorPayload } from '@astrale-os/kernel-protocol/errors';
2
2
  /** A transport cancellation after stream.start necessarily follows the Function effect boundary. */
3
3
  export declare function interruptedStreamError(timedOut: boolean): ErrorPayload;
4
- //# sourceMappingURL=stream-error.d.ts.map
@@ -11,4 +11,3 @@ export function interruptedStreamError(timedOut) {
11
11
  message: 'Function stream was cancelled after execution began; outcome is unknown.',
12
12
  };
13
13
  }
14
- //# sourceMappingURL=stream-error.js.map
@@ -26,4 +26,3 @@ export interface WebSocketUpgradeOptions {
26
26
  export interface WebSocketAdapter {
27
27
  upgrade(request: Request, options: WebSocketUpgradeOptions): Response | Promise<Response>;
28
28
  }
29
- //# sourceMappingURL=types.d.ts.map
@@ -1,2 +1 @@
1
1
  export {};
2
- //# sourceMappingURL=types.js.map
@@ -1,3 +1,2 @@
1
1
  export { createWebSocketSession, type WebSocketSessionConfig } from './session.js';
2
2
  export { handleWebSocketUpgrade, type WebSocketHandlerConfig } from './upgrade.js';
3
- //# sourceMappingURL=index.d.ts.map
@@ -1,3 +1,2 @@
1
1
  export { createWebSocketSession } from './session.js';
2
2
  export { handleWebSocketUpgrade } from './upgrade.js';
3
- //# sourceMappingURL=index.js.map
@@ -1,7 +1,7 @@
1
1
  import type { Codec } from '@astrale-os/kernel-protocol/codecs';
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 { WebSocketHandlers } from '../types.js';
6
6
  import { type ApplicationHost, type Handler } from '../../invocation/index.js';
7
7
  export interface WebSocketSessionConfig {
@@ -13,9 +13,9 @@ export interface WebSocketSessionConfig {
13
13
  readonly maximumRequestBytes: number;
14
14
  readonly maximumResponseBytes: number;
15
15
  readonly invocationTimeoutMs: number;
16
- readonly currentPublication?: () => PublicationSnapshot | undefined;
16
+ /** Present exactly when the Server serves a Release; bound to the upgrade. */
17
+ readonly serving?: RequestServing;
17
18
  readonly host?: ApplicationHost;
18
19
  }
19
20
  /** Build one socket-pinned transport session. */
20
21
  export declare function createWebSocketSession(config: WebSocketSessionConfig): WebSocketHandlers;
21
- //# sourceMappingURL=session.d.ts.map
@@ -1,11 +1,13 @@
1
1
  import * as errors from '@astrale-os/kernel-protocol/errors';
2
2
  import * as protocol from '@astrale-os/kernel-protocol/invocation';
3
- import { classifyError } from '../../errors/index.js';
3
+ import { deploymentRetiredBody } from '@astrale-os/kernel-protocol/routes';
4
+ import { admissionRefusal, classifyError, classifyRequestError } from '../../errors/index.js';
4
5
  import { ResponseBodyTooLargeError } from '../../errors/index.js';
5
- import { invocationContext, publicationRouteDecision, } from '../../invocation/index.js';
6
+ import { admitVia, invocationContext, } from '../../invocation/index.js';
7
+ import { pinned } from '../../release/served.js';
6
8
  import { byteLength } from '../body.js';
7
9
  import { resolveCredential } from '../credential.js';
8
- import { renderBinary, renderRedirect } from '../http/render.js';
10
+ import { isStreamingBinary, renderBinary, renderRedirect } from '../result.js';
9
11
  import { interruptedStreamError } from '../stream-error.js';
10
12
  const WS_OPEN = 1;
11
13
  /** Build one socket-pinned transport session. */
@@ -100,25 +102,23 @@ export function createWebSocketSession(config) {
100
102
  }, sendOutput);
101
103
  return;
102
104
  }
103
- const publication = config.currentPublication?.();
104
- if (config.currentPublication !== undefined && publication === undefined) {
105
+ const serving = config.serving;
106
+ const served = serving?.current();
107
+ if (serving !== undefined && served === undefined) {
105
108
  await sendError(socket, admittedCodec, envelope.requestId, assigned, {
106
109
  code: errors.CODES.BACKEND_UNAVAILABLE,
107
- message: 'Publication is unavailable.',
110
+ message: 'Release is unavailable.',
108
111
  }, sendOutput);
109
112
  return;
110
113
  }
111
114
  if (envelope.routing?.kind === 'via') {
112
- if (publication === undefined) {
113
- await sendError(socket, admittedCodec, envelope.requestId, assigned, {
114
- code: errors.CODES.INVALID_REQUEST,
115
- message: 'Publication routing requires a Publication-backed destination.',
116
- }, sendOutput);
117
- return;
118
- }
119
- const decision = publicationRouteDecision(publication.publication, envelope.routing.publication);
120
- if (decision.kind === 'rejected') {
121
- await sendError(socket, admittedCodec, envelope.requestId, assigned, decision.error, sendOutput);
115
+ const decision = admitVia(served, envelope.routing);
116
+ if (decision.kind !== 'admitted') {
117
+ // A socket has no HTTP status: a retired deployment answers this request with the
118
+ // DEPLOYMENT_RETIRED error payload of the reserved control, correlated to its request.
119
+ await sendError(socket, admittedCodec, envelope.requestId, assigned, decision.kind === 'retired'
120
+ ? deploymentRetiredBody(serving.deployment(), decision.release).error
121
+ : decision.error, sendOutput);
122
122
  return;
123
123
  }
124
124
  }
@@ -129,10 +129,7 @@ export function createWebSocketSession(config) {
129
129
  }
130
130
  const operation = config.active.begin(config.invocationTimeoutMs);
131
131
  if (operation === undefined) {
132
- await sendError(socket, admittedCodec, envelope.requestId, assigned, {
133
- code: errors.CODES.BACKEND_UNAVAILABLE,
134
- message: 'server is unavailable.',
135
- }, sendOutput);
132
+ await sendError(socket, admittedCodec, envelope.requestId, assigned, admissionRefusal(config.active.isAccepting), sendOutput);
136
133
  return;
137
134
  }
138
135
  operations.set(key, operation);
@@ -145,7 +142,7 @@ export function createWebSocketSession(config) {
145
142
  ...(envelope.delegate === undefined ? {} : { delegate: envelope.delegate }),
146
143
  ...(envelope.routing?.kind === 'via' ? { via: envelope.routing } : {}),
147
144
  ...(envelope.schema === undefined ? {} : { schema: envelope.schema }),
148
- ...(publication === undefined ? {} : { publication }),
145
+ ...(served === undefined ? {} : pinned(served)),
149
146
  context: invocationContext(assigned, operation, config.active, config.host, undefined, envelope.idempotencyKey),
150
147
  }));
151
148
  await sendResult(socket, admittedCodec, envelope.requestId, assigned, result, operation, sendOutput);
@@ -155,14 +152,7 @@ export function createWebSocketSession(config) {
155
152
  return;
156
153
  }
157
154
  if (socket.readyState === WS_OPEN) {
158
- const error = operation.timedOut
159
- ? {
160
- code: errors.CODES.DEADLINE_EXCEEDED,
161
- message: 'Invocation deadline exceeded.',
162
- }
163
- : operation.signal.aborted
164
- ? { code: errors.CODES.CANCELLED, message: 'Invocation was cancelled.' }
165
- : classifyError(input);
155
+ const error = classifyRequestError(input, operation);
166
156
  if (error.code === errors.CODES.INTERNAL_ERROR) {
167
157
  socket.close(1011, 'Internal error');
168
158
  return;
@@ -211,6 +201,17 @@ async function sendResult(socket, codec, requestId, assigned, result, operation,
211
201
  await send(socket, codec, protocol.miss(requestId, assigned), sendOutput);
212
202
  return;
213
203
  case 'binary': {
204
+ if (isStreamingBinary(result.value)) {
205
+ const streaming = result.value;
206
+ await Promise.allSettled([
207
+ sendError(socket, codec, requestId, assigned, {
208
+ code: errors.CODES.UNSUPPORTED,
209
+ message: 'Streaming binary output requires the HTTP transport.',
210
+ }, sendOutput),
211
+ Promise.resolve().then(() => streaming.body[Symbol.asyncIterator]().return?.()),
212
+ ]);
213
+ return;
214
+ }
214
215
  const binary = renderBinary(requestId, assigned, result.value);
215
216
  if (socket.readyState === WS_OPEN) {
216
217
  await sendOutput(socket, protocol.websocket.encodeBinary(binary));
@@ -333,4 +334,3 @@ function isCancelRequest(input) {
333
334
  !Array.isArray(input) &&
334
335
  input.kind === 'cancel');
335
336
  }
336
- //# sourceMappingURL=session.js.map
@@ -2,7 +2,7 @@ import type { CorsPolicy } from '../../cors/index.js';
2
2
  import type { ApplicationHost, Handler } from '../../invocation/index.js';
3
3
  import type { NextInvocationId } from '../../invocation/index.js';
4
4
  import type { ActiveOperations } from '../../lifecycle/index.js';
5
- import type { PublicationSnapshot } from '../../publication/index.js';
5
+ import type { RequestServing } from '../../release/served.js';
6
6
  import type { WebSocketAdapter } from '../types.js';
7
7
  export interface WebSocketHandlerConfig {
8
8
  readonly request: Request;
@@ -14,8 +14,7 @@ export interface WebSocketHandlerConfig {
14
14
  readonly maximumResponseBytes: number;
15
15
  readonly invocationTimeoutMs: number;
16
16
  readonly cors: CorsPolicy;
17
- readonly currentPublication?: () => PublicationSnapshot | undefined;
17
+ readonly serving?: RequestServing;
18
18
  readonly host?: ApplicationHost;
19
19
  }
20
20
  export declare function handleWebSocketUpgrade(config: WebSocketHandlerConfig): Promise<Response>;
21
- //# sourceMappingURL=upgrade.d.ts.map
@@ -1,14 +1,17 @@
1
1
  import * as protocol from '@astrale-os/kernel-protocol/invocation';
2
+ import { admissionRefusal, retryAfterHeaders } from '../../errors/index.js';
2
3
  import { loadCodecs } from '../codecs.js';
3
4
  import { createWebSocketSession } from './session.js';
4
5
  export async function handleWebSocketUpgrade(config) {
5
6
  if (!config.cors.allowsBrowserOrigin(config.request))
6
7
  return failure(403);
7
8
  const operation = config.active.begin(config.invocationTimeoutMs, config.request.signal);
8
- if (operation === undefined)
9
- return failure(503, config.cors.response(config.request));
9
+ if (operation === undefined) {
10
+ const retry = retryAfterHeaders(admissionRefusal(config.active.isAccepting));
11
+ return failure(503, { ...config.cors.response(config.request, Object.keys(retry)), ...retry });
12
+ }
10
13
  try {
11
- const supported = await loadCodecs();
14
+ const supported = loadCodecs();
12
15
  const selection = protocol.websocket.selectSubprotocol(config.request.headers.get('sec-websocket-protocol'), supported);
13
16
  if (selection === undefined)
14
17
  return failure(400, config.cors.response(config.request));
@@ -23,9 +26,7 @@ export async function handleWebSocketUpgrade(config) {
23
26
  maximumRequestBytes: config.maximumRequestBytes,
24
27
  maximumResponseBytes: config.maximumResponseBytes,
25
28
  invocationTimeoutMs: config.invocationTimeoutMs,
26
- ...(config.currentPublication === undefined
27
- ? {}
28
- : { currentPublication: config.currentPublication }),
29
+ ...(config.serving === undefined ? {} : { serving: config.serving }),
29
30
  ...(config.host === undefined ? {} : { host: config.host }),
30
31
  }),
31
32
  signal: operation.signal,
@@ -44,4 +45,3 @@ function failure(status, input = {}) {
44
45
  headers: { ...input, 'cache-control': 'no-store' },
45
46
  });
46
47
  }
47
- //# sourceMappingURL=upgrade.js.map
package/dist/types.d.ts CHANGED
@@ -1,20 +1,32 @@
1
1
  import type { CorsConfig } from './cors/index.js';
2
2
  import type { Handler, InvocationSource } from './invocation/index.js';
3
- import type { exchange, Issuer } from './issuer/index.js';
4
- import type { Provider as DeliveryProvider } from './publication/delivery/index.js';
5
- import type { PublicationSource } from './publication/index.js';
3
+ import type { Context as ExchangeContext, Provider as ExchangeProvider } from './issuer/exchange.js';
4
+ import type { Issuer } from './issuer/index.js';
5
+ import type { Provider as DeliveryProvider } from './release/delivery/index.js';
6
+ import type { ReleaseSource } from './release/index.js';
6
7
  import type { Application, WebSocketAdapter } from './transport/index.js';
7
8
  export interface ServerLimits {
8
9
  readonly maximumRequestBytes: number;
9
- /** Maximum bytes in one encoded envelope, finite-binary body, or stream frame. */
10
+ /** Deployment cap for a streamed binary HTTP request; defaults to maximumRequestBytes. */
11
+ readonly maximumBinaryRequestBytes?: number;
12
+ /** Maximum bytes in one encoded envelope, buffered binary body, or stream frame. */
10
13
  readonly maximumResponseBytes?: number;
11
14
  /** Maximum Server-owned active operations across all mounted protocol surfaces. */
12
15
  readonly maximumConcurrentOperations?: number;
13
- readonly maximumPublicationBytes?: number;
16
+ /** Maximum bytes of each served discovery document (`release.json`). */
17
+ readonly maximumReleaseBytes?: number;
14
18
  readonly maximumBundleBytes?: number;
15
19
  readonly maximumDeliveryBytes?: number;
16
20
  /** Maximum lifetime of one invocation, including a returned stream. */
17
21
  readonly invocationTimeoutMs: number;
22
+ /** Binary request lifetime; defaults to invocationTimeoutMs. */
23
+ readonly binaryRequestTimeoutMs?: number;
24
+ /** Maximum wait for the next binary body chunk while a consumer is reading. */
25
+ readonly binaryRequestIdleTimeoutMs?: number;
26
+ /** Exact Host-selected callable Path whose ordinary JSON invocation may stream a large result. */
27
+ readonly binaryDownloadTarget?: string;
28
+ /** Required with binaryDownloadTarget; selected before semantic dispatch. */
29
+ readonly binaryDownloadTimeoutMs?: number;
18
30
  }
19
31
  export interface ServerCloseOptions {
20
32
  /** Absolute Unix time in milliseconds after which active work is cancelled. */
@@ -37,10 +49,16 @@ export interface ServerOptions {
37
49
  readonly probe: HealthProbe;
38
50
  } | false;
39
51
  readonly issuer?: Issuer;
52
+ /** Public HTTP origin for transport placement, independent of the stable issuer. */
53
+ readonly publicOrigin?: string;
40
54
  /** Present only for the configured self issuer; owns verification and signing. */
41
55
  readonly tokenExchange?: exchange.Provider;
42
- readonly publication?: PublicationSource;
43
- /** Required exactly when the current Publication advertises delivery. */
56
+ /**
57
+ * Exact release, bundle, Delivery v2 and native routes served by this deployment. With no
58
+ * source the Server serves no document and admits no routed call.
59
+ */
60
+ readonly release?: ReleaseSource;
61
+ /** Required exactly when the current release advertises Delivery. */
44
62
  readonly delivery?: DeliveryProvider;
45
63
  readonly websocket?: WebSocketAdapter;
46
64
  }
@@ -60,7 +78,12 @@ export interface Server {
60
78
  export type { CorsConfig } from './cors/index.js';
61
79
  export type { InvocationSource } from './invocation/index.js';
62
80
  export type { ApplicationHost, ExecutionControl, Handler, HandlerRequest, HandlerResult, HandlerStream, InvocationContext, RequestBackground, RequestEvidence, RequestSleep, } from './invocation/index.js';
63
- export type { exchange, Issuer } from './issuer/index.js';
64
- export type { PublicationSnapshot, PublicationSnapshotInput, PublicationSource, } from './publication/index.js';
81
+ /** Public token-exchange provider contract; transport capture and mounting stay private. */
82
+ export declare namespace exchange {
83
+ type Context = ExchangeContext;
84
+ type Provider = ExchangeProvider;
85
+ }
86
+ export type { Issuer } from './issuer/index.js';
87
+ export type { Provider as DeliveryProvider } from './release/delivery/index.js';
88
+ export type { ReleaseSnapshot, ReleaseSnapshotInput, ReleaseSource } from './release/index.js';
65
89
  export type { Application, WebSocketAdapter, WebSocketHandlers, WebSocketLike, WebSocketUpgradeOptions, } from './transport/index.js';
66
- //# sourceMappingURL=types.d.ts.map
package/dist/types.js CHANGED
@@ -1,2 +1 @@
1
1
  export {};
2
- //# sourceMappingURL=types.js.map