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

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,56 +1,67 @@
1
- import { errors, invocation as protocol, routes } from '@astrale-os/kernel-protocol';
1
+ import * as errors from '@astrale-os/kernel-protocol/errors';
2
+ import * as protocol from '@astrale-os/kernel-protocol/invocation';
3
+ import { HTTP_ROUTE_MISS, HTTP_ROUTE_STALE } from '@astrale-os/kernel-protocol/routes/routing';
2
4
  import { classifyError } from '../../errors/index.js';
3
5
  import { ResponseBodyTooLargeError } from '../../errors/index.js';
4
6
  import { interruptedStreamError } from '../stream-error.js';
5
7
  export function renderHttpResult(result, context) {
6
8
  switch (result.kind) {
7
9
  case 'value':
8
- return settled(context.operation, envelopeResponse(context.codec, { result: result.value, id: context.id }, context.cors(), 200, true, context.maximumResponseBytes));
10
+ return settled(context.active, envelopeResponse(context.codec, {
11
+ result: result.value,
12
+ requestId: context.requestId,
13
+ invocation: context.invocation,
14
+ }, context.cors(), 200, true, context.maximumResponseBytes));
9
15
  case 'redirect': {
10
- const response = renderRedirect(context.id, result.redirect);
11
- return settled(context.operation, envelopeResponse(context.codec, response, context.cors(), 200, true, context.maximumResponseBytes));
16
+ const response = renderRedirect(context.requestId, context.invocation, result.redirect);
17
+ return settled(context.active, envelopeResponse(context.codec, response, context.cors(), 200, true, context.maximumResponseBytes));
12
18
  }
13
19
  case 'miss':
14
- return settled(context.operation, envelopeResponse(context.codec, protocol.miss(context.id), context.cors(), 200, true, context.maximumResponseBytes));
20
+ return settled(context.active, envelopeResponse(context.codec, protocol.miss(context.requestId, context.invocation), context.cors(), 200, true, context.maximumResponseBytes));
15
21
  case 'binary': {
16
- const binary = renderBinary(context.id, result.value);
17
- return settled(context.operation, binaryHttpResponse(binary, context.cors, context.maximumResponseBytes));
22
+ if (isStreamingBinary(result.value))
23
+ return streamingBinaryHttpResponse(result.value, context);
24
+ const binary = renderBinary(context.requestId, context.invocation, result.value);
25
+ return settled(context.active, binaryHttpResponse(binary, context.cors, context.maximumResponseBytes));
18
26
  }
19
27
  case 'stream':
20
28
  return streamHttpResponse(result.stream, context);
21
29
  }
22
30
  }
23
- export function renderBinary(id, binary) {
24
- if (Object.keys(binary.headers ?? {}).some((name) => {
25
- const lower = name.toLowerCase();
26
- return lower === routes.HTTP_ROUTE_STALE || lower === routes.HTTP_ROUTE_MISS;
27
- })) {
28
- throw new TypeError(`${routes.HTTP_ROUTE_STALE} is reserved for stale-route control.`);
29
- }
31
+ export function renderBinary(requestId, invocation, binary) {
32
+ const reserved = Object.keys(binary.headers ?? {}).find((name) => {
33
+ const normalized = name.toLowerCase();
34
+ return (normalized === protocol.http.INVOCATION_FIELD ||
35
+ normalized === HTTP_ROUTE_STALE ||
36
+ normalized === HTTP_ROUTE_MISS);
37
+ });
38
+ if (reserved !== undefined)
39
+ throw new TypeError(`${reserved} is reserved by Protocol.`);
30
40
  return protocol.decodeBinaryResponse({
31
41
  kind: 'binary',
32
- id,
42
+ requestId,
43
+ invocation,
33
44
  body: binary.body,
34
45
  mediaType: binary.mediaType,
46
+ status: binary.status ?? 200,
35
47
  ...(binary.headers === undefined ? {} : { headers: binary.headers }),
36
48
  });
37
49
  }
38
- export function renderRedirect(id, redirect) {
39
- return protocol.decodeRedirect({
50
+ export function renderRedirect(requestId, invocation, redirect) {
51
+ return protocol.decodeRedirectResponse({
40
52
  kind: 'redirect',
41
- id,
42
- route: redirect.route,
43
- ...(redirect.credential === undefined ? {} : { credential: redirect.credential }),
44
- ...(redirect.trace === undefined ? {} : { trace: redirect.trace }),
53
+ requestId,
54
+ invocation,
55
+ redirect,
45
56
  });
46
57
  }
47
- export function renderHttpError(id, error, codec, cors, options = {}) {
58
+ export function renderHttpError(requestId, invocation, error, codec, cors, options = {}) {
48
59
  const status = options.status ?? errors.httpStatusOf(error);
49
60
  const extra = status === 401 ? { 'www-authenticate': 'Bearer realm="astrale-invocation"' } : {};
50
- return errorEnvelopeResponse(codec, { error, id }, { ...cors(), ...extra }, status, options.negotiated ?? true, options.maximumResponseBytes);
61
+ return errorEnvelopeResponse(codec, { error, requestId, invocation }, { ...cors(), ...extra }, status, options.negotiated ?? true, options.maximumResponseBytes);
51
62
  }
52
- export function renderHttpStale(id, current, codec, cors, maximumResponseBytes) {
53
- return envelopeResponse(codec, protocol.stale(id, current), cors(), 200, true, maximumResponseBytes);
63
+ export function renderHttpStale(requestId, invocation, current, codec, cors, maximumResponseBytes) {
64
+ return envelopeResponse(codec, protocol.stale(requestId, invocation, current), cors(), 200, true, maximumResponseBytes);
54
65
  }
55
66
  export function encodeEnvelope(codec, input) {
56
67
  return codec.encode(input);
@@ -67,10 +78,74 @@ function envelopeResponse(codec, input, cors, status = 200, negotiated = true, m
67
78
  }
68
79
  function binaryHttpResponse(binary, cors, maximumResponseBytes) {
69
80
  requireResponseBound(binary.body, maximumResponseBytes);
81
+ const headers = binaryHttpHeaders(binary, cors, false);
82
+ return new Response(toBody(binary.body), { status: binary.status, headers });
83
+ }
84
+ function streamingBinaryHttpResponse(binary, context) {
85
+ const iterator = binary.body[Symbol.asyncIterator]();
86
+ const headers = binaryHttpHeaders(Object.freeze({
87
+ requestId: context.requestId,
88
+ invocation: context.invocation,
89
+ mediaType: binary.mediaType,
90
+ headers: binary.headers,
91
+ }), context.cors, true);
92
+ let terminal = false;
93
+ let stopping;
94
+ const stop = () => {
95
+ stopping ??= Promise.resolve().then(async () => {
96
+ if (terminal)
97
+ return;
98
+ terminal = true;
99
+ try {
100
+ await iterator.return?.();
101
+ }
102
+ finally {
103
+ context.active.settle();
104
+ }
105
+ });
106
+ return stopping;
107
+ };
108
+ const body = new ReadableStream({
109
+ async pull(controller) {
110
+ if (terminal)
111
+ return;
112
+ try {
113
+ const next = await iterator.next();
114
+ if (terminal)
115
+ return;
116
+ if (next.done) {
117
+ terminal = true;
118
+ controller.close();
119
+ context.active.settle();
120
+ return;
121
+ }
122
+ controller.enqueue(next.value);
123
+ }
124
+ catch (cause) {
125
+ terminal = true;
126
+ controller.error(cause);
127
+ context.active.settle();
128
+ }
129
+ },
130
+ async cancel(reason) {
131
+ const message = typeof reason === 'string' ? reason : 'binary response consumer cancelled';
132
+ context.active.cancel(message);
133
+ await stop();
134
+ },
135
+ });
136
+ context.active.onCancel(stop);
137
+ return new Response(body, { status: binary.status ?? 200, headers });
138
+ }
139
+ export function isStreamingBinary(input) {
140
+ return !(input.body instanceof Uint8Array);
141
+ }
142
+ function binaryHttpHeaders(binary, cors, streaming) {
70
143
  const applicationHeaders = Object.keys(binary.headers ?? {}).filter((name) => protocol.http.isApplicationBinaryHeader(name));
71
144
  const headers = new Headers(cors([
72
145
  protocol.http.REQUEST_ID_FIELD,
146
+ protocol.http.INVOCATION_FIELD,
73
147
  protocol.http.BINARY_HEADERS_FIELD,
148
+ ...(streaming ? [protocol.http.BINARY_DELIVERY_FIELD] : []),
74
149
  ...applicationHeaders,
75
150
  ]));
76
151
  for (const [name, value] of Object.entries(binary.headers ?? {})) {
@@ -79,14 +154,18 @@ function binaryHttpResponse(binary, cors, maximumResponseBytes) {
79
154
  }
80
155
  headers.set('content-type', binary.mediaType);
81
156
  headers.set(protocol.http.BINARY_HEADERS_FIELD, protocol.http.encodeBinaryHeaderNames(binary.headers));
82
- headers.set(protocol.http.REQUEST_ID_FIELD, String(binary.id));
157
+ headers.set(protocol.http.REQUEST_ID_FIELD, String(binary.requestId));
158
+ headers.set(protocol.http.INVOCATION_FIELD, protocol.http.encodeInvocationId(binary.invocation));
159
+ if (streaming) {
160
+ headers.set(protocol.http.BINARY_DELIVERY_FIELD, protocol.http.STREAMING_BINARY_DELIVERY);
161
+ }
83
162
  headers.set('cache-control', 'no-store');
84
163
  appendVary(headers, 'accept');
85
- return new Response(toBody(binary.body), { status: 200, headers });
164
+ return headers;
86
165
  }
87
166
  function streamHttpResponse(stream, context) {
88
167
  const iterator = stream[Symbol.asyncIterator]();
89
- const startFrame = encodeBoundedStreamFrame(context.codec, { kind: 'stream.start', id: context.id }, context.maximumResponseBytes);
168
+ const startFrame = encodeBoundedStreamFrame(context.codec, { kind: 'stream.start', requestId: context.requestId, invocation: context.invocation }, context.maximumResponseBytes);
90
169
  let count = 0;
91
170
  let terminal = false;
92
171
  let controller;
@@ -122,7 +201,7 @@ function streamHttpResponse(stream, context) {
122
201
  ]);
123
202
  }
124
203
  finally {
125
- context.operation.settle();
204
+ context.active.settle();
126
205
  }
127
206
  }
128
207
  const body = new ReadableStream({
@@ -141,16 +220,16 @@ function streamHttpResponse(stream, context) {
141
220
  terminal = true;
142
221
  output.enqueue(encodeBoundedStreamFrame(context.codec, {
143
222
  kind: 'stream.end',
144
- id: context.id,
223
+ requestId: context.requestId,
145
224
  count,
146
225
  }, context.maximumResponseBytes));
147
226
  output.close();
148
- context.operation.settle();
227
+ context.active.settle();
149
228
  return;
150
229
  }
151
230
  const frame = protocol.decodeStreamFrame({
152
231
  kind: 'stream.item',
153
- id: context.id,
232
+ requestId: context.requestId,
154
233
  index: count,
155
234
  value: next.value,
156
235
  });
@@ -161,11 +240,11 @@ function streamHttpResponse(stream, context) {
161
240
  if (terminal)
162
241
  return;
163
242
  terminal = true;
164
- if (!context.operation.signal.aborted) {
243
+ if (!context.active.signal.aborted) {
165
244
  try {
166
245
  output.enqueue(encodeBoundedStreamFrame(context.codec, {
167
246
  kind: 'stream.error',
168
- id: context.id,
247
+ requestId: context.requestId,
169
248
  error: classifyError(input),
170
249
  }, context.maximumResponseBytes));
171
250
  }
@@ -178,16 +257,16 @@ function streamHttpResponse(stream, context) {
178
257
  Promise.resolve().then(() => stream.cancel('stream failed')),
179
258
  Promise.resolve().then(() => iterator.return?.()),
180
259
  ]);
181
- context.operation.settle();
260
+ context.active.settle();
182
261
  }
183
262
  },
184
263
  async cancel(reason) {
185
264
  const message = typeof reason === 'string' ? reason : 'response consumer cancelled';
186
- context.operation.cancel(message);
265
+ context.active.cancel(message);
187
266
  await stop(message);
188
267
  },
189
268
  });
190
- context.operation.onCancel(stop);
269
+ context.active.onCancel(stop);
191
270
  return new Response(body, {
192
271
  status: 200,
193
272
  headers: {
@@ -214,7 +293,8 @@ function errorEnvelopeResponse(codec, response, cors, status, negotiated, maximu
214
293
  if (!(error instanceof ResponseBodyTooLargeError))
215
294
  throw error;
216
295
  const fallback = {
217
- id: response.id,
296
+ requestId: response.requestId,
297
+ invocation: response.invocation,
218
298
  error: {
219
299
  code: errors.CODES.LIMIT_EXCEEDED,
220
300
  message: 'Response body exceeds the configured limit.',
@@ -265,8 +345,8 @@ function mergeVary(headers, value) {
265
345
  function cancellationFrame(context) {
266
346
  return {
267
347
  kind: 'stream.error',
268
- id: context.id,
269
- error: interruptedStreamError(context.operation.timedOut),
348
+ requestId: context.requestId,
349
+ error: interruptedStreamError(context.active.timedOut),
270
350
  };
271
351
  }
272
352
  function toBody(input) {
@@ -275,4 +355,3 @@ function toBody(input) {
275
355
  const copy = new Uint8Array(input);
276
356
  return copy.buffer;
277
357
  }
278
- //# sourceMappingURL=render.js.map
@@ -7,4 +7,3 @@ export { interruptedStreamError } from './stream-error.js';
7
7
  export { createServerRouter, type ServerRouter } from './router.js';
8
8
  export { createWebSocketSession, handleWebSocketUpgrade, type WebSocketHandlerConfig, type WebSocketSessionConfig, } from './websocket/index.js';
9
9
  export type { Application, WebSocketAdapter, WebSocketHandlers, WebSocketLike, WebSocketUpgradeOptions, } from './types.js';
10
- //# sourceMappingURL=index.d.ts.map
@@ -6,4 +6,3 @@ export { encodeEnvelope, renderBinary, renderHttpError, renderHttpResult, render
6
6
  export { interruptedStreamError } from './stream-error.js';
7
7
  export { createServerRouter } from './router.js';
8
8
  export { createWebSocketSession, handleWebSocketUpgrade, } from './websocket/index.js';
9
- //# sourceMappingURL=index.js.map
@@ -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
- import { type errors } from '@astrale-os/kernel-protocol';
1
+ import type { ErrorPayload } from '@astrale-os/kernel-protocol/errors';
2
2
  /** A transport cancellation after stream.start necessarily follows the Function effect boundary. */
3
- export declare function interruptedStreamError(timedOut: boolean): errors.ErrorPayload;
4
- //# sourceMappingURL=stream-error.d.ts.map
3
+ export declare function interruptedStreamError(timedOut: boolean): ErrorPayload;
@@ -1,14 +1,13 @@
1
- import { errors as protocolErrors } from '@astrale-os/kernel-protocol';
1
+ import { CODES } from '@astrale-os/kernel-protocol/errors';
2
2
  /** A transport cancellation after stream.start necessarily follows the Function effect boundary. */
3
3
  export function interruptedStreamError(timedOut) {
4
4
  return timedOut
5
5
  ? {
6
- code: protocolErrors.CODES.OUTCOME_UNKNOWN,
6
+ code: CODES.OUTCOME_UNKNOWN,
7
7
  message: 'Invocation deadline elapsed after the Function stream began; outcome is unknown.',
8
8
  }
9
9
  : {
10
- code: protocolErrors.CODES.OUTCOME_UNKNOWN,
10
+ code: CODES.OUTCOME_UNKNOWN,
11
11
  message: 'Function stream was cancelled after execution began; outcome is unknown.',
12
12
  };
13
13
  }
14
- //# sourceMappingURL=stream-error.js.map
@@ -1,4 +1,4 @@
1
- import type { invocation as protocol } from '@astrale-os/kernel-protocol';
1
+ import type * as protocol from '@astrale-os/kernel-protocol/invocation';
2
2
  import type { ApplicationHost } from '../invocation/index.js';
3
3
  /** Portable Fetch application; framework and listener APIs are adapter-owned. */
4
4
  export interface Application {
@@ -26,4 +26,3 @@ export interface WebSocketUpgradeOptions {
26
26
  export interface WebSocketAdapter {
27
27
  upgrade(request: Request, options: WebSocketUpgradeOptions): Response | Promise<Response>;
28
28
  }
29
- //# sourceMappingURL=types.d.ts.map
@@ -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,13 +1,15 @@
1
- import { type codecs } from '@astrale-os/kernel-protocol';
1
+ import type { Codec } from '@astrale-os/kernel-protocol/codecs';
2
+ import type { NextInvocationId } from '../../invocation/index.js';
2
3
  import type { ActiveOperations } from '../../lifecycle/index.js';
3
4
  import type { PublicationSnapshot } from '../../publication/index.js';
4
5
  import type { WebSocketHandlers } from '../types.js';
5
6
  import { type ApplicationHost, type Handler } from '../../invocation/index.js';
6
7
  export interface WebSocketSessionConfig {
7
- readonly codec: codecs.Codec;
8
+ readonly codec: Codec;
8
9
  readonly authorization: string | null;
9
10
  readonly handler: Handler;
10
11
  readonly active: ActiveOperations;
12
+ readonly invocation: NextInvocationId;
11
13
  readonly maximumRequestBytes: number;
12
14
  readonly maximumResponseBytes: number;
13
15
  readonly invocationTimeoutMs: number;
@@ -16,4 +18,3 @@ export interface WebSocketSessionConfig {
16
18
  }
17
19
  /** Build one socket-pinned transport session. */
18
20
  export declare function createWebSocketSession(config: WebSocketSessionConfig): WebSocketHandlers;
19
- //# sourceMappingURL=session.d.ts.map
@@ -1,10 +1,11 @@
1
- import { errors, invocation as protocol } from '@astrale-os/kernel-protocol';
1
+ import * as errors from '@astrale-os/kernel-protocol/errors';
2
+ import * as protocol from '@astrale-os/kernel-protocol/invocation';
2
3
  import { classifyError } from '../../errors/index.js';
3
4
  import { ResponseBodyTooLargeError } from '../../errors/index.js';
4
5
  import { invocationContext, publicationRouteDecision, } from '../../invocation/index.js';
5
6
  import { byteLength } from '../body.js';
6
7
  import { resolveCredential } from '../credential.js';
7
- import { renderBinary, renderRedirect } from '../http/render.js';
8
+ import { isStreamingBinary, renderBinary, renderRedirect } from '../http/render.js';
8
9
  import { interruptedStreamError } from '../stream-error.js';
9
10
  const WS_OPEN = 1;
10
11
  /** Build one socket-pinned transport session. */
@@ -71,9 +72,9 @@ export function createWebSocketSession(config) {
71
72
  socket.close(1002, 'Invalid cancellation message');
72
73
  return;
73
74
  }
74
- const operation = operations.get(requestKey(cancellation.id));
75
+ const operation = operations.get(requestKey(cancellation.requestId));
75
76
  if (operation === undefined) {
76
- await sendError(socket, admittedCodec, cancellation.id, {
77
+ await sendError(socket, admittedCodec, cancellation.requestId, config.invocation(), {
77
78
  code: errors.CODES.INVALID_REQUEST,
78
79
  message: 'Request ID is not active on this connection.',
79
80
  }, sendOutput);
@@ -82,17 +83,18 @@ export function createWebSocketSession(config) {
82
83
  operation.cancel('client cancelled invocation');
83
84
  return;
84
85
  }
85
- let invocation;
86
+ let envelope;
86
87
  try {
87
- invocation = protocol.decodeRequest(decoded);
88
+ envelope = protocol.decodeRequest(decoded);
88
89
  }
89
90
  catch {
90
91
  socket.close(1002, 'Invalid Invocation request');
91
92
  return;
92
93
  }
93
- const key = requestKey(invocation.id);
94
+ const assigned = config.invocation();
95
+ const key = requestKey(envelope.requestId);
94
96
  if (operations.has(key)) {
95
- await sendError(socket, admittedCodec, invocation.id, {
97
+ await sendError(socket, admittedCodec, envelope.requestId, assigned, {
96
98
  code: errors.CODES.INVALID_REQUEST,
97
99
  message: 'Request ID is already active on this connection.',
98
100
  }, sendOutput);
@@ -100,34 +102,34 @@ export function createWebSocketSession(config) {
100
102
  }
101
103
  const publication = config.currentPublication?.();
102
104
  if (config.currentPublication !== undefined && publication === undefined) {
103
- await sendError(socket, admittedCodec, invocation.id, {
105
+ await sendError(socket, admittedCodec, envelope.requestId, assigned, {
104
106
  code: errors.CODES.BACKEND_UNAVAILABLE,
105
107
  message: 'Publication is unavailable.',
106
108
  }, sendOutput);
107
109
  return;
108
110
  }
109
- if (invocation.routing?.kind === 'via') {
111
+ if (envelope.routing?.kind === 'via') {
110
112
  if (publication === undefined) {
111
- await sendError(socket, admittedCodec, invocation.id, {
113
+ await sendError(socket, admittedCodec, envelope.requestId, assigned, {
112
114
  code: errors.CODES.INVALID_REQUEST,
113
115
  message: 'Publication routing requires a Publication-backed destination.',
114
116
  }, sendOutput);
115
117
  return;
116
118
  }
117
- const decision = publicationRouteDecision(publication.publication, invocation.routing.publication);
119
+ const decision = publicationRouteDecision(publication.publication, envelope.routing.publication);
118
120
  if (decision.kind === 'rejected') {
119
- await sendError(socket, admittedCodec, invocation.id, decision.error, sendOutput);
121
+ await sendError(socket, admittedCodec, envelope.requestId, assigned, decision.error, sendOutput);
120
122
  return;
121
123
  }
122
124
  }
123
- const credential = resolveCredential(invocation.credential, config.authorization);
125
+ const credential = resolveCredential(envelope.credential, config.authorization);
124
126
  if (!credential.ok) {
125
- await sendError(socket, admittedCodec, invocation.id, credential.error, sendOutput);
127
+ await sendError(socket, admittedCodec, envelope.requestId, assigned, credential.error, sendOutput);
126
128
  return;
127
129
  }
128
130
  const operation = config.active.begin(config.invocationTimeoutMs);
129
131
  if (operation === undefined) {
130
- await sendError(socket, admittedCodec, invocation.id, {
132
+ await sendError(socket, admittedCodec, envelope.requestId, assigned, {
131
133
  code: errors.CODES.BACKEND_UNAVAILABLE,
132
134
  message: 'server is unavailable.',
133
135
  }, sendOutput);
@@ -137,16 +139,16 @@ export function createWebSocketSession(config) {
137
139
  scopes.add(operation);
138
140
  try {
139
141
  const result = await config.handler.dispatch(Object.freeze({
140
- call: invocation.call,
141
- ...(invocation.trace === undefined ? {} : { trace: invocation.trace }),
142
+ call: envelope.call,
143
+ ...(envelope.trace === undefined ? {} : { trace: envelope.trace }),
142
144
  ...(credential.credential === undefined ? {} : { credential: credential.credential }),
143
- ...(invocation.delegate === undefined ? {} : { delegate: invocation.delegate }),
144
- ...(invocation.routing?.kind === 'via' ? { via: invocation.routing } : {}),
145
- ...(invocation.schema === undefined ? {} : { schema: invocation.schema }),
145
+ ...(envelope.delegate === undefined ? {} : { delegate: envelope.delegate }),
146
+ ...(envelope.routing?.kind === 'via' ? { via: envelope.routing } : {}),
147
+ ...(envelope.schema === undefined ? {} : { schema: envelope.schema }),
146
148
  ...(publication === undefined ? {} : { publication }),
147
- context: invocationContext(operation, config.active, config.host, undefined, invocation.idempotencyKey),
149
+ context: invocationContext(assigned, operation, config.active, config.host, undefined, envelope.idempotencyKey),
148
150
  }));
149
- await sendResult(socket, admittedCodec, invocation.id, result, operation, sendOutput);
151
+ await sendResult(socket, admittedCodec, envelope.requestId, assigned, result, operation, sendOutput);
150
152
  }
151
153
  catch (input) {
152
154
  if (input instanceof ResponseBodyTooLargeError || input instanceof WebSocketOutputError) {
@@ -165,7 +167,7 @@ export function createWebSocketSession(config) {
165
167
  socket.close(1011, 'Internal error');
166
168
  return;
167
169
  }
168
- await sendError(socket, admittedCodec, invocation.id, error, sendOutput);
170
+ await sendError(socket, admittedCodec, envelope.requestId, assigned, error, sendOutput);
169
171
  }
170
172
  }
171
173
  finally {
@@ -193,22 +195,34 @@ export function createWebSocketSession(config) {
193
195
  };
194
196
  return handlers;
195
197
  }
196
- async function sendResult(socket, codec, id, result, operation, sendOutput) {
198
+ async function sendResult(socket, codec, requestId, assigned, result, operation, sendOutput) {
197
199
  switch (result.kind) {
198
200
  case 'value':
199
201
  await send(socket, codec, {
200
202
  result: result.value,
201
- id,
203
+ requestId,
204
+ invocation: assigned,
202
205
  }, sendOutput);
203
206
  return;
204
207
  case 'redirect':
205
- await send(socket, codec, renderRedirect(id, result.redirect), sendOutput);
208
+ await send(socket, codec, renderRedirect(requestId, assigned, result.redirect), sendOutput);
206
209
  return;
207
210
  case 'miss':
208
- await send(socket, codec, protocol.miss(id), sendOutput);
211
+ await send(socket, codec, protocol.miss(requestId, assigned), sendOutput);
209
212
  return;
210
213
  case 'binary': {
211
- const binary = renderBinary(id, result.value);
214
+ if (isStreamingBinary(result.value)) {
215
+ const streaming = result.value;
216
+ await Promise.allSettled([
217
+ sendError(socket, codec, requestId, assigned, {
218
+ code: errors.CODES.UNSUPPORTED,
219
+ message: 'Streaming binary output requires the HTTP transport.',
220
+ }, sendOutput),
221
+ Promise.resolve().then(() => streaming.body[Symbol.asyncIterator]().return?.()),
222
+ ]);
223
+ return;
224
+ }
225
+ const binary = renderBinary(requestId, assigned, result.value);
212
226
  if (socket.readyState === WS_OPEN) {
213
227
  await sendOutput(socket, protocol.websocket.encodeBinary(binary));
214
228
  }
@@ -234,7 +248,7 @@ async function sendResult(socket, codec, id, result, operation, sendOutput) {
234
248
  terminal = true;
235
249
  const terminalOutput = emit({
236
250
  kind: 'stream.error',
237
- id,
251
+ requestId,
238
252
  error: interruptedStreamError(operation.timedOut),
239
253
  });
240
254
  await Promise.allSettled([
@@ -243,7 +257,11 @@ async function sendResult(socket, codec, id, result, operation, sendOutput) {
243
257
  Promise.resolve().then(() => iterator.return?.()),
244
258
  ]);
245
259
  };
246
- const started = emit({ kind: 'stream.start', id });
260
+ const started = emit({
261
+ kind: 'stream.start',
262
+ requestId,
263
+ invocation: assigned,
264
+ });
247
265
  operation.onCancel(cancel);
248
266
  let count = 0;
249
267
  try {
@@ -254,12 +272,12 @@ async function sendResult(socket, codec, id, result, operation, sendOutput) {
254
272
  break;
255
273
  if (next.done) {
256
274
  terminal = true;
257
- await emit({ kind: 'stream.end', id, count });
275
+ await emit({ kind: 'stream.end', requestId, count });
258
276
  break;
259
277
  }
260
278
  await emit(protocol.decodeStreamFrame({
261
279
  kind: 'stream.item',
262
- id,
280
+ requestId,
263
281
  index: count,
264
282
  value: next.value,
265
283
  }));
@@ -295,7 +313,7 @@ async function sendResult(socket, codec, id, result, operation, sendOutput) {
295
313
  await Promise.allSettled([
296
314
  emit({
297
315
  kind: 'stream.error',
298
- id,
316
+ requestId,
299
317
  error,
300
318
  }),
301
319
  Promise.resolve().then(() => result.stream.cancel('stream failed')),
@@ -305,8 +323,8 @@ async function sendResult(socket, codec, id, result, operation, sendOutput) {
305
323
  }
306
324
  }
307
325
  }
308
- function sendError(socket, codec, id, error, output) {
309
- return send(socket, codec, { error, id }, output);
326
+ function sendError(socket, codec, requestId, invocation, error, output) {
327
+ return send(socket, codec, { error, requestId, invocation }, output);
310
328
  }
311
329
  function send(socket, codec, value, output) {
312
330
  return output(socket, codec.encode(value));
@@ -317,8 +335,8 @@ class WebSocketOutputError extends Error {
317
335
  this.name = 'WebSocketOutputError';
318
336
  }
319
337
  }
320
- function requestKey(id) {
321
- return id === null ? 'null:' : `${typeof id}:${String(id)}`;
338
+ function requestKey(requestId) {
339
+ return requestId === null ? 'null:' : `${typeof requestId}:${String(requestId)}`;
322
340
  }
323
341
  function isCancelRequest(input) {
324
342
  return (typeof input === 'object' &&
@@ -326,4 +344,3 @@ function isCancelRequest(input) {
326
344
  !Array.isArray(input) &&
327
345
  input.kind === 'cancel');
328
346
  }
329
- //# sourceMappingURL=session.js.map
@@ -1,5 +1,6 @@
1
1
  import type { CorsPolicy } from '../../cors/index.js';
2
2
  import type { ApplicationHost, Handler } from '../../invocation/index.js';
3
+ import type { NextInvocationId } from '../../invocation/index.js';
3
4
  import type { ActiveOperations } from '../../lifecycle/index.js';
4
5
  import type { PublicationSnapshot } from '../../publication/index.js';
5
6
  import type { WebSocketAdapter } from '../types.js';
@@ -8,6 +9,7 @@ export interface WebSocketHandlerConfig {
8
9
  readonly adapter: WebSocketAdapter;
9
10
  readonly handler: Handler;
10
11
  readonly active: ActiveOperations;
12
+ readonly invocation: NextInvocationId;
11
13
  readonly maximumRequestBytes: number;
12
14
  readonly maximumResponseBytes: number;
13
15
  readonly invocationTimeoutMs: number;
@@ -16,4 +18,3 @@ export interface WebSocketHandlerConfig {
16
18
  readonly host?: ApplicationHost;
17
19
  }
18
20
  export declare function handleWebSocketUpgrade(config: WebSocketHandlerConfig): Promise<Response>;
19
- //# sourceMappingURL=upgrade.d.ts.map
@@ -1,4 +1,4 @@
1
- import { invocation as protocol } from '@astrale-os/kernel-protocol';
1
+ import * as protocol from '@astrale-os/kernel-protocol/invocation';
2
2
  import { loadCodecs } from '../codecs.js';
3
3
  import { createWebSocketSession } from './session.js';
4
4
  export async function handleWebSocketUpgrade(config) {
@@ -19,6 +19,7 @@ export async function handleWebSocketUpgrade(config) {
19
19
  authorization: config.request.headers.get('authorization'),
20
20
  handler: config.handler,
21
21
  active: config.active,
22
+ invocation: config.invocation,
22
23
  maximumRequestBytes: config.maximumRequestBytes,
23
24
  maximumResponseBytes: config.maximumResponseBytes,
24
25
  invocationTimeoutMs: config.invocationTimeoutMs,
@@ -43,4 +44,3 @@ function failure(status, input = {}) {
43
44
  headers: { ...input, 'cache-control': 'no-store' },
44
45
  });
45
46
  }
46
- //# sourceMappingURL=upgrade.js.map