@bleedingdev/modern-js-runtime-extensions 3.8.3-ultramodern.2

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 (54) hide show
  1. package/LICENSE +21 -0
  2. package/dist/cjs/helmetCompat.js +419 -0
  3. package/dist/cjs/html.js +45 -0
  4. package/dist/cjs/index.js +83 -0
  5. package/dist/cjs/navigationWarmup.js +59 -0
  6. package/dist/cjs/node.js +143 -0
  7. package/dist/cjs/rendererHead.js +263 -0
  8. package/dist/cjs/rscHtmlStream.js +128 -0
  9. package/dist/cjs/safeFailure.js +125 -0
  10. package/dist/cjs/shellStream.js +76 -0
  11. package/dist/esm/helmetCompat.mjs +357 -0
  12. package/dist/esm/html.mjs +4 -0
  13. package/dist/esm/index.mjs +4 -0
  14. package/dist/esm/navigationWarmup.mjs +21 -0
  15. package/dist/esm/node.mjs +61 -0
  16. package/dist/esm/rendererHead.mjs +162 -0
  17. package/dist/esm/rscHtmlStream.mjs +86 -0
  18. package/dist/esm/safeFailure.mjs +78 -0
  19. package/dist/esm/shellStream.mjs +38 -0
  20. package/dist/esm-node/helmetCompat.mjs +358 -0
  21. package/dist/esm-node/html.mjs +5 -0
  22. package/dist/esm-node/index.mjs +5 -0
  23. package/dist/esm-node/navigationWarmup.mjs +22 -0
  24. package/dist/esm-node/node.mjs +62 -0
  25. package/dist/esm-node/rendererHead.mjs +163 -0
  26. package/dist/esm-node/rscHtmlStream.mjs +87 -0
  27. package/dist/esm-node/safeFailure.mjs +79 -0
  28. package/dist/esm-node/shellStream.mjs +39 -0
  29. package/dist/types/helmetCompat.d.ts +75 -0
  30. package/dist/types/html.d.ts +2 -0
  31. package/dist/types/index.d.ts +4 -0
  32. package/dist/types/navigationWarmup.d.ts +8 -0
  33. package/dist/types/node.d.ts +11 -0
  34. package/dist/types/rendererHead.d.ts +17 -0
  35. package/dist/types/rscHtmlStream.d.ts +4 -0
  36. package/dist/types/safeFailure.d.ts +17 -0
  37. package/dist/types/shellStream.d.ts +1 -0
  38. package/package.json +90 -0
  39. package/rslib.config.mts +4 -0
  40. package/rstest.config.mts +7 -0
  41. package/src/helmetCompat.ts +628 -0
  42. package/src/html.ts +11 -0
  43. package/src/index.ts +4 -0
  44. package/src/navigationWarmup.ts +39 -0
  45. package/src/node.ts +93 -0
  46. package/src/rendererHead.ts +236 -0
  47. package/src/rscHtmlStream.ts +142 -0
  48. package/src/safeFailure.ts +137 -0
  49. package/src/shellStream.ts +53 -0
  50. package/tests/rendererHead.test.ts +299 -0
  51. package/tests/rscHtmlStream.test.ts +153 -0
  52. package/tests/safeFailure.test.ts +154 -0
  53. package/tests/shellStream.test.ts +85 -0
  54. package/tsconfig.json +10 -0
@@ -0,0 +1,299 @@
1
+ import { PassThrough, Readable } from 'node:stream';
2
+ import {
3
+ abortHeadRender,
4
+ beginHeadRender,
5
+ collectHeadRecord,
6
+ completeHeadRender,
7
+ createHeadChunkProcessor,
8
+ createWebHeadMarkerStripper,
9
+ publishHeadRender,
10
+ } from '../src';
11
+ import {
12
+ createNodeHeadMarkerStripper,
13
+ createOnceErrorReporter,
14
+ pipeNodeHeadStream,
15
+ } from '../src/node';
16
+
17
+ const marker = (props: Record<string, string>) =>
18
+ `<template data-modern-helmet="${props['data-modern-helmet']}"></template>`;
19
+
20
+ describe('renderer head transactions', () => {
21
+ it('commits only markers observed in completed output', () => {
22
+ const context = {};
23
+ let published: string[] = [];
24
+ beginHeadRender(context);
25
+ const committed = collectHeadRecord(
26
+ context,
27
+ () => 'committed',
28
+ records => {
29
+ published = records;
30
+ },
31
+ )!;
32
+ collectHeadRecord(
33
+ context,
34
+ () => 'abandoned',
35
+ records => {
36
+ published = records;
37
+ },
38
+ );
39
+
40
+ expect(completeHeadRender(context, `a${marker(committed)}b`)).toBe('ab');
41
+ expect(published).toEqual(['committed']);
42
+ });
43
+
44
+ it('preserves user templates that are not current transaction markers', () => {
45
+ const context = {};
46
+ beginHeadRender(context);
47
+ const userTemplate =
48
+ '<template data-modern-helmet="h00000000-0000-0000-0000-000000000000000000000000"></template>';
49
+
50
+ expect(completeHeadRender(context, userTemplate)).toBe(userTemplate);
51
+ });
52
+
53
+ it('does not retain ordinary streaming content', () => {
54
+ const context = {};
55
+ beginHeadRender(context);
56
+ const processor = createHeadChunkProcessor(context);
57
+ const content = 'x'.repeat(128 * 1024);
58
+
59
+ expect(processor.push(content)).toBe(content);
60
+ expect(processor.finish()).toBe('');
61
+ });
62
+
63
+ it('strips markers split across chunks without corrupting unicode', () => {
64
+ const sampleContext = {};
65
+ beginHeadRender(sampleContext);
66
+ const sampleProps = collectHeadRecord(
67
+ sampleContext,
68
+ () => 'head',
69
+ () => {},
70
+ )!;
71
+ const sampleHtml = `č${marker(sampleProps)}尾`;
72
+
73
+ for (let split = 1; split < sampleHtml.length; split += 1) {
74
+ const context = {};
75
+ beginHeadRender(context);
76
+ const props = collectHeadRecord(
77
+ context,
78
+ () => 'head',
79
+ () => {},
80
+ )!;
81
+ const html = `č${marker(props)}尾`;
82
+ const processor = createHeadChunkProcessor(context);
83
+ expect(
84
+ processor.push(html.slice(0, split)) +
85
+ processor.finish(html.slice(split)),
86
+ ).toBe('č尾');
87
+ }
88
+ });
89
+
90
+ it('freezes the published shell and ignores late records', () => {
91
+ const context = {};
92
+ let published: string[] = [];
93
+ beginHeadRender(context);
94
+ const shell = collectHeadRecord(
95
+ context,
96
+ () => 'shell',
97
+ records => {
98
+ published = records;
99
+ },
100
+ )!;
101
+ const late = collectHeadRecord(
102
+ context,
103
+ () => 'late',
104
+ records => {
105
+ published = records;
106
+ },
107
+ )!;
108
+ const processor = createHeadChunkProcessor(context);
109
+ expect(processor.push(marker(shell))).toBe('');
110
+ publishHeadRender(context);
111
+
112
+ expect(
113
+ collectHeadRecord(
114
+ context,
115
+ () => 'late',
116
+ records => {
117
+ published = records;
118
+ },
119
+ ),
120
+ ).toBeNull();
121
+ expect(processor.finish(marker(late))).toBe('');
122
+ expect(published).toEqual(['shell']);
123
+ });
124
+
125
+ it('clears the previous snapshot while rendering and restores it on abort', () => {
126
+ const context = {};
127
+ let published: string[] = [];
128
+ const publish = (records: string[]) => {
129
+ published = records;
130
+ };
131
+
132
+ beginHeadRender(context);
133
+ const previous = collectHeadRecord(context, () => 'previous', publish)!;
134
+ completeHeadRender(context, marker(previous));
135
+ expect(published).toEqual(['previous']);
136
+
137
+ beginHeadRender(context);
138
+ expect(published).toEqual([]);
139
+ collectHeadRecord(context, () => 'provisional', publish);
140
+ abortHeadRender(context);
141
+ expect(published).toEqual(['previous']);
142
+ });
143
+
144
+ it('strips split markers from a web byte stream', async () => {
145
+ const context = {};
146
+ let published: string[] = [];
147
+ beginHeadRender(context);
148
+ const props = collectHeadRecord(
149
+ context,
150
+ () => 'web',
151
+ records => {
152
+ published = records;
153
+ },
154
+ )!;
155
+ const html = `č${marker(props)}尾`;
156
+ const encoder = new TextEncoder();
157
+ const encoded = encoder.encode(html);
158
+ const source = new ReadableStream<Uint8Array>({
159
+ start(controller) {
160
+ controller.enqueue(encoded.slice(0, 1));
161
+ controller.enqueue(encoded.slice(1, 17));
162
+ controller.enqueue(encoded.slice(17));
163
+ controller.close();
164
+ },
165
+ });
166
+
167
+ const output = await new Response(
168
+ source.pipeThrough(createWebHeadMarkerStripper(context)),
169
+ ).text();
170
+ expect(output).toBe('č尾');
171
+ expect(published).toEqual(['web']);
172
+ });
173
+
174
+ it('strips split markers from a Node stream', async () => {
175
+ const context = {};
176
+ let published: string[] = [];
177
+ beginHeadRender(context);
178
+ const props = collectHeadRecord(
179
+ context,
180
+ () => 'node',
181
+ records => {
182
+ published = records;
183
+ },
184
+ )!;
185
+ const html = `č${marker(props)}尾`;
186
+ const encoded = Buffer.from(html);
187
+ const stripper = createNodeHeadMarkerStripper(context);
188
+ const output = new Promise<string>((resolve, reject) => {
189
+ let rendered = '';
190
+ stripper.setEncoding('utf8');
191
+ stripper.on('data', chunk => {
192
+ rendered += chunk;
193
+ });
194
+ stripper.on('end', () => resolve(rendered));
195
+ stripper.on('error', reject);
196
+ });
197
+ stripper.write(encoded.subarray(0, 1));
198
+ stripper.write(encoded.subarray(1, 17));
199
+ stripper.end(encoded.subarray(17));
200
+
201
+ await expect(output).resolves.toBe('č尾');
202
+ expect(published).toEqual(['node']);
203
+ });
204
+
205
+ it('injects one missing terminal marker without truncating multichunk UTF-8', async () => {
206
+ const context = {};
207
+ const terminalMarker = '<!-- shell stream end -->';
208
+ const prefix = Buffer.from('x'.repeat(9 * 1024));
209
+ const unicodeTail = Buffer.from('č尾');
210
+ const input = Buffer.concat([prefix, unicodeTail]);
211
+ beginHeadRender(context);
212
+ const stripper = createNodeHeadMarkerStripper(context, terminalMarker);
213
+ const output = new Promise<string>((resolve, reject) => {
214
+ let rendered = '';
215
+ stripper.setEncoding('utf8');
216
+ stripper.on('data', chunk => {
217
+ rendered += chunk;
218
+ });
219
+ stripper.on('end', () => resolve(rendered));
220
+ stripper.on('error', reject);
221
+ });
222
+ stripper.write(input.subarray(0, prefix.length + 1));
223
+ stripper.write(input.subarray(prefix.length + 1, prefix.length + 3));
224
+ stripper.end(input.subarray(prefix.length + 3));
225
+
226
+ await expect(output).resolves.toBe(
227
+ `${input.toString('utf8')}${terminalMarker}`,
228
+ );
229
+ });
230
+
231
+ it('does not duplicate a split terminal marker or corrupt its tail', async () => {
232
+ const context = {};
233
+ const terminalMarker = '<!-- shell stream end -->';
234
+ const input = Buffer.from(`shell${terminalMarker}č尾`);
235
+ const markerOffset = Buffer.byteLength('shell') + 7;
236
+ beginHeadRender(context);
237
+ const stripper = createNodeHeadMarkerStripper(context, terminalMarker);
238
+ const output = new Promise<string>((resolve, reject) => {
239
+ let rendered = '';
240
+ stripper.setEncoding('utf8');
241
+ stripper.on('data', chunk => {
242
+ rendered += chunk;
243
+ });
244
+ stripper.on('end', () => resolve(rendered));
245
+ stripper.on('error', reject);
246
+ });
247
+ stripper.write(input.subarray(0, markerOffset));
248
+ stripper.write(input.subarray(markerOffset, input.length - 1));
249
+ stripper.end(input.subarray(input.length - 1));
250
+
251
+ await expect(output).resolves.toBe(input.toString('utf8'));
252
+ });
253
+
254
+ it('rejects the destination and reports a source error exactly once', async () => {
255
+ const source = new PassThrough();
256
+ const destination = new PassThrough();
257
+ const output = new Response(
258
+ Readable.toWeb(destination) as ReadableStream<Uint8Array>,
259
+ ).text();
260
+ const onError = rstest.fn();
261
+ pipeNodeHeadStream({ source, destination, context: {}, onError });
262
+
263
+ source.destroy(new Error('source failed'));
264
+
265
+ await expect(output).rejects.toThrow('source failed');
266
+ expect(onError).toHaveBeenCalledTimes(1);
267
+ });
268
+
269
+ it('rejects the destination and reports a stripper error exactly once', async () => {
270
+ const source = new PassThrough();
271
+ const destination = new PassThrough();
272
+ const output = new Response(
273
+ Readable.toWeb(destination) as ReadableStream<Uint8Array>,
274
+ ).text();
275
+ const onError = rstest.fn();
276
+ pipeNodeHeadStream({
277
+ source,
278
+ destination,
279
+ context: Object.freeze({}),
280
+ onError,
281
+ });
282
+
283
+ source.end('trigger frozen-context failure');
284
+
285
+ await expect(output).rejects.toThrow('object is not extensible');
286
+ expect(onError).toHaveBeenCalledTimes(1);
287
+ });
288
+
289
+ it('reports a shared render and stream failure only once', () => {
290
+ const onError = rstest.fn();
291
+ const reportError = createOnceErrorReporter(onError);
292
+ const failure = new Error('shared failure');
293
+
294
+ reportError(failure);
295
+ reportError(failure);
296
+
297
+ expect(onError).toHaveBeenCalledExactlyOnceWith(failure);
298
+ });
299
+ });
@@ -0,0 +1,153 @@
1
+ import {
2
+ injectRSCPayload,
3
+ RSC_HTML_CLOSING_TAIL_LIMIT,
4
+ } from '../src/rscHtmlStream';
5
+
6
+ const encoder = new TextEncoder();
7
+ const flight = '<script>(self.__FLIGHT_DATA||=[]).push("payload")</script>';
8
+
9
+ async function readStream(stream: ReadableStream<Uint8Array>) {
10
+ const reader = stream.getReader();
11
+ const decoder = new TextDecoder();
12
+ let value = '';
13
+ for (;;) {
14
+ const result = await reader.read();
15
+ if (result.done) {
16
+ return value + decoder.decode();
17
+ }
18
+ value += decoder.decode(result.value, { stream: true });
19
+ }
20
+ }
21
+
22
+ describe('injectRSCPayload', () => {
23
+ test('backpressures at the retained-tail limit and conserves the trailer', async () => {
24
+ let rscController!: ReadableStreamDefaultController<Uint8Array>;
25
+ const rscStream = new ReadableStream<Uint8Array>({
26
+ start(controller) {
27
+ rscController = controller;
28
+ },
29
+ });
30
+ const transform = injectRSCPayload(rscStream);
31
+ const output = readStream(transform.readable);
32
+ const writer = transform.writable.getWriter();
33
+
34
+ const retainedWhitespace = ' '.repeat(
35
+ RSC_HTML_CLOSING_TAIL_LIMIT - '</body>'.length,
36
+ );
37
+ await writer.write(encoder.encode(`<body>x</body>${retainedWhitespace}`));
38
+
39
+ let overflowSettled = false;
40
+ const overflow = writer.write(encoder.encode(' ')).then(() => {
41
+ overflowSettled = true;
42
+ });
43
+ await new Promise(resolve => setTimeout(resolve, 20));
44
+ expect(overflowSettled).toBe(false);
45
+
46
+ rscController.enqueue(encoder.encode('payload'));
47
+ rscController.close();
48
+ await overflow;
49
+ await writer.write(encoder.encode('</html>'));
50
+ await writer.close();
51
+
52
+ const spaces = `${retainedWhitespace} `;
53
+ expect(await output).toBe(`<body>x${flight}</body>${spaces}</html>`);
54
+ });
55
+
56
+ test('does not let flight overtake any split of an ordinary html tag', async () => {
57
+ const tag = '<span class="ordinary">';
58
+
59
+ for (let split = 1; split < tag.length; split++) {
60
+ const rscStream = new ReadableStream<Uint8Array>({
61
+ start(controller) {
62
+ controller.enqueue(encoder.encode('payload'));
63
+ controller.close();
64
+ },
65
+ });
66
+ const transform = injectRSCPayload(rscStream);
67
+ const output = readStream(transform.readable);
68
+ const writer = transform.writable.getWriter();
69
+
70
+ await writer.write(encoder.encode(`<body>x${tag.slice(0, split)}`));
71
+ await writer.write(
72
+ encoder.encode(`${tag.slice(split)}y</span></body></html>`),
73
+ );
74
+ await writer.close();
75
+
76
+ expect(await output, `split after ${tag.slice(0, split)}`).toBe(
77
+ `<body>x${tag}y</span>${flight}</body></html>`,
78
+ );
79
+ }
80
+ });
81
+
82
+ test('conserves multi-chunk html and orders every flight chunk before the trailer', async () => {
83
+ let rscController!: ReadableStreamDefaultController<Uint8Array>;
84
+ const rscStream = new ReadableStream<Uint8Array>({
85
+ start(controller) {
86
+ rscController = controller;
87
+ },
88
+ });
89
+ const transform = injectRSCPayload(rscStream);
90
+ const output = readStream(transform.readable);
91
+ const writer = transform.writable.getWriter();
92
+ const unicode = encoder.encode('–');
93
+
94
+ await writer.write(encoder.encode('<html><body><main>first'));
95
+ await writer.write(unicode.slice(0, 1));
96
+ await writer.write(unicode.slice(1));
97
+ await writer.write(encoder.encode('middle</main></bo'));
98
+ await writer.write(encoder.encode('dy></ht'));
99
+ await writer.write(encoder.encode('ml>'));
100
+
101
+ rscController.enqueue(encoder.encode('first'));
102
+ rscController.enqueue(encoder.encode('second'));
103
+ rscController.close();
104
+ await writer.close();
105
+
106
+ expect(await output).toBe(
107
+ '<html><body><main>first–middle</main>' +
108
+ '<script>(self.__FLIGHT_DATA||=[]).push("first")</script>' +
109
+ '<script>(self.__FLIGHT_DATA||=[]).push("second")</script>' +
110
+ '</body></html>',
111
+ );
112
+ });
113
+
114
+ test('does not truncate or inject inside an over-limit ordinary tag', async () => {
115
+ const attribute = 'x'.repeat(RSC_HTML_CLOSING_TAIL_LIMIT);
116
+ const partialTag = `<div data-value="${attribute}"`;
117
+ const rscStream = new ReadableStream<Uint8Array>({
118
+ start(controller) {
119
+ controller.enqueue(encoder.encode('payload'));
120
+ controller.close();
121
+ },
122
+ });
123
+ const transform = injectRSCPayload(rscStream);
124
+ const output = readStream(transform.readable);
125
+ const writer = transform.writable.getWriter();
126
+
127
+ await writer.write(encoder.encode(`<body>x${partialTag}`));
128
+ await writer.write(encoder.encode('>y</div></body></html>'));
129
+ await writer.close();
130
+
131
+ expect(await output).toBe(
132
+ `<body>x${flight}${partialTag}>y</div></body></html>`,
133
+ );
134
+ });
135
+
136
+ test('propagates flight errors without publishing a synthetic trailer', async () => {
137
+ let rscController!: ReadableStreamDefaultController<Uint8Array>;
138
+ const failure = new Error('flight failed');
139
+ const rscStream = new ReadableStream<Uint8Array>({
140
+ start(controller) {
141
+ rscController = controller;
142
+ },
143
+ });
144
+ const transform = injectRSCPayload(rscStream);
145
+ const output = readStream(transform.readable);
146
+ const writer = transform.writable.getWriter();
147
+
148
+ await writer.write(encoder.encode('<body>html</body></html>'));
149
+ rscController.error(failure);
150
+
151
+ await expect(Promise.all([writer.close(), output])).rejects.toBe(failure);
152
+ });
153
+ });
@@ -0,0 +1,154 @@
1
+ import {
2
+ createSafeFailureHttpResult,
3
+ createSafeFailureResponse,
4
+ createSafeJsonFailureResponse,
5
+ getSafeFailureStatus,
6
+ } from '../src/safeFailure';
7
+
8
+ const readBody = async (response: Response) =>
9
+ (await response.json()) as Record<string, unknown>;
10
+
11
+ describe('safe failure responses', () => {
12
+ it.each([
13
+ [404, 'REQUEST_FAILED', 'Request failed'],
14
+ [500, 'INTERNAL_SERVER_ERROR', 'Internal Server Error'],
15
+ [503, 'SERVICE_UNAVAILABLE', 'Service Unavailable'],
16
+ ])('redacts a %i failure through every response surface', async (status, code, message) => {
17
+ const error = Object.assign(new Error('database-password'), {
18
+ status,
19
+ code: 'SECRET_CODE',
20
+ cause: 'root-cause',
21
+ details: 'internal-details',
22
+ stack: 'hidden-stack',
23
+ });
24
+ const expectedBody = {
25
+ success: false,
26
+ error: { code, message, status },
27
+ };
28
+
29
+ expect(createSafeFailureHttpResult(error)).toMatchObject({
30
+ status,
31
+ body: expectedBody,
32
+ });
33
+ for (const createResponse of [
34
+ createSafeFailureResponse,
35
+ createSafeJsonFailureResponse,
36
+ ]) {
37
+ const response = createResponse(error);
38
+ expect(response.status).toBe(status);
39
+ expect(response.headers.get('content-type')).toBe(
40
+ 'application/json; charset=utf-8',
41
+ );
42
+ const body = await readBody(response);
43
+ expect(body).toEqual(expectedBody);
44
+ expect(JSON.stringify(body)).not.toMatch(
45
+ /database-password|SECRET_CODE|root-cause|internal-details|hidden-stack/u,
46
+ );
47
+ }
48
+
49
+ // Response construction must not destroy the raw error retained for
50
+ // internal structured diagnostics.
51
+ expect(error.cause).toBe('root-cause');
52
+ expect(error.details).toBe('internal-details');
53
+ });
54
+
55
+ it.each([
56
+ ['delay seconds text', ' 120 ', '120'],
57
+ ['leading-zero delay text', '000120', '120'],
58
+ ['delay seconds number', 2.1, '3'],
59
+ [
60
+ 'largest safe delay number',
61
+ Number.MAX_SAFE_INTEGER,
62
+ String(Number.MAX_SAFE_INTEGER),
63
+ ],
64
+ [
65
+ 'largest safe delay text',
66
+ String(Number.MAX_SAFE_INTEGER),
67
+ String(Number.MAX_SAFE_INTEGER),
68
+ ],
69
+ [
70
+ 'canonical HTTP-date text',
71
+ 'Sun, 30 Aug 2026 20:00:00 GMT',
72
+ 'Sun, 30 Aug 2026 20:00:00 GMT',
73
+ ],
74
+ [
75
+ 'valid Date object',
76
+ new Date(Date.UTC(2026, 7, 30, 20, 0, 0)),
77
+ 'Sun, 30 Aug 2026 20:00:00 GMT',
78
+ ],
79
+ ])('canonicalizes %s for Retry-After', (_, retryAfter, expected) => {
80
+ const result = createSafeFailureHttpResult({ status: 503, retryAfter });
81
+ expect(result.headers['Retry-After']).toBe(expected);
82
+ });
83
+
84
+ it('converts Retry-After milliseconds to canonical delay seconds', () => {
85
+ expect(
86
+ createSafeFailureHttpResult({ status: 503, retryAfterMs: 2500 }).headers[
87
+ 'Retry-After'
88
+ ],
89
+ ).toBe('3');
90
+ });
91
+
92
+ it.each([
93
+ ['a header injection payload', '120\r\nX-Injected: true'],
94
+ ['arbitrary text', 'after maintenance'],
95
+ ['an exponent string', '1e3'],
96
+ ['a decimal string', '2.1'],
97
+ ['a negative string', '-1'],
98
+ ['an unsafe integer string', '9007199254740992'],
99
+ ['an unsafe number', 1e21],
100
+ ['infinity', Number.POSITIVE_INFINITY],
101
+ ['a noncanonical date', 'Sunday, 30-Aug-26 20:00:00 GMT'],
102
+ ['an invalid date string', 'Wed, 99 Jun 2026 25:61:61 GMT'],
103
+ ['an invalid Date object', new Date(Number.NaN)],
104
+ ])('rejects %s as Retry-After', (_, retryAfter) => {
105
+ const result = createSafeFailureHttpResult({ status: 503, retryAfter });
106
+ expect(result.headers['Retry-After']).toBeUndefined();
107
+ expect(() =>
108
+ createSafeFailureResponse({ status: 503, retryAfter }),
109
+ ).not.toThrow();
110
+ });
111
+
112
+ it('never emits Retry-After for a non-503 response', () => {
113
+ expect(
114
+ createSafeFailureHttpResult({ status: 500, retryAfter: '120' }).headers[
115
+ 'Retry-After'
116
+ ],
117
+ ).toBeUndefined();
118
+ });
119
+
120
+ it('fails closed without throwing when error property access is hostile', () => {
121
+ const hostile = new Proxy(
122
+ {},
123
+ {
124
+ has() {
125
+ throw new Error('proxy trap secret');
126
+ },
127
+ get() {
128
+ throw new Error('getter secret');
129
+ },
130
+ },
131
+ );
132
+
133
+ expect(getSafeFailureStatus(hostile)).toBe(500);
134
+ expect(createSafeFailureHttpResult(hostile)).toEqual({
135
+ status: 500,
136
+ body: {
137
+ success: false,
138
+ error: {
139
+ code: 'INTERNAL_SERVER_ERROR',
140
+ message: 'Internal Server Error',
141
+ status: 500,
142
+ },
143
+ },
144
+ headers: {
145
+ 'content-type': 'application/json; charset=utf-8',
146
+ },
147
+ });
148
+ });
149
+
150
+ it('uses statusCode only when it is a valid failure status', () => {
151
+ expect(getSafeFailureStatus({ status: 200, statusCode: 503 })).toBe(503);
152
+ expect(getSafeFailureStatus({ status: 503.5, statusCode: 799 })).toBe(500);
153
+ });
154
+ });
@@ -0,0 +1,85 @@
1
+ import {
2
+ beginHeadRender,
3
+ collectHeadRecord,
4
+ completeHeadRender,
5
+ createConservingWebShellStream,
6
+ } from '../src';
7
+
8
+ const MARKER = '&lt;!--&lt;?- SHELL_STREAM_END ?&gt;--&gt;';
9
+ const encoder = new TextEncoder();
10
+ const headMarker = (props: Record<string, string>) =>
11
+ `<template data-modern-helmet="${props['data-modern-helmet']}"></template>`;
12
+
13
+ const streamFromChunks = (chunks: Uint8Array[]) =>
14
+ new ReadableStream<Uint8Array>({
15
+ start(controller) {
16
+ for (const chunk of chunks) {
17
+ controller.enqueue(chunk);
18
+ }
19
+ controller.close();
20
+ },
21
+ });
22
+
23
+ const splitAt = (value: Uint8Array, offsets: number[]) => {
24
+ const chunks: Uint8Array[] = [];
25
+ let cursor = 0;
26
+ for (const offset of offsets) {
27
+ chunks.push(value.slice(cursor, offset));
28
+ cursor = offset;
29
+ }
30
+ chunks.push(value.slice(cursor));
31
+ return chunks;
32
+ };
33
+
34
+ describe('conserving web shell stream', () => {
35
+ it('preserves a large multichunk shell and tail across UTF-8 splits', async () => {
36
+ const shell = `α${'s'.repeat(9 * 1024)}`;
37
+ const tail = `尾${'t'.repeat(9 * 1024)}🌐done`;
38
+ const html = `${shell}${MARKER}${tail}`;
39
+ const bytes = encoder.encode(html);
40
+ const markerStart = encoder.encode(shell).length;
41
+ const markerEnd = markerStart + encoder.encode(MARKER).length;
42
+ const chunks = splitAt(bytes, [
43
+ 1,
44
+ 8192,
45
+ markerStart + 7,
46
+ markerEnd - 3,
47
+ markerEnd + 1,
48
+ bytes.length - 2,
49
+ ]);
50
+
51
+ const output = await new Response(
52
+ createConservingWebShellStream(streamFromChunks(chunks), {}, MARKER),
53
+ ).text();
54
+
55
+ expect(output).toBe(html);
56
+ });
57
+
58
+ it('reports once and errors when the source closes without a marker', async () => {
59
+ const onMissingMarker = rstest.fn();
60
+ const context = {};
61
+ let published: string[] = [];
62
+ const publish = (records: string[]) => {
63
+ published = records;
64
+ };
65
+ beginHeadRender(context);
66
+ const previous = collectHeadRecord(context, () => 'previous', publish)!;
67
+ completeHeadRender(context, headMarker(previous));
68
+ beginHeadRender(context);
69
+ collectHeadRecord(context, () => 'incomplete', publish);
70
+ const bytes = encoder.encode(`α${'x'.repeat(9 * 1024)}尾`);
71
+ const stream = createConservingWebShellStream(
72
+ streamFromChunks(splitAt(bytes, [1, 8192, bytes.length - 1])),
73
+ context,
74
+ MARKER,
75
+ onMissingMarker,
76
+ );
77
+
78
+ await expect(new Response(stream).text()).rejects.toThrow(
79
+ 'React SSR stream ended before the shell marker',
80
+ );
81
+ expect(onMissingMarker).toHaveBeenCalledTimes(1);
82
+ expect(onMissingMarker).toHaveBeenCalledWith(expect.any(Error));
83
+ expect(published).toEqual(['previous']);
84
+ });
85
+ });
package/tsconfig.json ADDED
@@ -0,0 +1,10 @@
1
+ {
2
+ "extends": "@modern-js/tsconfig/base",
3
+ "compilerOptions": {
4
+ "declaration": false,
5
+ "isolatedModules": true,
6
+ "rootDir": "./src",
7
+ "types": ["node"]
8
+ },
9
+ "include": ["src"]
10
+ }