@bleedingdev/modern-js-runtime-extensions 3.9.0-ultramodern.1 → 3.9.0-ultramodern.10

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 (198) hide show
  1. package/dist/cjs/buildIdentity.js +73 -0
  2. package/dist/cjs/contextExtensions.js +74 -0
  3. package/dist/cjs/headRuntime.js +91 -0
  4. package/dist/cjs/helmetContext.js +54 -0
  5. package/dist/cjs/index.js +18 -4
  6. package/dist/cjs/localisedLoaderIdentity.js +51 -0
  7. package/dist/cjs/prefetchPolicy.js +52 -0
  8. package/dist/cjs/reactContext.js +45 -0
  9. package/dist/cjs/request-policy/browser.js +139 -0
  10. package/dist/cjs/request-policy/client.js +234 -0
  11. package/dist/cjs/request-policy/node.js +149 -0
  12. package/dist/cjs/request-policy/policyCore.js +266 -0
  13. package/dist/cjs/request-policy/requestContext.js +137 -0
  14. package/dist/cjs/request-policy/traceparent.js +56 -0
  15. package/dist/cjs/request-policy/transport.js +234 -0
  16. package/dist/cjs/request-policy/types.js +57 -0
  17. package/dist/cjs/routeHydration.js +127 -0
  18. package/dist/cjs/routerPrefetchPolicy.js +153 -0
  19. package/dist/cjs/routerProvider.js +105 -0
  20. package/dist/cjs/routerState.js +204 -0
  21. package/dist/cjs/routerStatePlugin.js +86 -0
  22. package/dist/cjs/routerStateTypes.js +18 -0
  23. package/dist/cjs/rsc-disabled/rscDisabledClientBrowserRuntime.js +69 -0
  24. package/dist/cjs/rsc-disabled/rscDisabledClientEdgeRuntime.js +61 -0
  25. package/dist/cjs/rsc-disabled/rscDisabledClientNodeRuntime.js +65 -0
  26. package/dist/cjs/rsc-disabled/rscDisabledRuntimeError.js +42 -0
  27. package/dist/cjs/rsc-disabled/rscDisabledServerEdgeRuntime.js +93 -0
  28. package/dist/cjs/rsc-disabled/rscDisabledServerNodeRuntime.js +101 -0
  29. package/dist/cjs/runtimeContextProjection.js +112 -0
  30. package/dist/cjs/server-config/bffRuntime.js +18 -0
  31. package/dist/cjs/server-config/index.js +18 -0
  32. package/dist/cjs/server-config/serverTelemetry.js +18 -0
  33. package/dist/cjs/shellStream.js +34 -2
  34. package/dist/cjs/workspaceEvents.js +159 -0
  35. package/dist/esm/buildIdentity.mjs +35 -0
  36. package/dist/esm/contextExtensions.mjs +33 -0
  37. package/dist/esm/headRuntime.mjs +43 -0
  38. package/dist/esm/helmetContext.mjs +13 -0
  39. package/dist/esm/index.mjs +2 -0
  40. package/dist/esm/localisedLoaderIdentity.mjs +13 -0
  41. package/dist/esm/prefetchPolicy.mjs +11 -0
  42. package/dist/esm/reactContext.mjs +7 -0
  43. package/dist/esm/request-policy/browser.mjs +11 -0
  44. package/dist/esm/request-policy/client.mjs +195 -0
  45. package/dist/esm/request-policy/policyCore.mjs +171 -0
  46. package/dist/esm/request-policy/requestContext.mjs +75 -0
  47. package/dist/esm/request-policy/traceparent.mjs +18 -0
  48. package/dist/esm/request-policy/transport.mjs +196 -0
  49. package/dist/esm/request-policy/types.mjs +10 -0
  50. package/dist/esm/routeHydration.mjs +77 -0
  51. package/dist/esm/routerPrefetchPolicy.mjs +115 -0
  52. package/dist/esm/routerProvider.mjs +58 -0
  53. package/dist/esm/routerState.mjs +139 -0
  54. package/dist/esm/routerStatePlugin.mjs +48 -0
  55. package/dist/esm/routerStateTypes.mjs +0 -0
  56. package/dist/esm/rsc-disabled/rscDisabledClientBrowserRuntime.mjs +10 -0
  57. package/dist/esm/rsc-disabled/rscDisabledClientEdgeRuntime.mjs +8 -0
  58. package/dist/esm/rsc-disabled/rscDisabledClientNodeRuntime.mjs +9 -0
  59. package/dist/esm/rsc-disabled/rscDisabledRuntimeError.mjs +4 -0
  60. package/dist/esm/rsc-disabled/rscDisabledServerEdgeRuntime.mjs +16 -0
  61. package/dist/esm/rsc-disabled/rscDisabledServerNodeRuntime.mjs +18 -0
  62. package/dist/esm/runtimeContextProjection.mjs +74 -0
  63. package/dist/esm/server-config/bffRuntime.mjs +0 -0
  64. package/dist/esm/server-config/index.mjs +0 -0
  65. package/dist/esm/server-config/serverTelemetry.mjs +0 -0
  66. package/dist/esm/shellStream.mjs +34 -2
  67. package/dist/esm/workspaceEvents.mjs +66 -0
  68. package/dist/esm-node/buildIdentity.mjs +36 -0
  69. package/dist/esm-node/contextExtensions.mjs +34 -0
  70. package/dist/esm-node/headRuntime.mjs +44 -0
  71. package/dist/esm-node/helmetContext.mjs +14 -0
  72. package/dist/esm-node/index.mjs +2 -0
  73. package/dist/esm-node/localisedLoaderIdentity.mjs +14 -0
  74. package/dist/esm-node/prefetchPolicy.mjs +12 -0
  75. package/dist/esm-node/reactContext.mjs +8 -0
  76. package/dist/esm-node/request-policy/browser.mjs +12 -0
  77. package/dist/esm-node/request-policy/client.mjs +196 -0
  78. package/dist/esm-node/request-policy/node.mjs +22 -0
  79. package/dist/esm-node/request-policy/policyCore.mjs +172 -0
  80. package/dist/esm-node/request-policy/requestContext.mjs +76 -0
  81. package/dist/esm-node/request-policy/traceparent.mjs +19 -0
  82. package/dist/esm-node/request-policy/transport.mjs +197 -0
  83. package/dist/esm-node/request-policy/types.mjs +11 -0
  84. package/dist/esm-node/routeHydration.mjs +78 -0
  85. package/dist/esm-node/routerPrefetchPolicy.mjs +116 -0
  86. package/dist/esm-node/routerProvider.mjs +59 -0
  87. package/dist/esm-node/routerState.mjs +140 -0
  88. package/dist/esm-node/routerStatePlugin.mjs +49 -0
  89. package/dist/esm-node/routerStateTypes.mjs +1 -0
  90. package/dist/esm-node/rsc-disabled/rscDisabledClientBrowserRuntime.mjs +11 -0
  91. package/dist/esm-node/rsc-disabled/rscDisabledClientEdgeRuntime.mjs +9 -0
  92. package/dist/esm-node/rsc-disabled/rscDisabledClientNodeRuntime.mjs +10 -0
  93. package/dist/esm-node/rsc-disabled/rscDisabledRuntimeError.mjs +5 -0
  94. package/dist/esm-node/rsc-disabled/rscDisabledServerEdgeRuntime.mjs +17 -0
  95. package/dist/esm-node/rsc-disabled/rscDisabledServerNodeRuntime.mjs +19 -0
  96. package/dist/esm-node/runtimeContextProjection.mjs +75 -0
  97. package/dist/esm-node/server-config/bffRuntime.mjs +1 -0
  98. package/dist/esm-node/server-config/index.mjs +1 -0
  99. package/dist/esm-node/server-config/serverTelemetry.mjs +1 -0
  100. package/dist/esm-node/shellStream.mjs +34 -2
  101. package/dist/esm-node/workspaceEvents.mjs +67 -0
  102. package/dist/types/buildIdentity.d.ts +37 -0
  103. package/dist/types/contextExtensions.d.ts +34 -0
  104. package/dist/types/headRuntime.d.ts +12 -0
  105. package/dist/types/helmetContext.d.ts +10 -0
  106. package/dist/types/index.d.ts +2 -0
  107. package/dist/types/localisedLoaderIdentity.d.ts +10 -0
  108. package/dist/types/prefetchPolicy.d.ts +4 -0
  109. package/dist/types/reactContext.d.ts +6 -0
  110. package/dist/types/request-policy/browser.d.ts +10 -0
  111. package/dist/types/request-policy/client.d.ts +14 -0
  112. package/dist/types/request-policy/node.d.ts +10 -0
  113. package/dist/types/request-policy/policyCore.d.ts +107 -0
  114. package/dist/types/request-policy/requestContext.d.ts +22 -0
  115. package/dist/types/request-policy/traceparent.d.ts +10 -0
  116. package/dist/types/request-policy/transport.d.ts +12 -0
  117. package/dist/types/request-policy/types.d.ts +144 -0
  118. package/dist/types/routeHydration.d.ts +24 -0
  119. package/dist/types/routerPrefetchPolicy.d.ts +28 -0
  120. package/dist/types/routerProvider.d.ts +55 -0
  121. package/dist/types/routerState.d.ts +18 -0
  122. package/dist/types/routerStatePlugin.d.ts +19 -0
  123. package/dist/types/routerStateTypes.d.ts +40 -0
  124. package/dist/types/rsc-disabled/rscDisabledClientBrowserRuntime.d.ts +9 -0
  125. package/dist/types/rsc-disabled/rscDisabledClientEdgeRuntime.d.ts +7 -0
  126. package/dist/types/rsc-disabled/rscDisabledClientNodeRuntime.d.ts +8 -0
  127. package/dist/types/rsc-disabled/rscDisabledRuntimeError.d.ts +1 -0
  128. package/dist/types/rsc-disabled/rscDisabledServerEdgeRuntime.d.ts +15 -0
  129. package/dist/types/rsc-disabled/rscDisabledServerNodeRuntime.d.ts +17 -0
  130. package/dist/types/runtimeContextProjection.d.ts +30 -0
  131. package/dist/types/server-config/bffRuntime.d.ts +122 -0
  132. package/dist/types/server-config/index.d.ts +2 -0
  133. package/dist/types/server-config/serverTelemetry.d.ts +322 -0
  134. package/dist/types/workspaceEvents.d.ts +62 -0
  135. package/package.json +239 -14
  136. package/rslib.config.mts +17 -2
  137. package/rstest.config.mts +33 -2
  138. package/src/buildIdentity.ts +61 -0
  139. package/src/contextExtensions.ts +81 -0
  140. package/src/headRuntime.tsx +77 -0
  141. package/src/helmetContext.ts +31 -0
  142. package/src/index.ts +2 -0
  143. package/src/localisedLoaderIdentity.ts +30 -0
  144. package/src/prefetchPolicy.ts +33 -0
  145. package/src/reactContext.ts +16 -0
  146. package/src/request-policy/browser.ts +22 -0
  147. package/src/request-policy/client.ts +404 -0
  148. package/src/request-policy/node.ts +41 -0
  149. package/src/request-policy/policyCore.ts +424 -0
  150. package/src/request-policy/requestContext.ts +149 -0
  151. package/src/request-policy/traceparent.ts +43 -0
  152. package/src/request-policy/transport.ts +349 -0
  153. package/src/request-policy/types.ts +229 -0
  154. package/src/routeHydration.ts +208 -0
  155. package/src/routerPrefetchPolicy.ts +195 -0
  156. package/src/routerProvider.ts +160 -0
  157. package/src/routerState.ts +290 -0
  158. package/src/routerStatePlugin.ts +86 -0
  159. package/src/routerStateTypes.ts +46 -0
  160. package/src/rsc-disabled/rscDisabledClientBrowserRuntime.ts +10 -0
  161. package/src/rsc-disabled/rscDisabledClientEdgeRuntime.ts +8 -0
  162. package/src/rsc-disabled/rscDisabledClientNodeRuntime.ts +9 -0
  163. package/src/rsc-disabled/rscDisabledRuntimeError.ts +3 -0
  164. package/src/rsc-disabled/rscDisabledServerEdgeRuntime.ts +16 -0
  165. package/src/rsc-disabled/rscDisabledServerNodeRuntime.ts +18 -0
  166. package/src/runtimeContextProjection.ts +105 -0
  167. package/src/server-config/bffRuntime.ts +136 -0
  168. package/src/server-config/index.ts +2 -0
  169. package/src/server-config/serverTelemetry.ts +337 -0
  170. package/src/shellStream.ts +55 -25
  171. package/src/workspaceEvents.ts +324 -0
  172. package/tests/buildIdentity.test.ts +51 -0
  173. package/tests/contextExtensions.test.ts +27 -0
  174. package/tests/headRuntime.test.tsx +229 -0
  175. package/tests/rendererHead.test.ts +1 -113
  176. package/tests/request-policy/browser-policy.test.ts +108 -0
  177. package/tests/request-policy/client-isolation.test.ts +109 -0
  178. package/tests/request-policy/node-policy.test.ts +447 -0
  179. package/tests/request-policy/policyCore.test.ts +129 -0
  180. package/tests/request-policy/requestContext.test.ts +66 -0
  181. package/tests/request-policy/requestFactory.outbound-contract.test.ts +290 -0
  182. package/tests/request-policy/traceparent.test.ts +52 -0
  183. package/tests/request-policy/transport-retry.test.ts +367 -0
  184. package/tests/routeHydration.test.ts +180 -0
  185. package/tests/routerPrefetchPolicy.test.ts +102 -0
  186. package/tests/routerProvider.test.ts +29 -0
  187. package/tests/routerState.test.ts +78 -0
  188. package/tests/routerStatePlugin.test.ts +63 -0
  189. package/tests/runtimeContextProjection.test.ts +83 -0
  190. package/tests/safeFailure.test.ts +10 -28
  191. package/tests/shellStream.test.ts +37 -0
  192. package/tests/workspaceEvents.test.ts +221 -0
  193. package/dist/cjs/rscHtmlStream.js +0 -128
  194. package/dist/esm/rscHtmlStream.mjs +0 -86
  195. package/dist/esm-node/rscHtmlStream.mjs +0 -87
  196. package/dist/types/rscHtmlStream.d.ts +0 -4
  197. package/src/rscHtmlStream.ts +0 -142
  198. package/tests/rscHtmlStream.test.ts +0 -153
@@ -5,14 +5,8 @@ import {
5
5
  collectHeadRecord,
6
6
  completeHeadRender,
7
7
  createHeadChunkProcessor,
8
- createWebHeadMarkerStripper,
9
- publishHeadRender,
10
8
  } from '../src';
11
- import {
12
- createNodeHeadMarkerStripper,
13
- createOnceErrorReporter,
14
- pipeNodeHeadStream,
15
- } from '../src/node';
9
+ import { createNodeHeadMarkerStripper, pipeNodeHeadStream } from '../src/node';
16
10
 
17
11
  const marker = (props: Record<string, string>) =>
18
12
  `<template data-modern-helmet="${props['data-modern-helmet']}"></template>`;
@@ -50,16 +44,6 @@ describe('renderer head transactions', () => {
50
44
  expect(completeHeadRender(context, userTemplate)).toBe(userTemplate);
51
45
  });
52
46
 
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
47
  it('strips markers split across chunks without corrupting unicode', () => {
64
48
  const sampleContext = {};
65
49
  beginHeadRender(sampleContext);
@@ -87,41 +71,6 @@ describe('renderer head transactions', () => {
87
71
  }
88
72
  });
89
73
 
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
74
  it('clears the previous snapshot while rendering and restores it on abort', () => {
126
75
  const context = {};
127
76
  let published: string[] = [];
@@ -141,36 +90,6 @@ describe('renderer head transactions', () => {
141
90
  expect(published).toEqual(['previous']);
142
91
  });
143
92
 
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
93
  it('strips split markers from a Node stream', async () => {
175
94
  const context = {};
176
95
  let published: string[] = [];
@@ -265,35 +184,4 @@ describe('renderer head transactions', () => {
265
184
  await expect(output).rejects.toThrow('source failed');
266
185
  expect(onError).toHaveBeenCalledTimes(1);
267
186
  });
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
187
  });
@@ -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
+ });