@bleedingdev/modern-js-plugin-tanstack 3.5.0-ultramodern.36 → 3.5.0-ultramodern.38
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/cli/tanstackTypes/shared.js +12 -19
- package/dist/cjs/cli/tanstackTypes/source.js +24 -19
- package/dist/cjs/runtime/blockingSubscribe.js +0 -7
- package/dist/cjs/runtime/clientHydration.js +2 -14
- package/dist/cjs/runtime/loaderBridge.js +3 -10
- package/dist/cjs/runtime/pluginShared.js +0 -3
- package/dist/cjs/runtime/register.js +1 -47
- package/dist/cjs/runtime/rsc/ReplayableStream.js +0 -4
- package/dist/cjs/runtime/rsc/payloadFetch.js +3 -16
- package/dist/cjs/runtime/rsc/payloadRoutes.js +2 -14
- package/dist/cjs/runtime/rsc/shared.js +2 -5
- package/dist/cjs/runtime/shared/isAbsoluteUrl.js +47 -0
- package/dist/esm/cli/index.mjs +4 -4
- package/dist/esm/cli/tanstackTypes/shared.mjs +12 -19
- package/dist/esm/cli/tanstackTypes/source.mjs +23 -18
- package/dist/esm/runtime/blockingSubscribe.mjs +1 -1
- package/dist/esm/runtime/clientHydration.mjs +1 -1
- package/dist/esm/runtime/loaderBridge.mjs +1 -8
- package/dist/esm/runtime/pluginShared.mjs +1 -1
- package/dist/esm/runtime/register.mjs +0 -14
- package/dist/esm/runtime/rsc/ReplayableStream.mjs +1 -1
- package/dist/esm/runtime/rsc/payloadFetch.mjs +2 -9
- package/dist/esm/runtime/rsc/payloadRoutes.mjs +1 -1
- package/dist/esm/runtime/rsc/shared.mjs +1 -1
- package/dist/esm/runtime/shared/isAbsoluteUrl.mjs +9 -0
- package/dist/esm-node/cli/index.mjs +4 -4
- package/dist/esm-node/cli/tanstackTypes/shared.mjs +12 -19
- package/dist/esm-node/cli/tanstackTypes/source.mjs +23 -18
- package/dist/esm-node/runtime/blockingSubscribe.mjs +1 -1
- package/dist/esm-node/runtime/clientHydration.mjs +1 -1
- package/dist/esm-node/runtime/loaderBridge.mjs +1 -8
- package/dist/esm-node/runtime/pluginShared.mjs +1 -1
- package/dist/esm-node/runtime/register.mjs +0 -14
- package/dist/esm-node/runtime/rsc/ReplayableStream.mjs +1 -1
- package/dist/esm-node/runtime/rsc/payloadFetch.mjs +2 -9
- package/dist/esm-node/runtime/rsc/payloadRoutes.mjs +1 -1
- package/dist/esm-node/runtime/rsc/shared.mjs +1 -1
- package/dist/esm-node/runtime/shared/isAbsoluteUrl.mjs +10 -0
- package/dist/types/cli/tanstackTypes/shared.d.ts +1 -1
- package/dist/types/cli/tanstackTypes/source.d.ts +3 -1
- package/dist/types/runtime/blockingSubscribe.d.ts +0 -2
- package/dist/types/runtime/clientHydration.d.ts +0 -9
- package/dist/types/runtime/formData.d.ts +2 -1
- package/dist/types/runtime/loaderBridge.d.ts +2 -1
- package/dist/types/runtime/pluginShared.d.ts +2 -3
- package/dist/types/runtime/register.d.ts +1 -9
- package/dist/types/runtime/routeTree/types.d.ts +2 -1
- package/dist/types/runtime/rsc/ReplayableStream.d.ts +3 -2
- package/dist/types/runtime/rsc/SlotContext.d.ts +2 -1
- package/dist/types/runtime/rsc/payloadFetch.d.ts +2 -4
- package/dist/types/runtime/rsc/payloadRoutes.d.ts +3 -6
- package/dist/types/runtime/rsc/shared.d.ts +0 -1
- package/dist/types/runtime/shared/isAbsoluteUrl.d.ts +1 -0
- package/dist/types/runtime/ssrTypes.d.ts +3 -2
- package/dist/types/runtime/types.d.ts +2 -3
- package/package.json +15 -16
- package/src/cli/tanstackTypes/canonicalRoutes.ts +1 -1
- package/src/cli/tanstackTypes/shared.ts +24 -30
- package/src/cli/tanstackTypes/source.ts +31 -21
- package/src/runtime/blockingSubscribe.ts +2 -2
- package/src/runtime/clientHydration.ts +5 -10
- package/src/runtime/formData.ts +1 -1
- package/src/runtime/loaderBridge.ts +3 -9
- package/src/runtime/pluginShared.ts +3 -3
- package/src/runtime/register.ts +5 -37
- package/src/runtime/routeTree/types.ts +1 -1
- package/src/runtime/rsc/ReplayableStream.ts +2 -2
- package/src/runtime/rsc/SlotContext.tsx +1 -1
- package/src/runtime/rsc/payloadFetch.ts +5 -11
- package/src/runtime/rsc/payloadRoutes.ts +6 -6
- package/src/runtime/rsc/shared.ts +1 -1
- package/src/runtime/shared/isAbsoluteUrl.ts +8 -0
- package/src/runtime/ssrTypes.ts +2 -2
- package/src/runtime/submitAction.ts +17 -10
- package/src/runtime/types.ts +1 -8
- package/tests/router/register.test.ts +1 -39
package/src/runtime/register.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Registers
|
|
2
|
+
* Registers TanStack router provider with the @modern-js/runtime router
|
|
3
3
|
* provider registry. Importing '@modern-js/plugin-tanstack/runtime' is enough
|
|
4
4
|
* to make `runtime.router.framework: 'tanstack'` resolvable by the built-in
|
|
5
5
|
* router runtime plugin.
|
|
@@ -12,47 +12,15 @@ import {
|
|
|
12
12
|
type RouterProviderPlugin,
|
|
13
13
|
registerRouterProvider,
|
|
14
14
|
} from '@modern-js/runtime/context';
|
|
15
|
-
import { Form, RouteActionResponseError, useFetcher } from './dataMutation';
|
|
16
|
-
import { Outlet } from './outlet';
|
|
17
15
|
import { tanstackRouterPlugin } from './plugin';
|
|
18
|
-
import { Link, NavLink } from './prefetchLink';
|
|
19
16
|
|
|
20
|
-
//
|
|
17
|
+
// TanStack runtime plugin types its API against its own hook registry,
|
|
21
18
|
// while the provider contract is typed against the built-in router hook
|
|
22
|
-
// registry
|
|
19
|
+
// registry from @modern-js/runtime. The two are runtime-compatible (the
|
|
23
20
|
// built-in router plugin registers the hooks and forwards its API to the
|
|
24
|
-
// resolved provider), but nominally distinct
|
|
25
|
-
// cast
|
|
21
|
+
// resolved provider), but nominally distinct, so keep an explicit adapter
|
|
22
|
+
// cast as the single boundary.
|
|
26
23
|
const tanstackRouterProviderFactory: RouterProviderFactory = userConfig =>
|
|
27
24
|
tanstackRouterPlugin(userConfig) as unknown as RouterProviderPlugin;
|
|
28
25
|
|
|
29
26
|
registerRouterProvider('tanstack', tanstackRouterProviderFactory);
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Compatibility bindings for the deprecated `@modern-js/runtime/tanstack-router`
|
|
33
|
-
* alias. `@modern-js/runtime` cannot depend on this package (the dependency
|
|
34
|
-
* direction is plugin-tanstack -> runtime), so the alias resolves the
|
|
35
|
-
* Modern.js specific bindings through this `Symbol.for` slot at use time.
|
|
36
|
-
*
|
|
37
|
-
* `??=` keeps the first copy: when Module Federation evaluates a second
|
|
38
|
-
* bundled copy of this module, both copies are functionally identical and the
|
|
39
|
-
* established registration wins (mirroring the router-provider registry).
|
|
40
|
-
*/
|
|
41
|
-
const COMPAT_BINDINGS_SLOT: unique symbol = Symbol.for(
|
|
42
|
-
'@modern-js/plugin-tanstack:runtime-compat-bindings',
|
|
43
|
-
);
|
|
44
|
-
|
|
45
|
-
export const tanstackRouterCompatBindings = {
|
|
46
|
-
Form,
|
|
47
|
-
Link,
|
|
48
|
-
NavLink,
|
|
49
|
-
Outlet,
|
|
50
|
-
RouteActionResponseError,
|
|
51
|
-
useFetcher,
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
(
|
|
55
|
-
globalThis as {
|
|
56
|
-
[COMPAT_BINDINGS_SLOT]?: typeof tanstackRouterCompatBindings;
|
|
57
|
-
}
|
|
58
|
-
)[COMPAT_BINDINGS_SLOT] ??= tanstackRouterCompatBindings;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// @effect-diagnostics asyncFunction:off newPromise:off strictBooleanExpressions:off
|
|
2
|
-
|
|
2
|
+
interface ReplayableStreamOptions {
|
|
3
3
|
signal?: AbortSignal;
|
|
4
4
|
}
|
|
5
5
|
|
|
@@ -8,7 +8,7 @@ type Waiter = {
|
|
|
8
8
|
resolve: () => void;
|
|
9
9
|
};
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
const REPLAYABLE_STREAM_MARKER = Symbol.for(
|
|
12
12
|
'modern.tanstack.rsc.ReplayableStream',
|
|
13
13
|
);
|
|
14
14
|
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import type React from 'react';
|
|
4
4
|
import { createContext, use } from 'react';
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
type SlotImplementations = Record<string, unknown>;
|
|
7
7
|
|
|
8
8
|
const SlotContext = createContext<{
|
|
9
9
|
implementations: SlotImplementations;
|
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
// @effect-diagnostics asyncFunction:off globalFetch:off processEnv:off strictBooleanExpressions:off
|
|
2
2
|
import type { ServerPayload } from '@modern-js/runtime/context';
|
|
3
3
|
import { notFound, redirect } from '@tanstack/react-router';
|
|
4
|
+
import { isAbsoluteUrl } from '../shared/isAbsoluteUrl';
|
|
4
5
|
import { reviveTanstackRscFlightValues } from './flightSerialization';
|
|
5
6
|
|
|
7
|
+
export { isAbsoluteUrl };
|
|
8
|
+
|
|
6
9
|
type PayloadDecoder = (stream: ReadableStream<Uint8Array>) => Promise<unknown>;
|
|
7
10
|
|
|
8
11
|
export const payloadFetchCache = new Map<string, Promise<ServerPayload>>();
|
|
9
12
|
let payloadDecoder: PayloadDecoder | undefined;
|
|
10
13
|
|
|
11
|
-
|
|
14
|
+
async function decodePayload(stream: ReadableStream<Uint8Array>) {
|
|
12
15
|
if (payloadDecoder) {
|
|
13
16
|
return reviveTanstackRscFlightValues(await payloadDecoder(stream));
|
|
14
17
|
}
|
|
@@ -19,7 +22,7 @@ export async function decodePayload(stream: ReadableStream<Uint8Array>) {
|
|
|
19
22
|
);
|
|
20
23
|
}
|
|
21
24
|
|
|
22
|
-
|
|
25
|
+
function isServerPayload(value: unknown): value is ServerPayload {
|
|
23
26
|
return (
|
|
24
27
|
Boolean(value) &&
|
|
25
28
|
typeof value === 'object' &&
|
|
@@ -38,15 +41,6 @@ export function createPayloadFetchKey(request: Request) {
|
|
|
38
41
|
]);
|
|
39
42
|
}
|
|
40
43
|
|
|
41
|
-
export function isAbsoluteUrl(value: string) {
|
|
42
|
-
try {
|
|
43
|
-
void new URL(value);
|
|
44
|
-
return true;
|
|
45
|
-
} catch {
|
|
46
|
-
return false;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
44
|
export async function fetchTanstackRscPayload(request: Request) {
|
|
51
45
|
const headers = new Headers(request.headers);
|
|
52
46
|
headers.set('x-rsc-tree', 'true');
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// @effect-diagnostics asyncFunction:off globalFetch:off processEnv:off strictBooleanExpressions:off
|
|
2
2
|
import type { PayloadRoute, ServerPayload } from '@modern-js/runtime/context';
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
type RouterStaticData = {
|
|
5
5
|
modernRouteAction?: unknown;
|
|
6
6
|
modernRouteHandle?: unknown;
|
|
7
7
|
modernRouteHasAction?: unknown;
|
|
@@ -11,7 +11,7 @@ export type RouterStaticData = {
|
|
|
11
11
|
modernRouteIsClientComponent?: unknown;
|
|
12
12
|
};
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
type RouterRouteLike = {
|
|
15
15
|
id?: unknown;
|
|
16
16
|
options?: {
|
|
17
17
|
index?: unknown;
|
|
@@ -40,7 +40,7 @@ export type TanstackPayloadRouterLike = {
|
|
|
40
40
|
};
|
|
41
41
|
};
|
|
42
42
|
|
|
43
|
-
|
|
43
|
+
function toPlainRecord(value: unknown): Record<string, unknown> {
|
|
44
44
|
if (!value || typeof value !== 'object') {
|
|
45
45
|
return {};
|
|
46
46
|
}
|
|
@@ -73,16 +73,16 @@ export function getRouteId(match: RouterMatchLike) {
|
|
|
73
73
|
return typeof routeId === 'string' ? routeId : undefined;
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
-
|
|
76
|
+
function getRouteStaticData(match: RouterMatchLike) {
|
|
77
77
|
return match.route?.options?.staticData || {};
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
-
|
|
80
|
+
function getRouteParentId(match: RouterMatchLike) {
|
|
81
81
|
const parentId = match.route?.parentRoute?.id;
|
|
82
82
|
return typeof parentId === 'string' ? parentId : undefined;
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
-
|
|
85
|
+
function toRoutePath(match: RouterMatchLike) {
|
|
86
86
|
const path = match.route?.options?.path;
|
|
87
87
|
return typeof path === 'string' ? path : undefined;
|
|
88
88
|
}
|
|
@@ -35,7 +35,7 @@ export function EmptyFallback() {
|
|
|
35
35
|
return null;
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
|
|
38
|
+
function selectTreePath(tree: unknown, path: string[]) {
|
|
39
39
|
let current = tree;
|
|
40
40
|
for (const key of path) {
|
|
41
41
|
if (current === null || typeof current !== 'object') {
|
package/src/runtime/ssrTypes.ts
CHANGED
|
@@ -23,14 +23,14 @@ export type RouterMatchWithError = {
|
|
|
23
23
|
routeId?: unknown;
|
|
24
24
|
};
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
type RouterRouteOptions = {
|
|
27
27
|
component?: unknown;
|
|
28
28
|
errorComponent?: unknown;
|
|
29
29
|
notFoundComponent?: unknown;
|
|
30
30
|
pendingComponent?: unknown;
|
|
31
31
|
};
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
type RouterRouteWithOptions = {
|
|
34
34
|
options?: RouterRouteOptions;
|
|
35
35
|
};
|
|
36
36
|
|
|
@@ -31,14 +31,21 @@ type RouteLoader = (args: {
|
|
|
31
31
|
context?: unknown;
|
|
32
32
|
}) => Promise<unknown> | unknown;
|
|
33
33
|
|
|
34
|
+
type RouterBuildLocationOptions = Parameters<AnyRouter['buildLocation']>[0];
|
|
35
|
+
type RouterBuiltLocation = ReturnType<AnyRouter['buildLocation']> & {
|
|
36
|
+
pathname: string;
|
|
37
|
+
};
|
|
38
|
+
type RouterParsedLocation = Parameters<AnyRouter['getParsedLocationHref']>[0];
|
|
39
|
+
type RouterNavigateOptions = Parameters<AnyRouter['navigate']>[0];
|
|
40
|
+
|
|
34
41
|
function resolveRouteHandlers(router: AnyRouter, actionTo: string) {
|
|
35
42
|
const builtLocation = router.buildLocation({
|
|
36
|
-
to: actionTo
|
|
37
|
-
} as
|
|
38
|
-
const href = router.getParsedLocationHref(
|
|
39
|
-
|
|
40
|
-
(builtLocation as any).pathname,
|
|
43
|
+
to: actionTo,
|
|
44
|
+
} as RouterBuildLocationOptions) as RouterBuiltLocation;
|
|
45
|
+
const href = router.getParsedLocationHref(
|
|
46
|
+
builtLocation as RouterParsedLocation,
|
|
41
47
|
);
|
|
48
|
+
const matchedRoutes = router.getMatchedRoutes(builtLocation.pathname);
|
|
42
49
|
const routeStaticData = matchedRoutes.foundRoute?.options?.staticData as
|
|
43
50
|
| Record<string, unknown>
|
|
44
51
|
| undefined;
|
|
@@ -118,8 +125,8 @@ export async function submitRouteAction({
|
|
|
118
125
|
result.headers.get('Location');
|
|
119
126
|
if (redirectTo || isRedirectResponse(result)) {
|
|
120
127
|
await router.navigate({
|
|
121
|
-
to:
|
|
122
|
-
} as
|
|
128
|
+
to: redirectTo || '/',
|
|
129
|
+
} as RouterNavigateOptions);
|
|
123
130
|
return parseResponseData(result);
|
|
124
131
|
}
|
|
125
132
|
return parseResponseResultOrThrow(result);
|
|
@@ -130,7 +137,7 @@ export async function submitRouteAction({
|
|
|
130
137
|
|
|
131
138
|
await router.navigate({
|
|
132
139
|
href: `${requestUrl.pathname}${requestUrl.search}${requestUrl.hash}`,
|
|
133
|
-
} as
|
|
140
|
+
} as RouterNavigateOptions);
|
|
134
141
|
return;
|
|
135
142
|
}
|
|
136
143
|
|
|
@@ -175,8 +182,8 @@ export async function submitRouteAction({
|
|
|
175
182
|
result.headers.get('Location');
|
|
176
183
|
if (redirectTo || isRedirectResponse(result)) {
|
|
177
184
|
await router.navigate({
|
|
178
|
-
to:
|
|
179
|
-
} as
|
|
185
|
+
to: redirectTo || '/',
|
|
186
|
+
} as RouterNavigateOptions);
|
|
180
187
|
return parseResponseData(result);
|
|
181
188
|
}
|
|
182
189
|
|
package/src/runtime/types.ts
CHANGED
|
@@ -1,22 +1,15 @@
|
|
|
1
|
-
import type { ModernRoute
|
|
1
|
+
import type { ModernRoute } from '@modern-js/runtime/context';
|
|
2
2
|
import type { RouteObject } from '@modern-js/runtime-utils/router';
|
|
3
3
|
import type React from 'react';
|
|
4
4
|
|
|
5
5
|
export type {
|
|
6
|
-
BuiltInRouterFramework,
|
|
7
|
-
InternalRouterRuntimeState,
|
|
8
6
|
InternalRouterServerSnapshot,
|
|
9
|
-
LoaderFunction,
|
|
10
|
-
LoaderFunctionArgs,
|
|
11
7
|
ModernRoute,
|
|
12
8
|
RouterFramework,
|
|
13
|
-
RouterRouteMatchSnapshot,
|
|
14
|
-
RouterServerPrepareResult,
|
|
15
9
|
} from '@modern-js/runtime/context';
|
|
16
10
|
|
|
17
11
|
/** TanStack-specific router config. */
|
|
18
12
|
export type RouterConfig = {
|
|
19
|
-
framework?: RouterFramework;
|
|
20
13
|
routesConfig: {
|
|
21
14
|
globalApp?: React.ComponentType<any>;
|
|
22
15
|
routes?: ModernRoute[];
|
|
@@ -1,46 +1,8 @@
|
|
|
1
1
|
import { resolveRouterProvider } from '@modern-js/runtime/context';
|
|
2
|
-
import
|
|
3
|
-
Form,
|
|
4
|
-
Link,
|
|
5
|
-
NavLink,
|
|
6
|
-
Outlet,
|
|
7
|
-
RouteActionResponseError,
|
|
8
|
-
useFetcher,
|
|
9
|
-
} from '../../src/runtime';
|
|
10
|
-
import { tanstackRouterCompatBindings } from '../../src/runtime/register';
|
|
11
|
-
|
|
12
|
-
const COMPAT_BINDINGS_SLOT = Symbol.for(
|
|
13
|
-
'@modern-js/plugin-tanstack:runtime-compat-bindings',
|
|
14
|
-
);
|
|
2
|
+
import '../../src/runtime/register';
|
|
15
3
|
|
|
16
4
|
describe("'@modern-js/plugin-tanstack/runtime' import side effects", () => {
|
|
17
5
|
it('registers the tanstack router provider', () => {
|
|
18
6
|
expect(typeof resolveRouterProvider('tanstack')).toBe('function');
|
|
19
7
|
});
|
|
20
|
-
|
|
21
|
-
it("publishes the compat bindings consumed by '@modern-js/runtime/tanstack-router'", () => {
|
|
22
|
-
const bindings = (globalThis as Record<symbol, unknown>)[
|
|
23
|
-
COMPAT_BINDINGS_SLOT
|
|
24
|
-
] as typeof tanstackRouterCompatBindings;
|
|
25
|
-
|
|
26
|
-
expect(bindings).toBeDefined();
|
|
27
|
-
expect(bindings).toBe(tanstackRouterCompatBindings);
|
|
28
|
-
expect(bindings.Form).toBe(Form);
|
|
29
|
-
expect(bindings.Link).toBe(Link);
|
|
30
|
-
expect(bindings.NavLink).toBe(NavLink);
|
|
31
|
-
expect(bindings.Outlet).toBe(Outlet);
|
|
32
|
-
expect(bindings.RouteActionResponseError).toBe(RouteActionResponseError);
|
|
33
|
-
expect(bindings.useFetcher).toBe(useFetcher);
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
it('keeps the first published bindings when a duplicate module copy evaluates', () => {
|
|
37
|
-
// Simulates a Module Federation remote evaluating its own copy of
|
|
38
|
-
// register.ts: `??=` must keep the established bindings.
|
|
39
|
-
const host = globalThis as Record<symbol, unknown>;
|
|
40
|
-
const established = host[COMPAT_BINDINGS_SLOT];
|
|
41
|
-
expect(established).toBeDefined();
|
|
42
|
-
|
|
43
|
-
host[COMPAT_BINDINGS_SLOT] ??= { duplicate: true };
|
|
44
|
-
expect(host[COMPAT_BINDINGS_SLOT]).toBe(established);
|
|
45
|
-
});
|
|
46
8
|
});
|