@bleedingdev/modern-js-plugin-tanstack 3.5.0-ultramodern.31 → 3.5.0-ultramodern.33
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/runtime/rsc/slotUsageSanitizer.js +1 -0
- package/dist/cjs/runtime/state.js +1 -1
- package/dist/cjs/runtime/utils.js +3 -3
- package/dist/esm/runtime/rsc/slotUsageSanitizer.mjs +1 -0
- package/dist/esm/runtime/state.mjs +1 -1
- package/dist/esm/runtime/utils.mjs +3 -3
- package/dist/esm-node/runtime/rsc/slotUsageSanitizer.mjs +1 -0
- package/dist/esm-node/runtime/state.mjs +1 -1
- package/dist/esm-node/runtime/utils.mjs +3 -3
- package/package.json +10 -10
- package/rstest.config.mts +2 -0
- package/src/runtime/rsc/slotUsageSanitizer.ts +4 -0
- package/src/runtime/state.ts +5 -1
- package/src/runtime/utils.tsx +3 -3
- package/tests/router/flightSerialization.roundtrip.test.tsx +137 -0
- package/tests/router/hooks.test.ts +14 -0
- package/tests/router/routeTree.test.ts +5 -0
- package/tests/router/slotUsageSanitizer.test.ts +23 -0
|
@@ -45,6 +45,7 @@ function sanitizeSlotArg(value, seen) {
|
|
|
45
45
|
if (null == value) return value;
|
|
46
46
|
if ('string' == typeof value || 'number' == typeof value || 'boolean' == typeof value || 'bigint' == typeof value) return value;
|
|
47
47
|
if ('object' != typeof value && 'function' != typeof value) return String(value);
|
|
48
|
+
if ('function' == typeof value) return '[Function]';
|
|
48
49
|
if (seen.has(value)) return '[Circular]';
|
|
49
50
|
seen.add(value);
|
|
50
51
|
if (Array.isArray(value)) return value.map((item)=>sanitizeSlotArg(item, seen));
|
|
@@ -33,7 +33,7 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
33
33
|
const context_namespaceObject = require("@modern-js/runtime/context");
|
|
34
34
|
function getTanstackRouterState(context) {
|
|
35
35
|
const state = (0, context_namespaceObject.getRouterRuntimeState)(context);
|
|
36
|
-
if (void 0 === state || 'tanstack' !== state.framework) return;
|
|
36
|
+
if (void 0 === state || 'tanstack' !== state.framework || void 0 === state.instance) return;
|
|
37
37
|
return state;
|
|
38
38
|
}
|
|
39
39
|
exports.getTanstackRouterState = __webpack_exports__.getTanstackRouterState;
|
|
@@ -67,9 +67,9 @@ function toTanstackRouteObject(route, globalApp) {
|
|
|
67
67
|
shouldRevalidate: route.shouldRevalidate,
|
|
68
68
|
handle: getRouteHandle(route),
|
|
69
69
|
index: route.index,
|
|
70
|
-
hasLoader: Boolean(route.loader),
|
|
71
|
-
hasClientLoader: Boolean(route.clientData),
|
|
72
|
-
hasAction: Boolean(route.action),
|
|
70
|
+
hasLoader: route.hasLoader || Boolean(route.loader),
|
|
71
|
+
hasClientLoader: route.hasClientLoader || Boolean(route.clientData),
|
|
72
|
+
hasAction: route.hasAction || Boolean(route.action),
|
|
73
73
|
...route.isClientComponent ? {
|
|
74
74
|
isClientComponent: true
|
|
75
75
|
} : {},
|
|
@@ -13,6 +13,7 @@ function sanitizeSlotArg(value, seen) {
|
|
|
13
13
|
if (null == value) return value;
|
|
14
14
|
if ('string' == typeof value || 'number' == typeof value || 'boolean' == typeof value || 'bigint' == typeof value) return value;
|
|
15
15
|
if ('object' != typeof value && 'function' != typeof value) return String(value);
|
|
16
|
+
if ('function' == typeof value) return '[Function]';
|
|
16
17
|
if (seen.has(value)) return '[Circular]';
|
|
17
18
|
seen.add(value);
|
|
18
19
|
if (Array.isArray(value)) return value.map((item)=>sanitizeSlotArg(item, seen));
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { getRouterRuntimeState } from "@modern-js/runtime/context";
|
|
2
2
|
function getTanstackRouterState(context) {
|
|
3
3
|
const state = getRouterRuntimeState(context);
|
|
4
|
-
if (void 0 === state || 'tanstack' !== state.framework) return;
|
|
4
|
+
if (void 0 === state || 'tanstack' !== state.framework || void 0 === state.instance) return;
|
|
5
5
|
return state;
|
|
6
6
|
}
|
|
7
7
|
export { getTanstackRouterState };
|
|
@@ -25,9 +25,9 @@ function toTanstackRouteObject(route, globalApp) {
|
|
|
25
25
|
shouldRevalidate: route.shouldRevalidate,
|
|
26
26
|
handle: getRouteHandle(route),
|
|
27
27
|
index: route.index,
|
|
28
|
-
hasLoader: Boolean(route.loader),
|
|
29
|
-
hasClientLoader: Boolean(route.clientData),
|
|
30
|
-
hasAction: Boolean(route.action),
|
|
28
|
+
hasLoader: route.hasLoader || Boolean(route.loader),
|
|
29
|
+
hasClientLoader: route.hasClientLoader || Boolean(route.clientData),
|
|
30
|
+
hasAction: route.hasAction || Boolean(route.action),
|
|
31
31
|
...route.isClientComponent ? {
|
|
32
32
|
isClientComponent: true
|
|
33
33
|
} : {},
|
|
@@ -14,6 +14,7 @@ function sanitizeSlotArg(value, seen) {
|
|
|
14
14
|
if (null == value) return value;
|
|
15
15
|
if ('string' == typeof value || 'number' == typeof value || 'boolean' == typeof value || 'bigint' == typeof value) return value;
|
|
16
16
|
if ('object' != typeof value && 'function' != typeof value) return String(value);
|
|
17
|
+
if ('function' == typeof value) return '[Function]';
|
|
17
18
|
if (seen.has(value)) return '[Circular]';
|
|
18
19
|
seen.add(value);
|
|
19
20
|
if (Array.isArray(value)) return value.map((item)=>sanitizeSlotArg(item, seen));
|
|
@@ -2,7 +2,7 @@ import "node:module";
|
|
|
2
2
|
import { getRouterRuntimeState } from "@modern-js/runtime/context";
|
|
3
3
|
function getTanstackRouterState(context) {
|
|
4
4
|
const state = getRouterRuntimeState(context);
|
|
5
|
-
if (void 0 === state || 'tanstack' !== state.framework) return;
|
|
5
|
+
if (void 0 === state || 'tanstack' !== state.framework || void 0 === state.instance) return;
|
|
6
6
|
return state;
|
|
7
7
|
}
|
|
8
8
|
export { getTanstackRouterState };
|
|
@@ -26,9 +26,9 @@ function toTanstackRouteObject(route, globalApp) {
|
|
|
26
26
|
shouldRevalidate: route.shouldRevalidate,
|
|
27
27
|
handle: getRouteHandle(route),
|
|
28
28
|
index: route.index,
|
|
29
|
-
hasLoader: Boolean(route.loader),
|
|
30
|
-
hasClientLoader: Boolean(route.clientData),
|
|
31
|
-
hasAction: Boolean(route.action),
|
|
29
|
+
hasLoader: route.hasLoader || Boolean(route.loader),
|
|
30
|
+
hasClientLoader: route.hasClientLoader || Boolean(route.clientData),
|
|
31
|
+
hasAction: route.hasAction || Boolean(route.action),
|
|
32
32
|
...route.isClientComponent ? {
|
|
33
33
|
isClientComponent: true
|
|
34
34
|
} : {},
|
package/package.json
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"modern.js",
|
|
19
19
|
"tanstack-router"
|
|
20
20
|
],
|
|
21
|
-
"version": "3.5.0-ultramodern.
|
|
21
|
+
"version": "3.5.0-ultramodern.33",
|
|
22
22
|
"engines": {
|
|
23
23
|
"node": ">=20"
|
|
24
24
|
},
|
|
@@ -98,14 +98,14 @@
|
|
|
98
98
|
"@tanstack/react-router": "1.170.16",
|
|
99
99
|
"@tanstack/router-core": "1.171.13",
|
|
100
100
|
"react-server-dom-rspack": "0.0.2",
|
|
101
|
-
"@modern-js/plugin": "npm:@bleedingdev/modern-js-plugin@3.5.0-ultramodern.
|
|
102
|
-
"@modern-js/types": "npm:@bleedingdev/modern-js-types@3.5.0-ultramodern.
|
|
103
|
-
"@modern-js/utils": "npm:@bleedingdev/modern-js-utils@3.5.0-ultramodern.
|
|
104
|
-
"@modern-js/
|
|
101
|
+
"@modern-js/plugin": "npm:@bleedingdev/modern-js-plugin@3.5.0-ultramodern.33",
|
|
102
|
+
"@modern-js/types": "npm:@bleedingdev/modern-js-types@3.5.0-ultramodern.33",
|
|
103
|
+
"@modern-js/runtime-utils": "npm:@bleedingdev/modern-js-runtime-utils@3.5.0-ultramodern.33",
|
|
104
|
+
"@modern-js/utils": "npm:@bleedingdev/modern-js-utils@3.5.0-ultramodern.33"
|
|
105
105
|
},
|
|
106
106
|
"peerDependencies": {
|
|
107
|
-
"@modern-js/app-tools": "3.5.0-ultramodern.
|
|
108
|
-
"@modern-js/runtime": "3.5.0-ultramodern.
|
|
107
|
+
"@modern-js/app-tools": "3.5.0-ultramodern.33",
|
|
108
|
+
"@modern-js/runtime": "3.5.0-ultramodern.33",
|
|
109
109
|
"react": "^19.2.7",
|
|
110
110
|
"react-dom": "^19.2.7"
|
|
111
111
|
},
|
|
@@ -120,9 +120,9 @@
|
|
|
120
120
|
"@typescript/native-preview": "7.0.0-dev.20260628.1",
|
|
121
121
|
"react": "^19.2.7",
|
|
122
122
|
"react-dom": "^19.2.7",
|
|
123
|
-
"@modern-js/app-tools": "npm:@bleedingdev/modern-js-app-tools@3.5.0-ultramodern.
|
|
124
|
-
"@
|
|
125
|
-
"@
|
|
123
|
+
"@modern-js/app-tools": "npm:@bleedingdev/modern-js-app-tools@3.5.0-ultramodern.33",
|
|
124
|
+
"@scripts/rstest-config": "2.66.0",
|
|
125
|
+
"@modern-js/runtime": "npm:@bleedingdev/modern-js-runtime@3.5.0-ultramodern.33"
|
|
126
126
|
},
|
|
127
127
|
"sideEffects": [
|
|
128
128
|
"./src/runtime/register.ts",
|
package/rstest.config.mts
CHANGED
|
@@ -25,6 +25,7 @@ export default {
|
|
|
25
25
|
include: [
|
|
26
26
|
'tests/router/cli.test.ts',
|
|
27
27
|
'tests/router/fastDefaults.test.ts',
|
|
28
|
+
'tests/router/flightSerialization.roundtrip.test.tsx',
|
|
28
29
|
'tests/router/generateRouteArtifacts.test.ts',
|
|
29
30
|
'tests/router/hooks.test.ts',
|
|
30
31
|
'tests/router/loaderBridge.test.ts',
|
|
@@ -33,6 +34,7 @@ export default {
|
|
|
33
34
|
'tests/router/register.test.ts',
|
|
34
35
|
'tests/router/routeHooks.test.ts',
|
|
35
36
|
'tests/router/rsc.test.tsx',
|
|
37
|
+
'tests/router/slotUsageSanitizer.test.ts',
|
|
36
38
|
'tests/router/ssrPreload.test.ts',
|
|
37
39
|
'tests/router/tanstackTypes.test.ts',
|
|
38
40
|
'tests/router/routeTree.test.ts',
|
package/src/runtime/state.ts
CHANGED
|
@@ -23,7 +23,11 @@ export function getTanstackRouterState(
|
|
|
23
23
|
context: object,
|
|
24
24
|
): TanstackRouterState | undefined {
|
|
25
25
|
const state = getRouterRuntimeState(context);
|
|
26
|
-
if (
|
|
26
|
+
if (
|
|
27
|
+
state === undefined ||
|
|
28
|
+
state.framework !== 'tanstack' ||
|
|
29
|
+
state.instance === undefined
|
|
30
|
+
) {
|
|
27
31
|
return undefined;
|
|
28
32
|
}
|
|
29
33
|
|
package/src/runtime/utils.tsx
CHANGED
|
@@ -69,9 +69,9 @@ function toTanstackRouteObject(
|
|
|
69
69
|
shouldRevalidate: route.shouldRevalidate,
|
|
70
70
|
handle: getRouteHandle(route),
|
|
71
71
|
index: route.index,
|
|
72
|
-
hasLoader: Boolean(route.loader),
|
|
73
|
-
hasClientLoader: Boolean(route.clientData),
|
|
74
|
-
hasAction: Boolean(route.action),
|
|
72
|
+
hasLoader: route.hasLoader || Boolean(route.loader),
|
|
73
|
+
hasClientLoader: route.hasClientLoader || Boolean(route.clientData),
|
|
74
|
+
hasAction: route.hasAction || Boolean(route.action),
|
|
75
75
|
...(route.isClientComponent ? { isClientComponent: true } : {}),
|
|
76
76
|
...(route.inValidSSRRoute ? { inValidSSRRoute: true } : {}),
|
|
77
77
|
lazyImport: route.lazyImport,
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import type React from 'react';
|
|
2
|
+
import { isValidElement } from 'react';
|
|
3
|
+
import { createRscProxy } from '../../src/runtime/rsc/createRscProxy';
|
|
4
|
+
import {
|
|
5
|
+
reviveTanstackRscFlightValues,
|
|
6
|
+
serializeTanstackRscFlightValues,
|
|
7
|
+
} from '../../src/runtime/rsc/flightSerialization';
|
|
8
|
+
import {
|
|
9
|
+
RENDERABLE_RSC,
|
|
10
|
+
SERVER_COMPONENT_STREAM,
|
|
11
|
+
type ServerComponentStream,
|
|
12
|
+
} from '../../src/runtime/rsc/symbols';
|
|
13
|
+
|
|
14
|
+
type RoundTripFixture = {
|
|
15
|
+
bigintValue: bigint;
|
|
16
|
+
booleanValue: boolean;
|
|
17
|
+
circular: Record<string, unknown>;
|
|
18
|
+
dateValue: Date;
|
|
19
|
+
falseValue: boolean;
|
|
20
|
+
mapValue: Map<unknown, unknown>;
|
|
21
|
+
nested: {
|
|
22
|
+
array: unknown[];
|
|
23
|
+
object: {
|
|
24
|
+
child: unknown;
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
nullValue: null;
|
|
28
|
+
numberValue: number;
|
|
29
|
+
rscProxy: React.ReactElement & Record<PropertyKey, unknown>;
|
|
30
|
+
setValue: Set<unknown>;
|
|
31
|
+
sharedA: Record<string, unknown>;
|
|
32
|
+
sharedB: Record<string, unknown>;
|
|
33
|
+
stringValue: string;
|
|
34
|
+
undefinedValue: undefined;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
function createStream(): ServerComponentStream {
|
|
38
|
+
return {
|
|
39
|
+
createReplayStream: () => new ReadableStream<Uint8Array>(),
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
test('round-trips TanStack RSC flight values across supported value types', async () => {
|
|
44
|
+
const shared = { marker: 'shared' };
|
|
45
|
+
const circular: Record<string, unknown> = { marker: 'circular' };
|
|
46
|
+
circular.self = circular;
|
|
47
|
+
|
|
48
|
+
const mapValue = new Map<unknown, unknown>([
|
|
49
|
+
['primitive', 1],
|
|
50
|
+
['shared', shared],
|
|
51
|
+
[shared, circular],
|
|
52
|
+
]);
|
|
53
|
+
mapValue.set('self', mapValue);
|
|
54
|
+
|
|
55
|
+
const setValue = new Set<unknown>(['set-item', shared, circular]);
|
|
56
|
+
setValue.add(setValue);
|
|
57
|
+
|
|
58
|
+
const rscProxy = createRscProxy(() => ({ slot: 'server' }), {
|
|
59
|
+
renderable: true,
|
|
60
|
+
stream: createStream(),
|
|
61
|
+
}) as React.ReactElement & Record<PropertyKey, unknown>;
|
|
62
|
+
|
|
63
|
+
const fixture: RoundTripFixture = {
|
|
64
|
+
bigintValue: 9007199254740993n,
|
|
65
|
+
booleanValue: true,
|
|
66
|
+
circular,
|
|
67
|
+
dateValue: new Date('2026-07-08T12:34:56.789Z'),
|
|
68
|
+
falseValue: false,
|
|
69
|
+
mapValue,
|
|
70
|
+
nested: {
|
|
71
|
+
array: [shared, [null, undefined, 7n]],
|
|
72
|
+
object: {
|
|
73
|
+
child: shared,
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
nullValue: null,
|
|
77
|
+
numberValue: 42,
|
|
78
|
+
rscProxy,
|
|
79
|
+
setValue,
|
|
80
|
+
sharedA: shared,
|
|
81
|
+
sharedB: shared,
|
|
82
|
+
stringValue: 'flight',
|
|
83
|
+
undefinedValue: undefined,
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
const serialized = serializeTanstackRscFlightValues(
|
|
87
|
+
fixture,
|
|
88
|
+
) as RoundTripFixture;
|
|
89
|
+
const revived = (await reviveTanstackRscFlightValues(
|
|
90
|
+
serialized,
|
|
91
|
+
)) as RoundTripFixture;
|
|
92
|
+
|
|
93
|
+
expect(revived).not.toBe(fixture);
|
|
94
|
+
expect(revived.stringValue).toBe('flight');
|
|
95
|
+
expect(revived.numberValue).toBe(42);
|
|
96
|
+
expect(revived.booleanValue).toBe(true);
|
|
97
|
+
expect(revived.falseValue).toBe(false);
|
|
98
|
+
expect(revived.nullValue).toBeNull();
|
|
99
|
+
expect(Object.hasOwn(revived, 'undefinedValue')).toBe(true);
|
|
100
|
+
expect(revived.undefinedValue).toBeUndefined();
|
|
101
|
+
expect(revived.bigintValue).toBe(9007199254740993n);
|
|
102
|
+
expect(revived.dateValue).toBeInstanceOf(Date);
|
|
103
|
+
expect(revived.dateValue.toISOString()).toBe('2026-07-08T12:34:56.789Z');
|
|
104
|
+
|
|
105
|
+
expect(revived.nested.array[0]).toBe(revived.sharedA);
|
|
106
|
+
expect(revived.nested.object.child).toBe(revived.sharedA);
|
|
107
|
+
expect(revived.sharedB).toBe(revived.sharedA);
|
|
108
|
+
|
|
109
|
+
expect(revived.circular).not.toBe(circular);
|
|
110
|
+
expect(revived.circular.self).toBe(revived.circular);
|
|
111
|
+
|
|
112
|
+
expect(revived.mapValue).toBeInstanceOf(Map);
|
|
113
|
+
expect(revived.mapValue).not.toBe(mapValue);
|
|
114
|
+
expect(revived.mapValue.get('primitive')).toBe(1);
|
|
115
|
+
expect(revived.mapValue.get('shared')).toBe(revived.sharedA);
|
|
116
|
+
expect(revived.mapValue.get(revived.sharedA)).toBe(revived.circular);
|
|
117
|
+
expect(revived.mapValue.get('self')).toBe(revived.mapValue);
|
|
118
|
+
|
|
119
|
+
expect(revived.setValue).toBeInstanceOf(Set);
|
|
120
|
+
expect(revived.setValue).not.toBe(setValue);
|
|
121
|
+
expect(revived.setValue.has('set-item')).toBe(true);
|
|
122
|
+
expect(revived.setValue.has(revived.sharedA)).toBe(true);
|
|
123
|
+
expect(revived.setValue.has(revived.circular)).toBe(true);
|
|
124
|
+
expect(revived.setValue.has(revived.setValue)).toBe(true);
|
|
125
|
+
|
|
126
|
+
expect(serialized.rscProxy).not.toBe(rscProxy);
|
|
127
|
+
expect(serialized.rscProxy).toMatchObject({
|
|
128
|
+
__modernTanstackRsc: true,
|
|
129
|
+
kind: 'renderable',
|
|
130
|
+
});
|
|
131
|
+
expect(serialized.rscProxy.stream).toBeInstanceOf(ReadableStream);
|
|
132
|
+
|
|
133
|
+
expect(revived.rscProxy).not.toBe(rscProxy);
|
|
134
|
+
expect(isValidElement(revived.rscProxy)).toBe(true);
|
|
135
|
+
expect(revived.rscProxy[RENDERABLE_RSC]).toBe(true);
|
|
136
|
+
expect(revived.rscProxy[SERVER_COMPONENT_STREAM]).toBeDefined();
|
|
137
|
+
});
|
|
@@ -3,8 +3,10 @@ import {
|
|
|
3
3
|
routerProviderRegistryHooks,
|
|
4
4
|
} from '@modern-js/runtime/context';
|
|
5
5
|
import * as tanstackHooks from '../../src/runtime/hooks';
|
|
6
|
+
import { applyRouterRuntimeState } from '../../src/runtime/lifecycle';
|
|
6
7
|
import { tanstackRouterPlugin as browserPlugin } from '../../src/runtime/plugin';
|
|
7
8
|
import { tanstackRouterPlugin as nodePlugin } from '../../src/runtime/plugin.node';
|
|
9
|
+
import { getTanstackRouterState } from '../../src/runtime/state';
|
|
8
10
|
|
|
9
11
|
describe('tanstack router hooks single declaration source', () => {
|
|
10
12
|
test('re-exports the canonical hook instances owned by @modern-js/runtime', () => {
|
|
@@ -24,3 +26,15 @@ describe('tanstack router hooks single declaration source', () => {
|
|
|
24
26
|
expect(nodePlugin().registryHooks).toBe(routerProviderRegistryHooks);
|
|
25
27
|
});
|
|
26
28
|
});
|
|
29
|
+
|
|
30
|
+
describe('tanstack router runtime state accessor', () => {
|
|
31
|
+
test('returns undefined before a tanstack router instance is created', () => {
|
|
32
|
+
const context = {};
|
|
33
|
+
|
|
34
|
+
applyRouterRuntimeState(context as never, {
|
|
35
|
+
framework: 'tanstack',
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
expect(getTanstackRouterState(context)).toBeUndefined();
|
|
39
|
+
});
|
|
40
|
+
});
|
|
@@ -809,6 +809,9 @@ describe('tanstack route tree from RouteObject[]', () => {
|
|
|
809
809
|
path: 'client',
|
|
810
810
|
clientData: './client.data',
|
|
811
811
|
data: './data',
|
|
812
|
+
hasAction: true,
|
|
813
|
+
hasClientLoader: true,
|
|
814
|
+
hasLoader: true,
|
|
812
815
|
inValidSSRRoute: true,
|
|
813
816
|
isClientComponent: true,
|
|
814
817
|
},
|
|
@@ -830,7 +833,9 @@ describe('tanstack route tree from RouteObject[]', () => {
|
|
|
830
833
|
|
|
831
834
|
expect(clientRoute.options.ssr).toBe(false);
|
|
832
835
|
expect(clientRoute.options.staticData).toMatchObject({
|
|
836
|
+
modernRouteHasAction: true,
|
|
833
837
|
modernRouteHasClientLoader: true,
|
|
838
|
+
modernRouteHasLoader: true,
|
|
834
839
|
modernRouteIsClientComponent: true,
|
|
835
840
|
});
|
|
836
841
|
});
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { sanitizeSlotArgs } from '../../src/runtime/rsc/slotUsageSanitizer';
|
|
2
|
+
|
|
3
|
+
describe('RSC slot usage sanitizer', () => {
|
|
4
|
+
test('redacts callable slot args without serializing function source', () => {
|
|
5
|
+
function tokenFactory() {
|
|
6
|
+
return 'token-secret';
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const args = sanitizeSlotArgs([
|
|
10
|
+
tokenFactory,
|
|
11
|
+
{ nested: tokenFactory },
|
|
12
|
+
[tokenFactory],
|
|
13
|
+
]);
|
|
14
|
+
|
|
15
|
+
expect(args).toEqual([
|
|
16
|
+
'[Function]',
|
|
17
|
+
{ nested: '[Function]' },
|
|
18
|
+
['[Function]'],
|
|
19
|
+
]);
|
|
20
|
+
expect(JSON.stringify(args)).not.toContain('token-secret');
|
|
21
|
+
expect(JSON.stringify(args)).not.toContain('tokenFactory');
|
|
22
|
+
});
|
|
23
|
+
});
|