@multiplatform.one/config 6.7.0 → 7.0.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/lib/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import { t as createViteConfig } from "./vite-C6psj1Lz.js";
2
- import { createStorybookViteConfig } from "./storybook.js";
1
+ import { t as createViteConfig } from "./vite-DzOl_bpS.js";
2
+ import { t as createStorybookViteConfig } from "./storybook-CrdwuS_Y.js";
3
3
  import { createVitestConfig } from "./vitest.js";
4
4
 
5
5
  export { createStorybookViteConfig, createViteConfig, createVitestConfig };
@@ -0,0 +1,274 @@
1
+ import { r as resolvePackageMainSource, t as discoverPublicPackageRoots } from "./workspacePublicPackages-COicQSj4.js";
2
+ import { createRequire } from "node:module";
3
+ import fs from "node:fs";
4
+ import path from "node:path";
5
+
6
+ //#region src/unexportedDepAliases.ts
7
+ /**
8
+ * Package subtrees that consumers deep-import but the publisher never declared
9
+ * in its `exports` map.
10
+ *
11
+ * `one`'s `fork/SSRNavigationContainer` (every dist flavour plus its source)
12
+ * imports three `@react-navigation/core` internals:
13
+ *
14
+ * @react-navigation/core/lib/module/NavigationBuilderContext
15
+ * @react-navigation/core/lib/module/NavigationStateContext
16
+ * @react-navigation/core/lib/module/EnsureSingleNavigator
17
+ *
18
+ * The published package exports only "." and "./package.json", so those are
19
+ * undeclared subpaths of a bare specifier — Node rejects them with
20
+ * ERR_PACKAGE_PATH_NOT_EXPORTED and Rolldown (Vite 8) rejects them at build
21
+ * time. Both are behaving correctly; the deep imports are the bug.
22
+ *
23
+ * vxrn papers over it by rewriting the dependency's package.json in place
24
+ * (`vxrn` builtInDepPatches, which leaves a package.json.vxrn.original behind),
25
+ * but that only runs when something invokes vxrn — never during a plain
26
+ * `vite build` or `storybook build`, and never on a fresh CI install. Mapping
27
+ * the subtree to its real directory resolves those files by path, which is
28
+ * exactly where the missing exports entries would have pointed.
29
+ */
30
+ const UNEXPORTED_SUBTREES = ["@react-navigation/core/lib/module"];
31
+ /**
32
+ * Vite `resolve.alias` entries that let known-undeclared package internals
33
+ * resolve by filesystem path.
34
+ *
35
+ * Scoped to one subtree of one package: Vite alias keys match the whole
36
+ * specifier or a `key + "/"` prefix, so sibling paths (`lib/moduleOther`) and
37
+ * the package's own entry (`@react-navigation/core`) keep going through the
38
+ * `exports` map. Nothing here disables exports enforcement globally.
39
+ *
40
+ * Entries are omitted when the package (or the target directory) is absent, so
41
+ * consumers that do not install `one`/react-navigation are unaffected.
42
+ *
43
+ * @param root Directory whose `node_modules` the packages resolve from.
44
+ */
45
+ function unexportedDepAliases(root = process.cwd()) {
46
+ const aliases = {};
47
+ const requireFrom = createRequire(path.join(root, "package.json"));
48
+ for (const specifier of UNEXPORTED_SUBTREES) {
49
+ const [pkgName, subpath] = splitPackageSubpath(specifier);
50
+ const pkgDir = resolvePackageDir(pkgName, root, requireFrom);
51
+ if (!pkgDir) continue;
52
+ const target = path.join(pkgDir, subpath);
53
+ if (fs.existsSync(target)) aliases[specifier] = target;
54
+ }
55
+ return aliases;
56
+ }
57
+ function splitPackageSubpath(specifier) {
58
+ const segments = specifier.split("/");
59
+ const nameLength = specifier.startsWith("@") ? 2 : 1;
60
+ return [segments.slice(0, nameLength).join("/"), segments.slice(nameLength).join("/")];
61
+ }
62
+ function resolvePackageDir(pkgName, root, requireFrom) {
63
+ try {
64
+ return path.dirname(requireFrom.resolve(`${pkgName}/package.json`));
65
+ } catch {
66
+ const hoisted = path.join(root, "node_modules", ...pkgName.split("/"));
67
+ return fs.existsSync(path.join(hoisted, "package.json")) ? hoisted : void 0;
68
+ }
69
+ }
70
+
71
+ //#endregion
72
+ //#region src/storybook.ts
73
+ /**
74
+ * Creates a Vite configuration for Storybook in the multiplatform.one monorepo.
75
+ *
76
+ * Auto-discovers packages/ entries (multiplatform.one, package, and root
77
+ * multiplatform.one scopes) and every workspace package under public/ with a
78
+ * package.json name (including other scopes such as bitspur). Aliases point at
79
+ * TypeScript source; sub-path exports come from each package exports field.
80
+ *
81
+ * Includes React plugin, node:async_hooks stub, and Storybook optimizeDeps.
82
+ *
83
+ * @example
84
+ * ```ts
85
+ * // apps/storybook/vite.config.ts
86
+ * import { createStorybookViteConfig } from "@multiplatform.one/config/storybook";
87
+ *
88
+ * export default createStorybookViteConfig();
89
+ * ```
90
+ */
91
+ function createStorybookViteConfig(options = {}) {
92
+ const workspaceRoot = options.workspaceRoot || findWorkspaceRoot();
93
+ const aliases = {
94
+ ...discoverPackageAliases(path.join(workspaceRoot, "packages")),
95
+ ...discoverPublicPackageViteAliases(workspaceRoot),
96
+ ...unexportedDepAliases(workspaceRoot)
97
+ };
98
+ if (options.aliases) Object.assign(aliases, options.aliases);
99
+ const sortedAliases = {};
100
+ for (const key of Object.keys(aliases).sort((a, b) => b.length - a.length)) sortedAliases[key] = aliases[key];
101
+ return {
102
+ define: {
103
+ "process.env.VITE_ENVIRONMENT": JSON.stringify("client"),
104
+ ...options.define
105
+ },
106
+ resolve: {
107
+ conditions: ["default"],
108
+ extensions: [
109
+ ".storybook.ts",
110
+ ".storybook.tsx",
111
+ ".storybook.js",
112
+ ".storybook.jsx",
113
+ ".web.ts",
114
+ ".web.tsx",
115
+ ".web.js",
116
+ ".web.jsx",
117
+ ".ts",
118
+ ".tsx",
119
+ ".js",
120
+ ".jsx",
121
+ ".mjs",
122
+ ".json"
123
+ ],
124
+ alias: sortedAliases
125
+ },
126
+ optimizeDeps: {
127
+ include: [
128
+ "react",
129
+ "react-dom",
130
+ "react-native-web",
131
+ "@tamagui/core",
132
+ "@tamagui/web",
133
+ "@tamagui/helpers-icon",
134
+ "tamagui",
135
+ "@mdx-js/react",
136
+ "i18next",
137
+ "react-i18next",
138
+ "d3-shape",
139
+ "d3-scale",
140
+ "@storybook-community/storybook-dark-mode",
141
+ "use-latest-callback",
142
+ "escape-string-regexp",
143
+ "use-sync-external-store",
144
+ "use-sync-external-store/with-selector",
145
+ "fast-deep-equal",
146
+ "color",
147
+ "query-string",
148
+ "react-is"
149
+ ],
150
+ exclude: [
151
+ "one/dist/esm/vite/one-server-only.mjs",
152
+ "@storybook/preview-api",
153
+ "@storybook/theming",
154
+ "@react-navigation/core",
155
+ "@react-navigation/native",
156
+ "@react-navigation/routers",
157
+ "@react-navigation/elements",
158
+ "@react-navigation/bottom-tabs",
159
+ "@react-navigation/native-stack"
160
+ ]
161
+ },
162
+ plugins: [nodeAsyncHooksStub(), ...options.plugins || []]
163
+ };
164
+ }
165
+ /**
166
+ * Scans packages/ for workspace packages (multiplatform.one and package scopes)
167
+ * and returns resolve aliases.
168
+ */
169
+ function discoverPackageAliases(packagesDir) {
170
+ const aliases = {};
171
+ if (!fs.existsSync(packagesDir)) return aliases;
172
+ const entries = fs.readdirSync(packagesDir, { withFileTypes: true });
173
+ for (const entry of entries) {
174
+ if (!entry.isDirectory()) continue;
175
+ const pkgDir = path.join(packagesDir, entry.name);
176
+ const pkgJsonPath = path.join(pkgDir, "package.json");
177
+ if (!fs.existsSync(pkgJsonPath)) continue;
178
+ let pkgJson;
179
+ try {
180
+ pkgJson = JSON.parse(fs.readFileSync(pkgJsonPath, "utf-8"));
181
+ } catch {
182
+ continue;
183
+ }
184
+ const pkgName = pkgJson.name;
185
+ if (!pkgName) continue;
186
+ if (!pkgName.startsWith("@multiplatform.one/") && !pkgName.startsWith("@package/") && pkgName !== "multiplatform.one") continue;
187
+ mergePackageResolveAliases(pkgDir, pkgName, pkgJson, aliases);
188
+ }
189
+ return aliases;
190
+ }
191
+ /** All workspace packages under public/ (any npm scope), including export subpaths. */
192
+ function discoverPublicPackageViteAliases(workspaceRoot) {
193
+ const aliases = {};
194
+ for (const [pkgName, pkgDir] of discoverPublicPackageRoots(workspaceRoot)) {
195
+ const pkgJsonPath = path.join(pkgDir, "package.json");
196
+ let pkgJson;
197
+ try {
198
+ pkgJson = JSON.parse(fs.readFileSync(pkgJsonPath, "utf-8"));
199
+ } catch {
200
+ continue;
201
+ }
202
+ mergePackageResolveAliases(pkgDir, pkgName, pkgJson, aliases);
203
+ }
204
+ return aliases;
205
+ }
206
+ function mergePackageResolveAliases(pkgDir, pkgName, pkgJson, aliases) {
207
+ const mainEntry = resolvePackageMainSource(pkgDir);
208
+ if (mainEntry) aliases[pkgName] = mainEntry;
209
+ if (pkgJson.exports && typeof pkgJson.exports === "object") for (const exportKey of Object.keys(pkgJson.exports)) {
210
+ if (exportKey === "." || exportKey === "./package.json") continue;
211
+ const subpath = exportKey.replace(/^\.\//, "");
212
+ if (path.extname(subpath)) {
213
+ const parentDir = path.dirname(subpath);
214
+ if (parentDir && parentDir !== ".") {
215
+ const fullParentDir = path.join(pkgDir, parentDir);
216
+ if (fs.existsSync(fullParentDir) && fs.statSync(fullParentDir).isDirectory()) aliases[`${pkgName}/${parentDir}`] = fullParentDir;
217
+ }
218
+ } else {
219
+ const resolved = resolveSubpathSource(pkgDir, subpath);
220
+ if (resolved) aliases[`${pkgName}/${subpath}`] = resolved;
221
+ }
222
+ }
223
+ }
224
+ function resolveSubpathSource(pkgDir, subpath) {
225
+ const candidates = [
226
+ path.join(pkgDir, "src", `${subpath}.storybook.ts`),
227
+ path.join(pkgDir, "src", `${subpath}.storybook.tsx`),
228
+ path.join(pkgDir, "src", `${subpath}.ts`),
229
+ path.join(pkgDir, "src", `${subpath}.tsx`),
230
+ path.join(pkgDir, "src", subpath, "index.storybook.ts"),
231
+ path.join(pkgDir, "src", subpath, "index.storybook.tsx"),
232
+ path.join(pkgDir, "src", subpath, "index.ts"),
233
+ path.join(pkgDir, "src", subpath, "index.tsx"),
234
+ path.join(pkgDir, `${subpath}.storybook.ts`),
235
+ path.join(pkgDir, `${subpath}.storybook.tsx`),
236
+ path.join(pkgDir, `${subpath}.ts`),
237
+ path.join(pkgDir, `${subpath}.tsx`),
238
+ path.join(pkgDir, subpath, "index.storybook.ts"),
239
+ path.join(pkgDir, subpath, "index.storybook.tsx"),
240
+ path.join(pkgDir, subpath, "index.ts"),
241
+ path.join(pkgDir, subpath, "index.tsx"),
242
+ path.join(pkgDir, subpath, "index.js")
243
+ ];
244
+ for (const c of candidates) if (fs.existsSync(c)) return c;
245
+ const dirPath = path.join(pkgDir, subpath);
246
+ if (fs.existsSync(dirPath) && fs.statSync(dirPath).isDirectory()) return dirPath;
247
+ }
248
+ /** Virtual module plugin that stubs `node:async_hooks` for browser environments. */
249
+ function nodeAsyncHooksStub() {
250
+ return {
251
+ name: "storybook:node-async-hooks-stub",
252
+ resolveId(id) {
253
+ if (id === "node:async_hooks") return "\0node:async_hooks";
254
+ },
255
+ load(id) {
256
+ if (id === "\0node:async_hooks") return "export class AsyncLocalStorage {}";
257
+ }
258
+ };
259
+ }
260
+ function findWorkspaceRoot() {
261
+ let dir = process.cwd();
262
+ while (dir !== path.dirname(dir)) {
263
+ if (fs.existsSync(path.join(dir, "pnpm-workspace.yaml"))) return dir;
264
+ const pkgJsonPath = path.join(dir, "package.json");
265
+ if (fs.existsSync(pkgJsonPath)) try {
266
+ if (JSON.parse(fs.readFileSync(pkgJsonPath, "utf-8")).workspaces) return dir;
267
+ } catch {}
268
+ dir = path.dirname(dir);
269
+ }
270
+ return process.cwd();
271
+ }
272
+
273
+ //#endregion
274
+ export { createStorybookViteConfig as t };
package/lib/storybook.js CHANGED
@@ -1,206 +1,3 @@
1
- import { r as resolvePackageMainSource, t as discoverPublicPackageRoots } from "./workspacePublicPackages-CkDbm3QT.js";
2
- import fs from "node:fs";
3
- import path from "node:path";
1
+ import { t as createStorybookViteConfig } from "./storybook-CrdwuS_Y.js";
4
2
 
5
- //#region src/storybook.ts
6
- /**
7
- * Creates a Vite configuration for Storybook in the multiplatform.one monorepo.
8
- *
9
- * Auto-discovers packages/ entries (multiplatform.one, package, and root
10
- * multiplatform.one scopes) and every workspace package under public/ with a
11
- * package.json name (including other scopes such as bitspur). Aliases point at
12
- * TypeScript source; sub-path exports come from each package exports field.
13
- *
14
- * Includes React plugin, node:async_hooks stub, and Storybook optimizeDeps.
15
- *
16
- * @example
17
- * ```ts
18
- * // apps/storybook/vite.config.ts
19
- * import { createStorybookViteConfig } from "@multiplatform.one/config/storybook";
20
- *
21
- * export default createStorybookViteConfig();
22
- * ```
23
- */
24
- function createStorybookViteConfig(options = {}) {
25
- const workspaceRoot = options.workspaceRoot || findWorkspaceRoot();
26
- const aliases = {
27
- ...discoverPackageAliases(path.join(workspaceRoot, "packages")),
28
- ...discoverPublicPackageViteAliases(workspaceRoot)
29
- };
30
- if (options.aliases) Object.assign(aliases, options.aliases);
31
- const sortedAliases = {};
32
- for (const key of Object.keys(aliases).sort((a, b) => b.length - a.length)) sortedAliases[key] = aliases[key];
33
- return {
34
- define: {
35
- "process.env.VITE_ENVIRONMENT": JSON.stringify("client"),
36
- ...options.define
37
- },
38
- resolve: {
39
- conditions: ["default"],
40
- extensions: [
41
- ".storybook.ts",
42
- ".storybook.tsx",
43
- ".storybook.js",
44
- ".storybook.jsx",
45
- ".web.ts",
46
- ".web.tsx",
47
- ".web.js",
48
- ".web.jsx",
49
- ".ts",
50
- ".tsx",
51
- ".js",
52
- ".jsx",
53
- ".mjs",
54
- ".json"
55
- ],
56
- alias: sortedAliases
57
- },
58
- optimizeDeps: {
59
- include: [
60
- "react",
61
- "react-dom",
62
- "react-native-web",
63
- "@tamagui/core",
64
- "@tamagui/web",
65
- "@tamagui/helpers-icon",
66
- "tamagui",
67
- "@mdx-js/react",
68
- "i18next",
69
- "react-i18next",
70
- "d3-shape",
71
- "d3-scale",
72
- "@storybook-community/storybook-dark-mode",
73
- "use-latest-callback",
74
- "escape-string-regexp",
75
- "use-sync-external-store",
76
- "use-sync-external-store/with-selector",
77
- "fast-deep-equal",
78
- "color",
79
- "query-string",
80
- "react-is"
81
- ],
82
- exclude: [
83
- "one/dist/esm/vite/one-server-only.mjs",
84
- "@storybook/preview-api",
85
- "@storybook/theming",
86
- "@react-navigation/core",
87
- "@react-navigation/native",
88
- "@react-navigation/routers",
89
- "@react-navigation/elements",
90
- "@react-navigation/bottom-tabs",
91
- "@react-navigation/native-stack"
92
- ]
93
- },
94
- plugins: [nodeAsyncHooksStub(), ...options.plugins || []]
95
- };
96
- }
97
- /**
98
- * Scans packages/ for workspace packages (multiplatform.one and package scopes)
99
- * and returns resolve aliases.
100
- */
101
- function discoverPackageAliases(packagesDir) {
102
- const aliases = {};
103
- if (!fs.existsSync(packagesDir)) return aliases;
104
- const entries = fs.readdirSync(packagesDir, { withFileTypes: true });
105
- for (const entry of entries) {
106
- if (!entry.isDirectory()) continue;
107
- const pkgDir = path.join(packagesDir, entry.name);
108
- const pkgJsonPath = path.join(pkgDir, "package.json");
109
- if (!fs.existsSync(pkgJsonPath)) continue;
110
- let pkgJson;
111
- try {
112
- pkgJson = JSON.parse(fs.readFileSync(pkgJsonPath, "utf-8"));
113
- } catch {
114
- continue;
115
- }
116
- const pkgName = pkgJson.name;
117
- if (!pkgName) continue;
118
- if (!pkgName.startsWith("@multiplatform.one/") && !pkgName.startsWith("@package/") && pkgName !== "multiplatform.one") continue;
119
- mergePackageResolveAliases(pkgDir, pkgName, pkgJson, aliases);
120
- }
121
- return aliases;
122
- }
123
- /** All workspace packages under public/ (any npm scope), including export subpaths. */
124
- function discoverPublicPackageViteAliases(workspaceRoot) {
125
- const aliases = {};
126
- for (const [pkgName, pkgDir] of discoverPublicPackageRoots(workspaceRoot)) {
127
- const pkgJsonPath = path.join(pkgDir, "package.json");
128
- let pkgJson;
129
- try {
130
- pkgJson = JSON.parse(fs.readFileSync(pkgJsonPath, "utf-8"));
131
- } catch {
132
- continue;
133
- }
134
- mergePackageResolveAliases(pkgDir, pkgName, pkgJson, aliases);
135
- }
136
- return aliases;
137
- }
138
- function mergePackageResolveAliases(pkgDir, pkgName, pkgJson, aliases) {
139
- const mainEntry = resolvePackageMainSource(pkgDir);
140
- if (mainEntry) aliases[pkgName] = mainEntry;
141
- if (pkgJson.exports && typeof pkgJson.exports === "object") for (const exportKey of Object.keys(pkgJson.exports)) {
142
- if (exportKey === "." || exportKey === "./package.json") continue;
143
- const subpath = exportKey.replace(/^\.\//, "");
144
- if (path.extname(subpath)) {
145
- const parentDir = path.dirname(subpath);
146
- if (parentDir && parentDir !== ".") {
147
- const fullParentDir = path.join(pkgDir, parentDir);
148
- if (fs.existsSync(fullParentDir) && fs.statSync(fullParentDir).isDirectory()) aliases[`${pkgName}/${parentDir}`] = fullParentDir;
149
- }
150
- } else {
151
- const resolved = resolveSubpathSource(pkgDir, subpath);
152
- if (resolved) aliases[`${pkgName}/${subpath}`] = resolved;
153
- }
154
- }
155
- }
156
- function resolveSubpathSource(pkgDir, subpath) {
157
- const candidates = [
158
- path.join(pkgDir, "src", `${subpath}.storybook.ts`),
159
- path.join(pkgDir, "src", `${subpath}.storybook.tsx`),
160
- path.join(pkgDir, "src", `${subpath}.ts`),
161
- path.join(pkgDir, "src", `${subpath}.tsx`),
162
- path.join(pkgDir, "src", subpath, "index.storybook.ts"),
163
- path.join(pkgDir, "src", subpath, "index.storybook.tsx"),
164
- path.join(pkgDir, "src", subpath, "index.ts"),
165
- path.join(pkgDir, "src", subpath, "index.tsx"),
166
- path.join(pkgDir, `${subpath}.storybook.ts`),
167
- path.join(pkgDir, `${subpath}.storybook.tsx`),
168
- path.join(pkgDir, `${subpath}.ts`),
169
- path.join(pkgDir, `${subpath}.tsx`),
170
- path.join(pkgDir, subpath, "index.storybook.ts"),
171
- path.join(pkgDir, subpath, "index.storybook.tsx"),
172
- path.join(pkgDir, subpath, "index.ts"),
173
- path.join(pkgDir, subpath, "index.tsx"),
174
- path.join(pkgDir, subpath, "index.js")
175
- ];
176
- for (const c of candidates) if (fs.existsSync(c)) return c;
177
- const dirPath = path.join(pkgDir, subpath);
178
- if (fs.existsSync(dirPath) && fs.statSync(dirPath).isDirectory()) return dirPath;
179
- }
180
- /** Virtual module plugin that stubs `node:async_hooks` for browser environments. */
181
- function nodeAsyncHooksStub() {
182
- return {
183
- name: "storybook:node-async-hooks-stub",
184
- resolveId(id) {
185
- if (id === "node:async_hooks") return "\0node:async_hooks";
186
- },
187
- load(id) {
188
- if (id === "\0node:async_hooks") return "export class AsyncLocalStorage {}";
189
- }
190
- };
191
- }
192
- function findWorkspaceRoot() {
193
- let dir = process.cwd();
194
- while (dir !== path.dirname(dir)) {
195
- if (fs.existsSync(path.join(dir, "pnpm-workspace.yaml"))) return dir;
196
- const pkgJsonPath = path.join(dir, "package.json");
197
- if (fs.existsSync(pkgJsonPath)) try {
198
- if (JSON.parse(fs.readFileSync(pkgJsonPath, "utf-8")).workspaces) return dir;
199
- } catch {}
200
- dir = path.dirname(dir);
201
- }
202
- return process.cwd();
203
- }
204
-
205
- //#endregion
206
3
  export { createStorybookViteConfig };
@@ -1,4 +1,4 @@
1
- import { t as discoverPublicPackageRoots } from "./workspacePublicPackages-CkDbm3QT.js";
1
+ import { t as discoverPublicPackageRoots } from "./workspacePublicPackages-COicQSj4.js";
2
2
  import { createRequire } from "node:module";
3
3
  import fs from "node:fs";
4
4
  import path from "node:path";
@@ -77,7 +77,7 @@ function lookupProjectRoot() {
77
77
  * ```
78
78
  */
79
79
  function createViteConfig(options = {}) {
80
- const { projectRoot: _projectRoot, publicConfigKeys = [], tamagui = true, i18n = false, one = false, ssr, server, plugins: extraPlugins = [], externalReactRouter, ssrDeps, ssrEntries } = options;
80
+ const { projectRoot: _projectRoot, publicConfigKeys = [], tamagui = true, i18n = false, one = false, ssr, server, plugins: extraPlugins = [], externalReactRouter, ssrDeps, ssrEntries, ssrCjsExternal, nativeFixes } = options;
81
81
  const projectRoot = _projectRoot || findProjectRoot();
82
82
  dotenv.config({ path: path.resolve(projectRoot, ".env") });
83
83
  if (publicConfigKeys.length > 0) process.env.VITE_MP_CONFIG = JSON.stringify(resolveConfig(publicConfigKeys));
@@ -89,6 +89,9 @@ function createViteConfig(options = {}) {
89
89
  registerNativeEngineIoBrowserTransports();
90
90
  registerNativeWorkspaceEntries();
91
91
  registerNativePhosphorIcons();
92
+ if (nativeFixes?.protoShadow !== false) registerNativeProtoShadowFix();
93
+ if (nativeFixes?.web3Stub !== false) registerNativeWeb3Stub();
94
+ if (ssrCjsExternal !== false) vitePlugins.push(ssrCjsExternalFixPlugin([...DEFAULT_SSR_CJS_EXTERNAL, ...ssrCjsExternal ?? []]));
92
95
  }
93
96
  if (tamagui) {
94
97
  const tamaguiOpts = typeof tamagui === "object" ? tamagui : {};
@@ -324,6 +327,111 @@ function registerNativeWorkspaceEntries() {
324
327
  }
325
328
  });
326
329
  }
330
+ /**
331
+ * CJS-only ids (no usable ESM build) that escape Vite's SSR dep optimizer and
332
+ * hit the ESM evaluator ("module is not defined" / "exports is not defined")
333
+ * unless Node's native CJS loader handles them. Union of the lists the
334
+ * monorepo's apps/one and downstream consumer apps (desibox) carried as
335
+ * app-side ssrExternalFix plugins; ids for packages an app never imports are
336
+ * inert, so one shared default list is safe.
337
+ */
338
+ const DEFAULT_SSR_CJS_EXTERNAL = [
339
+ "better-sqlite3",
340
+ "dotenv",
341
+ "color",
342
+ "use-sync-external-store",
343
+ "use-sync-external-store/shim",
344
+ "use-sync-external-store/shim/with-selector",
345
+ "highlight.js",
346
+ "highlight.js/lib/core",
347
+ "turndown",
348
+ "@mixmark-io/domino",
349
+ "lowlight",
350
+ "shallowequal",
351
+ "@emotion/is-prop-valid",
352
+ "hoist-non-react-statics",
353
+ "qrcode"
354
+ ];
355
+ /**
356
+ * Force-append CJS-only ids to `ssr.external`. The one() plugin REPLACES
357
+ * ssr.external with its own list during the config hook, dropping anything
358
+ * set statically by createViteConfig — configResolved runs after all config
359
+ * hooks are merged, so appends here survive.
360
+ */
361
+ function ssrCjsExternalFixPlugin(extras) {
362
+ return {
363
+ name: "multiplatform-ssr-cjs-external-fix",
364
+ configResolved(config) {
365
+ const external = config.ssr.external ?? [];
366
+ if (!Array.isArray(external)) return;
367
+ for (const e of extras) if (!external.includes(e)) external.push(e);
368
+ config.ssr.external = external;
369
+ }
370
+ };
371
+ }
372
+ /**
373
+ * Restore Object.prototype methods shadowed by hoisted globals on NATIVE.
374
+ *
375
+ * vxrn's rolldown native mode emits the whole dev bundle as ONE classic
376
+ * script and forces Hermes V1. Hermes V1 implements spec-compliant global
377
+ * var hoisting, so a flattened module's top-level `var hasOwnProperty`
378
+ * (e.g. acorn via an mdx pipeline) creates
379
+ * `globalThis.hasOwnProperty = undefined` at parse time, shadowing
380
+ * Object.prototype.hasOwnProperty for the entire runtime. React Native core
381
+ * calls `global.hasOwnProperty()` during boot (FuseboxSessionObserver) and
382
+ * dies with "undefined is not a function". Prepend a snippet that copies any
383
+ * Object.prototype method back over an undefined shadowing own-property
384
+ * before any module code runs — the shadowed vars are reassigned by their
385
+ * own modules on init, so this only bridges the parse-to-init window.
386
+ * Registered through globalThis.__vxrnAddNativePlugins (vxrn's native engine
387
+ * ignores vite resolve/config). Web/SSR bundles are ESM (module-scoped vars)
388
+ * and unaffected.
389
+ */
390
+ function registerNativeProtoShadowFix() {
391
+ const g = globalThis;
392
+ const name = "vxrn-proto-shadow-fix";
393
+ g.__vxrnAddNativePlugins = g.__vxrnAddNativePlugins ?? [];
394
+ if (g.__vxrnAddNativePlugins.some((p) => p?.name === name)) return;
395
+ const snippet = "(function(){var p=Object.prototype,h=p.hasOwnProperty,ns=Object.getOwnPropertyNames(p);for(var i=0;i<ns.length;i++){var k=ns[i];if(typeof p[k]===\"function\"&&globalThis[k]===void 0&&h.call(globalThis,k)){try{globalThis[k]=p[k]}catch(e){}}}})();";
396
+ g.__vxrnAddNativePlugins.push({
397
+ name,
398
+ renderChunk(code) {
399
+ return {
400
+ code: `${snippet}\n${code}`,
401
+ map: null
402
+ };
403
+ }
404
+ });
405
+ }
406
+ /**
407
+ * Redirect the OPTIONAL `@multiplatform.one/web3` native import to a no-op
408
+ * shim on NATIVE when the package is not installed (see the nativeFixes
409
+ * option docs). Rolldown leaves the unresolvable specifier as a bare dynamic
410
+ * `import()` in the classic-script native bundle — Hermes rejects that at
411
+ * lazy-compile time ("SyntaxError: Invalid expression encountered"), killing
412
+ * the root _layout route. Web/SSR resolve the same specifier through vite's
413
+ * normal pipeline and are unaffected.
414
+ */
415
+ function registerNativeWeb3Stub() {
416
+ const g = globalThis;
417
+ const name = "vxrn-web3-stub";
418
+ g.__vxrnAddNativePlugins = g.__vxrnAddNativePlugins ?? [];
419
+ if (g.__vxrnAddNativePlugins.some((p) => p?.name === name)) return;
420
+ try {
421
+ __require.resolve("@multiplatform.one/web3", { paths: [findProjectRoot(), process.cwd()] });
422
+ return;
423
+ } catch {}
424
+ const here = path.dirname(new URL(import.meta.url).pathname);
425
+ const shim = [path.resolve(here, "shims/web3Stub.native.js"), path.resolve(here, "../src/shims/web3Stub.native.js")].find((candidate) => fs.existsSync(candidate));
426
+ if (!shim) return;
427
+ g.__vxrnAddNativePlugins.push({
428
+ name,
429
+ resolveId(id) {
430
+ if (id === "@multiplatform.one/web3/native" || id === "@multiplatform.one/web3") return shim;
431
+ return null;
432
+ }
433
+ });
434
+ }
327
435
  function findProjectRoot() {
328
436
  try {
329
437
  const { execSync } = __require("node:child_process");
package/lib/vite.js CHANGED
@@ -1,4 +1,4 @@
1
- import { t as createViteConfig } from "./vite-C6psj1Lz.js";
2
- import { n as publicPackageViteSourceAliases, t as discoverPublicPackageRoots } from "./workspacePublicPackages-CkDbm3QT.js";
1
+ import { t as createViteConfig } from "./vite-DzOl_bpS.js";
2
+ import { n as publicPackageViteSourceAliases, t as discoverPublicPackageRoots } from "./workspacePublicPackages-COicQSj4.js";
3
3
 
4
4
  export { createViteConfig, discoverPublicPackageRoots, publicPackageViteSourceAliases };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@multiplatform.one/config",
3
- "version": "6.7.0",
3
+ "version": "7.0.0",
4
4
  "description": "Shared build and test configuration presets for multiplatform.one",
5
5
  "keywords": [
6
6
  "config",
@@ -80,14 +80,14 @@
80
80
  "access": "public"
81
81
  },
82
82
  "dependencies": {
83
- "@tamagui/vite-plugin": "2.0.0-rc.41",
83
+ "@tamagui/vite-plugin": "2.7.6",
84
84
  "@vitejs/plugin-react": "^6.0.1",
85
85
  "dotenv": "^17.4.2",
86
86
  "vite": "^8.0.10",
87
87
  "vite-plugin-external": "^6.2.2",
88
88
  "vite-plugin-i18next-loader": "^3.1.3",
89
89
  "vitest": "^4.1.5",
90
- "@multiplatform.one/utils": "6.7.0"
90
+ "@multiplatform.one/utils": "7.0.0"
91
91
  },
92
92
  "devDependencies": {
93
93
  "tsdown": "^0.21.10",
@@ -110,6 +110,7 @@
110
110
  },
111
111
  "scripts": {
112
112
  "typecheck": "tsgo --noEmit",
113
- "build": "rm -rf lib types 2>/dev/null && tsc -p tsconfig.build.json && tsdown"
113
+ "build": "rm -rf lib types 2>/dev/null && tsc -p tsconfig.build.json && tsdown",
114
+ "test": "vitest run --coverage --coverage.provider=v8 --coverage.reporter=text --coverage.reporter=lcov --coverage.reporter=html"
114
115
  }
115
116
  }
@@ -0,0 +1,18 @@
1
+ /**
2
+ * No-op `@multiplatform.one/web3(/native)` shim for NATIVE runs.
3
+ *
4
+ * `@multiplatform.one/core`'s loadWalletProvider.native.ts lazily
5
+ * `import("@multiplatform.one/web3/native")` — an OPTIONAL package many apps
6
+ * do not install. vxrn's rolldown native bundler leaves the unresolvable
7
+ * specifier as a bare dynamic `import()` expression in the classic-script
8
+ * bundle, which Hermes rejects at lazy-compile time with "SyntaxError:
9
+ * Invalid expression encountered", killing the root _layout route.
10
+ * createViteConfig's registerNativeWeb3Stub redirects the specifier here so
11
+ * the import inlines and parses; it auto-skips when web3 is installed.
12
+ *
13
+ * Plain JS (not TS): vxrn's native pipeline does not transform node_modules
14
+ * TypeScript.
15
+ */
16
+ export function WalletProvider({ children }) {
17
+ return children ?? null;
18
+ }
package/src/storybook.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import fs from "node:fs";
2
2
  import path from "node:path";
3
3
  import type { Plugin, UserConfig } from "vite";
4
+ import { unexportedDepAliases } from "./unexportedDepAliases.js";
4
5
  import { discoverPublicPackageRoots, resolvePackageMainSource } from "./workspacePublicPackages.js";
5
6
 
6
7
  export interface CreateStorybookViteConfigOptions {
@@ -54,6 +55,7 @@ export function createStorybookViteConfig(
54
55
  const aliases = {
55
56
  ...discoverPackageAliases(packagesDir),
56
57
  ...discoverPublicPackageViteAliases(workspaceRoot),
58
+ ...unexportedDepAliases(workspaceRoot),
57
59
  };
58
60
 
59
61
  if (options.aliases) {
@@ -81,10 +83,18 @@ export function createStorybookViteConfig(
81
83
  // transitive deps (color, query-string, etc.) to be served raw,
82
84
  // causing "require is not defined" / missing-export errors in the browser.
83
85
  //
84
- // "default" must be included: Rolldown 8 strictly enforces exports fields
85
- // and requires "default" in the conditions list to resolve unconditional
86
- // (plain-string) sub-path exports, e.g. @react-navigation/core's
87
- // "./lib/module/EnsureSingleNavigator" entry.
86
+ // This list does NOT resolve @react-navigation/core's internals. Those are
87
+ // undeclared subpaths, so no condition can reach them see
88
+ // unexportedDepAliases, which maps them by filesystem path instead.
89
+ //
90
+ // "default" must be included: Rolldown 8 strictly enforces exports
91
+ // fields and needs "default" in the conditions list to reach a target
92
+ // that is only reachable through the default branch — including the
93
+ // "./lib/module/*" subpath patches/@react-navigation__core@7.17.2.patch
94
+ // adds, which one's SSRNavigationContainer fork deep-imports. Stock
95
+ // 7.17.2 exports only "." and "./package.json", so no condition list
96
+ // alone resolves those files; the patch is what makes them reachable
97
+ // and this entry is what lets the resolver pick its default target.
88
98
  conditions: ["default"],
89
99
  extensions: [
90
100
  ".storybook.ts",
@@ -141,11 +151,11 @@ export function createStorybookViteConfig(
141
151
  "query-string",
142
152
  "react-is",
143
153
  ],
144
- // Rolldown rc.10+ enforces exports fields strictly @react-navigation/core has
145
- // internal files (EnsureSingleNavigator etc.) not listed in its exports map,
146
- // causing dep pre-bundle to crash. Exclude the nav packages from pre-bundling;
147
- // their CJS transitive deps (color, use-sync-external-store, fast-deep-equal)
148
- // are already explicitly in include above so they are still pre-bundled.
154
+ // Keeps the nav packages out of dep pre-bundling; their CJS transitive deps
155
+ // (color, use-sync-external-store, fast-deep-equal) are already explicitly in
156
+ // include above so they are still pre-bundled. Note this only covers the dev
157
+ // optimizer the undeclared @react-navigation/core internals that `one`
158
+ // deep-imports are handled for dev AND build by unexportedDepAliases.
149
159
  exclude: [
150
160
  "one/dist/esm/vite/one-server-only.mjs",
151
161
  "@storybook/preview-api",
@@ -0,0 +1,90 @@
1
+ import fs from "node:fs";
2
+ import { createRequire } from "node:module";
3
+ import os from "node:os";
4
+ import path from "node:path";
5
+ import { afterAll, beforeAll, describe, expect, it } from "vitest";
6
+ import { unexportedDepAliases } from "./unexportedDepAliases";
7
+
8
+ /**
9
+ * Builds a throwaway tree carrying the PUBLISHED @react-navigation/core exports
10
+ * map — the one CI installs, before vxrn rewrites it in place. The real tree on
11
+ * a dev machine is usually already patched, so asserting against it would prove
12
+ * nothing about the state this alias exists for.
13
+ */
14
+ function writePristineFixture(root: string, { withPackage = true } = {}) {
15
+ fs.mkdirSync(root, { recursive: true });
16
+ fs.writeFileSync(path.join(root, "package.json"), JSON.stringify({ name: "fixture-root" }));
17
+ if (!withPackage) return;
18
+
19
+ const pkgDir = path.join(root, "node_modules", "@react-navigation", "core");
20
+ fs.mkdirSync(path.join(pkgDir, "lib", "module"), { recursive: true });
21
+ fs.writeFileSync(
22
+ path.join(pkgDir, "package.json"),
23
+ JSON.stringify({
24
+ name: "@react-navigation/core",
25
+ version: "7.17.2",
26
+ main: "./lib/module/index.js",
27
+ // Verbatim shape of the published manifest: no ./lib/module/* entries.
28
+ exports: { ".": { default: "./lib/module/index.js" }, "./package.json": "./package.json" },
29
+ }),
30
+ );
31
+ fs.writeFileSync(
32
+ path.join(pkgDir, "lib", "module", "EnsureSingleNavigator.js"),
33
+ "export const SingleNavigatorContext = {};\n",
34
+ );
35
+ fs.writeFileSync(path.join(pkgDir, "lib", "module", "index.js"), "export const x = 1;\n");
36
+ }
37
+
38
+ describe("unexportedDepAliases", () => {
39
+ // realpath: macOS /var is a symlink to /private/var, and require.resolve
40
+ // reports the resolved path.
41
+ const root = fs.realpathSync(fs.mkdtempSync(path.join(os.tmpdir(), "unexported-dep-aliases-")));
42
+ const deepSpecifier = "@react-navigation/core/lib/module/EnsureSingleNavigator";
43
+
44
+ beforeAll(() => writePristineFixture(root));
45
+ afterAll(() => fs.rmSync(root, { recursive: true, force: true }));
46
+
47
+ it("positive control: the published exports map really does reject the deep import", () => {
48
+ // Without this, every assertion below could be green against a package that
49
+ // resolves fine on its own — i.e. an alias guarding nothing.
50
+ const requireFrom = createRequire(path.join(root, "package.json"));
51
+ expect(() => requireFrom.resolve(deepSpecifier)).toThrowError(
52
+ expect.objectContaining({ code: "ERR_PACKAGE_PATH_NOT_EXPORTED" }),
53
+ );
54
+ });
55
+
56
+ it("maps the internals `one` deep-imports onto a directory that holds them", () => {
57
+ const aliases = unexportedDepAliases(root);
58
+ const target = aliases["@react-navigation/core/lib/module"];
59
+
60
+ expect(target).toBe(
61
+ path.join(root, "node_modules", "@react-navigation", "core", "lib", "module"),
62
+ );
63
+ // The alias is only worth anything if rewriting the specifier lands on a
64
+ // real file — Vite replaces the matched key and resolves the rest by path.
65
+ const rewritten = deepSpecifier.replace("@react-navigation/core/lib/module", target);
66
+ expect(fs.existsSync(`${rewritten}.js`)).toBe(true);
67
+ });
68
+
69
+ it("scopes the alias to the subtree, leaving the package entry on its exports map", () => {
70
+ const keys = Object.keys(unexportedDepAliases(root));
71
+
72
+ // Vite matches an alias key exactly or as a `key + "/"` prefix. A bare
73
+ // "@react-navigation/core" key would swallow the package's own entry, and a
74
+ // trailing slash would stop the key matching at all.
75
+ expect(keys).toEqual(["@react-navigation/core/lib/module"]);
76
+ expect(keys[0]).not.toMatch(/\/$/);
77
+ });
78
+
79
+ it("emits nothing when the package is not installed", () => {
80
+ const bare = fs.realpathSync(
81
+ fs.mkdtempSync(path.join(os.tmpdir(), "unexported-dep-aliases-bare-")),
82
+ );
83
+ writePristineFixture(bare, { withPackage: false });
84
+ try {
85
+ expect(unexportedDepAliases(bare)).toEqual({});
86
+ } finally {
87
+ fs.rmSync(bare, { recursive: true, force: true });
88
+ }
89
+ });
90
+ });
@@ -0,0 +1,77 @@
1
+ import fs from "node:fs";
2
+ import { createRequire } from "node:module";
3
+ import path from "node:path";
4
+
5
+ /**
6
+ * Package subtrees that consumers deep-import but the publisher never declared
7
+ * in its `exports` map.
8
+ *
9
+ * `one`'s `fork/SSRNavigationContainer` (every dist flavour plus its source)
10
+ * imports three `@react-navigation/core` internals:
11
+ *
12
+ * @react-navigation/core/lib/module/NavigationBuilderContext
13
+ * @react-navigation/core/lib/module/NavigationStateContext
14
+ * @react-navigation/core/lib/module/EnsureSingleNavigator
15
+ *
16
+ * The published package exports only "." and "./package.json", so those are
17
+ * undeclared subpaths of a bare specifier — Node rejects them with
18
+ * ERR_PACKAGE_PATH_NOT_EXPORTED and Rolldown (Vite 8) rejects them at build
19
+ * time. Both are behaving correctly; the deep imports are the bug.
20
+ *
21
+ * vxrn papers over it by rewriting the dependency's package.json in place
22
+ * (`vxrn` builtInDepPatches, which leaves a package.json.vxrn.original behind),
23
+ * but that only runs when something invokes vxrn — never during a plain
24
+ * `vite build` or `storybook build`, and never on a fresh CI install. Mapping
25
+ * the subtree to its real directory resolves those files by path, which is
26
+ * exactly where the missing exports entries would have pointed.
27
+ */
28
+ const UNEXPORTED_SUBTREES: readonly string[] = ["@react-navigation/core/lib/module"];
29
+
30
+ /**
31
+ * Vite `resolve.alias` entries that let known-undeclared package internals
32
+ * resolve by filesystem path.
33
+ *
34
+ * Scoped to one subtree of one package: Vite alias keys match the whole
35
+ * specifier or a `key + "/"` prefix, so sibling paths (`lib/moduleOther`) and
36
+ * the package's own entry (`@react-navigation/core`) keep going through the
37
+ * `exports` map. Nothing here disables exports enforcement globally.
38
+ *
39
+ * Entries are omitted when the package (or the target directory) is absent, so
40
+ * consumers that do not install `one`/react-navigation are unaffected.
41
+ *
42
+ * @param root Directory whose `node_modules` the packages resolve from.
43
+ */
44
+ export function unexportedDepAliases(root: string = process.cwd()): Record<string, string> {
45
+ const aliases: Record<string, string> = {};
46
+ const requireFrom = createRequire(path.join(root, "package.json"));
47
+
48
+ for (const specifier of UNEXPORTED_SUBTREES) {
49
+ const [pkgName, subpath] = splitPackageSubpath(specifier);
50
+ const pkgDir = resolvePackageDir(pkgName, root, requireFrom);
51
+ if (!pkgDir) continue;
52
+ const target = path.join(pkgDir, subpath);
53
+ if (fs.existsSync(target)) aliases[specifier] = target;
54
+ }
55
+
56
+ return aliases;
57
+ }
58
+
59
+ function splitPackageSubpath(specifier: string): [pkgName: string, subpath: string] {
60
+ const segments = specifier.split("/");
61
+ const nameLength = specifier.startsWith("@") ? 2 : 1;
62
+ return [segments.slice(0, nameLength).join("/"), segments.slice(nameLength).join("/")];
63
+ }
64
+
65
+ function resolvePackageDir(
66
+ pkgName: string,
67
+ root: string,
68
+ requireFrom: NodeRequire,
69
+ ): string | undefined {
70
+ try {
71
+ return path.dirname(requireFrom.resolve(`${pkgName}/package.json`));
72
+ } catch {
73
+ // Packages that don't export "./package.json" can't be resolved that way.
74
+ const hoisted = path.join(root, "node_modules", ...pkgName.split("/"));
75
+ return fs.existsSync(path.join(hoisted, "package.json")) ? hoisted : undefined;
76
+ }
77
+ }
@@ -0,0 +1,117 @@
1
+ /**
2
+ * createViteConfig — absorbed consumer workarounds (ssr CJS externals +
3
+ * native Hermes fixes). These used to live per-app (apps/one and downstream
4
+ * consumer vite configs); the spec pins the shared defaults and their
5
+ * escape hatches.
6
+ */
7
+
8
+ import { beforeEach, describe, expect, it } from "vitest";
9
+ import type { Plugin } from "vite";
10
+ import { createViteConfig } from "./vite.js";
11
+
12
+ type NativePlugin = {
13
+ name?: string;
14
+ renderChunk?: (code: string) => { code: string; map: null };
15
+ };
16
+
17
+ const globalWithNativePlugins = globalThis as unknown as {
18
+ __vxrnAddNativePlugins?: NativePlugin[];
19
+ };
20
+
21
+ function findPlugin(config: ReturnType<typeof createViteConfig>, name: string): Plugin | undefined {
22
+ return (config.plugins as Plugin[]).flat().find((p) => p && (p as Plugin).name === name) as
23
+ | Plugin
24
+ | undefined;
25
+ }
26
+
27
+ function runConfigResolved(plugin: Plugin, ssrExternal: string[] | boolean | undefined) {
28
+ const fakeConfig = { ssr: { external: ssrExternal } } as any;
29
+ (plugin.configResolved as any)(fakeConfig);
30
+ return fakeConfig.ssr.external;
31
+ }
32
+
33
+ beforeEach(() => {
34
+ // Native fix registration is global and deduped — reset between tests.
35
+ delete globalWithNativePlugins.__vxrnAddNativePlugins;
36
+ });
37
+
38
+ describe("ssrCjsExternal", () => {
39
+ it("appends the default CJS-only ids to ssr.external after one() replaces the list", () => {
40
+ const config = createViteConfig({ one: true });
41
+ const plugin = findPlugin(config, "multiplatform-ssr-cjs-external-fix");
42
+ expect(plugin).toBeDefined();
43
+ // Simulate one() having replaced ssr.external with its own list.
44
+ const external = runConfigResolved(plugin!, ["one-framework-entry"]) as string[];
45
+ expect(external).toContain("one-framework-entry");
46
+ expect(external).toContain("use-sync-external-store");
47
+ expect(external).toContain("use-sync-external-store/shim/with-selector");
48
+ expect(external).toContain("highlight.js/lib/core");
49
+ expect(external).toContain("turndown");
50
+ expect(external).toContain("@mixmark-io/domino");
51
+ expect(external).toContain("qrcode");
52
+ });
53
+
54
+ it("does not duplicate ids already present", () => {
55
+ const config = createViteConfig({ one: true });
56
+ const plugin = findPlugin(config, "multiplatform-ssr-cjs-external-fix");
57
+ const external = runConfigResolved(plugin!, ["use-sync-external-store"]) as string[];
58
+ expect(external.filter((e) => e === "use-sync-external-store")).toHaveLength(1);
59
+ });
60
+
61
+ it("extends the default list with consumer extras", () => {
62
+ const config = createViteConfig({ one: true, ssrCjsExternal: ["my-cjs-dep"] });
63
+ const plugin = findPlugin(config, "multiplatform-ssr-cjs-external-fix");
64
+ const external = runConfigResolved(plugin!, []) as string[];
65
+ expect(external).toContain("my-cjs-dep");
66
+ expect(external).toContain("use-sync-external-store");
67
+ });
68
+
69
+ it("leaves ssr.external: true untouched (everything already external)", () => {
70
+ const config = createViteConfig({ one: true });
71
+ const plugin = findPlugin(config, "multiplatform-ssr-cjs-external-fix");
72
+ expect(runConfigResolved(plugin!, true)).toBe(true);
73
+ });
74
+
75
+ it("can be disabled with ssrCjsExternal: false", () => {
76
+ const config = createViteConfig({ one: true, ssrCjsExternal: false });
77
+ expect(findPlugin(config, "multiplatform-ssr-cjs-external-fix")).toBeUndefined();
78
+ });
79
+
80
+ it("is not added without the one framework", () => {
81
+ const config = createViteConfig({ one: false });
82
+ expect(findPlugin(config, "multiplatform-ssr-cjs-external-fix")).toBeUndefined();
83
+ });
84
+ });
85
+
86
+ describe("nativeFixes.protoShadow", () => {
87
+ it("registers the Hermes proto-shadow renderChunk fix by default", () => {
88
+ createViteConfig({ one: true });
89
+ const plugin = globalWithNativePlugins.__vxrnAddNativePlugins?.find(
90
+ (p) => p.name === "vxrn-proto-shadow-fix",
91
+ );
92
+ expect(plugin).toBeDefined();
93
+ const result = plugin!.renderChunk!("var x = 1;");
94
+ // The restore snippet is PREPENDED so it runs before any module code.
95
+ expect(result.code.endsWith("var x = 1;")).toBe(true);
96
+ expect(result.code).toContain("Object.prototype");
97
+ expect(result.code).toContain("hasOwnProperty");
98
+ });
99
+
100
+ it("can be disabled with nativeFixes.protoShadow: false", () => {
101
+ createViteConfig({ one: true, nativeFixes: { protoShadow: false } });
102
+ expect(
103
+ globalWithNativePlugins.__vxrnAddNativePlugins?.some(
104
+ (p) => p.name === "vxrn-proto-shadow-fix",
105
+ ),
106
+ ).toBeFalsy();
107
+ });
108
+ });
109
+
110
+ describe("nativeFixes.web3Stub", () => {
111
+ it("auto-skips when @multiplatform.one/web3 is installed (monorepo has it)", () => {
112
+ createViteConfig({ one: true });
113
+ expect(
114
+ globalWithNativePlugins.__vxrnAddNativePlugins?.some((p) => p.name === "vxrn-web3-stub"),
115
+ ).toBeFalsy();
116
+ });
117
+ });
package/src/vite.ts CHANGED
@@ -114,6 +114,41 @@ export interface CreateViteConfigOptions {
114
114
  * Only used when `one` is enabled.
115
115
  */
116
116
  ssrEntries?: string[];
117
+
118
+ /**
119
+ * CJS-only package ids force-appended to `ssr.external` AFTER the one()
120
+ * plugin replaces the list (via configResolved), so Node's native CJS
121
+ * loader handles them instead of Vite's ESM evaluator (which chokes on
122
+ * `module.exports` with "module is not defined"). Only used when `one` is
123
+ * enabled. Defaults to a list covering use-sync-external-store,
124
+ * highlight.js, turndown, and friends; pass an array to EXTEND the default
125
+ * list or `false` to disable entirely.
126
+ */
127
+ ssrCjsExternal?: string[] | false;
128
+
129
+ /**
130
+ * Native (vxrn rolldown / Hermes) workaround toggles. Only used when `one`
131
+ * is enabled; all default to true.
132
+ */
133
+ nativeFixes?: {
134
+ /**
135
+ * Prepend a snippet to the classic-script native bundle that restores
136
+ * Object.prototype methods shadowed by hoisted top-level vars (Hermes V1
137
+ * spec-compliant var hoisting turns a flattened module's
138
+ * `var hasOwnProperty` into `globalThis.hasOwnProperty = undefined` at
139
+ * parse time, and React Native core dies at boot calling it).
140
+ */
141
+ protoShadow?: boolean;
142
+ /**
143
+ * When `@multiplatform.one/web3` is NOT installed, redirect the OPTIONAL
144
+ * `@multiplatform.one/web3/native` import (from core's
145
+ * loadWalletProvider.native.ts) to a no-op shim — rolldown otherwise
146
+ * leaves the unresolvable specifier as a bare dynamic `import()` in the
147
+ * classic-script bundle, which Hermes rejects at lazy-compile time.
148
+ * Auto-skipped when web3 is installed.
149
+ */
150
+ web3Stub?: boolean;
151
+ };
117
152
  }
118
153
 
119
154
  /**
@@ -150,6 +185,8 @@ export function createViteConfig(options: CreateViteConfigOptions = {}): UserCon
150
185
  externalReactRouter,
151
186
  ssrDeps,
152
187
  ssrEntries,
188
+ ssrCjsExternal,
189
+ nativeFixes,
153
190
  } = options;
154
191
 
155
192
  const projectRoot = _projectRoot || findProjectRoot();
@@ -189,6 +226,19 @@ export function createViteConfig(options: CreateViteConfigOptions = {}): UserCon
189
226
  // react-native-svg, so source keeps importing @phosphor-icons/react and
190
227
  // native transparently gets the RN implementation.
191
228
  registerNativePhosphorIcons();
229
+ // Hermes V1 hoisted-var Object.prototype shadow fix (see the nativeFixes
230
+ // option docs). Every rolldown classic-script native bundle is exposed.
231
+ if (nativeFixes?.protoShadow !== false) registerNativeProtoShadowFix();
232
+ // Optional-web3 stub for apps that don't install @multiplatform.one/web3
233
+ // (auto-skipped when the package resolves).
234
+ if (nativeFixes?.web3Stub !== false) registerNativeWeb3Stub();
235
+ // CJS-only ids must land on ssr.external AFTER the one() plugin replaces
236
+ // the list during config — configResolved runs last, so the appends stick.
237
+ if (ssrCjsExternal !== false) {
238
+ vitePlugins.push(
239
+ ssrCjsExternalFixPlugin([...DEFAULT_SSR_CJS_EXTERNAL, ...(ssrCjsExternal ?? [])]),
240
+ );
241
+ }
192
242
  }
193
243
 
194
244
  // Tamagui plugin
@@ -571,6 +621,132 @@ function registerNativeWorkspaceEntries(): void {
571
621
  });
572
622
  }
573
623
 
624
+ /**
625
+ * CJS-only ids (no usable ESM build) that escape Vite's SSR dep optimizer and
626
+ * hit the ESM evaluator ("module is not defined" / "exports is not defined")
627
+ * unless Node's native CJS loader handles them. Union of the lists the
628
+ * monorepo's apps/one and downstream consumer apps (desibox) carried as
629
+ * app-side ssrExternalFix plugins; ids for packages an app never imports are
630
+ * inert, so one shared default list is safe.
631
+ */
632
+ const DEFAULT_SSR_CJS_EXTERNAL = [
633
+ "better-sqlite3",
634
+ "dotenv",
635
+ "color",
636
+ "use-sync-external-store",
637
+ "use-sync-external-store/shim",
638
+ "use-sync-external-store/shim/with-selector",
639
+ "highlight.js",
640
+ "highlight.js/lib/core",
641
+ "turndown",
642
+ "@mixmark-io/domino",
643
+ "lowlight",
644
+ // CJS-only (module.exports / exports, no usable ESM build) pulled in by
645
+ // connectkit/wagmi/framer-motion.
646
+ "shallowequal",
647
+ "@emotion/is-prop-valid",
648
+ "hoist-non-react-statics",
649
+ "qrcode",
650
+ ];
651
+
652
+ /**
653
+ * Force-append CJS-only ids to `ssr.external`. The one() plugin REPLACES
654
+ * ssr.external with its own list during the config hook, dropping anything
655
+ * set statically by createViteConfig — configResolved runs after all config
656
+ * hooks are merged, so appends here survive.
657
+ */
658
+ function ssrCjsExternalFixPlugin(extras: string[]): Plugin {
659
+ return {
660
+ name: "multiplatform-ssr-cjs-external-fix",
661
+ configResolved(config) {
662
+ const external = config.ssr.external ?? [];
663
+ if (!Array.isArray(external)) return; // true = everything external already
664
+ for (const e of extras) {
665
+ if (!external.includes(e)) external.push(e);
666
+ }
667
+ (config.ssr as { external?: string[] | boolean }).external = external;
668
+ },
669
+ };
670
+ }
671
+
672
+ /**
673
+ * Restore Object.prototype methods shadowed by hoisted globals on NATIVE.
674
+ *
675
+ * vxrn's rolldown native mode emits the whole dev bundle as ONE classic
676
+ * script and forces Hermes V1. Hermes V1 implements spec-compliant global
677
+ * var hoisting, so a flattened module's top-level `var hasOwnProperty`
678
+ * (e.g. acorn via an mdx pipeline) creates
679
+ * `globalThis.hasOwnProperty = undefined` at parse time, shadowing
680
+ * Object.prototype.hasOwnProperty for the entire runtime. React Native core
681
+ * calls `global.hasOwnProperty()` during boot (FuseboxSessionObserver) and
682
+ * dies with "undefined is not a function". Prepend a snippet that copies any
683
+ * Object.prototype method back over an undefined shadowing own-property
684
+ * before any module code runs — the shadowed vars are reassigned by their
685
+ * own modules on init, so this only bridges the parse-to-init window.
686
+ * Registered through globalThis.__vxrnAddNativePlugins (vxrn's native engine
687
+ * ignores vite resolve/config). Web/SSR bundles are ESM (module-scoped vars)
688
+ * and unaffected.
689
+ */
690
+ function registerNativeProtoShadowFix(): void {
691
+ const g = globalThis as unknown as { __vxrnAddNativePlugins?: unknown[] };
692
+ const name = "vxrn-proto-shadow-fix";
693
+ g.__vxrnAddNativePlugins = g.__vxrnAddNativePlugins ?? [];
694
+ if (g.__vxrnAddNativePlugins.some((p) => (p as { name?: string })?.name === name)) return;
695
+ const snippet =
696
+ `(function(){var p=Object.prototype,h=p.hasOwnProperty,ns=Object.getOwnPropertyNames(p);` +
697
+ `for(var i=0;i<ns.length;i++){var k=ns[i];` +
698
+ `if(typeof p[k]==="function"&&globalThis[k]===void 0&&h.call(globalThis,k)){` +
699
+ `try{globalThis[k]=p[k]}catch(e){}}}})();`;
700
+ g.__vxrnAddNativePlugins.push({
701
+ name,
702
+ renderChunk(code: string) {
703
+ return { code: `${snippet}\n${code}`, map: null };
704
+ },
705
+ });
706
+ }
707
+
708
+ /**
709
+ * Redirect the OPTIONAL `@multiplatform.one/web3` native import to a no-op
710
+ * shim on NATIVE when the package is not installed (see the nativeFixes
711
+ * option docs). Rolldown leaves the unresolvable specifier as a bare dynamic
712
+ * `import()` in the classic-script native bundle — Hermes rejects that at
713
+ * lazy-compile time ("SyntaxError: Invalid expression encountered"), killing
714
+ * the root _layout route. Web/SSR resolve the same specifier through vite's
715
+ * normal pipeline and are unaffected.
716
+ */
717
+ function registerNativeWeb3Stub(): void {
718
+ const g = globalThis as unknown as { __vxrnAddNativePlugins?: unknown[] };
719
+ const name = "vxrn-web3-stub";
720
+ g.__vxrnAddNativePlugins = g.__vxrnAddNativePlugins ?? [];
721
+ if (g.__vxrnAddNativePlugins.some((p) => (p as { name?: string })?.name === name)) return;
722
+ try {
723
+ // web3 installed — its real native entry resolves; no stub needed.
724
+ require.resolve("@multiplatform.one/web3", { paths: [findProjectRoot(), process.cwd()] });
725
+ return;
726
+ } catch {
727
+ // not installed — stub below
728
+ }
729
+ // The shim ships as plain JS (vxrn does not transform node_modules TS).
730
+ // Resolve it relative to this module: `src/shims/` when running from
731
+ // source, `../src/shims/` from the built `lib/` bundle (src ships in the
732
+ // published tarball).
733
+ const here = path.dirname(new URL(import.meta.url).pathname);
734
+ const shim = [
735
+ path.resolve(here, "shims/web3Stub.native.js"),
736
+ path.resolve(here, "../src/shims/web3Stub.native.js"),
737
+ ].find((candidate) => fs.existsSync(candidate));
738
+ if (!shim) return;
739
+ g.__vxrnAddNativePlugins.push({
740
+ name,
741
+ resolveId(id: string) {
742
+ if (id === "@multiplatform.one/web3/native" || id === "@multiplatform.one/web3") {
743
+ return shim;
744
+ }
745
+ return null;
746
+ },
747
+ });
748
+ }
749
+
574
750
  function findProjectRoot(): string {
575
751
  try {
576
752
  const { execSync } = require("node:child_process");
@@ -1 +1 @@
1
- {"version":3,"file":"storybook.d.ts","sourceRoot":"","sources":["../src/storybook.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAU,UAAU,EAAE,MAAM,MAAM,CAAC;AAG/C,MAAM,WAAW,gCAAgC;IAC/C;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAEjC;;OAEG;IACH,OAAO,CAAC,EAAE,UAAU,CAAC,SAAS,CAAC,CAAC;IAEhC;;OAEG;IACH,MAAM,CAAC,EAAE,UAAU,CAAC,QAAQ,CAAC,CAAC;CAC/B;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,yBAAyB,CACvC,OAAO,GAAE,gCAAqC,GAC7C,UAAU,CAiHZ"}
1
+ {"version":3,"file":"storybook.d.ts","sourceRoot":"","sources":["../src/storybook.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAU,UAAU,EAAE,MAAM,MAAM,CAAC;AAI/C,MAAM,WAAW,gCAAgC;IAC/C;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAEjC;;OAEG;IACH,OAAO,CAAC,EAAE,UAAU,CAAC,SAAS,CAAC,CAAC;IAEhC;;OAEG;IACH,MAAM,CAAC,EAAE,UAAU,CAAC,QAAQ,CAAC,CAAC;CAC/B;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,yBAAyB,CACvC,OAAO,GAAE,gCAAqC,GAC7C,UAAU,CA0HZ"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Vite `resolve.alias` entries that let known-undeclared package internals
3
+ * resolve by filesystem path.
4
+ *
5
+ * Scoped to one subtree of one package: Vite alias keys match the whole
6
+ * specifier or a `key + "/"` prefix, so sibling paths (`lib/moduleOther`) and
7
+ * the package's own entry (`@react-navigation/core`) keep going through the
8
+ * `exports` map. Nothing here disables exports enforcement globally.
9
+ *
10
+ * Entries are omitted when the package (or the target directory) is absent, so
11
+ * consumers that do not install `one`/react-navigation are unaffected.
12
+ *
13
+ * @param root Directory whose `node_modules` the packages resolve from.
14
+ */
15
+ export declare function unexportedDepAliases(root?: string): Record<string, string>;
16
+ //# sourceMappingURL=unexportedDepAliases.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unexportedDepAliases.d.ts","sourceRoot":"","sources":["../src/unexportedDepAliases.ts"],"names":[],"mappings":"AA6BA;;;;;;;;;;;;;GAaG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,GAAE,MAAsB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAazF"}
package/types/vite.d.ts CHANGED
@@ -95,6 +95,39 @@ export interface CreateViteConfigOptions {
95
95
  * Only used when `one` is enabled.
96
96
  */
97
97
  ssrEntries?: string[];
98
+ /**
99
+ * CJS-only package ids force-appended to `ssr.external` AFTER the one()
100
+ * plugin replaces the list (via configResolved), so Node's native CJS
101
+ * loader handles them instead of Vite's ESM evaluator (which chokes on
102
+ * `module.exports` with "module is not defined"). Only used when `one` is
103
+ * enabled. Defaults to a list covering use-sync-external-store,
104
+ * highlight.js, turndown, and friends; pass an array to EXTEND the default
105
+ * list or `false` to disable entirely.
106
+ */
107
+ ssrCjsExternal?: string[] | false;
108
+ /**
109
+ * Native (vxrn rolldown / Hermes) workaround toggles. Only used when `one`
110
+ * is enabled; all default to true.
111
+ */
112
+ nativeFixes?: {
113
+ /**
114
+ * Prepend a snippet to the classic-script native bundle that restores
115
+ * Object.prototype methods shadowed by hoisted top-level vars (Hermes V1
116
+ * spec-compliant var hoisting turns a flattened module's
117
+ * `var hasOwnProperty` into `globalThis.hasOwnProperty = undefined` at
118
+ * parse time, and React Native core dies at boot calling it).
119
+ */
120
+ protoShadow?: boolean;
121
+ /**
122
+ * When `@multiplatform.one/web3` is NOT installed, redirect the OPTIONAL
123
+ * `@multiplatform.one/web3/native` import (from core's
124
+ * loadWalletProvider.native.ts) to a no-op shim — rolldown otherwise
125
+ * leaves the unresolvable specifier as a bare dynamic `import()` in the
126
+ * classic-script bundle, which Hermes rejects at lazy-compile time.
127
+ * Auto-skipped when web3 is installed.
128
+ */
129
+ web3Stub?: boolean;
130
+ };
98
131
  }
99
132
  /**
100
133
  * Creates a shared Vite configuration for multiplatform.one apps.
@@ -1 +1 @@
1
- {"version":3,"file":"vite.d.ts","sourceRoot":"","sources":["../src/vite.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAU,UAAU,EAAE,MAAM,MAAM,CAAC;AAI/C,MAAM,WAAW,uBAAuB;IACtC;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;;OAGG;IACH,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAE5B;;OAEG;IACH,OAAO,CAAC,EACJ,OAAO,GACP;QACE;;;WAGG;QACH,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;QAEtB;;;WAGG;QACH,MAAM,CAAC,EAAE,MAAM,CAAC;QAEhB;;WAEG;QACH,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC;IAEN;;OAEG;IACH,IAAI,CAAC,EACD,OAAO,GACP;QACE;;;WAGG;QACH,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;QAEjB;;WAEG;QACH,mBAAmB,CAAC,EAAE,MAAM,CAAC;KAC9B,CAAC;IAEN;;;OAGG;IACH,GAAG,CAAC,EACA,OAAO,GACP;QACE,MAAM,CAAC,EAAE;YAAE,IAAI,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC;QAC3B,GAAG,CAAC,EAAE;YAAE,MAAM,CAAC,EAAE,MAAM,CAAC;YAAC,iBAAiB,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC;QACtD,KAAK,CAAC,EAAE;YAAE,QAAQ,CAAC,EAAE,OAAO,CAAA;SAAE,CAAC;QAC/B,MAAM,CAAC,EAAE;YAAE,GAAG,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC;QAC1B,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KAChC,CAAC;IAEN;;OAEG;IACH,GAAG,CAAC,EAAE,UAAU,CAAC,KAAK,CAAC,CAAC;IAExB;;OAEG;IACH,MAAM,CAAC,EAAE,UAAU,CAAC,QAAQ,CAAC,CAAC;IAE9B;;OAEG;IACH,OAAO,CAAC,EAAE,UAAU,CAAC,SAAS,CAAC,CAAC;IAEhC;;OAEG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAE9B;;OAEG;IACH,OAAO,CAAC,EAAE;QACR,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;QACnB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;QACnB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;KACrB,CAAC;IAEF;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;CACvB;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,GAAE,uBAA4B,GAAG,UAAU,CA0QlF;AAED,OAAO,EACL,0BAA0B,EAC1B,8BAA8B,GAC/B,MAAM,8BAA8B,CAAC"}
1
+ {"version":3,"file":"vite.d.ts","sourceRoot":"","sources":["../src/vite.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAU,UAAU,EAAE,MAAM,MAAM,CAAC;AAI/C,MAAM,WAAW,uBAAuB;IACtC;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;;OAGG;IACH,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAE5B;;OAEG;IACH,OAAO,CAAC,EACJ,OAAO,GACP;QACE;;;WAGG;QACH,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;QAEtB;;;WAGG;QACH,MAAM,CAAC,EAAE,MAAM,CAAC;QAEhB;;WAEG;QACH,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC;IAEN;;OAEG;IACH,IAAI,CAAC,EACD,OAAO,GACP;QACE;;;WAGG;QACH,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;QAEjB;;WAEG;QACH,mBAAmB,CAAC,EAAE,MAAM,CAAC;KAC9B,CAAC;IAEN;;;OAGG;IACH,GAAG,CAAC,EACA,OAAO,GACP;QACE,MAAM,CAAC,EAAE;YAAE,IAAI,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC;QAC3B,GAAG,CAAC,EAAE;YAAE,MAAM,CAAC,EAAE,MAAM,CAAC;YAAC,iBAAiB,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC;QACtD,KAAK,CAAC,EAAE;YAAE,QAAQ,CAAC,EAAE,OAAO,CAAA;SAAE,CAAC;QAC/B,MAAM,CAAC,EAAE;YAAE,GAAG,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC;QAC1B,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KAChC,CAAC;IAEN;;OAEG;IACH,GAAG,CAAC,EAAE,UAAU,CAAC,KAAK,CAAC,CAAC;IAExB;;OAEG;IACH,MAAM,CAAC,EAAE,UAAU,CAAC,QAAQ,CAAC,CAAC;IAE9B;;OAEG;IACH,OAAO,CAAC,EAAE,UAAU,CAAC,SAAS,CAAC,CAAC;IAEhC;;OAEG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAE9B;;OAEG;IACH,OAAO,CAAC,EAAE;QACR,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;QACnB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;QACnB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;KACrB,CAAC;IAEF;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IAEtB;;;;;;;;OAQG;IACH,cAAc,CAAC,EAAE,MAAM,EAAE,GAAG,KAAK,CAAC;IAElC;;;OAGG;IACH,WAAW,CAAC,EAAE;QACZ;;;;;;WAMG;QACH,WAAW,CAAC,EAAE,OAAO,CAAC;QACtB;;;;;;;WAOG;QACH,QAAQ,CAAC,EAAE,OAAO,CAAC;KACpB,CAAC;CACH;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,GAAE,uBAA4B,GAAG,UAAU,CAyRlF;AAED,OAAO,EACL,0BAA0B,EAC1B,8BAA8B,GAC/B,MAAM,8BAA8B,CAAC"}