@multiplatform.one/core 7.4.1 → 7.6.0
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@multiplatform.one/core",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.6.0",
|
|
4
4
|
"description": "Core framework shell, provider composition, and layout factories for multiplatform.one",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"app",
|
|
@@ -47,11 +47,11 @@
|
|
|
47
47
|
"@tanstack/react-devtools": "^0.10.2",
|
|
48
48
|
"@tanstack/react-form-devtools": "0.2.22",
|
|
49
49
|
"react-cookie": "^8.1.2",
|
|
50
|
-
"@multiplatform.one/i18n": "7.
|
|
51
|
-
"@multiplatform.one/logger": "7.
|
|
52
|
-
"@multiplatform.one/platform": "7.
|
|
53
|
-
"@multiplatform.one/store": "7.
|
|
54
|
-
"@multiplatform.one/theme": "7.
|
|
50
|
+
"@multiplatform.one/i18n": "7.6.0",
|
|
51
|
+
"@multiplatform.one/logger": "7.6.0",
|
|
52
|
+
"@multiplatform.one/platform": "7.6.0",
|
|
53
|
+
"@multiplatform.one/store": "7.6.0",
|
|
54
|
+
"@multiplatform.one/theme": "7.6.0"
|
|
55
55
|
},
|
|
56
56
|
"devDependencies": {
|
|
57
57
|
"@sentry/react": "^10.51.0",
|
|
@@ -69,8 +69,8 @@
|
|
|
69
69
|
"tamagui": "2.7.6",
|
|
70
70
|
"typescript": "~5.9.3",
|
|
71
71
|
"vitest": "^4.1.5",
|
|
72
|
-
"@multiplatform.one/frappe": "7.
|
|
73
|
-
"@multiplatform.one/web3": "7.
|
|
72
|
+
"@multiplatform.one/frappe": "7.6.0",
|
|
73
|
+
"@multiplatform.one/web3": "7.6.0"
|
|
74
74
|
},
|
|
75
75
|
"peerDependencies": {
|
|
76
76
|
"@sentry/react": "^9.0.0",
|
|
@@ -86,10 +86,10 @@
|
|
|
86
86
|
"react-native-gesture-handler": ">=2.0.0",
|
|
87
87
|
"react-native-safe-area-context": ">=4.0.0",
|
|
88
88
|
"tamagui": "^2.0.0-rc",
|
|
89
|
-
"@multiplatform.one/frappe": "^7.
|
|
90
|
-
"@multiplatform.one/frappe-ui": "^7.
|
|
91
|
-
"@multiplatform.one/keycloak": "^7.
|
|
92
|
-
"@multiplatform.one/web3": "^7.
|
|
89
|
+
"@multiplatform.one/frappe": "^7.6.0",
|
|
90
|
+
"@multiplatform.one/frappe-ui": "^7.6.0",
|
|
91
|
+
"@multiplatform.one/keycloak": "^7.6.0",
|
|
92
|
+
"@multiplatform.one/web3": "^7.6.0"
|
|
93
93
|
},
|
|
94
94
|
"peerDependenciesMeta": {
|
|
95
95
|
"@multiplatform.one/web3": {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { SchemeProvider, useUserScheme } from "@vxrn/color-scheme";
|
|
2
2
|
import { useFonts } from "expo-font";
|
|
3
3
|
import i18n from "i18next";
|
|
4
|
-
import { Slot } from "one";
|
|
4
|
+
import { Slot, routerStore } from "one";
|
|
5
5
|
import type { ComponentType, ReactNode } from "react";
|
|
6
6
|
import { StyleSheet } from "react-native";
|
|
7
7
|
import { GestureHandlerRootView } from "react-native-gesture-handler";
|
|
@@ -58,6 +58,21 @@ export function createRootLayout(cfg: CreateRootLayoutConfig): ComponentType {
|
|
|
58
58
|
}
|
|
59
59
|
DeepLinkBridge.displayName = "DeepLinkBridge";
|
|
60
60
|
|
|
61
|
+
// One's native usePathname() reads useRouteInfo().pathname. For a layout
|
|
62
|
+
// node that is the store's routeInfo, which is undefined from module load
|
|
63
|
+
// until initialize() runs setupLinkingAndRouteInfo() (and then notifies
|
|
64
|
+
// store subscribers — not root-state subscribers). Rendering RootLayout
|
|
65
|
+
// in that window throws `Cannot read property 'pathname' of undefined`
|
|
66
|
+
// into RootErrorBoundary and the app never boots (MPO-24). useOneRouter
|
|
67
|
+
// is the store subscription, so the consumer layout's first paint is the
|
|
68
|
+
// one where routeInfo already exists (initial path is "/").
|
|
69
|
+
function NativeRootLayout({ children }: { children: ReactNode }) {
|
|
70
|
+
const snap = routerStore.useOneRouter();
|
|
71
|
+
if (!snap?.routeInfo) return children;
|
|
72
|
+
return <RootLayout>{children}</RootLayout>;
|
|
73
|
+
}
|
|
74
|
+
NativeRootLayout.displayName = "NativeRootLayout";
|
|
75
|
+
|
|
61
76
|
function Layout() {
|
|
62
77
|
const [fontsLoaded, fontError] = useFonts(fontsMap);
|
|
63
78
|
// Gate on fonts being ready, but never block forever: if font loading
|
|
@@ -70,9 +85,9 @@ export function createRootLayout(cfg: CreateRootLayoutConfig): ComponentType {
|
|
|
70
85
|
<SchemeProvider>
|
|
71
86
|
<NativeRootProvider>
|
|
72
87
|
{cfg.deepLinks !== false && <DeepLinkBridge />}
|
|
73
|
-
<
|
|
88
|
+
<NativeRootLayout>
|
|
74
89
|
<Slot />
|
|
75
|
-
</
|
|
90
|
+
</NativeRootLayout>
|
|
76
91
|
</NativeRootProvider>
|
|
77
92
|
</SchemeProvider>
|
|
78
93
|
</SafeAreaProvider>
|
|
@@ -1,10 +1,23 @@
|
|
|
1
1
|
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
|
2
|
-
import { Suspense, lazy, type PropsWithChildren } from "react";
|
|
2
|
+
import { Suspense, lazy, useEffect, useState, type PropsWithChildren } from "react";
|
|
3
3
|
import { platform } from "@multiplatform.one/platform";
|
|
4
4
|
import type { ProviderComponent, TanstackConfig } from "./CreateApp";
|
|
5
5
|
|
|
6
6
|
const LazyDevtools = lazy(() => import("./TanstackDevtools"));
|
|
7
7
|
|
|
8
|
+
/**
|
|
9
|
+
* True only after hydration has finished on the client. `useEffect` never
|
|
10
|
+
* runs on the server and does not run during the hydration render, so the
|
|
11
|
+
* server markup and the first client render agree on `false`.
|
|
12
|
+
*/
|
|
13
|
+
function useHydrated(): boolean {
|
|
14
|
+
const [hydrated, setHydrated] = useState(false);
|
|
15
|
+
useEffect(() => {
|
|
16
|
+
setHydrated(true);
|
|
17
|
+
}, []);
|
|
18
|
+
return hydrated;
|
|
19
|
+
}
|
|
20
|
+
|
|
8
21
|
export function createTanstackProvider(tanstackConfig: TanstackConfig): ProviderComponent {
|
|
9
22
|
const queryClient = new QueryClient({
|
|
10
23
|
defaultOptions: {
|
|
@@ -20,7 +33,18 @@ export function createTanstackProvider(tanstackConfig: TanstackConfig): Provider
|
|
|
20
33
|
// TODO(native): TanStack Devtools does not yet support React Native. When it does,
|
|
21
34
|
// revisit this guard to also handle native (e.g. !platform.isNative) so devtools
|
|
22
35
|
// are enabled on native when supported.
|
|
23
|
-
const
|
|
36
|
+
const wantsDevtools = tanstackConfig.debug && !platform.isStorybook;
|
|
37
|
+
const hydrated = useHydrated();
|
|
38
|
+
|
|
39
|
+
// Devtools mount CLIENT-ONLY, after hydration. Rendering the lazy
|
|
40
|
+
// component inside a fallback-less <Suspense> during SSR made the server
|
|
41
|
+
// suspend on a chunk that only exists in the browser, and React raced
|
|
42
|
+
// that boundary against Fizz streaming: suspense markers leaked into the
|
|
43
|
+
// served document under a cold module cache, which broke the marketplace
|
|
44
|
+
// SSR smoke (SHC-329). Apps worked around it with per-app vite rewrites;
|
|
45
|
+
// gating here retires those. Nothing devtools-related reaches the server
|
|
46
|
+
// renderer now, so the served document is identical with debug on or off.
|
|
47
|
+
const showDevtools = wantsDevtools && hydrated;
|
|
24
48
|
|
|
25
49
|
const scheme = tanstackConfig.useUserScheme?.();
|
|
26
50
|
const resolvedScheme = scheme?.value ?? "light";
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MPO-8 / SHC-329 regression guard.
|
|
3
|
+
*
|
|
4
|
+
* The devtools used to render as `lazy()` inside a fallback-less <Suspense>
|
|
5
|
+
* whenever `debug` was on. On the server that boundary suspends on a chunk
|
|
6
|
+
* that only exists in the browser, and React raced it against Fizz
|
|
7
|
+
* streaming — suspense markers (`<!--$?-->`, `<template id="B:0">`) landed in
|
|
8
|
+
* the served document under a cold module cache and broke the marketplace SSR
|
|
9
|
+
* smoke. Apps papered over it with per-app vite rewrites.
|
|
10
|
+
*
|
|
11
|
+
* The rule now: nothing devtools-related reaches the server renderer, so the
|
|
12
|
+
* served document is identical with debug on or off, and the overlay mounts
|
|
13
|
+
* client-side after hydration instead.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { renderToString } from "react-dom/server";
|
|
17
|
+
import { describe, expect, it } from "vitest";
|
|
18
|
+
import { createTanstackProvider } from "./TanstackProvider";
|
|
19
|
+
import type { TanstackConfig } from "./CreateApp";
|
|
20
|
+
|
|
21
|
+
function ssr(config: TanstackConfig) {
|
|
22
|
+
const Provider = createTanstackProvider(config);
|
|
23
|
+
return renderToString(
|
|
24
|
+
<Provider>
|
|
25
|
+
<main>app</main>
|
|
26
|
+
</Provider>,
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
describe("createTanstackProvider on the server", () => {
|
|
31
|
+
it("serves the same document with debug on and off", () => {
|
|
32
|
+
expect(ssr({ debug: true })).toBe(ssr({ debug: false }));
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
// Without the client-only gate this renders
|
|
36
|
+
// `<!--$!--><template data-msg="Switched to client rendering…` — the exact
|
|
37
|
+
// marker family that leaked into the marketplace document.
|
|
38
|
+
it("emits no suspense seam when debug is on", () => {
|
|
39
|
+
const html = ssr({ debug: true });
|
|
40
|
+
expect(html).toBe("<main>app</main>");
|
|
41
|
+
expect(html).not.toContain("<!--$");
|
|
42
|
+
expect(html).not.toContain("<template");
|
|
43
|
+
});
|
|
44
|
+
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CreateRootLayout.native.d.ts","sourceRoot":"","sources":["../../src/app/CreateRootLayout.native.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAa,MAAM,OAAO,CAAC;AAQtD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAGjE,YAAY,EACV,sBAAsB,EACtB,UAAU,EACV,eAAe,EACf,cAAc,EACd,YAAY,GACb,MAAM,oBAAoB,CAAC;AAM5B;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,sBAAsB,GAAG,aAAa,
|
|
1
|
+
{"version":3,"file":"CreateRootLayout.native.d.ts","sourceRoot":"","sources":["../../src/app/CreateRootLayout.native.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAa,MAAM,OAAO,CAAC;AAQtD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAGjE,YAAY,EACV,sBAAsB,EACtB,UAAU,EACV,eAAe,EACf,cAAc,EACd,YAAY,GACb,MAAM,oBAAoB,CAAC;AAM5B;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,sBAAsB,GAAG,aAAa,CA+D3E"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TanstackProvider.d.ts","sourceRoot":"","sources":["../../src/app/TanstackProvider.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"TanstackProvider.d.ts","sourceRoot":"","sources":["../../src/app/TanstackProvider.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAiBrE,wBAAgB,sBAAsB,CAAC,cAAc,EAAE,cAAc,GAAG,iBAAiB,CA4CxF"}
|