@astrale-os/kernel-server 0.5.0-beta.9 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/capture.d.ts +0 -1
- package/dist/capture.js +0 -1
- package/dist/cors/cors.d.ts +0 -1
- package/dist/cors/cors.js +11 -4
- package/dist/cors/index.d.ts +0 -1
- package/dist/cors/index.js +0 -1
- package/dist/cors/types.d.ts +0 -1
- package/dist/cors/types.js +0 -1
- package/dist/errors/admission.d.ts +7 -0
- package/dist/errors/admission.js +22 -0
- package/dist/errors/availability.d.ts +0 -1
- package/dist/errors/availability.js +0 -1
- package/dist/errors/classify.d.ts +10 -1
- package/dist/errors/classify.js +25 -1
- package/dist/errors/index.d.ts +2 -2
- package/dist/errors/index.js +2 -2
- package/dist/errors/request-body.d.ts +0 -1
- package/dist/errors/request-body.js +0 -1
- package/dist/errors/response-body.d.ts +0 -1
- package/dist/errors/response-body.js +0 -1
- package/dist/index.d.ts +3 -4
- package/dist/index.js +2 -3
- package/dist/invocation/context.d.ts +2 -2
- package/dist/invocation/context.js +2 -2
- package/dist/invocation/identity.d.ts +0 -1
- package/dist/invocation/identity.js +0 -1
- package/dist/invocation/index.d.ts +1 -2
- package/dist/invocation/index.js +1 -2
- package/dist/invocation/release-route.d.ts +22 -0
- package/dist/invocation/release-route.js +32 -0
- package/dist/invocation/types.d.ts +9 -6
- package/dist/invocation/types.js +0 -1
- package/dist/issuer/exchange.d.ts +0 -1
- package/dist/issuer/exchange.js +20 -10
- package/dist/issuer/index.d.ts +0 -1
- package/dist/issuer/index.js +0 -1
- package/dist/issuer/routes.d.ts +0 -1
- package/dist/issuer/routes.js +57 -48
- package/dist/issuer/types.d.ts +5 -1
- package/dist/issuer/types.js +0 -1
- package/dist/lifecycle/active.d.ts +6 -2
- package/dist/lifecycle/active.js +55 -14
- package/dist/lifecycle/index.d.ts +0 -1
- package/dist/lifecycle/index.js +0 -1
- package/dist/release/delivery/handler.d.ts +9 -0
- package/dist/{publication → release}/delivery/handler.js +18 -13
- package/dist/release/delivery/index.d.ts +1 -0
- package/dist/release/delivery/index.js +1 -0
- package/dist/{publication → release}/delivery/types.d.ts +4 -5
- package/dist/release/delivery/types.js +1 -0
- package/dist/release/index.d.ts +3 -0
- package/dist/release/index.js +2 -0
- package/dist/release/served.d.ts +21 -0
- package/dist/release/served.js +10 -0
- package/dist/release/snapshot.d.ts +22 -0
- package/dist/release/snapshot.js +49 -0
- package/dist/release/table.d.ts +4 -0
- package/dist/release/table.js +11 -0
- package/dist/release/types.d.ts +23 -0
- package/dist/release/types.js +1 -0
- package/dist/routes/address.d.ts +2 -0
- package/dist/routes/address.js +6 -0
- package/dist/routes/binary.d.ts +9 -0
- package/dist/routes/binary.js +110 -0
- package/dist/routes/bundle.d.ts +5 -0
- package/dist/routes/bundle.js +50 -0
- package/dist/routes/csrf.d.ts +16 -0
- package/dist/routes/csrf.js +35 -0
- package/dist/routes/document.d.ts +6 -0
- package/dist/routes/document.js +57 -0
- package/dist/routes/index.d.ts +3 -2
- package/dist/routes/index.js +2 -2
- package/dist/routes/model.d.ts +15 -0
- package/dist/routes/model.js +1 -0
- package/dist/routes/native.d.ts +17 -0
- package/dist/routes/native.js +136 -0
- package/dist/routes/preflight.d.ts +4 -0
- package/dist/routes/preflight.js +55 -0
- package/dist/routes/response.d.ts +14 -0
- package/dist/routes/response.js +33 -0
- package/dist/routes/routes.d.ts +7 -24
- package/dist/routes/routes.js +24 -439
- package/dist/routes/snapshot.d.ts +13 -0
- package/dist/routes/snapshot.js +39 -0
- package/dist/routes/stream.d.ts +6 -0
- package/dist/routes/stream.js +122 -0
- package/dist/server.d.ts +0 -1
- package/dist/server.js +121 -53
- package/dist/transport/body.d.ts +0 -1
- package/dist/transport/body.js +0 -1
- package/dist/transport/codecs.d.ts +2 -3
- package/dist/transport/codecs.js +4 -4
- package/dist/transport/credential.d.ts +0 -1
- package/dist/transport/credential.js +0 -1
- package/dist/transport/http/binary-request.d.ts +11 -0
- package/dist/transport/http/binary-request.js +102 -0
- package/dist/transport/http/binary.d.ts +6 -0
- package/dist/transport/http/binary.js +35 -0
- package/dist/transport/http/byte-stream.d.ts +4 -0
- package/dist/transport/http/byte-stream.js +123 -0
- package/dist/transport/http/control.d.ts +12 -0
- package/dist/transport/http/control.js +24 -0
- package/dist/transport/http/handler.d.ts +8 -3
- package/dist/transport/http/handler.js +98 -45
- package/dist/transport/http/index.d.ts +3 -2
- package/dist/transport/http/index.js +2 -2
- package/dist/transport/http/model.d.ts +20 -0
- package/dist/transport/http/model.js +1 -0
- package/dist/transport/http/render.d.ts +3 -31
- package/dist/transport/http/render.js +25 -269
- package/dist/transport/http/response.d.ts +14 -0
- package/dist/transport/http/response.js +77 -0
- package/dist/transport/http/stream.d.ts +5 -0
- package/dist/transport/http/stream.js +134 -0
- package/dist/transport/index.d.ts +2 -2
- package/dist/transport/index.js +2 -2
- package/dist/transport/result.d.ts +13 -0
- package/dist/transport/result.js +35 -0
- package/dist/transport/router.d.ts +0 -1
- package/dist/transport/router.js +0 -1
- package/dist/transport/stream-error.d.ts +0 -1
- package/dist/transport/stream-error.js +0 -1
- package/dist/transport/types.d.ts +0 -1
- package/dist/transport/types.js +0 -1
- package/dist/transport/websocket/index.d.ts +0 -1
- package/dist/transport/websocket/index.js +0 -1
- package/dist/transport/websocket/session.d.ts +3 -3
- package/dist/transport/websocket/session.js +38 -30
- package/dist/transport/websocket/upgrade.d.ts +2 -3
- package/dist/transport/websocket/upgrade.js +7 -7
- package/dist/types.d.ts +43 -10
- package/dist/types.js +0 -1
- package/package.json +11 -22
- package/dist/capture.d.ts.map +0 -1
- package/dist/capture.js.map +0 -1
- package/dist/cors/cors.d.ts.map +0 -1
- package/dist/cors/cors.js.map +0 -1
- package/dist/cors/index.d.ts.map +0 -1
- package/dist/cors/index.js.map +0 -1
- package/dist/cors/types.d.ts.map +0 -1
- package/dist/cors/types.js.map +0 -1
- package/dist/errors/availability.d.ts.map +0 -1
- package/dist/errors/availability.js.map +0 -1
- package/dist/errors/classify.d.ts.map +0 -1
- package/dist/errors/classify.js.map +0 -1
- package/dist/errors/index.d.ts.map +0 -1
- package/dist/errors/index.js.map +0 -1
- package/dist/errors/request-body.d.ts.map +0 -1
- package/dist/errors/request-body.js.map +0 -1
- package/dist/errors/response-body.d.ts.map +0 -1
- package/dist/errors/response-body.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/invocation/context.d.ts.map +0 -1
- package/dist/invocation/context.js.map +0 -1
- package/dist/invocation/identity.d.ts.map +0 -1
- package/dist/invocation/identity.js.map +0 -1
- package/dist/invocation/index.d.ts.map +0 -1
- package/dist/invocation/index.js.map +0 -1
- package/dist/invocation/publication-route.d.ts +0 -14
- package/dist/invocation/publication-route.d.ts.map +0 -1
- package/dist/invocation/publication-route.js +0 -45
- package/dist/invocation/publication-route.js.map +0 -1
- package/dist/invocation/types.d.ts.map +0 -1
- package/dist/invocation/types.js.map +0 -1
- package/dist/issuer/exchange.d.ts.map +0 -1
- package/dist/issuer/exchange.js.map +0 -1
- package/dist/issuer/index.d.ts.map +0 -1
- package/dist/issuer/index.js.map +0 -1
- package/dist/issuer/routes.d.ts.map +0 -1
- package/dist/issuer/routes.js.map +0 -1
- package/dist/issuer/types.d.ts.map +0 -1
- package/dist/issuer/types.js.map +0 -1
- package/dist/lifecycle/active.d.ts.map +0 -1
- package/dist/lifecycle/active.js.map +0 -1
- package/dist/lifecycle/index.d.ts.map +0 -1
- package/dist/lifecycle/index.js.map +0 -1
- package/dist/publication/delivery/handler.d.ts +0 -10
- package/dist/publication/delivery/handler.d.ts.map +0 -1
- package/dist/publication/delivery/handler.js.map +0 -1
- package/dist/publication/delivery/index.d.ts +0 -3
- package/dist/publication/delivery/index.d.ts.map +0 -1
- package/dist/publication/delivery/index.js +0 -2
- package/dist/publication/delivery/index.js.map +0 -1
- package/dist/publication/delivery/types.d.ts.map +0 -1
- package/dist/publication/delivery/types.js +0 -2
- package/dist/publication/delivery/types.js.map +0 -1
- package/dist/publication/index.d.ts +0 -4
- package/dist/publication/index.d.ts.map +0 -1
- package/dist/publication/index.js +0 -3
- package/dist/publication/index.js.map +0 -1
- package/dist/publication/snapshot.d.ts +0 -17
- package/dist/publication/snapshot.d.ts.map +0 -1
- package/dist/publication/snapshot.js +0 -38
- package/dist/publication/snapshot.js.map +0 -1
- package/dist/publication/table.d.ts +0 -5
- package/dist/publication/table.d.ts.map +0 -1
- package/dist/publication/table.js +0 -17
- package/dist/publication/table.js.map +0 -1
- package/dist/publication/types.d.ts +0 -23
- package/dist/publication/types.d.ts.map +0 -1
- package/dist/publication/types.js +0 -2
- package/dist/publication/types.js.map +0 -1
- package/dist/routes/index.d.ts.map +0 -1
- package/dist/routes/index.js.map +0 -1
- package/dist/routes/routes.d.ts.map +0 -1
- package/dist/routes/routes.js.map +0 -1
- package/dist/server.d.ts.map +0 -1
- package/dist/server.js.map +0 -1
- package/dist/transport/body.d.ts.map +0 -1
- package/dist/transport/body.js.map +0 -1
- package/dist/transport/codecs.d.ts.map +0 -1
- package/dist/transport/codecs.js.map +0 -1
- package/dist/transport/credential.d.ts.map +0 -1
- package/dist/transport/credential.js.map +0 -1
- package/dist/transport/http/handler.d.ts.map +0 -1
- package/dist/transport/http/handler.js.map +0 -1
- package/dist/transport/http/index.d.ts.map +0 -1
- package/dist/transport/http/index.js.map +0 -1
- package/dist/transport/http/render.d.ts.map +0 -1
- package/dist/transport/http/render.js.map +0 -1
- package/dist/transport/index.d.ts.map +0 -1
- package/dist/transport/index.js.map +0 -1
- package/dist/transport/router.d.ts.map +0 -1
- package/dist/transport/router.js.map +0 -1
- package/dist/transport/stream-error.d.ts.map +0 -1
- package/dist/transport/stream-error.js.map +0 -1
- package/dist/transport/types.d.ts.map +0 -1
- package/dist/transport/types.js.map +0 -1
- package/dist/transport/websocket/index.d.ts.map +0 -1
- package/dist/transport/websocket/index.js.map +0 -1
- package/dist/transport/websocket/session.d.ts.map +0 -1
- package/dist/transport/websocket/session.js.map +0 -1
- package/dist/transport/websocket/upgrade.d.ts.map +0 -1
- package/dist/transport/websocket/upgrade.js.map +0 -1
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js.map +0 -1
|
@@ -1,289 +1,45 @@
|
|
|
1
|
-
import * as errors from '@astrale-os/kernel-protocol/errors';
|
|
2
1
|
import * as protocol from '@astrale-os/kernel-protocol/invocation';
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
2
|
+
import { isStreamingBinary, renderBinary, renderRedirect } from '../result.js';
|
|
3
|
+
import { binaryHttpResponse } from './binary.js';
|
|
4
|
+
import { streamingBinaryHttpResponse } from './byte-stream.js';
|
|
5
|
+
import { envelopeResponse } from './response.js';
|
|
6
|
+
import { streamHttpResponse } from './stream.js';
|
|
7
|
+
/** Render one admitted Handler result and retain only live producers in the active operation. */
|
|
7
8
|
export function renderHttpResult(result, context) {
|
|
9
|
+
let envelope;
|
|
8
10
|
switch (result.kind) {
|
|
9
11
|
case 'value':
|
|
10
|
-
|
|
12
|
+
envelope = {
|
|
11
13
|
result: result.value,
|
|
12
14
|
requestId: context.requestId,
|
|
13
15
|
invocation: context.invocation,
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
};
|
|
17
|
+
break;
|
|
18
|
+
case 'execution':
|
|
19
|
+
envelope = {
|
|
20
|
+
execution: result.execution,
|
|
21
|
+
requestId: context.requestId,
|
|
22
|
+
invocation: context.invocation,
|
|
23
|
+
};
|
|
24
|
+
break;
|
|
25
|
+
case 'redirect':
|
|
26
|
+
envelope = renderRedirect(context.requestId, context.invocation, result.redirect);
|
|
27
|
+
break;
|
|
19
28
|
case 'miss':
|
|
20
|
-
|
|
29
|
+
envelope = protocol.miss(context.requestId, context.invocation);
|
|
30
|
+
break;
|
|
21
31
|
case 'binary': {
|
|
32
|
+
if (isStreamingBinary(result.value))
|
|
33
|
+
return streamingBinaryHttpResponse(result.value, context);
|
|
22
34
|
const binary = renderBinary(context.requestId, context.invocation, result.value);
|
|
23
35
|
return settled(context.active, binaryHttpResponse(binary, context.cors, context.maximumResponseBytes));
|
|
24
36
|
}
|
|
25
37
|
case 'stream':
|
|
26
38
|
return streamHttpResponse(result.stream, context);
|
|
27
39
|
}
|
|
28
|
-
|
|
29
|
-
export function renderBinary(requestId, invocation, binary) {
|
|
30
|
-
const reserved = Object.keys(binary.headers ?? {}).find((name) => {
|
|
31
|
-
const normalized = name.toLowerCase();
|
|
32
|
-
return (normalized === protocol.http.INVOCATION_FIELD ||
|
|
33
|
-
normalized === HTTP_ROUTE_STALE ||
|
|
34
|
-
normalized === HTTP_ROUTE_MISS);
|
|
35
|
-
});
|
|
36
|
-
if (reserved !== undefined)
|
|
37
|
-
throw new TypeError(`${reserved} is reserved by Protocol.`);
|
|
38
|
-
return protocol.decodeBinaryResponse({
|
|
39
|
-
kind: 'binary',
|
|
40
|
-
requestId,
|
|
41
|
-
invocation,
|
|
42
|
-
body: binary.body,
|
|
43
|
-
mediaType: binary.mediaType,
|
|
44
|
-
...(binary.headers === undefined ? {} : { headers: binary.headers }),
|
|
45
|
-
});
|
|
46
|
-
}
|
|
47
|
-
export function renderRedirect(requestId, invocation, redirect) {
|
|
48
|
-
return protocol.decodeRedirectResponse({
|
|
49
|
-
kind: 'redirect',
|
|
50
|
-
requestId,
|
|
51
|
-
invocation,
|
|
52
|
-
redirect,
|
|
53
|
-
});
|
|
54
|
-
}
|
|
55
|
-
export function renderHttpError(requestId, invocation, error, codec, cors, options = {}) {
|
|
56
|
-
const status = options.status ?? errors.httpStatusOf(error);
|
|
57
|
-
const extra = status === 401 ? { 'www-authenticate': 'Bearer realm="astrale-invocation"' } : {};
|
|
58
|
-
return errorEnvelopeResponse(codec, { error, requestId, invocation }, { ...cors(), ...extra }, status, options.negotiated ?? true, options.maximumResponseBytes);
|
|
59
|
-
}
|
|
60
|
-
export function renderHttpStale(requestId, invocation, current, codec, cors, maximumResponseBytes) {
|
|
61
|
-
return envelopeResponse(codec, protocol.stale(requestId, invocation, current), cors(), 200, true, maximumResponseBytes);
|
|
62
|
-
}
|
|
63
|
-
export function encodeEnvelope(codec, input) {
|
|
64
|
-
return codec.encode(input);
|
|
65
|
-
}
|
|
66
|
-
function envelopeResponse(codec, input, cors, status = 200, negotiated = true, maximumResponseBytes) {
|
|
67
|
-
const encoded = codec.encode(input);
|
|
68
|
-
requireResponseBound(encoded, maximumResponseBytes);
|
|
69
|
-
const headers = bindingHeaders(cors, negotiated);
|
|
70
|
-
headers.set('content-type', codec.contentType);
|
|
71
|
-
return new Response(toBody(encoded), {
|
|
72
|
-
status,
|
|
73
|
-
headers,
|
|
74
|
-
});
|
|
75
|
-
}
|
|
76
|
-
function binaryHttpResponse(binary, cors, maximumResponseBytes) {
|
|
77
|
-
requireResponseBound(binary.body, maximumResponseBytes);
|
|
78
|
-
const applicationHeaders = Object.keys(binary.headers ?? {}).filter((name) => protocol.http.isApplicationBinaryHeader(name));
|
|
79
|
-
const headers = new Headers(cors([
|
|
80
|
-
protocol.http.REQUEST_ID_FIELD,
|
|
81
|
-
protocol.http.INVOCATION_FIELD,
|
|
82
|
-
protocol.http.BINARY_HEADERS_FIELD,
|
|
83
|
-
...applicationHeaders,
|
|
84
|
-
]));
|
|
85
|
-
for (const [name, value] of Object.entries(binary.headers ?? {})) {
|
|
86
|
-
if (protocol.http.isApplicationBinaryHeader(name))
|
|
87
|
-
headers.set(name, value);
|
|
88
|
-
}
|
|
89
|
-
headers.set('content-type', binary.mediaType);
|
|
90
|
-
headers.set(protocol.http.BINARY_HEADERS_FIELD, protocol.http.encodeBinaryHeaderNames(binary.headers));
|
|
91
|
-
headers.set(protocol.http.REQUEST_ID_FIELD, String(binary.requestId));
|
|
92
|
-
headers.set(protocol.http.INVOCATION_FIELD, protocol.http.encodeInvocationId(binary.invocation));
|
|
93
|
-
headers.set('cache-control', 'no-store');
|
|
94
|
-
appendVary(headers, 'accept');
|
|
95
|
-
return new Response(toBody(binary.body), { status: 200, headers });
|
|
96
|
-
}
|
|
97
|
-
function streamHttpResponse(stream, context) {
|
|
98
|
-
const iterator = stream[Symbol.asyncIterator]();
|
|
99
|
-
const startFrame = encodeBoundedStreamFrame(context.codec, { kind: 'stream.start', requestId: context.requestId, invocation: context.invocation }, context.maximumResponseBytes);
|
|
100
|
-
let count = 0;
|
|
101
|
-
let terminal = false;
|
|
102
|
-
let controller;
|
|
103
|
-
let stopping;
|
|
104
|
-
const stop = (reason) => {
|
|
105
|
-
stopping ??= stopStream(reason);
|
|
106
|
-
return stopping;
|
|
107
|
-
};
|
|
108
|
-
async function stopStream(reason) {
|
|
109
|
-
if (terminal)
|
|
110
|
-
return;
|
|
111
|
-
terminal = true;
|
|
112
|
-
// End the wire response immediately. Producer cleanup remains part of the active operation,
|
|
113
|
-
// but an uncooperative producer must not leave the client waiting for a terminal frame.
|
|
114
|
-
if (controller !== undefined) {
|
|
115
|
-
try {
|
|
116
|
-
controller.enqueue(encodeBoundedStreamFrame(context.codec, cancellationFrame(context), context.maximumResponseBytes));
|
|
117
|
-
}
|
|
118
|
-
catch {
|
|
119
|
-
// The transport consumer may already have disconnected.
|
|
120
|
-
}
|
|
121
|
-
try {
|
|
122
|
-
controller.close();
|
|
123
|
-
}
|
|
124
|
-
catch {
|
|
125
|
-
// The stream may already be closed or cancelled by the consumer.
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
try {
|
|
129
|
-
await Promise.allSettled([
|
|
130
|
-
Promise.resolve().then(() => stream.cancel(reason)),
|
|
131
|
-
Promise.resolve().then(() => iterator.return?.()),
|
|
132
|
-
]);
|
|
133
|
-
}
|
|
134
|
-
finally {
|
|
135
|
-
context.active.settle();
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
const body = new ReadableStream({
|
|
139
|
-
start(output) {
|
|
140
|
-
controller = output;
|
|
141
|
-
output.enqueue(startFrame);
|
|
142
|
-
},
|
|
143
|
-
async pull(output) {
|
|
144
|
-
if (terminal)
|
|
145
|
-
return;
|
|
146
|
-
try {
|
|
147
|
-
const next = await iterator.next();
|
|
148
|
-
if (terminal)
|
|
149
|
-
return;
|
|
150
|
-
if (next.done) {
|
|
151
|
-
terminal = true;
|
|
152
|
-
output.enqueue(encodeBoundedStreamFrame(context.codec, {
|
|
153
|
-
kind: 'stream.end',
|
|
154
|
-
requestId: context.requestId,
|
|
155
|
-
count,
|
|
156
|
-
}, context.maximumResponseBytes));
|
|
157
|
-
output.close();
|
|
158
|
-
context.active.settle();
|
|
159
|
-
return;
|
|
160
|
-
}
|
|
161
|
-
const frame = protocol.decodeStreamFrame({
|
|
162
|
-
kind: 'stream.item',
|
|
163
|
-
requestId: context.requestId,
|
|
164
|
-
index: count,
|
|
165
|
-
value: next.value,
|
|
166
|
-
});
|
|
167
|
-
output.enqueue(encodeBoundedStreamFrame(context.codec, frame, context.maximumResponseBytes));
|
|
168
|
-
count += 1;
|
|
169
|
-
}
|
|
170
|
-
catch (input) {
|
|
171
|
-
if (terminal)
|
|
172
|
-
return;
|
|
173
|
-
terminal = true;
|
|
174
|
-
if (!context.active.signal.aborted) {
|
|
175
|
-
try {
|
|
176
|
-
output.enqueue(encodeBoundedStreamFrame(context.codec, {
|
|
177
|
-
kind: 'stream.error',
|
|
178
|
-
requestId: context.requestId,
|
|
179
|
-
error: classifyError(input),
|
|
180
|
-
}, context.maximumResponseBytes));
|
|
181
|
-
}
|
|
182
|
-
catch {
|
|
183
|
-
// No valid terminal frame can be formed; closing is the only remaining signal.
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
output.close();
|
|
187
|
-
await Promise.allSettled([
|
|
188
|
-
Promise.resolve().then(() => stream.cancel('stream failed')),
|
|
189
|
-
Promise.resolve().then(() => iterator.return?.()),
|
|
190
|
-
]);
|
|
191
|
-
context.active.settle();
|
|
192
|
-
}
|
|
193
|
-
},
|
|
194
|
-
async cancel(reason) {
|
|
195
|
-
const message = typeof reason === 'string' ? reason : 'response consumer cancelled';
|
|
196
|
-
context.active.cancel(message);
|
|
197
|
-
await stop(message);
|
|
198
|
-
},
|
|
199
|
-
});
|
|
200
|
-
context.active.onCancel(stop);
|
|
201
|
-
return new Response(body, {
|
|
202
|
-
status: 200,
|
|
203
|
-
headers: {
|
|
204
|
-
...context.cors([protocol.http.STREAM_FRAMING_FIELD]),
|
|
205
|
-
'cache-control': 'no-store',
|
|
206
|
-
'content-type': context.codec.contentType,
|
|
207
|
-
vary: mergeVary(context.cors(), 'accept'),
|
|
208
|
-
[protocol.http.STREAM_FRAMING_FIELD]: protocol.http.LENGTH_PREFIX_V1,
|
|
209
|
-
},
|
|
210
|
-
});
|
|
211
|
-
}
|
|
212
|
-
function bindingHeaders(input, negotiated) {
|
|
213
|
-
const headers = new Headers(input);
|
|
214
|
-
headers.set('cache-control', 'no-store');
|
|
215
|
-
if (negotiated)
|
|
216
|
-
appendVary(headers, 'accept');
|
|
217
|
-
return headers;
|
|
218
|
-
}
|
|
219
|
-
function errorEnvelopeResponse(codec, response, cors, status, negotiated, maximumResponseBytes) {
|
|
220
|
-
try {
|
|
221
|
-
return envelopeResponse(codec, response, cors, status, negotiated, maximumResponseBytes);
|
|
222
|
-
}
|
|
223
|
-
catch (error) {
|
|
224
|
-
if (!(error instanceof ResponseBodyTooLargeError))
|
|
225
|
-
throw error;
|
|
226
|
-
const fallback = {
|
|
227
|
-
requestId: response.requestId,
|
|
228
|
-
invocation: response.invocation,
|
|
229
|
-
error: {
|
|
230
|
-
code: errors.CODES.LIMIT_EXCEEDED,
|
|
231
|
-
message: 'Response body exceeds the configured limit.',
|
|
232
|
-
},
|
|
233
|
-
};
|
|
234
|
-
try {
|
|
235
|
-
return envelopeResponse(codec, fallback, cors, errors.httpStatusOf(fallback.error), negotiated, maximumResponseBytes);
|
|
236
|
-
}
|
|
237
|
-
catch (fallbackError) {
|
|
238
|
-
if (!(fallbackError instanceof ResponseBodyTooLargeError))
|
|
239
|
-
throw fallbackError;
|
|
240
|
-
return new Response(null, {
|
|
241
|
-
status: 500,
|
|
242
|
-
headers: bindingHeaders(cors, negotiated),
|
|
243
|
-
});
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
function encodeBoundedStreamFrame(codec, frame, maximumResponseBytes) {
|
|
248
|
-
const encoded = protocol.http.encodeStreamFrame(codec, frame);
|
|
249
|
-
if (encoded.byteLength - 4 > maximumResponseBytes) {
|
|
250
|
-
throw new ResponseBodyTooLargeError(maximumResponseBytes);
|
|
251
|
-
}
|
|
252
|
-
return encoded;
|
|
253
|
-
}
|
|
254
|
-
function requireResponseBound(input, maximumResponseBytes) {
|
|
255
|
-
if (maximumResponseBytes === undefined)
|
|
256
|
-
return;
|
|
257
|
-
const bytes = typeof input === 'string' ? new TextEncoder().encode(input).byteLength : input.byteLength;
|
|
258
|
-
if (bytes > maximumResponseBytes)
|
|
259
|
-
throw new ResponseBodyTooLargeError(maximumResponseBytes);
|
|
40
|
+
return settled(context.active, envelopeResponse(context.codec, envelope, context.cors(), 200, true, context.maximumResponseBytes));
|
|
260
41
|
}
|
|
261
42
|
function settled(operation, response) {
|
|
262
43
|
operation.settle();
|
|
263
44
|
return response;
|
|
264
45
|
}
|
|
265
|
-
function appendVary(headers, value) {
|
|
266
|
-
headers.set('vary', mergeVary(Object.fromEntries(headers), value));
|
|
267
|
-
}
|
|
268
|
-
function mergeVary(headers, value) {
|
|
269
|
-
const names = new Set((headers.vary ?? '')
|
|
270
|
-
.split(',')
|
|
271
|
-
.map((name) => name.trim().toLowerCase())
|
|
272
|
-
.filter(Boolean));
|
|
273
|
-
names.add(value.toLowerCase());
|
|
274
|
-
return [...names].join(', ');
|
|
275
|
-
}
|
|
276
|
-
function cancellationFrame(context) {
|
|
277
|
-
return {
|
|
278
|
-
kind: 'stream.error',
|
|
279
|
-
requestId: context.requestId,
|
|
280
|
-
error: interruptedStreamError(context.active.timedOut),
|
|
281
|
-
};
|
|
282
|
-
}
|
|
283
|
-
function toBody(input) {
|
|
284
|
-
if (typeof input === 'string')
|
|
285
|
-
return input;
|
|
286
|
-
const copy = new Uint8Array(input);
|
|
287
|
-
return copy.buffer;
|
|
288
|
-
}
|
|
289
|
-
//# sourceMappingURL=render.js.map
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Codec } from '@astrale-os/kernel-protocol/codecs';
|
|
2
|
+
import type * as protocol from '@astrale-os/kernel-protocol/invocation';
|
|
3
|
+
/** Encode a bounded envelope with its binding content type and cache policy. */
|
|
4
|
+
export declare function envelopeResponse(codec: Codec, input: unknown, cors: Readonly<Record<string, string>>, status?: number, negotiated?: boolean, maximumResponseBytes?: number): Response;
|
|
5
|
+
/** Bound an error, falling back to a correlated limit refusal or an empty response. */
|
|
6
|
+
export declare function errorEnvelopeResponse(codec: Codec, response: protocol.ErrorResponse, cors: Readonly<Record<string, string>>, status: number, negotiated: boolean, maximumResponseBytes: number | undefined): Response;
|
|
7
|
+
/** Enforce the configured byte budget before a buffered response is handed off. */
|
|
8
|
+
export declare function requireResponseBound(input: string | Uint8Array, maximumResponseBytes: number | undefined): void;
|
|
9
|
+
/** Retain existing Vary fields while declaring another response selector. */
|
|
10
|
+
export declare function appendVary(headers: Headers, value: string): void;
|
|
11
|
+
/** Merge one case-insensitive selector into the response Vary field. */
|
|
12
|
+
export declare function mergeVary(headers: Readonly<Record<string, string>>, value: string): string;
|
|
13
|
+
/** Detach encoded bytes for Fetch while retaining encoded text as text. */
|
|
14
|
+
export declare function toBody(input: string | Uint8Array): BodyInit;
|
|
@@ -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 {
|
|
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
|
package/dist/transport/index.js
CHANGED
|
@@ -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 {
|
|
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
|
+
}
|
package/dist/transport/router.js
CHANGED
|
@@ -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
|
package/dist/transport/types.js
CHANGED