@bleedingdev/modern-js-runtime-extensions 3.9.0-ultramodern.2 → 3.9.0-ultramodern.21
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/cjs/buildIdentity.js +73 -0
- package/dist/cjs/contextExtensions.js +74 -0
- package/dist/cjs/headRuntime.js +91 -0
- package/dist/cjs/helmetContext.js +54 -0
- package/dist/cjs/index.js +18 -4
- package/dist/cjs/localisedLoaderIdentity.js +51 -0
- package/dist/cjs/localisedUrls/config.js +49 -0
- package/dist/cjs/localisedUrls/index.js +95 -0
- package/dist/cjs/localisedUrls/normalise.js +87 -0
- package/dist/cjs/localisedUrls/pathname.js +68 -0
- package/dist/cjs/localisedUrls/patterns.js +214 -0
- package/dist/cjs/localisedUrls/redirect.js +100 -0
- package/dist/cjs/localisedUrls/resolve.js +78 -0
- package/dist/cjs/localisedUrls/routeIdentity.js +92 -0
- package/dist/cjs/localisedUrls/routes.js +217 -0
- package/dist/cjs/localisedUrls/types.js +18 -0
- package/dist/cjs/prefetchPolicy.js +52 -0
- package/dist/cjs/rendererHead.js +18 -5
- package/dist/cjs/request-policy/browser.js +139 -0
- package/dist/cjs/request-policy/client.js +234 -0
- package/dist/cjs/request-policy/node.js +149 -0
- package/dist/cjs/request-policy/policyCore.js +266 -0
- package/dist/cjs/request-policy/requestContext.js +137 -0
- package/dist/cjs/request-policy/traceparent.js +56 -0
- package/dist/cjs/request-policy/transport.js +234 -0
- package/dist/cjs/request-policy/types.js +57 -0
- package/dist/cjs/routeHydration.js +127 -0
- package/dist/cjs/routerPrefetchPolicy.js +153 -0
- package/dist/cjs/routerProvider.js +105 -0
- package/dist/cjs/routerState.js +175 -0
- package/dist/cjs/routerStatePlugin.js +113 -0
- package/dist/cjs/routerStateTypes.js +18 -0
- package/dist/cjs/rsc-disabled/rscDisabledClientBrowserRuntime.js +69 -0
- package/dist/cjs/rsc-disabled/rscDisabledClientEdgeRuntime.js +61 -0
- package/dist/cjs/rsc-disabled/rscDisabledClientNodeRuntime.js +65 -0
- package/dist/cjs/rsc-disabled/rscDisabledRuntimeError.js +42 -0
- package/dist/cjs/rsc-disabled/rscDisabledServerEdgeRuntime.js +93 -0
- package/dist/cjs/rsc-disabled/rscDisabledServerNodeRuntime.js +101 -0
- package/dist/cjs/runtimeContextProjection.js +112 -0
- package/dist/cjs/server-config/bffRuntime.js +18 -0
- package/dist/cjs/server-config/index.js +18 -0
- package/dist/cjs/server-config/serverTelemetry.js +18 -0
- package/dist/cjs/shellStream.js +34 -2
- package/dist/cjs/workspaceEvents.js +159 -0
- package/dist/esm/buildIdentity.mjs +35 -0
- package/dist/esm/contextExtensions.mjs +33 -0
- package/dist/esm/headRuntime.mjs +43 -0
- package/dist/esm/helmetContext.mjs +13 -0
- package/dist/esm/index.mjs +2 -0
- package/dist/esm/localisedLoaderIdentity.mjs +13 -0
- package/dist/esm/localisedUrls/config.mjs +11 -0
- package/dist/esm/localisedUrls/index.mjs +8 -0
- package/dist/esm/localisedUrls/normalise.mjs +37 -0
- package/dist/esm/localisedUrls/pathname.mjs +24 -0
- package/dist/esm/localisedUrls/patterns.mjs +152 -0
- package/dist/esm/localisedUrls/redirect.mjs +53 -0
- package/dist/esm/localisedUrls/resolve.mjs +37 -0
- package/dist/esm/localisedUrls/routeIdentity.mjs +54 -0
- package/dist/esm/localisedUrls/routes.mjs +176 -0
- package/dist/esm/localisedUrls/types.mjs +0 -0
- package/dist/esm/prefetchPolicy.mjs +11 -0
- package/dist/esm/rendererHead.mjs +14 -5
- package/dist/esm/request-policy/browser.mjs +11 -0
- package/dist/esm/request-policy/client.mjs +195 -0
- package/dist/esm/request-policy/policyCore.mjs +171 -0
- package/dist/esm/request-policy/requestContext.mjs +75 -0
- package/dist/esm/request-policy/traceparent.mjs +18 -0
- package/dist/esm/request-policy/transport.mjs +196 -0
- package/dist/esm/request-policy/types.mjs +10 -0
- package/dist/esm/routeHydration.mjs +77 -0
- package/dist/esm/routerPrefetchPolicy.mjs +115 -0
- package/dist/esm/routerProvider.mjs +58 -0
- package/dist/esm/routerState.mjs +113 -0
- package/dist/esm/routerStatePlugin.mjs +75 -0
- package/dist/esm/routerStateTypes.mjs +0 -0
- package/dist/esm/rsc-disabled/rscDisabledClientBrowserRuntime.mjs +10 -0
- package/dist/esm/rsc-disabled/rscDisabledClientEdgeRuntime.mjs +8 -0
- package/dist/esm/rsc-disabled/rscDisabledClientNodeRuntime.mjs +9 -0
- package/dist/esm/rsc-disabled/rscDisabledRuntimeError.mjs +4 -0
- package/dist/esm/rsc-disabled/rscDisabledServerEdgeRuntime.mjs +16 -0
- package/dist/esm/rsc-disabled/rscDisabledServerNodeRuntime.mjs +18 -0
- package/dist/esm/runtimeContextProjection.mjs +74 -0
- package/dist/esm/server-config/bffRuntime.mjs +0 -0
- package/dist/esm/server-config/index.mjs +0 -0
- package/dist/esm/server-config/serverTelemetry.mjs +0 -0
- package/dist/esm/shellStream.mjs +34 -2
- package/dist/esm/workspaceEvents.mjs +66 -0
- package/dist/esm-node/buildIdentity.mjs +36 -0
- package/dist/esm-node/contextExtensions.mjs +34 -0
- package/dist/esm-node/headRuntime.mjs +44 -0
- package/dist/esm-node/helmetContext.mjs +14 -0
- package/dist/esm-node/index.mjs +2 -0
- package/dist/esm-node/localisedLoaderIdentity.mjs +14 -0
- package/dist/esm-node/localisedUrls/config.mjs +12 -0
- package/dist/esm-node/localisedUrls/index.mjs +9 -0
- package/dist/esm-node/localisedUrls/normalise.mjs +38 -0
- package/dist/esm-node/localisedUrls/pathname.mjs +25 -0
- package/dist/esm-node/localisedUrls/patterns.mjs +153 -0
- package/dist/esm-node/localisedUrls/redirect.mjs +54 -0
- package/dist/esm-node/localisedUrls/resolve.mjs +38 -0
- package/dist/esm-node/localisedUrls/routeIdentity.mjs +55 -0
- package/dist/esm-node/localisedUrls/routes.mjs +177 -0
- package/dist/esm-node/localisedUrls/types.mjs +1 -0
- package/dist/esm-node/prefetchPolicy.mjs +12 -0
- package/dist/esm-node/rendererHead.mjs +14 -5
- package/dist/esm-node/request-policy/browser.mjs +12 -0
- package/dist/esm-node/request-policy/client.mjs +196 -0
- package/dist/esm-node/request-policy/node.mjs +22 -0
- package/dist/esm-node/request-policy/policyCore.mjs +172 -0
- package/dist/esm-node/request-policy/requestContext.mjs +76 -0
- package/dist/esm-node/request-policy/traceparent.mjs +19 -0
- package/dist/esm-node/request-policy/transport.mjs +197 -0
- package/dist/esm-node/request-policy/types.mjs +11 -0
- package/dist/esm-node/routeHydration.mjs +78 -0
- package/dist/esm-node/routerPrefetchPolicy.mjs +116 -0
- package/dist/esm-node/routerProvider.mjs +59 -0
- package/dist/esm-node/routerState.mjs +114 -0
- package/dist/esm-node/routerStatePlugin.mjs +76 -0
- package/dist/esm-node/routerStateTypes.mjs +1 -0
- package/dist/esm-node/rsc-disabled/rscDisabledClientBrowserRuntime.mjs +11 -0
- package/dist/esm-node/rsc-disabled/rscDisabledClientEdgeRuntime.mjs +9 -0
- package/dist/esm-node/rsc-disabled/rscDisabledClientNodeRuntime.mjs +10 -0
- package/dist/esm-node/rsc-disabled/rscDisabledRuntimeError.mjs +5 -0
- package/dist/esm-node/rsc-disabled/rscDisabledServerEdgeRuntime.mjs +17 -0
- package/dist/esm-node/rsc-disabled/rscDisabledServerNodeRuntime.mjs +19 -0
- package/dist/esm-node/runtimeContextProjection.mjs +75 -0
- package/dist/esm-node/server-config/bffRuntime.mjs +1 -0
- package/dist/esm-node/server-config/index.mjs +1 -0
- package/dist/esm-node/server-config/serverTelemetry.mjs +1 -0
- package/dist/esm-node/shellStream.mjs +34 -2
- package/dist/esm-node/workspaceEvents.mjs +67 -0
- package/dist/types/buildIdentity.d.ts +37 -0
- package/dist/types/contextExtensions.d.ts +34 -0
- package/dist/types/headRuntime.d.ts +12 -0
- package/dist/types/helmetCompat.d.ts +1 -1
- package/dist/types/helmetContext.d.ts +10 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/localisedLoaderIdentity.d.ts +10 -0
- package/dist/types/localisedUrls/config.d.ts +9 -0
- package/dist/types/localisedUrls/index.d.ts +10 -0
- package/dist/types/localisedUrls/normalise.d.ts +10 -0
- package/dist/types/localisedUrls/pathname.d.ts +4 -0
- package/dist/types/localisedUrls/patterns.d.ts +11 -0
- package/dist/types/localisedUrls/redirect.d.ts +19 -0
- package/dist/types/localisedUrls/resolve.d.ts +7 -0
- package/dist/types/localisedUrls/routeIdentity.d.ts +22 -0
- package/dist/types/localisedUrls/routes.d.ts +3 -0
- package/dist/types/localisedUrls/types.d.ts +14 -0
- package/dist/types/prefetchPolicy.d.ts +4 -0
- package/dist/types/rendererHead.d.ts +5 -3
- package/dist/types/request-policy/browser.d.ts +10 -0
- package/dist/types/request-policy/client.d.ts +14 -0
- package/dist/types/request-policy/node.d.ts +10 -0
- package/dist/types/request-policy/policyCore.d.ts +107 -0
- package/dist/types/request-policy/requestContext.d.ts +22 -0
- package/dist/types/request-policy/traceparent.d.ts +10 -0
- package/dist/types/request-policy/transport.d.ts +12 -0
- package/dist/types/request-policy/types.d.ts +144 -0
- package/dist/types/routeHydration.d.ts +24 -0
- package/dist/types/routerPrefetchPolicy.d.ts +28 -0
- package/dist/types/routerProvider.d.ts +55 -0
- package/dist/types/routerState.d.ts +17 -0
- package/dist/types/routerStatePlugin.d.ts +19 -0
- package/dist/types/routerStateTypes.d.ts +70 -0
- package/dist/types/rsc-disabled/rscDisabledClientBrowserRuntime.d.ts +9 -0
- package/dist/types/rsc-disabled/rscDisabledClientEdgeRuntime.d.ts +7 -0
- package/dist/types/rsc-disabled/rscDisabledClientNodeRuntime.d.ts +8 -0
- package/dist/types/rsc-disabled/rscDisabledRuntimeError.d.ts +1 -0
- package/dist/types/rsc-disabled/rscDisabledServerEdgeRuntime.d.ts +15 -0
- package/dist/types/rsc-disabled/rscDisabledServerNodeRuntime.d.ts +17 -0
- package/dist/types/runtimeContextProjection.d.ts +30 -0
- package/dist/types/server-config/bffRuntime.d.ts +122 -0
- package/dist/types/server-config/index.d.ts +2 -0
- package/dist/types/server-config/serverTelemetry.d.ts +322 -0
- package/dist/types/workspaceEvents.d.ts +62 -0
- package/package.json +240 -15
- package/rslib.config.mts +17 -2
- package/rstest.config.mts +33 -2
- package/src/buildIdentity.ts +61 -0
- package/src/contextExtensions.ts +81 -0
- package/src/headRuntime.tsx +77 -0
- package/src/helmetCompat.ts +1 -1
- package/src/helmetContext.ts +31 -0
- package/src/index.ts +2 -0
- package/src/localisedLoaderIdentity.ts +30 -0
- package/src/localisedUrls/config.ts +18 -0
- package/src/localisedUrls/index.ts +25 -0
- package/src/localisedUrls/normalise.ts +62 -0
- package/src/localisedUrls/pathname.ts +60 -0
- package/src/localisedUrls/patterns.ts +283 -0
- package/src/localisedUrls/redirect.ts +107 -0
- package/src/localisedUrls/resolve.ts +106 -0
- package/src/localisedUrls/routeIdentity.ts +83 -0
- package/src/localisedUrls/routes.ts +451 -0
- package/src/localisedUrls/types.ts +18 -0
- package/src/prefetchPolicy.ts +33 -0
- package/src/rendererHead.ts +25 -8
- package/src/request-policy/browser.ts +22 -0
- package/src/request-policy/client.ts +404 -0
- package/src/request-policy/node.ts +41 -0
- package/src/request-policy/policyCore.ts +424 -0
- package/src/request-policy/requestContext.ts +149 -0
- package/src/request-policy/traceparent.ts +43 -0
- package/src/request-policy/transport.ts +349 -0
- package/src/request-policy/types.ts +229 -0
- package/src/routeHydration.ts +208 -0
- package/src/routerPrefetchPolicy.ts +195 -0
- package/src/routerProvider.ts +160 -0
- package/src/routerState.ts +220 -0
- package/src/routerStatePlugin.ts +125 -0
- package/src/routerStateTypes.ts +76 -0
- package/src/rsc-disabled/rscDisabledClientBrowserRuntime.ts +10 -0
- package/src/rsc-disabled/rscDisabledClientEdgeRuntime.ts +8 -0
- package/src/rsc-disabled/rscDisabledClientNodeRuntime.ts +9 -0
- package/src/rsc-disabled/rscDisabledRuntimeError.ts +3 -0
- package/src/rsc-disabled/rscDisabledServerEdgeRuntime.ts +16 -0
- package/src/rsc-disabled/rscDisabledServerNodeRuntime.ts +18 -0
- package/src/runtimeContextProjection.ts +105 -0
- package/src/server-config/bffRuntime.ts +136 -0
- package/src/server-config/index.ts +2 -0
- package/src/server-config/serverTelemetry.ts +337 -0
- package/src/shellStream.ts +55 -25
- package/src/workspaceEvents.ts +324 -0
- package/tests/buildIdentity.test.ts +51 -0
- package/tests/contextExtensions.test.ts +27 -0
- package/tests/headRuntime.test.tsx +229 -0
- package/tests/localisedUrls.test.ts +560 -0
- package/tests/rendererHead.test.ts +52 -121
- package/tests/request-policy/browser-policy.test.ts +108 -0
- package/tests/request-policy/client-isolation.test.ts +109 -0
- package/tests/request-policy/node-policy.test.ts +447 -0
- package/tests/request-policy/policyCore.test.ts +129 -0
- package/tests/request-policy/requestContext.test.ts +66 -0
- package/tests/request-policy/requestFactory.outbound-contract.test.ts +290 -0
- package/tests/request-policy/traceparent.test.ts +52 -0
- package/tests/request-policy/transport-retry.test.ts +367 -0
- package/tests/routeHydration.test.ts +180 -0
- package/tests/routerPrefetchPolicy.test.ts +102 -0
- package/tests/routerProvider.test.ts +29 -0
- package/tests/routerState.test.ts +77 -0
- package/tests/routerStatePlugin.test.ts +63 -0
- package/tests/runtimeContextProjection.test.ts +83 -0
- package/tests/safeFailure.test.ts +10 -28
- package/tests/shellStream.test.ts +39 -2
- package/tests/workspaceEvents.test.ts +221 -0
- package/dist/cjs/rscHtmlStream.js +0 -128
- package/dist/esm/rscHtmlStream.mjs +0 -86
- package/dist/esm-node/rscHtmlStream.mjs +0 -87
- package/dist/types/rscHtmlStream.d.ts +0 -4
- package/src/rscHtmlStream.ts +0 -142
- package/tests/rscHtmlStream.test.ts +0 -153
|
@@ -5,14 +5,10 @@ import {
|
|
|
5
5
|
collectHeadRecord,
|
|
6
6
|
completeHeadRender,
|
|
7
7
|
createHeadChunkProcessor,
|
|
8
|
-
|
|
8
|
+
LATE_HEAD_MESSAGE,
|
|
9
9
|
publishHeadRender,
|
|
10
10
|
} from '../src';
|
|
11
|
-
import {
|
|
12
|
-
createNodeHeadMarkerStripper,
|
|
13
|
-
createOnceErrorReporter,
|
|
14
|
-
pipeNodeHeadStream,
|
|
15
|
-
} from '../src/node';
|
|
11
|
+
import { createNodeHeadMarkerStripper, pipeNodeHeadStream } from '../src/node';
|
|
16
12
|
|
|
17
13
|
const marker = (props: Record<string, string>) =>
|
|
18
14
|
`<template data-modern-helmet="${props['data-modern-helmet']}"></template>`;
|
|
@@ -21,7 +17,7 @@ describe('renderer head transactions', () => {
|
|
|
21
17
|
it('commits only markers observed in completed output', () => {
|
|
22
18
|
const context = {};
|
|
23
19
|
let published: string[] = [];
|
|
24
|
-
beginHeadRender(context);
|
|
20
|
+
beginHeadRender(context, () => {});
|
|
25
21
|
const committed = collectHeadRecord(
|
|
26
22
|
context,
|
|
27
23
|
() => 'committed',
|
|
@@ -41,28 +37,59 @@ describe('renderer head transactions', () => {
|
|
|
41
37
|
expect(published).toEqual(['committed']);
|
|
42
38
|
});
|
|
43
39
|
|
|
44
|
-
it('
|
|
40
|
+
it('reports head records whose markers commit after the seal', () => {
|
|
45
41
|
const context = {};
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
42
|
+
const reports: string[] = [];
|
|
43
|
+
let published: string[] = [];
|
|
44
|
+
const publish = (records: string[]) => {
|
|
45
|
+
published = records;
|
|
46
|
+
};
|
|
47
|
+
beginHeadRender(context, message => reports.push(message));
|
|
48
|
+
const shell = collectHeadRecord(context, () => 'shell', publish)!;
|
|
49
|
+
// A boundary rendered before the seal but flushed after it.
|
|
50
|
+
const flushedLate = collectHeadRecord(context, () => 'flushed', publish)!;
|
|
51
|
+
const processor = createHeadChunkProcessor(context);
|
|
52
|
+
expect(processor.push(`a${marker(shell)}`)).toBe('a');
|
|
53
|
+
publishHeadRender(context);
|
|
54
|
+
// A boundary rendered after the seal.
|
|
55
|
+
const renderedLate = collectHeadRecord(context, () => 'rendered', publish)!;
|
|
56
|
+
// A retry that renders a Helmet and then suspends again never commits.
|
|
57
|
+
collectHeadRecord(context, () => 'discarded', publish);
|
|
58
|
+
expect(reports).toEqual([]);
|
|
49
59
|
|
|
50
|
-
expect(
|
|
60
|
+
expect(processor.push(`b${marker(flushedLate)}${marker(shell)}`)).toBe('b');
|
|
61
|
+
expect(processor.finish(`c${marker(renderedLate)}`)).toBe('c');
|
|
62
|
+
|
|
63
|
+
expect(published).toEqual(['shell']);
|
|
64
|
+
expect(reports).toEqual([LATE_HEAD_MESSAGE]);
|
|
51
65
|
});
|
|
52
66
|
|
|
53
|
-
it('does not
|
|
67
|
+
it('does not report a late Helmet whose boundary never commits', () => {
|
|
54
68
|
const context = {};
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
69
|
+
const reports: string[] = [];
|
|
70
|
+
beginHeadRender(context, message => reports.push(message));
|
|
71
|
+
publishHeadRender(context);
|
|
72
|
+
collectHeadRecord(
|
|
73
|
+
context,
|
|
74
|
+
() => 'discarded',
|
|
75
|
+
() => {},
|
|
76
|
+
);
|
|
77
|
+
expect(completeHeadRender(context, 'done')).toBe('done');
|
|
78
|
+
expect(reports).toEqual([]);
|
|
79
|
+
});
|
|
58
80
|
|
|
59
|
-
|
|
60
|
-
|
|
81
|
+
it('preserves user templates that are not current transaction markers', () => {
|
|
82
|
+
const context = {};
|
|
83
|
+
beginHeadRender(context, () => {});
|
|
84
|
+
const userTemplate =
|
|
85
|
+
'<template data-modern-helmet="h00000000-0000-0000-0000-000000000000000000000000"></template>';
|
|
86
|
+
|
|
87
|
+
expect(completeHeadRender(context, userTemplate)).toBe(userTemplate);
|
|
61
88
|
});
|
|
62
89
|
|
|
63
90
|
it('strips markers split across chunks without corrupting unicode', () => {
|
|
64
91
|
const sampleContext = {};
|
|
65
|
-
beginHeadRender(sampleContext);
|
|
92
|
+
beginHeadRender(sampleContext, () => {});
|
|
66
93
|
const sampleProps = collectHeadRecord(
|
|
67
94
|
sampleContext,
|
|
68
95
|
() => 'head',
|
|
@@ -72,7 +99,7 @@ describe('renderer head transactions', () => {
|
|
|
72
99
|
|
|
73
100
|
for (let split = 1; split < sampleHtml.length; split += 1) {
|
|
74
101
|
const context = {};
|
|
75
|
-
beginHeadRender(context);
|
|
102
|
+
beginHeadRender(context, () => {});
|
|
76
103
|
const props = collectHeadRecord(
|
|
77
104
|
context,
|
|
78
105
|
() => 'head',
|
|
@@ -87,41 +114,6 @@ describe('renderer head transactions', () => {
|
|
|
87
114
|
}
|
|
88
115
|
});
|
|
89
116
|
|
|
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
117
|
it('clears the previous snapshot while rendering and restores it on abort', () => {
|
|
126
118
|
const context = {};
|
|
127
119
|
let published: string[] = [];
|
|
@@ -129,52 +121,22 @@ describe('renderer head transactions', () => {
|
|
|
129
121
|
published = records;
|
|
130
122
|
};
|
|
131
123
|
|
|
132
|
-
beginHeadRender(context);
|
|
124
|
+
beginHeadRender(context, () => {});
|
|
133
125
|
const previous = collectHeadRecord(context, () => 'previous', publish)!;
|
|
134
126
|
completeHeadRender(context, marker(previous));
|
|
135
127
|
expect(published).toEqual(['previous']);
|
|
136
128
|
|
|
137
|
-
beginHeadRender(context);
|
|
129
|
+
beginHeadRender(context, () => {});
|
|
138
130
|
expect(published).toEqual([]);
|
|
139
131
|
collectHeadRecord(context, () => 'provisional', publish);
|
|
140
132
|
abortHeadRender(context);
|
|
141
133
|
expect(published).toEqual(['previous']);
|
|
142
134
|
});
|
|
143
135
|
|
|
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
136
|
it('strips split markers from a Node stream', async () => {
|
|
175
137
|
const context = {};
|
|
176
138
|
let published: string[] = [];
|
|
177
|
-
beginHeadRender(context);
|
|
139
|
+
beginHeadRender(context, () => {});
|
|
178
140
|
const props = collectHeadRecord(
|
|
179
141
|
context,
|
|
180
142
|
() => 'node',
|
|
@@ -208,7 +170,7 @@ describe('renderer head transactions', () => {
|
|
|
208
170
|
const prefix = Buffer.from('x'.repeat(9 * 1024));
|
|
209
171
|
const unicodeTail = Buffer.from('č尾');
|
|
210
172
|
const input = Buffer.concat([prefix, unicodeTail]);
|
|
211
|
-
beginHeadRender(context);
|
|
173
|
+
beginHeadRender(context, () => {});
|
|
212
174
|
const stripper = createNodeHeadMarkerStripper(context, terminalMarker);
|
|
213
175
|
const output = new Promise<string>((resolve, reject) => {
|
|
214
176
|
let rendered = '';
|
|
@@ -233,7 +195,7 @@ describe('renderer head transactions', () => {
|
|
|
233
195
|
const terminalMarker = '<!-- shell stream end -->';
|
|
234
196
|
const input = Buffer.from(`shell${terminalMarker}č尾`);
|
|
235
197
|
const markerOffset = Buffer.byteLength('shell') + 7;
|
|
236
|
-
beginHeadRender(context);
|
|
198
|
+
beginHeadRender(context, () => {});
|
|
237
199
|
const stripper = createNodeHeadMarkerStripper(context, terminalMarker);
|
|
238
200
|
const output = new Promise<string>((resolve, reject) => {
|
|
239
201
|
let rendered = '';
|
|
@@ -265,35 +227,4 @@ describe('renderer head transactions', () => {
|
|
|
265
227
|
await expect(output).rejects.toThrow('source failed');
|
|
266
228
|
expect(onError).toHaveBeenCalledTimes(1);
|
|
267
229
|
});
|
|
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
230
|
});
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import {
|
|
2
|
+
configure,
|
|
3
|
+
createRequest,
|
|
4
|
+
} from '@modern-js/runtime-extensions/request-policy/client';
|
|
5
|
+
import nock from 'nock';
|
|
6
|
+
|
|
7
|
+
describe('configure', () => {
|
|
8
|
+
const path = '/api';
|
|
9
|
+
const method = 'GET';
|
|
10
|
+
const response = {
|
|
11
|
+
code: 200,
|
|
12
|
+
data: {
|
|
13
|
+
message: 'hello Modernjs',
|
|
14
|
+
},
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
test('should allow explicit cross-origin policy and attach envelope header', async () => {
|
|
18
|
+
const producer = 'producer-browser-policy';
|
|
19
|
+
const producerUrl = 'https://producer.internal';
|
|
20
|
+
const previousEnv = process.env.NODE_ENV;
|
|
21
|
+
process.env.NODE_ENV = 'production';
|
|
22
|
+
|
|
23
|
+
try {
|
|
24
|
+
nock(producerUrl).get(path).reply(200, response);
|
|
25
|
+
const customRequest = rs.fn(
|
|
26
|
+
(requestPath: RequestInfo, init?: RequestInit) =>
|
|
27
|
+
fetch(requestPath, init),
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
configure({
|
|
31
|
+
request: customRequest,
|
|
32
|
+
requestId: producer,
|
|
33
|
+
operationContract: {
|
|
34
|
+
enabled: false,
|
|
35
|
+
},
|
|
36
|
+
setDomain: () => producerUrl,
|
|
37
|
+
allowCrossOriginEnvelope: true,
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
const request = createRequest(
|
|
41
|
+
path,
|
|
42
|
+
method,
|
|
43
|
+
8080,
|
|
44
|
+
undefined,
|
|
45
|
+
undefined,
|
|
46
|
+
producer,
|
|
47
|
+
);
|
|
48
|
+
const res = await request();
|
|
49
|
+
|
|
50
|
+
const headers = customRequest.mock.calls[0][1].headers as Record<
|
|
51
|
+
string,
|
|
52
|
+
string
|
|
53
|
+
>;
|
|
54
|
+
const envelope = JSON.parse(headers['x-modernjs-bff-envelope']);
|
|
55
|
+
expect(envelope.requestId).toBe(producer);
|
|
56
|
+
expect(envelope.target).toBe('browser');
|
|
57
|
+
expect(res instanceof Response).toBe(true);
|
|
58
|
+
} finally {
|
|
59
|
+
process.env.NODE_ENV = previousEnv;
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
test('should not require process to exist in browser runtime', async () => {
|
|
64
|
+
const previousProcess = globalThis.process;
|
|
65
|
+
const customRequest = rs.fn(() =>
|
|
66
|
+
Promise.resolve(
|
|
67
|
+
new Response(
|
|
68
|
+
JSON.stringify({
|
|
69
|
+
code: 200,
|
|
70
|
+
data: {
|
|
71
|
+
message: 'ok',
|
|
72
|
+
},
|
|
73
|
+
}),
|
|
74
|
+
),
|
|
75
|
+
),
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
try {
|
|
79
|
+
Object.defineProperty(globalThis, 'process', {
|
|
80
|
+
configurable: true,
|
|
81
|
+
value: undefined,
|
|
82
|
+
});
|
|
83
|
+
configure({
|
|
84
|
+
request: customRequest,
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
const request = createRequest({
|
|
88
|
+
path,
|
|
89
|
+
method,
|
|
90
|
+
port: 8080,
|
|
91
|
+
});
|
|
92
|
+
const response = await request();
|
|
93
|
+
const data = await response.json();
|
|
94
|
+
|
|
95
|
+
expect(data).toStrictEqual({
|
|
96
|
+
code: 200,
|
|
97
|
+
data: {
|
|
98
|
+
message: 'ok',
|
|
99
|
+
},
|
|
100
|
+
});
|
|
101
|
+
} finally {
|
|
102
|
+
Object.defineProperty(globalThis, 'process', {
|
|
103
|
+
configurable: true,
|
|
104
|
+
value: previousProcess,
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
});
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { createClient as createNativeClient } from '@modern-js/create-request/server';
|
|
2
|
+
import * as server from '@modern-js/runtime-extensions/request-policy/server';
|
|
3
|
+
|
|
4
|
+
const options = {
|
|
5
|
+
path: '/api',
|
|
6
|
+
method: 'GET',
|
|
7
|
+
port: 8080,
|
|
8
|
+
requestId: 'shared-producer',
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
describe('isolated producer policy clients', () => {
|
|
12
|
+
test('does not share producer initialization or request configuration between instances', async () => {
|
|
13
|
+
const first = server.createClient();
|
|
14
|
+
const second = server.createClient();
|
|
15
|
+
const firstRequest = rs.fn(async () => new Response('first'));
|
|
16
|
+
const secondRequest = rs.fn(async () => new Response('second'));
|
|
17
|
+
first.configure({
|
|
18
|
+
requestId: options.requestId,
|
|
19
|
+
request: firstRequest,
|
|
20
|
+
setDomain: () => 'https://first.example',
|
|
21
|
+
operationContract: { enabled: false },
|
|
22
|
+
});
|
|
23
|
+
expect(() => second.createRequest(options)()).toThrow(
|
|
24
|
+
server.ProducerClientNotInitializedError,
|
|
25
|
+
);
|
|
26
|
+
second.configure({
|
|
27
|
+
requestId: options.requestId,
|
|
28
|
+
request: secondRequest,
|
|
29
|
+
setDomain: () => 'https://second.example',
|
|
30
|
+
operationContract: { enabled: false },
|
|
31
|
+
});
|
|
32
|
+
expect(await (await first.createRequest(options)()).text()).toBe('first');
|
|
33
|
+
expect(await (await second.createRequest(options)()).text()).toBe('second');
|
|
34
|
+
expect(firstRequest).toHaveBeenCalledWith(
|
|
35
|
+
'https://first.example/api',
|
|
36
|
+
expect.any(Object),
|
|
37
|
+
);
|
|
38
|
+
expect(secondRequest).toHaveBeenCalledWith(
|
|
39
|
+
'https://second.example/api',
|
|
40
|
+
expect.any(Object),
|
|
41
|
+
);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
test('does not initialize producer policy by configuring a separate native client', () => {
|
|
45
|
+
createNativeClient().configure({
|
|
46
|
+
requestId: options.requestId,
|
|
47
|
+
request: rs.fn(),
|
|
48
|
+
});
|
|
49
|
+
const producer = server.createClient();
|
|
50
|
+
expect(() => producer.createRequest(options)()).toThrow(
|
|
51
|
+
server.ProducerClientNotInitializedError,
|
|
52
|
+
);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
test('retains secured behavior for an explicitly empty requestId', () => {
|
|
56
|
+
const client = server.createClient();
|
|
57
|
+
const request = rs.fn();
|
|
58
|
+
client.configure({
|
|
59
|
+
requestId: '',
|
|
60
|
+
request,
|
|
61
|
+
setDomain: () => 'https://producer.example',
|
|
62
|
+
});
|
|
63
|
+
expect(() => client.createRequest({ ...options, requestId: '' })()).toThrow(
|
|
64
|
+
server.OperationContractViolationError,
|
|
65
|
+
);
|
|
66
|
+
expect(request).not.toHaveBeenCalled();
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
test('calls setDomain once after interceptor and keeps native and policy state on rejection', async () => {
|
|
70
|
+
const client = server.createClient();
|
|
71
|
+
const order: string[] = [];
|
|
72
|
+
const request = rs.fn(async () => new Response('original'));
|
|
73
|
+
const setDomain = rs.fn(() => {
|
|
74
|
+
order.push('domain');
|
|
75
|
+
return 'https://original.example';
|
|
76
|
+
});
|
|
77
|
+
client.configure({
|
|
78
|
+
requestId: options.requestId,
|
|
79
|
+
interceptor: () => {
|
|
80
|
+
order.push('interceptor');
|
|
81
|
+
return request;
|
|
82
|
+
},
|
|
83
|
+
setDomain,
|
|
84
|
+
requireEnvelope: false,
|
|
85
|
+
operationContract: { enabled: false },
|
|
86
|
+
});
|
|
87
|
+
const replacement = rs.fn();
|
|
88
|
+
expect(() =>
|
|
89
|
+
client.configure({
|
|
90
|
+
requestId: options.requestId,
|
|
91
|
+
request: replacement,
|
|
92
|
+
setDomain: () => '',
|
|
93
|
+
}),
|
|
94
|
+
).toThrow(server.ProducerDomainNotConfiguredError);
|
|
95
|
+
const response = await client.createRequest(options)();
|
|
96
|
+
expect(await response.text()).toBe('original');
|
|
97
|
+
expect(order).toEqual(['interceptor', 'domain']);
|
|
98
|
+
expect(setDomain).toHaveBeenCalledTimes(1);
|
|
99
|
+
expect(request).toHaveBeenCalledWith(
|
|
100
|
+
'https://original.example/api',
|
|
101
|
+
expect.objectContaining({
|
|
102
|
+
headers: expect.not.objectContaining({
|
|
103
|
+
'x-modernjs-bff-envelope': expect.anything(),
|
|
104
|
+
}),
|
|
105
|
+
}),
|
|
106
|
+
);
|
|
107
|
+
expect(replacement).not.toHaveBeenCalled();
|
|
108
|
+
});
|
|
109
|
+
});
|