every-plugin 3.0.0-rc.0 → 3.0.0-rc.11
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/build/rspack/chunk-completeness-plugin.cjs +19 -7
- package/dist/build/rspack/chunk-completeness-plugin.cjs.map +1 -1
- package/dist/build/rspack/chunk-completeness-plugin.mjs +19 -7
- package/dist/build/rspack/chunk-completeness-plugin.mjs.map +1 -1
- package/dist/build/ui/generated-config.cjs +4 -0
- package/dist/build/ui/generated-config.cjs.map +1 -1
- package/dist/build/ui/generated-config.d.cts.map +1 -1
- package/dist/build/ui/generated-config.d.mts.map +1 -1
- package/dist/build/ui/generated-config.mjs +4 -1
- package/dist/build/ui/generated-config.mjs.map +1 -1
- package/dist/build/ui/rsbuild-config.cjs +1 -0
- package/dist/build/ui/rsbuild-config.cjs.map +1 -1
- package/dist/build/ui/rsbuild-config.mjs +1 -0
- package/dist/build/ui/rsbuild-config.mjs.map +1 -1
- package/dist/client.cjs +69 -0
- package/dist/client.cjs.map +1 -0
- package/dist/client.d.cts +15 -0
- package/dist/client.d.cts.map +1 -0
- package/dist/client.d.mts +15 -0
- package/dist/client.d.mts.map +1 -0
- package/dist/client.mjs +68 -0
- package/dist/client.mjs.map +1 -0
- package/dist/dev/host.cjs +149 -0
- package/dist/dev/host.cjs.map +1 -0
- package/dist/dev/host.d.cts +32 -0
- package/dist/dev/host.d.cts.map +1 -0
- package/dist/dev/host.d.mts +32 -0
- package/dist/dev/host.d.mts.map +1 -0
- package/dist/dev/host.mjs +148 -0
- package/dist/dev/host.mjs.map +1 -0
- package/dist/dev/serve.cjs +16 -111
- package/dist/dev/serve.cjs.map +1 -1
- package/dist/dev/serve.d.cts.map +1 -1
- package/dist/dev/serve.d.mts.map +1 -1
- package/dist/dev/serve.mjs +17 -112
- package/dist/dev/serve.mjs.map +1 -1
- package/dist/errors.cjs +1 -0
- package/dist/errors.cjs.map +1 -1
- package/dist/errors.d.cts +2 -2
- package/dist/errors.d.mts +2 -2
- package/dist/errors.mjs +2 -2
- package/dist/errors.mjs.map +1 -1
- package/dist/index.cjs +3 -0
- package/dist/index.d.cts +5 -4
- package/dist/index.d.mts +5 -4
- package/dist/index.mjs +3 -2
- package/dist/plugin.cjs +1 -0
- package/dist/plugin.cjs.map +1 -1
- package/dist/plugin.d.cts +23 -3
- package/dist/plugin.d.cts.map +1 -1
- package/dist/plugin.d.mts +22 -2
- package/dist/plugin.d.mts.map +1 -1
- package/dist/plugin.mjs +1 -0
- package/dist/plugin.mjs.map +1 -1
- package/dist/remote-entry.cjs +0 -1
- package/dist/remote-entry.cjs.map +1 -1
- package/dist/remote-entry.d.cts +1 -2
- package/dist/remote-entry.d.cts.map +1 -1
- package/dist/remote-entry.d.mts +1 -2
- package/dist/remote-entry.d.mts.map +1 -1
- package/dist/remote-entry.mjs +1 -1
- package/dist/remote-entry.mjs.map +1 -1
- package/dist/runtime/errors.cjs +20 -0
- package/dist/runtime/errors.cjs.map +1 -1
- package/dist/runtime/errors.d.cts +23 -1
- package/dist/runtime/errors.d.cts.map +1 -1
- package/dist/runtime/errors.d.mts +23 -1
- package/dist/runtime/errors.d.mts.map +1 -1
- package/dist/runtime/errors.mjs +20 -1
- package/dist/runtime/errors.mjs.map +1 -1
- package/dist/runtime/mf-config.cjs +1 -1
- package/dist/runtime/mf-config.mjs +1 -1
- package/dist/runtime/services/module-federation.service.cjs +1 -7
- package/dist/runtime/services/module-federation.service.cjs.map +1 -1
- package/dist/runtime/services/module-federation.service.mjs +1 -7
- package/dist/runtime/services/module-federation.service.mjs.map +1 -1
- package/dist/runtime/services/plugin-loader.service.cjs +29 -1
- package/dist/runtime/services/plugin-loader.service.cjs.map +1 -1
- package/dist/runtime/services/plugin-loader.service.d.cts +2 -2
- package/dist/runtime/services/plugin-loader.service.mjs +29 -1
- package/dist/runtime/services/plugin-loader.service.mjs.map +1 -1
- package/dist/runtime/services/shared-identity.cjs +1 -1
- package/dist/runtime/services/shared-identity.cjs.map +1 -1
- package/dist/runtime/services/shared-identity.mjs +1 -1
- package/dist/runtime/services/shared-identity.mjs.map +1 -1
- package/dist/types.d.cts +27 -2
- package/dist/types.d.cts.map +1 -1
- package/dist/types.d.mts +26 -1
- package/dist/types.d.mts.map +1 -1
- package/dist/ui/manifest/construct.cjs +69 -18
- package/dist/ui/manifest/construct.cjs.map +1 -1
- package/dist/ui/manifest/construct.d.cts.map +1 -1
- package/dist/ui/manifest/construct.d.mts.map +1 -1
- package/dist/ui/manifest/construct.mjs +69 -18
- package/dist/ui/manifest/construct.mjs.map +1 -1
- package/dist/ui/manifest/generator.cjs +1 -1
- package/dist/ui/manifest/generator.mjs +1 -1
- package/dist/ui/manifest/index.cjs +1 -1
- package/dist/ui/manifest/index.mjs +1 -1
- package/dist/version-manifest.cjs +14 -2
- package/dist/version-manifest.cjs.map +1 -1
- package/dist/version-manifest.d.cts +11 -1
- package/dist/version-manifest.d.cts.map +1 -1
- package/dist/version-manifest.d.mts +11 -1
- package/dist/version-manifest.d.mts.map +1 -1
- package/dist/version-manifest.mjs +14 -2
- package/dist/version-manifest.mjs.map +1 -1
- package/package.json +20 -3
- package/skills/plugin-client/SKILL.md +10 -4
- package/skills/plugin-testing/SKILL.md +2 -1
- package/src/build/rspack/chunk-completeness-plugin.ts +15 -6
- package/src/build/ui/generated-config.ts +4 -0
- package/src/build/ui/rsbuild-config.ts +1 -0
- package/src/client.ts +111 -0
- package/src/dev/host.ts +235 -0
- package/src/dev/serve.ts +22 -140
- package/src/errors.ts +2 -1
- package/src/index.ts +9 -0
- package/src/plugin.ts +26 -1
- package/src/remote-entry.ts +1 -2
- package/src/runtime/errors.ts +44 -0
- package/src/runtime/services/module-federation.service.ts +4 -7
- package/src/runtime/services/plugin-loader.service.ts +46 -2
- package/src/runtime/services/shared-identity.ts +1 -1
- package/src/types.ts +40 -2
- package/src/ui/manifest/construct.ts +68 -15
- package/src/version-manifest.ts +19 -1
|
@@ -28,14 +28,26 @@ var ChunkCompletenessPlugin = class {
|
|
|
28
28
|
const entry = require_build_artifact_names.findHashedEntry(names, this.entryBase) ?? names.find((n) => n === `${this.entryBase}.js`);
|
|
29
29
|
if (!entry) return;
|
|
30
30
|
const jsFiles = new Set(names.filter((n) => n.endsWith(".js")));
|
|
31
|
-
const
|
|
31
|
+
const entryAsset = assets[entry];
|
|
32
|
+
if (!entryAsset) return;
|
|
33
|
+
const source = entryAsset.source().toString();
|
|
32
34
|
const special = /* @__PURE__ */ new Map();
|
|
33
|
-
const
|
|
34
|
-
if (
|
|
35
|
-
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
|
|
35
|
+
const uExpression = source.match(/\.u\s*=\s*(\w+)=>([^,;]+)/)?.[2];
|
|
36
|
+
if (uExpression) for (const m of uExpression.matchAll(/(\d+)\s*===\s*\w+\s*\?\s*"([^"]+)"/g)) {
|
|
37
|
+
const chunkId = m[1];
|
|
38
|
+
const chunkName = m[2];
|
|
39
|
+
if (chunkId && chunkName) special.set(chunkId, chunkName);
|
|
40
|
+
}
|
|
41
|
+
for (const pa of source.matchAll(/Promise\.all\(\[([^\]]*)\]\)/g)) {
|
|
42
|
+
const eagerList = pa[1];
|
|
43
|
+
if (!eagerList) continue;
|
|
44
|
+
for (const m of eagerList.matchAll(/(?:__webpack_require__|\w+)\.e\((\d+)\)/g)) {
|
|
45
|
+
const id = m[1];
|
|
46
|
+
if (!id) continue;
|
|
47
|
+
const chunkName = special.get(id);
|
|
48
|
+
const file = chunkName ? `${chunkName}.js` : `${id}.js`;
|
|
49
|
+
if (!jsFiles.has(file)) compilation.errors.push(/* @__PURE__ */ new Error(`[${this.name}] entry ${entry} eagerly loads chunk ${id} (${file}) but the compilation never emitted it — the built remote would fail at load time with "__webpack_modules__[r] is not a function".`));
|
|
50
|
+
}
|
|
39
51
|
}
|
|
40
52
|
});
|
|
41
53
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chunk-completeness-plugin.cjs","names":["findHashedEntry"],"sources":["../../../src/build/rspack/chunk-completeness-plugin.ts"],"sourcesContent":["import type { Compiler, RspackPluginInstance } from \"@rspack/core\";\nimport { findHashedEntry } from \"../artifact-names\";\n\n/**\n * Fails the build when a container entry's eager chunk references\n * (`Promise.all([__webpack_require__.e(N), …])` in get factories) point at\n * chunk files the compilation never emits. Rspack 2.x splitChunks re-ids the\n * final chunk graph while the federation get-factory codegen can keep\n * pre-split ids — the emitted entry then 404s its own chunks at load time and\n * the failure surfaces downstream as `__webpack_modules__[r] is not a\n * function`. SplitChunks is disabled in the composition for exactly this\n * reason; this gate catches any regression loudly at build time instead.\n */\nexport class ChunkCompletenessPlugin implements RspackPluginInstance {\n name = \"ChunkCompletenessPlugin\";\n\n constructor(private entryBase = \"remoteEntry\") {}\n\n apply(compiler: Compiler) {\n compiler.hooks.thisCompilation.tap(this.name, (compilation) => {\n const webpack = (compiler as Compiler & { webpack?: any }).webpack;\n const stage = webpack?.Compilation?.PROCESS_ASSETS_STAGE_ADDITIONS ?? 1000;\n\n compilation.hooks.processAssets.tap({ name: this.name, stage }, (assets) => {\n const names = Object.keys(assets);\n const entry =\n findHashedEntry(names, this.entryBase) ?? names.find((n) => n === `${this.entryBase}.js`);\n if (!entry) return;\n\n const jsFiles = new Set(names.filter((n) => n.endsWith(\".js\")));\n const
|
|
1
|
+
{"version":3,"file":"chunk-completeness-plugin.cjs","names":["findHashedEntry"],"sources":["../../../src/build/rspack/chunk-completeness-plugin.ts"],"sourcesContent":["import type { Compiler, RspackPluginInstance } from \"@rspack/core\";\nimport { findHashedEntry } from \"../artifact-names\";\n\n/**\n * Fails the build when a container entry's eager chunk references\n * (`Promise.all([__webpack_require__.e(N), …])` in get factories) point at\n * chunk files the compilation never emits. Rspack 2.x splitChunks re-ids the\n * final chunk graph while the federation get-factory codegen can keep\n * pre-split ids — the emitted entry then 404s its own chunks at load time and\n * the failure surfaces downstream as `__webpack_modules__[r] is not a\n * function`. SplitChunks is disabled in the composition for exactly this\n * reason; this gate catches any regression loudly at build time instead.\n */\nexport class ChunkCompletenessPlugin implements RspackPluginInstance {\n name = \"ChunkCompletenessPlugin\";\n\n constructor(private entryBase = \"remoteEntry\") {}\n\n apply(compiler: Compiler) {\n compiler.hooks.thisCompilation.tap(this.name, (compilation) => {\n const webpack = (compiler as Compiler & { webpack?: any }).webpack;\n const stage = webpack?.Compilation?.PROCESS_ASSETS_STAGE_ADDITIONS ?? 1000;\n\n compilation.hooks.processAssets.tap({ name: this.name, stage }, (assets) => {\n const names = Object.keys(assets);\n const entry =\n findHashedEntry(names, this.entryBase) ?? names.find((n) => n === `${this.entryBase}.js`);\n if (!entry) return;\n\n const jsFiles = new Set(names.filter((n) => n.endsWith(\".js\")));\n const entryAsset = assets[entry];\n if (!entryAsset) return;\n const source = entryAsset.source().toString();\n\n const special = new Map<string, string>();\n const u = source.match(/\\.u\\s*=\\s*(\\w+)=>([^,;]+)/);\n const uExpression = u?.[2];\n if (uExpression) {\n for (const m of uExpression.matchAll(/(\\d+)\\s*===\\s*\\w+\\s*\\?\\s*\"([^\"]+)\"/g)) {\n const chunkId = m[1];\n const chunkName = m[2];\n if (chunkId && chunkName) special.set(chunkId, chunkName);\n }\n }\n\n for (const pa of source.matchAll(/Promise\\.all\\(\\[([^\\]]*)\\]\\)/g)) {\n const eagerList = pa[1];\n if (!eagerList) continue;\n for (const m of eagerList.matchAll(/(?:__webpack_require__|\\w+)\\.e\\((\\d+)\\)/g)) {\n const id = m[1];\n if (!id) continue;\n const chunkName = special.get(id);\n const file = chunkName ? `${chunkName}.js` : `${id}.js`;\n if (!jsFiles.has(file)) {\n compilation.errors.push(\n new Error(\n `[${this.name}] entry ${entry} eagerly loads chunk ${id} (${file}) but the compilation never emitted it — the built remote would fail at load time with \"__webpack_modules__[r] is not a function\".`,\n ),\n );\n }\n }\n }\n });\n });\n }\n}\n"],"mappings":";;;;;;;;;;;;;AAaA,IAAa,0BAAb,MAAqE;CAG/C;CAFpB,OAAO;CAEP,YAAY,AAAQ,YAAY,eAAe;EAA3B;CAA4B;CAEhD,MAAM,UAAoB;EACxB,SAAS,MAAM,gBAAgB,IAAI,KAAK,OAAO,gBAAgB;GAE7D,MAAM,QADW,SAA0C,SACpC,aAAa,kCAAkC;GAEtE,YAAY,MAAM,cAAc,IAAI;IAAE,MAAM,KAAK;IAAM;GAAM,IAAI,WAAW;IAC1E,MAAM,QAAQ,OAAO,KAAK,MAAM;IAChC,MAAM,QACJA,6CAAgB,OAAO,KAAK,SAAS,KAAK,MAAM,MAAM,MAAM,MAAM,GAAG,KAAK,UAAU,IAAI;IAC1F,IAAI,CAAC,OAAO;IAEZ,MAAM,UAAU,IAAI,IAAI,MAAM,QAAQ,MAAM,EAAE,SAAS,KAAK,CAAC,CAAC;IAC9D,MAAM,aAAa,OAAO;IAC1B,IAAI,CAAC,YAAY;IACjB,MAAM,SAAS,WAAW,OAAO,CAAC,CAAC,SAAS;IAE5C,MAAM,0BAAU,IAAI,IAAoB;IAExC,MAAM,cADI,OAAO,MAAM,2BACH,CAAC,GAAG;IACxB,IAAI,aACF,KAAK,MAAM,KAAK,YAAY,SAAS,qCAAqC,GAAG;KAC3E,MAAM,UAAU,EAAE;KAClB,MAAM,YAAY,EAAE;KACpB,IAAI,WAAW,WAAW,QAAQ,IAAI,SAAS,SAAS;IAC1D;IAGF,KAAK,MAAM,MAAM,OAAO,SAAS,+BAA+B,GAAG;KACjE,MAAM,YAAY,GAAG;KACrB,IAAI,CAAC,WAAW;KAChB,KAAK,MAAM,KAAK,UAAU,SAAS,0CAA0C,GAAG;MAC9E,MAAM,KAAK,EAAE;MACb,IAAI,CAAC,IAAI;MACT,MAAM,YAAY,QAAQ,IAAI,EAAE;MAChC,MAAM,OAAO,YAAY,GAAG,UAAU,OAAO,GAAG,GAAG;MACnD,IAAI,CAAC,QAAQ,IAAI,IAAI,GACnB,YAAY,OAAO,qBACjB,IAAI,MACF,IAAI,KAAK,KAAK,UAAU,MAAM,uBAAuB,GAAG,IAAI,KAAK,mIACnE,CACF;KAEJ;IACF;GACF,CAAC;EACH,CAAC;CACH;AACF"}
|
|
@@ -28,14 +28,26 @@ var ChunkCompletenessPlugin = class {
|
|
|
28
28
|
const entry = findHashedEntry(names, this.entryBase) ?? names.find((n) => n === `${this.entryBase}.js`);
|
|
29
29
|
if (!entry) return;
|
|
30
30
|
const jsFiles = new Set(names.filter((n) => n.endsWith(".js")));
|
|
31
|
-
const
|
|
31
|
+
const entryAsset = assets[entry];
|
|
32
|
+
if (!entryAsset) return;
|
|
33
|
+
const source = entryAsset.source().toString();
|
|
32
34
|
const special = /* @__PURE__ */ new Map();
|
|
33
|
-
const
|
|
34
|
-
if (
|
|
35
|
-
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
|
|
35
|
+
const uExpression = source.match(/\.u\s*=\s*(\w+)=>([^,;]+)/)?.[2];
|
|
36
|
+
if (uExpression) for (const m of uExpression.matchAll(/(\d+)\s*===\s*\w+\s*\?\s*"([^"]+)"/g)) {
|
|
37
|
+
const chunkId = m[1];
|
|
38
|
+
const chunkName = m[2];
|
|
39
|
+
if (chunkId && chunkName) special.set(chunkId, chunkName);
|
|
40
|
+
}
|
|
41
|
+
for (const pa of source.matchAll(/Promise\.all\(\[([^\]]*)\]\)/g)) {
|
|
42
|
+
const eagerList = pa[1];
|
|
43
|
+
if (!eagerList) continue;
|
|
44
|
+
for (const m of eagerList.matchAll(/(?:__webpack_require__|\w+)\.e\((\d+)\)/g)) {
|
|
45
|
+
const id = m[1];
|
|
46
|
+
if (!id) continue;
|
|
47
|
+
const chunkName = special.get(id);
|
|
48
|
+
const file = chunkName ? `${chunkName}.js` : `${id}.js`;
|
|
49
|
+
if (!jsFiles.has(file)) compilation.errors.push(/* @__PURE__ */ new Error(`[${this.name}] entry ${entry} eagerly loads chunk ${id} (${file}) but the compilation never emitted it — the built remote would fail at load time with "__webpack_modules__[r] is not a function".`));
|
|
50
|
+
}
|
|
39
51
|
}
|
|
40
52
|
});
|
|
41
53
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chunk-completeness-plugin.mjs","names":[],"sources":["../../../src/build/rspack/chunk-completeness-plugin.ts"],"sourcesContent":["import type { Compiler, RspackPluginInstance } from \"@rspack/core\";\nimport { findHashedEntry } from \"../artifact-names\";\n\n/**\n * Fails the build when a container entry's eager chunk references\n * (`Promise.all([__webpack_require__.e(N), …])` in get factories) point at\n * chunk files the compilation never emits. Rspack 2.x splitChunks re-ids the\n * final chunk graph while the federation get-factory codegen can keep\n * pre-split ids — the emitted entry then 404s its own chunks at load time and\n * the failure surfaces downstream as `__webpack_modules__[r] is not a\n * function`. SplitChunks is disabled in the composition for exactly this\n * reason; this gate catches any regression loudly at build time instead.\n */\nexport class ChunkCompletenessPlugin implements RspackPluginInstance {\n name = \"ChunkCompletenessPlugin\";\n\n constructor(private entryBase = \"remoteEntry\") {}\n\n apply(compiler: Compiler) {\n compiler.hooks.thisCompilation.tap(this.name, (compilation) => {\n const webpack = (compiler as Compiler & { webpack?: any }).webpack;\n const stage = webpack?.Compilation?.PROCESS_ASSETS_STAGE_ADDITIONS ?? 1000;\n\n compilation.hooks.processAssets.tap({ name: this.name, stage }, (assets) => {\n const names = Object.keys(assets);\n const entry =\n findHashedEntry(names, this.entryBase) ?? names.find((n) => n === `${this.entryBase}.js`);\n if (!entry) return;\n\n const jsFiles = new Set(names.filter((n) => n.endsWith(\".js\")));\n const
|
|
1
|
+
{"version":3,"file":"chunk-completeness-plugin.mjs","names":[],"sources":["../../../src/build/rspack/chunk-completeness-plugin.ts"],"sourcesContent":["import type { Compiler, RspackPluginInstance } from \"@rspack/core\";\nimport { findHashedEntry } from \"../artifact-names\";\n\n/**\n * Fails the build when a container entry's eager chunk references\n * (`Promise.all([__webpack_require__.e(N), …])` in get factories) point at\n * chunk files the compilation never emits. Rspack 2.x splitChunks re-ids the\n * final chunk graph while the federation get-factory codegen can keep\n * pre-split ids — the emitted entry then 404s its own chunks at load time and\n * the failure surfaces downstream as `__webpack_modules__[r] is not a\n * function`. SplitChunks is disabled in the composition for exactly this\n * reason; this gate catches any regression loudly at build time instead.\n */\nexport class ChunkCompletenessPlugin implements RspackPluginInstance {\n name = \"ChunkCompletenessPlugin\";\n\n constructor(private entryBase = \"remoteEntry\") {}\n\n apply(compiler: Compiler) {\n compiler.hooks.thisCompilation.tap(this.name, (compilation) => {\n const webpack = (compiler as Compiler & { webpack?: any }).webpack;\n const stage = webpack?.Compilation?.PROCESS_ASSETS_STAGE_ADDITIONS ?? 1000;\n\n compilation.hooks.processAssets.tap({ name: this.name, stage }, (assets) => {\n const names = Object.keys(assets);\n const entry =\n findHashedEntry(names, this.entryBase) ?? names.find((n) => n === `${this.entryBase}.js`);\n if (!entry) return;\n\n const jsFiles = new Set(names.filter((n) => n.endsWith(\".js\")));\n const entryAsset = assets[entry];\n if (!entryAsset) return;\n const source = entryAsset.source().toString();\n\n const special = new Map<string, string>();\n const u = source.match(/\\.u\\s*=\\s*(\\w+)=>([^,;]+)/);\n const uExpression = u?.[2];\n if (uExpression) {\n for (const m of uExpression.matchAll(/(\\d+)\\s*===\\s*\\w+\\s*\\?\\s*\"([^\"]+)\"/g)) {\n const chunkId = m[1];\n const chunkName = m[2];\n if (chunkId && chunkName) special.set(chunkId, chunkName);\n }\n }\n\n for (const pa of source.matchAll(/Promise\\.all\\(\\[([^\\]]*)\\]\\)/g)) {\n const eagerList = pa[1];\n if (!eagerList) continue;\n for (const m of eagerList.matchAll(/(?:__webpack_require__|\\w+)\\.e\\((\\d+)\\)/g)) {\n const id = m[1];\n if (!id) continue;\n const chunkName = special.get(id);\n const file = chunkName ? `${chunkName}.js` : `${id}.js`;\n if (!jsFiles.has(file)) {\n compilation.errors.push(\n new Error(\n `[${this.name}] entry ${entry} eagerly loads chunk ${id} (${file}) but the compilation never emitted it — the built remote would fail at load time with \"__webpack_modules__[r] is not a function\".`,\n ),\n );\n }\n }\n }\n });\n });\n }\n}\n"],"mappings":";;;;;;;;;;;;;AAaA,IAAa,0BAAb,MAAqE;CAG/C;CAFpB,OAAO;CAEP,YAAY,AAAQ,YAAY,eAAe;EAA3B;CAA4B;CAEhD,MAAM,UAAoB;EACxB,SAAS,MAAM,gBAAgB,IAAI,KAAK,OAAO,gBAAgB;GAE7D,MAAM,QADW,SAA0C,SACpC,aAAa,kCAAkC;GAEtE,YAAY,MAAM,cAAc,IAAI;IAAE,MAAM,KAAK;IAAM;GAAM,IAAI,WAAW;IAC1E,MAAM,QAAQ,OAAO,KAAK,MAAM;IAChC,MAAM,QACJ,gBAAgB,OAAO,KAAK,SAAS,KAAK,MAAM,MAAM,MAAM,MAAM,GAAG,KAAK,UAAU,IAAI;IAC1F,IAAI,CAAC,OAAO;IAEZ,MAAM,UAAU,IAAI,IAAI,MAAM,QAAQ,MAAM,EAAE,SAAS,KAAK,CAAC,CAAC;IAC9D,MAAM,aAAa,OAAO;IAC1B,IAAI,CAAC,YAAY;IACjB,MAAM,SAAS,WAAW,OAAO,CAAC,CAAC,SAAS;IAE5C,MAAM,0BAAU,IAAI,IAAoB;IAExC,MAAM,cADI,OAAO,MAAM,2BACH,CAAC,GAAG;IACxB,IAAI,aACF,KAAK,MAAM,KAAK,YAAY,SAAS,qCAAqC,GAAG;KAC3E,MAAM,UAAU,EAAE;KAClB,MAAM,YAAY,EAAE;KACpB,IAAI,WAAW,WAAW,QAAQ,IAAI,SAAS,SAAS;IAC1D;IAGF,KAAK,MAAM,MAAM,OAAO,SAAS,+BAA+B,GAAG;KACjE,MAAM,YAAY,GAAG;KACrB,IAAI,CAAC,WAAW;KAChB,KAAK,MAAM,KAAK,UAAU,SAAS,0CAA0C,GAAG;MAC9E,MAAM,KAAK,EAAE;MACb,IAAI,CAAC,IAAI;MACT,MAAM,YAAY,QAAQ,IAAI,EAAE;MAChC,MAAM,OAAO,YAAY,GAAG,UAAU,OAAO,GAAG,GAAG;MACnD,IAAI,CAAC,QAAQ,IAAI,IAAI,GACnB,YAAY,OAAO,qBACjB,IAAI,MACF,IAAI,KAAK,KAAK,UAAU,MAAM,uBAAuB,GAAG,IAAI,KAAK,mIACnE,CACF;KAEJ;IACF;GACF,CAAC;EACH,CAAC;CACH;AACF"}
|
|
@@ -19,6 +19,9 @@ function hasFolderFormUi(cwd) {
|
|
|
19
19
|
const uiDir = node_path.default.join(cwd, UI_DIR);
|
|
20
20
|
return node_fs.default.existsSync(node_path.default.join(uiDir, "src", "routes")) && !node_fs.default.existsSync(node_path.default.join(uiDir, "package.json"));
|
|
21
21
|
}
|
|
22
|
+
function uiDistDirFor(cwd) {
|
|
23
|
+
return node_path.default.join(cwd, UI_DIR, "dist");
|
|
24
|
+
}
|
|
22
25
|
function generatedUiConfig(pluginId) {
|
|
23
26
|
return `import path from "node:path";
|
|
24
27
|
import { createUiRsbuildConfig } from "every-plugin/build/ui";
|
|
@@ -115,4 +118,5 @@ exports.ensureGeneratedUiRsbuildConfig = ensureGeneratedUiRsbuildConfig;
|
|
|
115
118
|
exports.hasCoreUiWorkspace = hasCoreUiWorkspace;
|
|
116
119
|
exports.hasFolderFormUi = hasFolderFormUi;
|
|
117
120
|
exports.pluginLayoutKey = pluginLayoutKey;
|
|
121
|
+
exports.uiDistDirFor = uiDistDirFor;
|
|
118
122
|
//# sourceMappingURL=generated-config.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generated-config.cjs","names":["path","fs","findBosConfigPath"],"sources":["../../../src/build/ui/generated-config.ts"],"sourcesContent":["import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { findBosConfigPath } from \"../rspack/compose\";\n\nconst UI_DIR = \"ui\";\nconst GENERATED_CONFIG_DIR = \".every-plugin\";\nconst GENERATED_UI_CONFIG = \"ui.rsbuild.config.generated.mjs\";\n\n/**\n * Folder-form UI source: a `ui/` directory with route files but no own\n * package.json — the plugin workspace owns the build (single-workspace\n * plugin, one dev process, one deploy train). Workspace-form ui sources\n * (own package.json + scripts) are NOT managed here.\n */\nexport function hasFolderFormUi(cwd: string): boolean {\n const uiDir = path.join(cwd, UI_DIR);\n return (\n fs.existsSync(path.join(uiDir, \"src\", \"routes\")) &&\n !fs.existsSync(path.join(uiDir, \"package.json\"))\n );\n}\n\nfunction generatedUiConfig(pluginId: string): string {\n return `import path from \"node:path\";\nimport { createUiRsbuildConfig } from \"every-plugin/build/ui\";\nimport pkg from \"../package.json\";\n\nconst workspaceRoot = path.resolve(import.meta.dirname, \"..\", \"ui\");\n\nexport default createUiRsbuildConfig({\n workspaceRoot,\n pkg,\n role: \"consumer\",\n manifestName: ${JSON.stringify(pluginId)},\n devPort: Number(process.env.BOS_UI_PORT) || 0,\n webEntry: \"./ui/src/routeConfig.gen.ts\",\n webExposes: { \"./routeConfig\": \"./ui/src/routeConfig.gen.ts\" },\n nodeEntry: \"./ui/src/routeConfig.gen.ts\",\n nodeExposes: { \"./routeConfig\": \"./ui/src/routeConfig.gen.ts\" },\n routesDirectory: \"./ui/src/routes\",\n});\n`;\n}\n\n/**\n * Canonical config-layout derivation: the composition key for a plugin\n * workspace — the `<key>` of the `plugins/<key>` directory relative to the\n * nearest `bos.config.json`. The dev server and the generated ui config\n * both key off this; no consumer keeps a private copy.\n */\nexport function pluginLayoutKey(cwd: string): string | null {\n const bosConfigPath = findBosConfigPath(cwd);\n const relativeWorkspace = bosConfigPath\n ? path.relative(path.dirname(bosConfigPath), cwd)\n : undefined;\n const [workspaceGroup, layoutKey] = relativeWorkspace?.split(path.sep) ?? [];\n return workspaceGroup === \"plugins\" && layoutKey ? layoutKey : null;\n}\n\n/**\n * Synthesize the rsbuild config for a folder-form ui source (the plugin\n * build contract, not per-plugin config — mirrors the rspack generated\n * config). Returns the config file path, or null when the workspace has no\n * folder-form ui source.\n */\nexport function ensureGeneratedUiRsbuildConfig(cwd: string): string | null {\n if (!hasFolderFormUi(cwd)) return null;\n // The manifest's name derives ONLY from the plugins/<key> layout key\n // (ADR 0008 §2) — a non-derivable key fails the build loudly, never the\n // container-name fallback that mis-keyed manifests.\n const pluginId = pluginLayoutKey(cwd);\n if (!pluginId) {\n throw new Error(\n `[every-plugin] cannot derive the ui's composition key from ${cwd} — no authored config (bos.app.ts / bos.config.json) found above a plugins/<key> directory. The manifest name is the layout key; the container name is never a fallback.`,\n );\n }\n const outDir = path.join(cwd, GENERATED_CONFIG_DIR);\n fs.mkdirSync(outDir, { recursive: true });\n const outPath = path.join(outDir, GENERATED_UI_CONFIG);\n const next = generatedUiConfig(pluginId);\n if (!fs.existsSync(outPath) || fs.readFileSync(outPath, \"utf8\") !== next) {\n fs.writeFileSync(outPath, next);\n }\n return outPath;\n}\n\nconst CORE_UI_MARKERS = {\n routes: \"src/routes\",\n contract: \"src/contract.ts\",\n};\n\n/**\n * Workspace-form core ui: the workspace IS the ui (own package.json, route\n * tree) and is not plugin-shaped — the /api counterpart of the plugin\n * workspace form. The entry stub is NOT a marker: it is generated\n * (ADR 0023), so a fresh clone has no bootstrap stubs until the first\n * generation pass.\n */\nexport function hasCoreUiWorkspace(cwd: string = process.cwd()): boolean {\n return (\n fs.existsSync(path.join(cwd, CORE_UI_MARKERS.routes)) &&\n !fs.existsSync(path.join(cwd, CORE_UI_MARKERS.contract)) &&\n !fs.existsSync(path.join(cwd, \"plugin.dev.ts\"))\n );\n}\n\nfunction generatedCoreUiConfig(): string {\n return `import { defineConfig } from \"@rsbuild/core\";\nimport { readAuthoredConfigInput } from \"everything-dev/config\";\nimport { createCoreUiRsbuildConfig } from \"every-plugin/build/ui\";\n\nexport default defineConfig(async () =>\n createCoreUiRsbuildConfig(await readAuthoredConfigInput()),\n);\n`;\n}\n\n/**\n * Synthesize the rsbuild config for a workspace-form core ui with no local\n * `rsbuild.config.ts` — the /api generated-config model. A local file is an\n * override and wins untouched. Returns the workspace-relative config path,\n * or null when the workspace is not a core ui (or has a local config).\n */\nexport function ensureGeneratedCoreUiRsbuildConfig(cwd: string = process.cwd()): string | null {\n if (!hasCoreUiWorkspace(cwd)) return null;\n if (fs.existsSync(path.join(cwd, \"rsbuild.config.ts\"))) return null;\n const outDir = path.join(cwd, GENERATED_CONFIG_DIR);\n fs.mkdirSync(outDir, { recursive: true });\n const outPath = path.join(outDir, GENERATED_UI_CONFIG);\n fs.writeFileSync(outPath, generatedCoreUiConfig());\n console.log(\"[every-plugin] rsbuild.config.ts not found — using the core ui build factory.\");\n return path.join(GENERATED_CONFIG_DIR, GENERATED_UI_CONFIG);\n}\n"],"mappings":";;;;;;;;AAIA,MAAM,SAAS;AACf,MAAM,uBAAuB;AAC7B,MAAM,sBAAsB;;;;;;;AAQ5B,SAAgB,gBAAgB,KAAsB;CACpD,MAAM,QAAQA,kBAAK,KAAK,KAAK,MAAM;CACnC,OACEC,gBAAG,WAAWD,kBAAK,KAAK,OAAO,OAAO,QAAQ,CAAC,KAC/C,CAACC,gBAAG,WAAWD,kBAAK,KAAK,OAAO,cAAc,CAAC;AAEnD;AAEA,SAAS,kBAAkB,UAA0B;CACnD,OAAO;;;;;;;;;;kBAUS,KAAK,UAAU,QAAQ,EAAE;;;;;;;;;AAS3C;;;;;;;AAQA,SAAgB,gBAAgB,KAA4B;CAC1D,MAAM,gBAAgBE,kCAAkB,GAAG;CAI3C,MAAM,CAAC,gBAAgB,cAHG,gBACtBF,kBAAK,SAASA,kBAAK,QAAQ,aAAa,GAAG,GAAG,IAC9C,OACiD,EAAE,MAAMA,kBAAK,GAAG,KAAK,CAAC;CAC3E,OAAO,mBAAmB,aAAa,YAAY,YAAY;AACjE;;;;;;;AAQA,SAAgB,+BAA+B,KAA4B;CACzE,IAAI,CAAC,gBAAgB,GAAG,GAAG,OAAO;CAIlC,MAAM,WAAW,gBAAgB,GAAG;CACpC,IAAI,CAAC,UACH,MAAM,IAAI,MACR,8DAA8D,IAAI,yKACpE;CAEF,MAAM,SAASA,kBAAK,KAAK,KAAK,oBAAoB;CAClD,gBAAG,UAAU,QAAQ,EAAE,WAAW,KAAK,CAAC;CACxC,MAAM,UAAUA,kBAAK,KAAK,QAAQ,mBAAmB;CACrD,MAAM,OAAO,kBAAkB,QAAQ;CACvC,IAAI,CAACC,gBAAG,WAAW,OAAO,KAAKA,gBAAG,aAAa,SAAS,MAAM,MAAM,MAClE,gBAAG,cAAc,SAAS,IAAI;CAEhC,OAAO;AACT;AAEA,MAAM,kBAAkB;CACtB,QAAQ;CACR,UAAU;AACZ;;;;;;;;AASA,SAAgB,mBAAmB,MAAc,QAAQ,IAAI,GAAY;CACvE,OACEA,gBAAG,WAAWD,kBAAK,KAAK,KAAK,gBAAgB,MAAM,CAAC,KACpD,CAACC,gBAAG,WAAWD,kBAAK,KAAK,KAAK,gBAAgB,QAAQ,CAAC,KACvD,CAACC,gBAAG,WAAWD,kBAAK,KAAK,KAAK,eAAe,CAAC;AAElD;AAEA,SAAS,wBAAgC;CACvC,OAAO;;;;;;;;AAQT;;;;;;;AAQA,SAAgB,mCAAmC,MAAc,QAAQ,IAAI,GAAkB;CAC7F,IAAI,CAAC,mBAAmB,GAAG,GAAG,OAAO;CACrC,IAAIC,gBAAG,WAAWD,kBAAK,KAAK,KAAK,mBAAmB,CAAC,GAAG,OAAO;CAC/D,MAAM,SAASA,kBAAK,KAAK,KAAK,oBAAoB;CAClD,gBAAG,UAAU,QAAQ,EAAE,WAAW,KAAK,CAAC;CACxC,MAAM,UAAUA,kBAAK,KAAK,QAAQ,mBAAmB;CACrD,gBAAG,cAAc,SAAS,sBAAsB,CAAC;CACjD,QAAQ,IAAI,+EAA+E;CAC3F,OAAOA,kBAAK,KAAK,sBAAsB,mBAAmB;AAC5D"}
|
|
1
|
+
{"version":3,"file":"generated-config.cjs","names":["path","fs","findBosConfigPath"],"sources":["../../../src/build/ui/generated-config.ts"],"sourcesContent":["import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { findBosConfigPath } from \"../rspack/compose\";\n\nconst UI_DIR = \"ui\";\nconst GENERATED_CONFIG_DIR = \".every-plugin\";\nconst GENERATED_UI_CONFIG = \"ui.rsbuild.config.generated.mjs\";\n\n/**\n * Folder-form UI source: a `ui/` directory with route files but no own\n * package.json — the plugin workspace owns the build (single-workspace\n * plugin, one dev process, one deploy train). Workspace-form ui sources\n * (own package.json + scripts) are NOT managed here.\n */\nexport function hasFolderFormUi(cwd: string): boolean {\n const uiDir = path.join(cwd, UI_DIR);\n return (\n fs.existsSync(path.join(uiDir, \"src\", \"routes\")) &&\n !fs.existsSync(path.join(uiDir, \"package.json\"))\n );\n}\n\nexport function uiDistDirFor(cwd: string): string {\n return path.join(cwd, UI_DIR, \"dist\");\n}\n\nfunction generatedUiConfig(pluginId: string): string {\n return `import path from \"node:path\";\nimport { createUiRsbuildConfig } from \"every-plugin/build/ui\";\nimport pkg from \"../package.json\";\n\nconst workspaceRoot = path.resolve(import.meta.dirname, \"..\", \"ui\");\n\nexport default createUiRsbuildConfig({\n workspaceRoot,\n pkg,\n role: \"consumer\",\n manifestName: ${JSON.stringify(pluginId)},\n devPort: Number(process.env.BOS_UI_PORT) || 0,\n webEntry: \"./ui/src/routeConfig.gen.ts\",\n webExposes: { \"./routeConfig\": \"./ui/src/routeConfig.gen.ts\" },\n nodeEntry: \"./ui/src/routeConfig.gen.ts\",\n nodeExposes: { \"./routeConfig\": \"./ui/src/routeConfig.gen.ts\" },\n routesDirectory: \"./ui/src/routes\",\n});\n`;\n}\n\n/**\n * Canonical config-layout derivation: the composition key for a plugin\n * workspace — the `<key>` of the `plugins/<key>` directory relative to the\n * nearest `bos.config.json`. The dev server and the generated ui config\n * both key off this; no consumer keeps a private copy.\n */\nexport function pluginLayoutKey(cwd: string): string | null {\n const bosConfigPath = findBosConfigPath(cwd);\n const relativeWorkspace = bosConfigPath\n ? path.relative(path.dirname(bosConfigPath), cwd)\n : undefined;\n const [workspaceGroup, layoutKey] = relativeWorkspace?.split(path.sep) ?? [];\n return workspaceGroup === \"plugins\" && layoutKey ? layoutKey : null;\n}\n\n/**\n * Synthesize the rsbuild config for a folder-form ui source (the plugin\n * build contract, not per-plugin config — mirrors the rspack generated\n * config). Returns the config file path, or null when the workspace has no\n * folder-form ui source.\n */\nexport function ensureGeneratedUiRsbuildConfig(cwd: string): string | null {\n if (!hasFolderFormUi(cwd)) return null;\n // The manifest's name derives ONLY from the plugins/<key> layout key\n // (ADR 0008 §2) — a non-derivable key fails the build loudly, never the\n // container-name fallback that mis-keyed manifests.\n const pluginId = pluginLayoutKey(cwd);\n if (!pluginId) {\n throw new Error(\n `[every-plugin] cannot derive the ui's composition key from ${cwd} — no authored config (bos.app.ts / bos.config.json) found above a plugins/<key> directory. The manifest name is the layout key; the container name is never a fallback.`,\n );\n }\n const outDir = path.join(cwd, GENERATED_CONFIG_DIR);\n fs.mkdirSync(outDir, { recursive: true });\n const outPath = path.join(outDir, GENERATED_UI_CONFIG);\n const next = generatedUiConfig(pluginId);\n if (!fs.existsSync(outPath) || fs.readFileSync(outPath, \"utf8\") !== next) {\n fs.writeFileSync(outPath, next);\n }\n return outPath;\n}\n\nconst CORE_UI_MARKERS = {\n routes: \"src/routes\",\n contract: \"src/contract.ts\",\n};\n\n/**\n * Workspace-form core ui: the workspace IS the ui (own package.json, route\n * tree) and is not plugin-shaped — the /api counterpart of the plugin\n * workspace form. The entry stub is NOT a marker: it is generated\n * (ADR 0023), so a fresh clone has no bootstrap stubs until the first\n * generation pass.\n */\nexport function hasCoreUiWorkspace(cwd: string = process.cwd()): boolean {\n return (\n fs.existsSync(path.join(cwd, CORE_UI_MARKERS.routes)) &&\n !fs.existsSync(path.join(cwd, CORE_UI_MARKERS.contract)) &&\n !fs.existsSync(path.join(cwd, \"plugin.dev.ts\"))\n );\n}\n\nfunction generatedCoreUiConfig(): string {\n return `import { defineConfig } from \"@rsbuild/core\";\nimport { readAuthoredConfigInput } from \"everything-dev/config\";\nimport { createCoreUiRsbuildConfig } from \"every-plugin/build/ui\";\n\nexport default defineConfig(async () =>\n createCoreUiRsbuildConfig(await readAuthoredConfigInput()),\n);\n`;\n}\n\n/**\n * Synthesize the rsbuild config for a workspace-form core ui with no local\n * `rsbuild.config.ts` — the /api generated-config model. A local file is an\n * override and wins untouched. Returns the workspace-relative config path,\n * or null when the workspace is not a core ui (or has a local config).\n */\nexport function ensureGeneratedCoreUiRsbuildConfig(cwd: string = process.cwd()): string | null {\n if (!hasCoreUiWorkspace(cwd)) return null;\n if (fs.existsSync(path.join(cwd, \"rsbuild.config.ts\"))) return null;\n const outDir = path.join(cwd, GENERATED_CONFIG_DIR);\n fs.mkdirSync(outDir, { recursive: true });\n const outPath = path.join(outDir, GENERATED_UI_CONFIG);\n fs.writeFileSync(outPath, generatedCoreUiConfig());\n console.log(\"[every-plugin] rsbuild.config.ts not found — using the core ui build factory.\");\n return path.join(GENERATED_CONFIG_DIR, GENERATED_UI_CONFIG);\n}\n"],"mappings":";;;;;;;;AAIA,MAAM,SAAS;AACf,MAAM,uBAAuB;AAC7B,MAAM,sBAAsB;;;;;;;AAQ5B,SAAgB,gBAAgB,KAAsB;CACpD,MAAM,QAAQA,kBAAK,KAAK,KAAK,MAAM;CACnC,OACEC,gBAAG,WAAWD,kBAAK,KAAK,OAAO,OAAO,QAAQ,CAAC,KAC/C,CAACC,gBAAG,WAAWD,kBAAK,KAAK,OAAO,cAAc,CAAC;AAEnD;AAEA,SAAgB,aAAa,KAAqB;CAChD,OAAOA,kBAAK,KAAK,KAAK,QAAQ,MAAM;AACtC;AAEA,SAAS,kBAAkB,UAA0B;CACnD,OAAO;;;;;;;;;;kBAUS,KAAK,UAAU,QAAQ,EAAE;;;;;;;;;AAS3C;;;;;;;AAQA,SAAgB,gBAAgB,KAA4B;CAC1D,MAAM,gBAAgBE,kCAAkB,GAAG;CAI3C,MAAM,CAAC,gBAAgB,cAHG,gBACtBF,kBAAK,SAASA,kBAAK,QAAQ,aAAa,GAAG,GAAG,IAC9C,OACiD,EAAE,MAAMA,kBAAK,GAAG,KAAK,CAAC;CAC3E,OAAO,mBAAmB,aAAa,YAAY,YAAY;AACjE;;;;;;;AAQA,SAAgB,+BAA+B,KAA4B;CACzE,IAAI,CAAC,gBAAgB,GAAG,GAAG,OAAO;CAIlC,MAAM,WAAW,gBAAgB,GAAG;CACpC,IAAI,CAAC,UACH,MAAM,IAAI,MACR,8DAA8D,IAAI,yKACpE;CAEF,MAAM,SAASA,kBAAK,KAAK,KAAK,oBAAoB;CAClD,gBAAG,UAAU,QAAQ,EAAE,WAAW,KAAK,CAAC;CACxC,MAAM,UAAUA,kBAAK,KAAK,QAAQ,mBAAmB;CACrD,MAAM,OAAO,kBAAkB,QAAQ;CACvC,IAAI,CAACC,gBAAG,WAAW,OAAO,KAAKA,gBAAG,aAAa,SAAS,MAAM,MAAM,MAClE,gBAAG,cAAc,SAAS,IAAI;CAEhC,OAAO;AACT;AAEA,MAAM,kBAAkB;CACtB,QAAQ;CACR,UAAU;AACZ;;;;;;;;AASA,SAAgB,mBAAmB,MAAc,QAAQ,IAAI,GAAY;CACvE,OACEA,gBAAG,WAAWD,kBAAK,KAAK,KAAK,gBAAgB,MAAM,CAAC,KACpD,CAACC,gBAAG,WAAWD,kBAAK,KAAK,KAAK,gBAAgB,QAAQ,CAAC,KACvD,CAACC,gBAAG,WAAWD,kBAAK,KAAK,KAAK,eAAe,CAAC;AAElD;AAEA,SAAS,wBAAgC;CACvC,OAAO;;;;;;;;AAQT;;;;;;;AAQA,SAAgB,mCAAmC,MAAc,QAAQ,IAAI,GAAkB;CAC7F,IAAI,CAAC,mBAAmB,GAAG,GAAG,OAAO;CACrC,IAAIC,gBAAG,WAAWD,kBAAK,KAAK,KAAK,mBAAmB,CAAC,GAAG,OAAO;CAC/D,MAAM,SAASA,kBAAK,KAAK,KAAK,oBAAoB;CAClD,gBAAG,UAAU,QAAQ,EAAE,WAAW,KAAK,CAAC;CACxC,MAAM,UAAUA,kBAAK,KAAK,QAAQ,mBAAmB;CACrD,gBAAG,cAAc,SAAS,sBAAsB,CAAC;CACjD,QAAQ,IAAI,+EAA+E;CAC3F,OAAOA,kBAAK,KAAK,sBAAsB,mBAAmB;AAC5D"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generated-config.d.cts","names":[],"sources":["../../../src/build/ui/generated-config.ts"],"mappings":";;;;;;;iBAcgB,gBAAgB;;;;;;;
|
|
1
|
+
{"version":3,"file":"generated-config.d.cts","names":[],"sources":["../../../src/build/ui/generated-config.ts"],"mappings":";;;;;;;iBAcgB,gBAAgB;;;;;;;iBAuDhB,+BAA+B;;;;;;;;iBAiC/B,mBAAmB;;;;;;;iBAyBnB,mCAAmC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generated-config.d.mts","names":[],"sources":["../../../src/build/ui/generated-config.ts"],"mappings":";;;;;;;iBAcgB,gBAAgB;;;;;;;
|
|
1
|
+
{"version":3,"file":"generated-config.d.mts","names":[],"sources":["../../../src/build/ui/generated-config.ts"],"mappings":";;;;;;;iBAcgB,gBAAgB;;;;;;;iBAuDhB,+BAA+B;;;;;;;;iBAiC/B,mBAAmB;;;;;;;iBAyBnB,mCAAmC"}
|
|
@@ -16,6 +16,9 @@ function hasFolderFormUi(cwd) {
|
|
|
16
16
|
const uiDir = path.join(cwd, UI_DIR);
|
|
17
17
|
return fs.existsSync(path.join(uiDir, "src", "routes")) && !fs.existsSync(path.join(uiDir, "package.json"));
|
|
18
18
|
}
|
|
19
|
+
function uiDistDirFor(cwd) {
|
|
20
|
+
return path.join(cwd, UI_DIR, "dist");
|
|
21
|
+
}
|
|
19
22
|
function generatedUiConfig(pluginId) {
|
|
20
23
|
return `import path from "node:path";
|
|
21
24
|
import { createUiRsbuildConfig } from "every-plugin/build/ui";
|
|
@@ -107,5 +110,5 @@ function ensureGeneratedCoreUiRsbuildConfig(cwd = process.cwd()) {
|
|
|
107
110
|
}
|
|
108
111
|
|
|
109
112
|
//#endregion
|
|
110
|
-
export { ensureGeneratedCoreUiRsbuildConfig, ensureGeneratedUiRsbuildConfig, hasCoreUiWorkspace, hasFolderFormUi, pluginLayoutKey };
|
|
113
|
+
export { ensureGeneratedCoreUiRsbuildConfig, ensureGeneratedUiRsbuildConfig, hasCoreUiWorkspace, hasFolderFormUi, pluginLayoutKey, uiDistDirFor };
|
|
111
114
|
//# sourceMappingURL=generated-config.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generated-config.mjs","names":[],"sources":["../../../src/build/ui/generated-config.ts"],"sourcesContent":["import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { findBosConfigPath } from \"../rspack/compose\";\n\nconst UI_DIR = \"ui\";\nconst GENERATED_CONFIG_DIR = \".every-plugin\";\nconst GENERATED_UI_CONFIG = \"ui.rsbuild.config.generated.mjs\";\n\n/**\n * Folder-form UI source: a `ui/` directory with route files but no own\n * package.json — the plugin workspace owns the build (single-workspace\n * plugin, one dev process, one deploy train). Workspace-form ui sources\n * (own package.json + scripts) are NOT managed here.\n */\nexport function hasFolderFormUi(cwd: string): boolean {\n const uiDir = path.join(cwd, UI_DIR);\n return (\n fs.existsSync(path.join(uiDir, \"src\", \"routes\")) &&\n !fs.existsSync(path.join(uiDir, \"package.json\"))\n );\n}\n\nfunction generatedUiConfig(pluginId: string): string {\n return `import path from \"node:path\";\nimport { createUiRsbuildConfig } from \"every-plugin/build/ui\";\nimport pkg from \"../package.json\";\n\nconst workspaceRoot = path.resolve(import.meta.dirname, \"..\", \"ui\");\n\nexport default createUiRsbuildConfig({\n workspaceRoot,\n pkg,\n role: \"consumer\",\n manifestName: ${JSON.stringify(pluginId)},\n devPort: Number(process.env.BOS_UI_PORT) || 0,\n webEntry: \"./ui/src/routeConfig.gen.ts\",\n webExposes: { \"./routeConfig\": \"./ui/src/routeConfig.gen.ts\" },\n nodeEntry: \"./ui/src/routeConfig.gen.ts\",\n nodeExposes: { \"./routeConfig\": \"./ui/src/routeConfig.gen.ts\" },\n routesDirectory: \"./ui/src/routes\",\n});\n`;\n}\n\n/**\n * Canonical config-layout derivation: the composition key for a plugin\n * workspace — the `<key>` of the `plugins/<key>` directory relative to the\n * nearest `bos.config.json`. The dev server and the generated ui config\n * both key off this; no consumer keeps a private copy.\n */\nexport function pluginLayoutKey(cwd: string): string | null {\n const bosConfigPath = findBosConfigPath(cwd);\n const relativeWorkspace = bosConfigPath\n ? path.relative(path.dirname(bosConfigPath), cwd)\n : undefined;\n const [workspaceGroup, layoutKey] = relativeWorkspace?.split(path.sep) ?? [];\n return workspaceGroup === \"plugins\" && layoutKey ? layoutKey : null;\n}\n\n/**\n * Synthesize the rsbuild config for a folder-form ui source (the plugin\n * build contract, not per-plugin config — mirrors the rspack generated\n * config). Returns the config file path, or null when the workspace has no\n * folder-form ui source.\n */\nexport function ensureGeneratedUiRsbuildConfig(cwd: string): string | null {\n if (!hasFolderFormUi(cwd)) return null;\n // The manifest's name derives ONLY from the plugins/<key> layout key\n // (ADR 0008 §2) — a non-derivable key fails the build loudly, never the\n // container-name fallback that mis-keyed manifests.\n const pluginId = pluginLayoutKey(cwd);\n if (!pluginId) {\n throw new Error(\n `[every-plugin] cannot derive the ui's composition key from ${cwd} — no authored config (bos.app.ts / bos.config.json) found above a plugins/<key> directory. The manifest name is the layout key; the container name is never a fallback.`,\n );\n }\n const outDir = path.join(cwd, GENERATED_CONFIG_DIR);\n fs.mkdirSync(outDir, { recursive: true });\n const outPath = path.join(outDir, GENERATED_UI_CONFIG);\n const next = generatedUiConfig(pluginId);\n if (!fs.existsSync(outPath) || fs.readFileSync(outPath, \"utf8\") !== next) {\n fs.writeFileSync(outPath, next);\n }\n return outPath;\n}\n\nconst CORE_UI_MARKERS = {\n routes: \"src/routes\",\n contract: \"src/contract.ts\",\n};\n\n/**\n * Workspace-form core ui: the workspace IS the ui (own package.json, route\n * tree) and is not plugin-shaped — the /api counterpart of the plugin\n * workspace form. The entry stub is NOT a marker: it is generated\n * (ADR 0023), so a fresh clone has no bootstrap stubs until the first\n * generation pass.\n */\nexport function hasCoreUiWorkspace(cwd: string = process.cwd()): boolean {\n return (\n fs.existsSync(path.join(cwd, CORE_UI_MARKERS.routes)) &&\n !fs.existsSync(path.join(cwd, CORE_UI_MARKERS.contract)) &&\n !fs.existsSync(path.join(cwd, \"plugin.dev.ts\"))\n );\n}\n\nfunction generatedCoreUiConfig(): string {\n return `import { defineConfig } from \"@rsbuild/core\";\nimport { readAuthoredConfigInput } from \"everything-dev/config\";\nimport { createCoreUiRsbuildConfig } from \"every-plugin/build/ui\";\n\nexport default defineConfig(async () =>\n createCoreUiRsbuildConfig(await readAuthoredConfigInput()),\n);\n`;\n}\n\n/**\n * Synthesize the rsbuild config for a workspace-form core ui with no local\n * `rsbuild.config.ts` — the /api generated-config model. A local file is an\n * override and wins untouched. Returns the workspace-relative config path,\n * or null when the workspace is not a core ui (or has a local config).\n */\nexport function ensureGeneratedCoreUiRsbuildConfig(cwd: string = process.cwd()): string | null {\n if (!hasCoreUiWorkspace(cwd)) return null;\n if (fs.existsSync(path.join(cwd, \"rsbuild.config.ts\"))) return null;\n const outDir = path.join(cwd, GENERATED_CONFIG_DIR);\n fs.mkdirSync(outDir, { recursive: true });\n const outPath = path.join(outDir, GENERATED_UI_CONFIG);\n fs.writeFileSync(outPath, generatedCoreUiConfig());\n console.log(\"[every-plugin] rsbuild.config.ts not found — using the core ui build factory.\");\n return path.join(GENERATED_CONFIG_DIR, GENERATED_UI_CONFIG);\n}\n"],"mappings":";;;;;AAIA,MAAM,SAAS;AACf,MAAM,uBAAuB;AAC7B,MAAM,sBAAsB;;;;;;;AAQ5B,SAAgB,gBAAgB,KAAsB;CACpD,MAAM,QAAQ,KAAK,KAAK,KAAK,MAAM;CACnC,OACE,GAAG,WAAW,KAAK,KAAK,OAAO,OAAO,QAAQ,CAAC,KAC/C,CAAC,GAAG,WAAW,KAAK,KAAK,OAAO,cAAc,CAAC;AAEnD;AAEA,SAAS,kBAAkB,UAA0B;CACnD,OAAO;;;;;;;;;;kBAUS,KAAK,UAAU,QAAQ,EAAE;;;;;;;;;AAS3C;;;;;;;AAQA,SAAgB,gBAAgB,KAA4B;CAC1D,MAAM,gBAAgB,kBAAkB,GAAG;CAI3C,MAAM,CAAC,gBAAgB,cAHG,gBACtB,KAAK,SAAS,KAAK,QAAQ,aAAa,GAAG,GAAG,IAC9C,OACiD,EAAE,MAAM,KAAK,GAAG,KAAK,CAAC;CAC3E,OAAO,mBAAmB,aAAa,YAAY,YAAY;AACjE;;;;;;;AAQA,SAAgB,+BAA+B,KAA4B;CACzE,IAAI,CAAC,gBAAgB,GAAG,GAAG,OAAO;CAIlC,MAAM,WAAW,gBAAgB,GAAG;CACpC,IAAI,CAAC,UACH,MAAM,IAAI,MACR,8DAA8D,IAAI,yKACpE;CAEF,MAAM,SAAS,KAAK,KAAK,KAAK,oBAAoB;CAClD,GAAG,UAAU,QAAQ,EAAE,WAAW,KAAK,CAAC;CACxC,MAAM,UAAU,KAAK,KAAK,QAAQ,mBAAmB;CACrD,MAAM,OAAO,kBAAkB,QAAQ;CACvC,IAAI,CAAC,GAAG,WAAW,OAAO,KAAK,GAAG,aAAa,SAAS,MAAM,MAAM,MAClE,GAAG,cAAc,SAAS,IAAI;CAEhC,OAAO;AACT;AAEA,MAAM,kBAAkB;CACtB,QAAQ;CACR,UAAU;AACZ;;;;;;;;AASA,SAAgB,mBAAmB,MAAc,QAAQ,IAAI,GAAY;CACvE,OACE,GAAG,WAAW,KAAK,KAAK,KAAK,gBAAgB,MAAM,CAAC,KACpD,CAAC,GAAG,WAAW,KAAK,KAAK,KAAK,gBAAgB,QAAQ,CAAC,KACvD,CAAC,GAAG,WAAW,KAAK,KAAK,KAAK,eAAe,CAAC;AAElD;AAEA,SAAS,wBAAgC;CACvC,OAAO;;;;;;;;AAQT;;;;;;;AAQA,SAAgB,mCAAmC,MAAc,QAAQ,IAAI,GAAkB;CAC7F,IAAI,CAAC,mBAAmB,GAAG,GAAG,OAAO;CACrC,IAAI,GAAG,WAAW,KAAK,KAAK,KAAK,mBAAmB,CAAC,GAAG,OAAO;CAC/D,MAAM,SAAS,KAAK,KAAK,KAAK,oBAAoB;CAClD,GAAG,UAAU,QAAQ,EAAE,WAAW,KAAK,CAAC;CACxC,MAAM,UAAU,KAAK,KAAK,QAAQ,mBAAmB;CACrD,GAAG,cAAc,SAAS,sBAAsB,CAAC;CACjD,QAAQ,IAAI,+EAA+E;CAC3F,OAAO,KAAK,KAAK,sBAAsB,mBAAmB;AAC5D"}
|
|
1
|
+
{"version":3,"file":"generated-config.mjs","names":[],"sources":["../../../src/build/ui/generated-config.ts"],"sourcesContent":["import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { findBosConfigPath } from \"../rspack/compose\";\n\nconst UI_DIR = \"ui\";\nconst GENERATED_CONFIG_DIR = \".every-plugin\";\nconst GENERATED_UI_CONFIG = \"ui.rsbuild.config.generated.mjs\";\n\n/**\n * Folder-form UI source: a `ui/` directory with route files but no own\n * package.json — the plugin workspace owns the build (single-workspace\n * plugin, one dev process, one deploy train). Workspace-form ui sources\n * (own package.json + scripts) are NOT managed here.\n */\nexport function hasFolderFormUi(cwd: string): boolean {\n const uiDir = path.join(cwd, UI_DIR);\n return (\n fs.existsSync(path.join(uiDir, \"src\", \"routes\")) &&\n !fs.existsSync(path.join(uiDir, \"package.json\"))\n );\n}\n\nexport function uiDistDirFor(cwd: string): string {\n return path.join(cwd, UI_DIR, \"dist\");\n}\n\nfunction generatedUiConfig(pluginId: string): string {\n return `import path from \"node:path\";\nimport { createUiRsbuildConfig } from \"every-plugin/build/ui\";\nimport pkg from \"../package.json\";\n\nconst workspaceRoot = path.resolve(import.meta.dirname, \"..\", \"ui\");\n\nexport default createUiRsbuildConfig({\n workspaceRoot,\n pkg,\n role: \"consumer\",\n manifestName: ${JSON.stringify(pluginId)},\n devPort: Number(process.env.BOS_UI_PORT) || 0,\n webEntry: \"./ui/src/routeConfig.gen.ts\",\n webExposes: { \"./routeConfig\": \"./ui/src/routeConfig.gen.ts\" },\n nodeEntry: \"./ui/src/routeConfig.gen.ts\",\n nodeExposes: { \"./routeConfig\": \"./ui/src/routeConfig.gen.ts\" },\n routesDirectory: \"./ui/src/routes\",\n});\n`;\n}\n\n/**\n * Canonical config-layout derivation: the composition key for a plugin\n * workspace — the `<key>` of the `plugins/<key>` directory relative to the\n * nearest `bos.config.json`. The dev server and the generated ui config\n * both key off this; no consumer keeps a private copy.\n */\nexport function pluginLayoutKey(cwd: string): string | null {\n const bosConfigPath = findBosConfigPath(cwd);\n const relativeWorkspace = bosConfigPath\n ? path.relative(path.dirname(bosConfigPath), cwd)\n : undefined;\n const [workspaceGroup, layoutKey] = relativeWorkspace?.split(path.sep) ?? [];\n return workspaceGroup === \"plugins\" && layoutKey ? layoutKey : null;\n}\n\n/**\n * Synthesize the rsbuild config for a folder-form ui source (the plugin\n * build contract, not per-plugin config — mirrors the rspack generated\n * config). Returns the config file path, or null when the workspace has no\n * folder-form ui source.\n */\nexport function ensureGeneratedUiRsbuildConfig(cwd: string): string | null {\n if (!hasFolderFormUi(cwd)) return null;\n // The manifest's name derives ONLY from the plugins/<key> layout key\n // (ADR 0008 §2) — a non-derivable key fails the build loudly, never the\n // container-name fallback that mis-keyed manifests.\n const pluginId = pluginLayoutKey(cwd);\n if (!pluginId) {\n throw new Error(\n `[every-plugin] cannot derive the ui's composition key from ${cwd} — no authored config (bos.app.ts / bos.config.json) found above a plugins/<key> directory. The manifest name is the layout key; the container name is never a fallback.`,\n );\n }\n const outDir = path.join(cwd, GENERATED_CONFIG_DIR);\n fs.mkdirSync(outDir, { recursive: true });\n const outPath = path.join(outDir, GENERATED_UI_CONFIG);\n const next = generatedUiConfig(pluginId);\n if (!fs.existsSync(outPath) || fs.readFileSync(outPath, \"utf8\") !== next) {\n fs.writeFileSync(outPath, next);\n }\n return outPath;\n}\n\nconst CORE_UI_MARKERS = {\n routes: \"src/routes\",\n contract: \"src/contract.ts\",\n};\n\n/**\n * Workspace-form core ui: the workspace IS the ui (own package.json, route\n * tree) and is not plugin-shaped — the /api counterpart of the plugin\n * workspace form. The entry stub is NOT a marker: it is generated\n * (ADR 0023), so a fresh clone has no bootstrap stubs until the first\n * generation pass.\n */\nexport function hasCoreUiWorkspace(cwd: string = process.cwd()): boolean {\n return (\n fs.existsSync(path.join(cwd, CORE_UI_MARKERS.routes)) &&\n !fs.existsSync(path.join(cwd, CORE_UI_MARKERS.contract)) &&\n !fs.existsSync(path.join(cwd, \"plugin.dev.ts\"))\n );\n}\n\nfunction generatedCoreUiConfig(): string {\n return `import { defineConfig } from \"@rsbuild/core\";\nimport { readAuthoredConfigInput } from \"everything-dev/config\";\nimport { createCoreUiRsbuildConfig } from \"every-plugin/build/ui\";\n\nexport default defineConfig(async () =>\n createCoreUiRsbuildConfig(await readAuthoredConfigInput()),\n);\n`;\n}\n\n/**\n * Synthesize the rsbuild config for a workspace-form core ui with no local\n * `rsbuild.config.ts` — the /api generated-config model. A local file is an\n * override and wins untouched. Returns the workspace-relative config path,\n * or null when the workspace is not a core ui (or has a local config).\n */\nexport function ensureGeneratedCoreUiRsbuildConfig(cwd: string = process.cwd()): string | null {\n if (!hasCoreUiWorkspace(cwd)) return null;\n if (fs.existsSync(path.join(cwd, \"rsbuild.config.ts\"))) return null;\n const outDir = path.join(cwd, GENERATED_CONFIG_DIR);\n fs.mkdirSync(outDir, { recursive: true });\n const outPath = path.join(outDir, GENERATED_UI_CONFIG);\n fs.writeFileSync(outPath, generatedCoreUiConfig());\n console.log(\"[every-plugin] rsbuild.config.ts not found — using the core ui build factory.\");\n return path.join(GENERATED_CONFIG_DIR, GENERATED_UI_CONFIG);\n}\n"],"mappings":";;;;;AAIA,MAAM,SAAS;AACf,MAAM,uBAAuB;AAC7B,MAAM,sBAAsB;;;;;;;AAQ5B,SAAgB,gBAAgB,KAAsB;CACpD,MAAM,QAAQ,KAAK,KAAK,KAAK,MAAM;CACnC,OACE,GAAG,WAAW,KAAK,KAAK,OAAO,OAAO,QAAQ,CAAC,KAC/C,CAAC,GAAG,WAAW,KAAK,KAAK,OAAO,cAAc,CAAC;AAEnD;AAEA,SAAgB,aAAa,KAAqB;CAChD,OAAO,KAAK,KAAK,KAAK,QAAQ,MAAM;AACtC;AAEA,SAAS,kBAAkB,UAA0B;CACnD,OAAO;;;;;;;;;;kBAUS,KAAK,UAAU,QAAQ,EAAE;;;;;;;;;AAS3C;;;;;;;AAQA,SAAgB,gBAAgB,KAA4B;CAC1D,MAAM,gBAAgB,kBAAkB,GAAG;CAI3C,MAAM,CAAC,gBAAgB,cAHG,gBACtB,KAAK,SAAS,KAAK,QAAQ,aAAa,GAAG,GAAG,IAC9C,OACiD,EAAE,MAAM,KAAK,GAAG,KAAK,CAAC;CAC3E,OAAO,mBAAmB,aAAa,YAAY,YAAY;AACjE;;;;;;;AAQA,SAAgB,+BAA+B,KAA4B;CACzE,IAAI,CAAC,gBAAgB,GAAG,GAAG,OAAO;CAIlC,MAAM,WAAW,gBAAgB,GAAG;CACpC,IAAI,CAAC,UACH,MAAM,IAAI,MACR,8DAA8D,IAAI,yKACpE;CAEF,MAAM,SAAS,KAAK,KAAK,KAAK,oBAAoB;CAClD,GAAG,UAAU,QAAQ,EAAE,WAAW,KAAK,CAAC;CACxC,MAAM,UAAU,KAAK,KAAK,QAAQ,mBAAmB;CACrD,MAAM,OAAO,kBAAkB,QAAQ;CACvC,IAAI,CAAC,GAAG,WAAW,OAAO,KAAK,GAAG,aAAa,SAAS,MAAM,MAAM,MAClE,GAAG,cAAc,SAAS,IAAI;CAEhC,OAAO;AACT;AAEA,MAAM,kBAAkB;CACtB,QAAQ;CACR,UAAU;AACZ;;;;;;;;AASA,SAAgB,mBAAmB,MAAc,QAAQ,IAAI,GAAY;CACvE,OACE,GAAG,WAAW,KAAK,KAAK,KAAK,gBAAgB,MAAM,CAAC,KACpD,CAAC,GAAG,WAAW,KAAK,KAAK,KAAK,gBAAgB,QAAQ,CAAC,KACvD,CAAC,GAAG,WAAW,KAAK,KAAK,KAAK,eAAe,CAAC;AAElD;AAEA,SAAS,wBAAgC;CACvC,OAAO;;;;;;;;AAQT;;;;;;;AAQA,SAAgB,mCAAmC,MAAc,QAAQ,IAAI,GAAkB;CAC7F,IAAI,CAAC,mBAAmB,GAAG,GAAG,OAAO;CACrC,IAAI,GAAG,WAAW,KAAK,KAAK,KAAK,mBAAmB,CAAC,GAAG,OAAO;CAC/D,MAAM,SAAS,KAAK,KAAK,KAAK,oBAAoB;CAClD,GAAG,UAAU,QAAQ,EAAE,WAAW,KAAK,CAAC;CACxC,MAAM,UAAU,KAAK,KAAK,QAAQ,mBAAmB;CACrD,GAAG,cAAc,SAAS,sBAAsB,CAAC;CACjD,QAAQ,IAAI,+EAA+E;CAC3F,OAAO,KAAK,KAAK,sBAAsB,mBAAmB;AAC5D"}
|
|
@@ -88,6 +88,7 @@ function createUiRsbuildConfig(options) {
|
|
|
88
88
|
target: "react",
|
|
89
89
|
autoCodeSplitting: true,
|
|
90
90
|
routeFileIgnorePattern: "\\.(test|spec)\\.(ts|tsx)$",
|
|
91
|
+
generatedRouteTree: node_path.default.join(workspaceRootAbsolute, "src/routeTree.gen.ts"),
|
|
91
92
|
...routesDirectory ? { routesDirectory } : {}
|
|
92
93
|
}),
|
|
93
94
|
new require_fix_mf_data_uri_plugin.FixMfDataUriPlugin()
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rsbuild-config.cjs","names":["path","sanitizeContainerName","uiManifestGenPlugin","createUiSharedDeps","isBuildInvocation","pluginReact","pluginModuleFederation","uiEntryFilename","hashArtifactsPlugin","rspack","TanStackRouterRspack","FixMfDataUriPlugin","MANIFEST_FILENAME","restoreManifestPublicPath","defineConfig"],"sources":["../../../src/build/ui/rsbuild-config.ts"],"sourcesContent":["import path from \"node:path\";\nimport { pluginModuleFederation } from \"@module-federation/rsbuild-plugin\";\nimport { defineConfig, type EnvironmentConfig, type RsbuildConfig, rspack } from \"@rsbuild/core\";\nimport { pluginReact } from \"@rsbuild/plugin-react\";\nimport { TanStackRouterRspack } from \"@tanstack/router-plugin/rspack\";\nimport { FixMfDataUriPlugin } from \"../../build/rspack\";\nimport { createUiSharedDeps } from \"../../shared-deps-spec\";\nimport { sanitizeContainerName } from \"../../ui/manifest/contract\";\nimport { isBuildInvocation, uiEntryFilename } from \"../artifact-names\";\nimport { hashArtifactsPlugin } from \"./hash-artifacts-plugin\";\nimport { MANIFEST_FILENAME, restoreManifestPublicPath } from \"./index\";\nimport { uiManifestGenPlugin } from \"./manifest-plugin\";\n\n/**\n * The full dual-environment rsbuild config for a manifest-composed ui source\n * (ADR 0008 §7 — the plugin build contract, not per-plugin config). The core\n * ui and every plugin ui source build from this one factory: `web` emits the\n * browser remote, `node` the commonjs SSR container; shared deps are strict\n * singletons in the given role.\n */\nexport interface UiRsbuildConfigOptions {\n /** the ui source root — contains package.json, src/, and the routes dir */\n workspaceRoot: string;\n /** the ui workspace's package.json (shared-dep version resolution) */\n pkg: {\n name: string;\n version?: string;\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n };\n /** core provides the shared singletons; plugin remotes consume (`import: false`) */\n role: \"provider\" | \"consumer\";\n /** the composition key written into manifest.gen.json (the config-side key) */\n manifestName: string;\n devPort: number;\n webEntry: string;\n webExposes: Record<string, string>;\n nodeEntry: string;\n nodeExposes: Record<string, string>;\n copy?: Array<{\n from: string;\n to: string;\n globOptions?: { ignore?: string[] };\n }>;\n define?: Record<string, string>;\n /** routes dir relative to the rsbuild cwd — folder-form ui sources live at\n * `ui/src/routes` while the build runs from the plugin root */\n routesDirectory?: string;\n}\n\nexport { sanitizeContainerName };\n\n/**\n * The node environment never owns the routeTree write: the web env's\n * generator produces identical content, and both environments resolve the\n * same on-disk tree. Redirecting the node write to scratch removes the\n * concurrent-writers race on src/routeTree.gen.ts (the generator's\n * \"Cannot overwrite\" retry noise).\n */\nconst NODE_ROUTE_TREE_SCRATCH = \"./node_modules/.cache/manifest-compose/routeTree.node.gen.ts\";\n\nexport function createUiRsbuildConfig(options: UiRsbuildConfigOptions): RsbuildConfig {\n const {\n workspaceRoot,\n pkg,\n role,\n manifestName,\n devPort,\n webEntry,\n webExposes,\n nodeEntry,\n nodeExposes,\n copy = [],\n define,\n routesDirectory,\n } = options;\n const workspaceRootAbsolute = path.resolve(workspaceRoot);\n const normalizedName = sanitizeContainerName(pkg.name);\n const manifestGen = () =>\n uiManifestGenPlugin({ workspaceRoot: workspaceRootAbsolute, pluginName: manifestName });\n const uiSharedDeps = createUiSharedDeps({ role, workspaceRoot: workspaceRootAbsolute });\n\n const isBuild = isBuildInvocation();\n\n const webEnvironment: EnvironmentConfig = {\n plugins: [\n pluginReact(),\n manifestGen(),\n pluginModuleFederation(\n {\n name: normalizedName,\n filename: uiEntryFilename({ isBuild }),\n dts: false,\n exposes: webExposes,\n shared: uiSharedDeps,\n },\n { environment: \"web\" },\n ),\n ...(isBuild\n ? [\n hashArtifactsPlugin({\n entryBase: \"remoteEntry\",\n distRoot: path.join(workspaceRootAbsolute, \"dist\"),\n }),\n ]\n : []),\n ],\n source: { entry: { index: webEntry }, ...(define ? { define } : {}) },\n resolve: { alias: { \"@\": path.join(workspaceRootAbsolute, \"src\") } },\n tools: {\n rspack: (config) => {\n const cssPlugin = config.plugins?.find((p) => p instanceof rspack.CssExtractRspackPlugin) as\n | { options?: Record<string, string> }\n | undefined;\n if (cssPlugin) {\n cssPlugin.options ??= {};\n cssPlugin.options.chunkFilename = \"static/css/async/[name].[contenthash].css\";\n }\n Object.assign(config, {\n target: \"web\",\n output: {\n ...config.output,\n publicPath: \"auto\",\n uniqueName: normalizedName,\n chunkFilename: \"static/js/async/[name].[contenthash].js\",\n crossOriginLoading: \"anonymous\",\n },\n resolve: {\n ...config.resolve,\n fallback: { bufferutil: false, \"utf-8-validate\": false },\n },\n infrastructureLogging: { level: \"error\" },\n stats: \"errors-warnings\",\n plugins: [\n ...(config.plugins ?? []),\n TanStackRouterRspack({\n target: \"react\",\n autoCodeSplitting: true,\n routeFileIgnorePattern: \"\\\\.(test|spec)\\\\.(ts|tsx)$\",\n ...(routesDirectory ? { routesDirectory } : {}),\n }),\n new FixMfDataUriPlugin(),\n ],\n });\n return config;\n },\n },\n output: {\n // Absolute: the ui source root owns dist even when the build cwd is the\n // parent plugin workspace (folder-form ui sources).\n distPath: {\n root: path.join(workspaceRootAbsolute, \"dist\"),\n css: \"static/css\",\n js: \"static/js\",\n },\n assetPrefix: \"auto\",\n filename: { js: \"[name].js\", css: \"style.css\" },\n copy: [\n ...copy,\n { from: path.join(workspaceRootAbsolute, \"src\", MANIFEST_FILENAME), to: \"./\" },\n ],\n },\n };\n\n // Dev without SSR skips the node environment: it exists for the host's dev\n // SSR container and nothing else. Builds always emit both.\n const includeNodeEnv =\n process.env.BOS_SSR === \"1\" ||\n process.env.DEPLOY === \"true\" ||\n process.env.NODE_ENV !== \"development\";\n\n const nodeEnvironment: EnvironmentConfig = {\n plugins: [\n pluginReact(),\n manifestGen(),\n pluginModuleFederation(\n {\n name: normalizedName,\n filename: uiEntryFilename({ isBuild, server: true }),\n dts: false,\n exposes: nodeExposes,\n shared: uiSharedDeps,\n },\n { target: \"node\", environment: \"node\" },\n ),\n restoreManifestPublicPath(path.resolve(workspaceRootAbsolute, \"dist\", \"ssr\")),\n ...(isBuild\n ? [\n hashArtifactsPlugin({\n entryBase: \"remoteEntry.server\",\n distRoot: path.resolve(workspaceRootAbsolute, \"dist\", \"ssr\"),\n }),\n ]\n : []),\n ],\n source: { entry: { index: nodeEntry } },\n resolve: {\n alias: {\n \"@\": path.join(workspaceRootAbsolute, \"src\"),\n \"@tanstack/react-devtools\": false,\n \"@tanstack/react-router-devtools\": false,\n },\n },\n tools: {\n rspack: (config) => {\n Object.assign(config, {\n output: { ...config.output, uniqueName: `${normalizedName}_server` },\n resolve: {\n ...config.resolve,\n fallback: { bufferutil: false, \"utf-8-validate\": false },\n },\n externals: [/^node:/],\n infrastructureLogging: { level: \"error\" },\n stats: \"errors-warnings\",\n plugins: [\n ...(config.plugins ?? []),\n TanStackRouterRspack({\n target: \"react\",\n autoCodeSplitting: false,\n routeFileIgnorePattern: \"\\\\.(test|spec)\\\\.(ts|tsx)$\",\n generatedRouteTree: NODE_ROUTE_TREE_SCRATCH,\n ...(routesDirectory ? { routesDirectory } : {}),\n }),\n new FixMfDataUriPlugin(),\n ],\n });\n return config;\n },\n },\n // Absolute, like the web dist above — the node container must land in the\n // ui source root's dist/ssr where the host's local container server looks.\n output: { distPath: { root: path.join(workspaceRootAbsolute, \"dist\", \"ssr\") } },\n };\n\n return defineConfig({\n environments: {\n web: webEnvironment,\n ...(includeNodeEnv ? { node: nodeEnvironment } : {}),\n },\n dev: {\n lazyCompilation: false,\n progressBar: false,\n writeToDisk: true,\n client: { overlay: false },\n },\n server: {\n port: Number(process.env.PORT) || devPort,\n printUrls: ({ urls }) => urls.filter((url) => url.includes(\"localhost\")),\n headers: {\n \"Access-Control-Allow-Origin\": \"*\",\n \"Access-Control-Allow-Methods\": \"GET, POST, OPTIONS\",\n \"Access-Control-Allow-Headers\": \"Content-Type\",\n },\n },\n });\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"rsbuild-config.cjs","names":["path","sanitizeContainerName","uiManifestGenPlugin","createUiSharedDeps","isBuildInvocation","pluginReact","pluginModuleFederation","uiEntryFilename","hashArtifactsPlugin","rspack","TanStackRouterRspack","FixMfDataUriPlugin","MANIFEST_FILENAME","restoreManifestPublicPath","defineConfig"],"sources":["../../../src/build/ui/rsbuild-config.ts"],"sourcesContent":["import path from \"node:path\";\nimport { pluginModuleFederation } from \"@module-federation/rsbuild-plugin\";\nimport { defineConfig, type EnvironmentConfig, type RsbuildConfig, rspack } from \"@rsbuild/core\";\nimport { pluginReact } from \"@rsbuild/plugin-react\";\nimport { TanStackRouterRspack } from \"@tanstack/router-plugin/rspack\";\nimport { FixMfDataUriPlugin } from \"../../build/rspack\";\nimport { createUiSharedDeps } from \"../../shared-deps-spec\";\nimport { sanitizeContainerName } from \"../../ui/manifest/contract\";\nimport { isBuildInvocation, uiEntryFilename } from \"../artifact-names\";\nimport { hashArtifactsPlugin } from \"./hash-artifacts-plugin\";\nimport { MANIFEST_FILENAME, restoreManifestPublicPath } from \"./index\";\nimport { uiManifestGenPlugin } from \"./manifest-plugin\";\n\n/**\n * The full dual-environment rsbuild config for a manifest-composed ui source\n * (ADR 0008 §7 — the plugin build contract, not per-plugin config). The core\n * ui and every plugin ui source build from this one factory: `web` emits the\n * browser remote, `node` the commonjs SSR container; shared deps are strict\n * singletons in the given role.\n */\nexport interface UiRsbuildConfigOptions {\n /** the ui source root — contains package.json, src/, and the routes dir */\n workspaceRoot: string;\n /** the ui workspace's package.json (shared-dep version resolution) */\n pkg: {\n name: string;\n version?: string;\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n };\n /** core provides the shared singletons; plugin remotes consume (`import: false`) */\n role: \"provider\" | \"consumer\";\n /** the composition key written into manifest.gen.json (the config-side key) */\n manifestName: string;\n devPort: number;\n webEntry: string;\n webExposes: Record<string, string>;\n nodeEntry: string;\n nodeExposes: Record<string, string>;\n copy?: Array<{\n from: string;\n to: string;\n globOptions?: { ignore?: string[] };\n }>;\n define?: Record<string, string>;\n /** routes dir relative to the rsbuild cwd — folder-form ui sources live at\n * `ui/src/routes` while the build runs from the plugin root */\n routesDirectory?: string;\n}\n\nexport { sanitizeContainerName };\n\n/**\n * The node environment never owns the routeTree write: the web env's\n * generator produces identical content, and both environments resolve the\n * same on-disk tree. Redirecting the node write to scratch removes the\n * concurrent-writers race on src/routeTree.gen.ts (the generator's\n * \"Cannot overwrite\" retry noise).\n */\nconst NODE_ROUTE_TREE_SCRATCH = \"./node_modules/.cache/manifest-compose/routeTree.node.gen.ts\";\n\nexport function createUiRsbuildConfig(options: UiRsbuildConfigOptions): RsbuildConfig {\n const {\n workspaceRoot,\n pkg,\n role,\n manifestName,\n devPort,\n webEntry,\n webExposes,\n nodeEntry,\n nodeExposes,\n copy = [],\n define,\n routesDirectory,\n } = options;\n const workspaceRootAbsolute = path.resolve(workspaceRoot);\n const normalizedName = sanitizeContainerName(pkg.name);\n const manifestGen = () =>\n uiManifestGenPlugin({ workspaceRoot: workspaceRootAbsolute, pluginName: manifestName });\n const uiSharedDeps = createUiSharedDeps({ role, workspaceRoot: workspaceRootAbsolute });\n\n const isBuild = isBuildInvocation();\n\n const webEnvironment: EnvironmentConfig = {\n plugins: [\n pluginReact(),\n manifestGen(),\n pluginModuleFederation(\n {\n name: normalizedName,\n filename: uiEntryFilename({ isBuild }),\n dts: false,\n exposes: webExposes,\n shared: uiSharedDeps,\n },\n { environment: \"web\" },\n ),\n ...(isBuild\n ? [\n hashArtifactsPlugin({\n entryBase: \"remoteEntry\",\n distRoot: path.join(workspaceRootAbsolute, \"dist\"),\n }),\n ]\n : []),\n ],\n source: { entry: { index: webEntry }, ...(define ? { define } : {}) },\n resolve: { alias: { \"@\": path.join(workspaceRootAbsolute, \"src\") } },\n tools: {\n rspack: (config) => {\n const cssPlugin = config.plugins?.find((p) => p instanceof rspack.CssExtractRspackPlugin) as\n | { options?: Record<string, string> }\n | undefined;\n if (cssPlugin) {\n cssPlugin.options ??= {};\n cssPlugin.options.chunkFilename = \"static/css/async/[name].[contenthash].css\";\n }\n Object.assign(config, {\n target: \"web\",\n output: {\n ...config.output,\n publicPath: \"auto\",\n uniqueName: normalizedName,\n chunkFilename: \"static/js/async/[name].[contenthash].js\",\n crossOriginLoading: \"anonymous\",\n },\n resolve: {\n ...config.resolve,\n fallback: { bufferutil: false, \"utf-8-validate\": false },\n },\n infrastructureLogging: { level: \"error\" },\n stats: \"errors-warnings\",\n plugins: [\n ...(config.plugins ?? []),\n TanStackRouterRspack({\n target: \"react\",\n autoCodeSplitting: true,\n routeFileIgnorePattern: \"\\\\.(test|spec)\\\\.(ts|tsx)$\",\n generatedRouteTree: path.join(workspaceRootAbsolute, \"src/routeTree.gen.ts\"),\n ...(routesDirectory ? { routesDirectory } : {}),\n }),\n new FixMfDataUriPlugin(),\n ],\n });\n return config;\n },\n },\n output: {\n // Absolute: the ui source root owns dist even when the build cwd is the\n // parent plugin workspace (folder-form ui sources).\n distPath: {\n root: path.join(workspaceRootAbsolute, \"dist\"),\n css: \"static/css\",\n js: \"static/js\",\n },\n assetPrefix: \"auto\",\n filename: { js: \"[name].js\", css: \"style.css\" },\n copy: [\n ...copy,\n { from: path.join(workspaceRootAbsolute, \"src\", MANIFEST_FILENAME), to: \"./\" },\n ],\n },\n };\n\n // Dev without SSR skips the node environment: it exists for the host's dev\n // SSR container and nothing else. Builds always emit both.\n const includeNodeEnv =\n process.env.BOS_SSR === \"1\" ||\n process.env.DEPLOY === \"true\" ||\n process.env.NODE_ENV !== \"development\";\n\n const nodeEnvironment: EnvironmentConfig = {\n plugins: [\n pluginReact(),\n manifestGen(),\n pluginModuleFederation(\n {\n name: normalizedName,\n filename: uiEntryFilename({ isBuild, server: true }),\n dts: false,\n exposes: nodeExposes,\n shared: uiSharedDeps,\n },\n { target: \"node\", environment: \"node\" },\n ),\n restoreManifestPublicPath(path.resolve(workspaceRootAbsolute, \"dist\", \"ssr\")),\n ...(isBuild\n ? [\n hashArtifactsPlugin({\n entryBase: \"remoteEntry.server\",\n distRoot: path.resolve(workspaceRootAbsolute, \"dist\", \"ssr\"),\n }),\n ]\n : []),\n ],\n source: { entry: { index: nodeEntry } },\n resolve: {\n alias: {\n \"@\": path.join(workspaceRootAbsolute, \"src\"),\n \"@tanstack/react-devtools\": false,\n \"@tanstack/react-router-devtools\": false,\n },\n },\n tools: {\n rspack: (config) => {\n Object.assign(config, {\n output: { ...config.output, uniqueName: `${normalizedName}_server` },\n resolve: {\n ...config.resolve,\n fallback: { bufferutil: false, \"utf-8-validate\": false },\n },\n externals: [/^node:/],\n infrastructureLogging: { level: \"error\" },\n stats: \"errors-warnings\",\n plugins: [\n ...(config.plugins ?? []),\n TanStackRouterRspack({\n target: \"react\",\n autoCodeSplitting: false,\n routeFileIgnorePattern: \"\\\\.(test|spec)\\\\.(ts|tsx)$\",\n generatedRouteTree: NODE_ROUTE_TREE_SCRATCH,\n ...(routesDirectory ? { routesDirectory } : {}),\n }),\n new FixMfDataUriPlugin(),\n ],\n });\n return config;\n },\n },\n // Absolute, like the web dist above — the node container must land in the\n // ui source root's dist/ssr where the host's local container server looks.\n output: { distPath: { root: path.join(workspaceRootAbsolute, \"dist\", \"ssr\") } },\n };\n\n return defineConfig({\n environments: {\n web: webEnvironment,\n ...(includeNodeEnv ? { node: nodeEnvironment } : {}),\n },\n dev: {\n lazyCompilation: false,\n progressBar: false,\n writeToDisk: true,\n client: { overlay: false },\n },\n server: {\n port: Number(process.env.PORT) || devPort,\n printUrls: ({ urls }) => urls.filter((url) => url.includes(\"localhost\")),\n headers: {\n \"Access-Control-Allow-Origin\": \"*\",\n \"Access-Control-Allow-Methods\": \"GET, POST, OPTIONS\",\n \"Access-Control-Allow-Headers\": \"Content-Type\",\n },\n },\n });\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AA2DA,MAAM,0BAA0B;AAEhC,SAAgB,sBAAsB,SAAgD;CACpF,MAAM,EACJ,eACA,KACA,MACA,cACA,SACA,UACA,YACA,WACA,aACA,OAAO,CAAC,GACR,QACA,oBACE;CACJ,MAAM,wBAAwBA,kBAAK,QAAQ,aAAa;CACxD,MAAM,iBAAiBC,+BAAsB,IAAI,IAAI;CACrD,MAAM,oBACJC,4CAAoB;EAAE,eAAe;EAAuB,YAAY;CAAa,CAAC;CACxF,MAAM,eAAeC,4CAAmB;EAAE;EAAM,eAAe;CAAsB,CAAC;CAEtF,MAAM,UAAUC,+CAAkB;CAElC,MAAM,iBAAoC;EACxC,SAAS;OACPC,mCAAY;GACZ,YAAY;OACZC,0DACE;IACE,MAAM;IACN,UAAUC,6CAAgB,EAAE,QAAQ,CAAC;IACrC,KAAK;IACL,SAAS;IACT,QAAQ;GACV,GACA,EAAE,aAAa,MAAM,CACvB;GACA,GAAI,UACA,CACEC,kDAAoB;IAClB,WAAW;IACX,UAAUR,kBAAK,KAAK,uBAAuB,MAAM;GACnD,CAAC,CACH,IACA,CAAC;EACP;EACA,QAAQ;GAAE,OAAO,EAAE,OAAO,SAAS;GAAG,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;EAAG;EACpE,SAAS,EAAE,OAAO,EAAE,KAAKA,kBAAK,KAAK,uBAAuB,KAAK,EAAE,EAAE;EACnE,OAAO,EACL,SAAS,WAAW;GAClB,MAAM,YAAY,OAAO,SAAS,MAAM,MAAM,aAAaS,qBAAO,sBAAsB;GAGxF,IAAI,WAAW;IACb,UAAU,YAAY,CAAC;IACvB,UAAU,QAAQ,gBAAgB;GACpC;GACA,OAAO,OAAO,QAAQ;IACpB,QAAQ;IACR,QAAQ;KACN,GAAG,OAAO;KACV,YAAY;KACZ,YAAY;KACZ,eAAe;KACf,oBAAoB;IACtB;IACA,SAAS;KACP,GAAG,OAAO;KACV,UAAU;MAAE,YAAY;MAAO,kBAAkB;KAAM;IACzD;IACA,uBAAuB,EAAE,OAAO,QAAQ;IACxC,OAAO;IACP,SAAS;KACP,GAAI,OAAO,WAAW,CAAC;SACvBC,qDAAqB;MACnB,QAAQ;MACR,mBAAmB;MACnB,wBAAwB;MACxB,oBAAoBV,kBAAK,KAAK,uBAAuB,sBAAsB;MAC3E,GAAI,kBAAkB,EAAE,gBAAgB,IAAI,CAAC;KAC/C,CAAC;KACD,IAAIW,kDAAmB;IACzB;GACF,CAAC;GACD,OAAO;EACT,EACF;EACA,QAAQ;GAGN,UAAU;IACR,MAAMX,kBAAK,KAAK,uBAAuB,MAAM;IAC7C,KAAK;IACL,IAAI;GACN;GACA,aAAa;GACb,UAAU;IAAE,IAAI;IAAa,KAAK;GAAY;GAC9C,MAAM,CACJ,GAAG,MACH;IAAE,MAAMA,kBAAK,KAAK,uBAAuB,OAAOY,8CAAiB;IAAG,IAAI;GAAK,CAC/E;EACF;CACF;CAIA,MAAM,iBACJ,QAAQ,IAAI,YAAY,OACxB,QAAQ,IAAI,WAAW,UACvB,QAAQ,IAAI,aAAa;CAE3B,MAAM,kBAAqC;EACzC,SAAS;OACPP,mCAAY;GACZ,YAAY;OACZC,0DACE;IACE,MAAM;IACN,UAAUC,6CAAgB;KAAE;KAAS,QAAQ;IAAK,CAAC;IACnD,KAAK;IACL,SAAS;IACT,QAAQ;GACV,GACA;IAAE,QAAQ;IAAQ,aAAa;GAAO,CACxC;GACAM,iDAA0Bb,kBAAK,QAAQ,uBAAuB,QAAQ,KAAK,CAAC;GAC5E,GAAI,UACA,CACEQ,kDAAoB;IAClB,WAAW;IACX,UAAUR,kBAAK,QAAQ,uBAAuB,QAAQ,KAAK;GAC7D,CAAC,CACH,IACA,CAAC;EACP;EACA,QAAQ,EAAE,OAAO,EAAE,OAAO,UAAU,EAAE;EACtC,SAAS,EACP,OAAO;GACL,KAAKA,kBAAK,KAAK,uBAAuB,KAAK;GAC3C,4BAA4B;GAC5B,mCAAmC;EACrC,EACF;EACA,OAAO,EACL,SAAS,WAAW;GAClB,OAAO,OAAO,QAAQ;IACpB,QAAQ;KAAE,GAAG,OAAO;KAAQ,YAAY,GAAG,eAAe;IAAS;IACnE,SAAS;KACP,GAAG,OAAO;KACV,UAAU;MAAE,YAAY;MAAO,kBAAkB;KAAM;IACzD;IACA,WAAW,CAAC,QAAQ;IACpB,uBAAuB,EAAE,OAAO,QAAQ;IACxC,OAAO;IACP,SAAS;KACP,GAAI,OAAO,WAAW,CAAC;SACvBU,qDAAqB;MACnB,QAAQ;MACR,mBAAmB;MACnB,wBAAwB;MACxB,oBAAoB;MACpB,GAAI,kBAAkB,EAAE,gBAAgB,IAAI,CAAC;KAC/C,CAAC;KACD,IAAIC,kDAAmB;IACzB;GACF,CAAC;GACD,OAAO;EACT,EACF;EAGA,QAAQ,EAAE,UAAU,EAAE,MAAMX,kBAAK,KAAK,uBAAuB,QAAQ,KAAK,EAAE,EAAE;CAChF;CAEA,WAAOc,4BAAa;EAClB,cAAc;GACZ,KAAK;GACL,GAAI,iBAAiB,EAAE,MAAM,gBAAgB,IAAI,CAAC;EACpD;EACA,KAAK;GACH,iBAAiB;GACjB,aAAa;GACb,aAAa;GACb,QAAQ,EAAE,SAAS,MAAM;EAC3B;EACA,QAAQ;GACN,MAAM,OAAO,QAAQ,IAAI,IAAI,KAAK;GAClC,YAAY,EAAE,WAAW,KAAK,QAAQ,QAAQ,IAAI,SAAS,WAAW,CAAC;GACvE,SAAS;IACP,+BAA+B;IAC/B,gCAAgC;IAChC,gCAAgC;GAClC;EACF;CACF,CAAC;AACH"}
|
|
@@ -86,6 +86,7 @@ function createUiRsbuildConfig(options) {
|
|
|
86
86
|
target: "react",
|
|
87
87
|
autoCodeSplitting: true,
|
|
88
88
|
routeFileIgnorePattern: "\\.(test|spec)\\.(ts|tsx)$",
|
|
89
|
+
generatedRouteTree: path.join(workspaceRootAbsolute, "src/routeTree.gen.ts"),
|
|
89
90
|
...routesDirectory ? { routesDirectory } : {}
|
|
90
91
|
}),
|
|
91
92
|
new FixMfDataUriPlugin()
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rsbuild-config.mjs","names":["sanitizeContainerName"],"sources":["../../../src/build/ui/rsbuild-config.ts"],"sourcesContent":["import path from \"node:path\";\nimport { pluginModuleFederation } from \"@module-federation/rsbuild-plugin\";\nimport { defineConfig, type EnvironmentConfig, type RsbuildConfig, rspack } from \"@rsbuild/core\";\nimport { pluginReact } from \"@rsbuild/plugin-react\";\nimport { TanStackRouterRspack } from \"@tanstack/router-plugin/rspack\";\nimport { FixMfDataUriPlugin } from \"../../build/rspack\";\nimport { createUiSharedDeps } from \"../../shared-deps-spec\";\nimport { sanitizeContainerName } from \"../../ui/manifest/contract\";\nimport { isBuildInvocation, uiEntryFilename } from \"../artifact-names\";\nimport { hashArtifactsPlugin } from \"./hash-artifacts-plugin\";\nimport { MANIFEST_FILENAME, restoreManifestPublicPath } from \"./index\";\nimport { uiManifestGenPlugin } from \"./manifest-plugin\";\n\n/**\n * The full dual-environment rsbuild config for a manifest-composed ui source\n * (ADR 0008 §7 — the plugin build contract, not per-plugin config). The core\n * ui and every plugin ui source build from this one factory: `web` emits the\n * browser remote, `node` the commonjs SSR container; shared deps are strict\n * singletons in the given role.\n */\nexport interface UiRsbuildConfigOptions {\n /** the ui source root — contains package.json, src/, and the routes dir */\n workspaceRoot: string;\n /** the ui workspace's package.json (shared-dep version resolution) */\n pkg: {\n name: string;\n version?: string;\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n };\n /** core provides the shared singletons; plugin remotes consume (`import: false`) */\n role: \"provider\" | \"consumer\";\n /** the composition key written into manifest.gen.json (the config-side key) */\n manifestName: string;\n devPort: number;\n webEntry: string;\n webExposes: Record<string, string>;\n nodeEntry: string;\n nodeExposes: Record<string, string>;\n copy?: Array<{\n from: string;\n to: string;\n globOptions?: { ignore?: string[] };\n }>;\n define?: Record<string, string>;\n /** routes dir relative to the rsbuild cwd — folder-form ui sources live at\n * `ui/src/routes` while the build runs from the plugin root */\n routesDirectory?: string;\n}\n\nexport { sanitizeContainerName };\n\n/**\n * The node environment never owns the routeTree write: the web env's\n * generator produces identical content, and both environments resolve the\n * same on-disk tree. Redirecting the node write to scratch removes the\n * concurrent-writers race on src/routeTree.gen.ts (the generator's\n * \"Cannot overwrite\" retry noise).\n */\nconst NODE_ROUTE_TREE_SCRATCH = \"./node_modules/.cache/manifest-compose/routeTree.node.gen.ts\";\n\nexport function createUiRsbuildConfig(options: UiRsbuildConfigOptions): RsbuildConfig {\n const {\n workspaceRoot,\n pkg,\n role,\n manifestName,\n devPort,\n webEntry,\n webExposes,\n nodeEntry,\n nodeExposes,\n copy = [],\n define,\n routesDirectory,\n } = options;\n const workspaceRootAbsolute = path.resolve(workspaceRoot);\n const normalizedName = sanitizeContainerName(pkg.name);\n const manifestGen = () =>\n uiManifestGenPlugin({ workspaceRoot: workspaceRootAbsolute, pluginName: manifestName });\n const uiSharedDeps = createUiSharedDeps({ role, workspaceRoot: workspaceRootAbsolute });\n\n const isBuild = isBuildInvocation();\n\n const webEnvironment: EnvironmentConfig = {\n plugins: [\n pluginReact(),\n manifestGen(),\n pluginModuleFederation(\n {\n name: normalizedName,\n filename: uiEntryFilename({ isBuild }),\n dts: false,\n exposes: webExposes,\n shared: uiSharedDeps,\n },\n { environment: \"web\" },\n ),\n ...(isBuild\n ? [\n hashArtifactsPlugin({\n entryBase: \"remoteEntry\",\n distRoot: path.join(workspaceRootAbsolute, \"dist\"),\n }),\n ]\n : []),\n ],\n source: { entry: { index: webEntry }, ...(define ? { define } : {}) },\n resolve: { alias: { \"@\": path.join(workspaceRootAbsolute, \"src\") } },\n tools: {\n rspack: (config) => {\n const cssPlugin = config.plugins?.find((p) => p instanceof rspack.CssExtractRspackPlugin) as\n | { options?: Record<string, string> }\n | undefined;\n if (cssPlugin) {\n cssPlugin.options ??= {};\n cssPlugin.options.chunkFilename = \"static/css/async/[name].[contenthash].css\";\n }\n Object.assign(config, {\n target: \"web\",\n output: {\n ...config.output,\n publicPath: \"auto\",\n uniqueName: normalizedName,\n chunkFilename: \"static/js/async/[name].[contenthash].js\",\n crossOriginLoading: \"anonymous\",\n },\n resolve: {\n ...config.resolve,\n fallback: { bufferutil: false, \"utf-8-validate\": false },\n },\n infrastructureLogging: { level: \"error\" },\n stats: \"errors-warnings\",\n plugins: [\n ...(config.plugins ?? []),\n TanStackRouterRspack({\n target: \"react\",\n autoCodeSplitting: true,\n routeFileIgnorePattern: \"\\\\.(test|spec)\\\\.(ts|tsx)$\",\n ...(routesDirectory ? { routesDirectory } : {}),\n }),\n new FixMfDataUriPlugin(),\n ],\n });\n return config;\n },\n },\n output: {\n // Absolute: the ui source root owns dist even when the build cwd is the\n // parent plugin workspace (folder-form ui sources).\n distPath: {\n root: path.join(workspaceRootAbsolute, \"dist\"),\n css: \"static/css\",\n js: \"static/js\",\n },\n assetPrefix: \"auto\",\n filename: { js: \"[name].js\", css: \"style.css\" },\n copy: [\n ...copy,\n { from: path.join(workspaceRootAbsolute, \"src\", MANIFEST_FILENAME), to: \"./\" },\n ],\n },\n };\n\n // Dev without SSR skips the node environment: it exists for the host's dev\n // SSR container and nothing else. Builds always emit both.\n const includeNodeEnv =\n process.env.BOS_SSR === \"1\" ||\n process.env.DEPLOY === \"true\" ||\n process.env.NODE_ENV !== \"development\";\n\n const nodeEnvironment: EnvironmentConfig = {\n plugins: [\n pluginReact(),\n manifestGen(),\n pluginModuleFederation(\n {\n name: normalizedName,\n filename: uiEntryFilename({ isBuild, server: true }),\n dts: false,\n exposes: nodeExposes,\n shared: uiSharedDeps,\n },\n { target: \"node\", environment: \"node\" },\n ),\n restoreManifestPublicPath(path.resolve(workspaceRootAbsolute, \"dist\", \"ssr\")),\n ...(isBuild\n ? [\n hashArtifactsPlugin({\n entryBase: \"remoteEntry.server\",\n distRoot: path.resolve(workspaceRootAbsolute, \"dist\", \"ssr\"),\n }),\n ]\n : []),\n ],\n source: { entry: { index: nodeEntry } },\n resolve: {\n alias: {\n \"@\": path.join(workspaceRootAbsolute, \"src\"),\n \"@tanstack/react-devtools\": false,\n \"@tanstack/react-router-devtools\": false,\n },\n },\n tools: {\n rspack: (config) => {\n Object.assign(config, {\n output: { ...config.output, uniqueName: `${normalizedName}_server` },\n resolve: {\n ...config.resolve,\n fallback: { bufferutil: false, \"utf-8-validate\": false },\n },\n externals: [/^node:/],\n infrastructureLogging: { level: \"error\" },\n stats: \"errors-warnings\",\n plugins: [\n ...(config.plugins ?? []),\n TanStackRouterRspack({\n target: \"react\",\n autoCodeSplitting: false,\n routeFileIgnorePattern: \"\\\\.(test|spec)\\\\.(ts|tsx)$\",\n generatedRouteTree: NODE_ROUTE_TREE_SCRATCH,\n ...(routesDirectory ? { routesDirectory } : {}),\n }),\n new FixMfDataUriPlugin(),\n ],\n });\n return config;\n },\n },\n // Absolute, like the web dist above — the node container must land in the\n // ui source root's dist/ssr where the host's local container server looks.\n output: { distPath: { root: path.join(workspaceRootAbsolute, \"dist\", \"ssr\") } },\n };\n\n return defineConfig({\n environments: {\n web: webEnvironment,\n ...(includeNodeEnv ? { node: nodeEnvironment } : {}),\n },\n dev: {\n lazyCompilation: false,\n progressBar: false,\n writeToDisk: true,\n client: { overlay: false },\n },\n server: {\n port: Number(process.env.PORT) || devPort,\n printUrls: ({ urls }) => urls.filter((url) => url.includes(\"localhost\")),\n headers: {\n \"Access-Control-Allow-Origin\": \"*\",\n \"Access-Control-Allow-Methods\": \"GET, POST, OPTIONS\",\n \"Access-Control-Allow-Headers\": \"Content-Type\",\n },\n },\n });\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"rsbuild-config.mjs","names":["sanitizeContainerName"],"sources":["../../../src/build/ui/rsbuild-config.ts"],"sourcesContent":["import path from \"node:path\";\nimport { pluginModuleFederation } from \"@module-federation/rsbuild-plugin\";\nimport { defineConfig, type EnvironmentConfig, type RsbuildConfig, rspack } from \"@rsbuild/core\";\nimport { pluginReact } from \"@rsbuild/plugin-react\";\nimport { TanStackRouterRspack } from \"@tanstack/router-plugin/rspack\";\nimport { FixMfDataUriPlugin } from \"../../build/rspack\";\nimport { createUiSharedDeps } from \"../../shared-deps-spec\";\nimport { sanitizeContainerName } from \"../../ui/manifest/contract\";\nimport { isBuildInvocation, uiEntryFilename } from \"../artifact-names\";\nimport { hashArtifactsPlugin } from \"./hash-artifacts-plugin\";\nimport { MANIFEST_FILENAME, restoreManifestPublicPath } from \"./index\";\nimport { uiManifestGenPlugin } from \"./manifest-plugin\";\n\n/**\n * The full dual-environment rsbuild config for a manifest-composed ui source\n * (ADR 0008 §7 — the plugin build contract, not per-plugin config). The core\n * ui and every plugin ui source build from this one factory: `web` emits the\n * browser remote, `node` the commonjs SSR container; shared deps are strict\n * singletons in the given role.\n */\nexport interface UiRsbuildConfigOptions {\n /** the ui source root — contains package.json, src/, and the routes dir */\n workspaceRoot: string;\n /** the ui workspace's package.json (shared-dep version resolution) */\n pkg: {\n name: string;\n version?: string;\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n };\n /** core provides the shared singletons; plugin remotes consume (`import: false`) */\n role: \"provider\" | \"consumer\";\n /** the composition key written into manifest.gen.json (the config-side key) */\n manifestName: string;\n devPort: number;\n webEntry: string;\n webExposes: Record<string, string>;\n nodeEntry: string;\n nodeExposes: Record<string, string>;\n copy?: Array<{\n from: string;\n to: string;\n globOptions?: { ignore?: string[] };\n }>;\n define?: Record<string, string>;\n /** routes dir relative to the rsbuild cwd — folder-form ui sources live at\n * `ui/src/routes` while the build runs from the plugin root */\n routesDirectory?: string;\n}\n\nexport { sanitizeContainerName };\n\n/**\n * The node environment never owns the routeTree write: the web env's\n * generator produces identical content, and both environments resolve the\n * same on-disk tree. Redirecting the node write to scratch removes the\n * concurrent-writers race on src/routeTree.gen.ts (the generator's\n * \"Cannot overwrite\" retry noise).\n */\nconst NODE_ROUTE_TREE_SCRATCH = \"./node_modules/.cache/manifest-compose/routeTree.node.gen.ts\";\n\nexport function createUiRsbuildConfig(options: UiRsbuildConfigOptions): RsbuildConfig {\n const {\n workspaceRoot,\n pkg,\n role,\n manifestName,\n devPort,\n webEntry,\n webExposes,\n nodeEntry,\n nodeExposes,\n copy = [],\n define,\n routesDirectory,\n } = options;\n const workspaceRootAbsolute = path.resolve(workspaceRoot);\n const normalizedName = sanitizeContainerName(pkg.name);\n const manifestGen = () =>\n uiManifestGenPlugin({ workspaceRoot: workspaceRootAbsolute, pluginName: manifestName });\n const uiSharedDeps = createUiSharedDeps({ role, workspaceRoot: workspaceRootAbsolute });\n\n const isBuild = isBuildInvocation();\n\n const webEnvironment: EnvironmentConfig = {\n plugins: [\n pluginReact(),\n manifestGen(),\n pluginModuleFederation(\n {\n name: normalizedName,\n filename: uiEntryFilename({ isBuild }),\n dts: false,\n exposes: webExposes,\n shared: uiSharedDeps,\n },\n { environment: \"web\" },\n ),\n ...(isBuild\n ? [\n hashArtifactsPlugin({\n entryBase: \"remoteEntry\",\n distRoot: path.join(workspaceRootAbsolute, \"dist\"),\n }),\n ]\n : []),\n ],\n source: { entry: { index: webEntry }, ...(define ? { define } : {}) },\n resolve: { alias: { \"@\": path.join(workspaceRootAbsolute, \"src\") } },\n tools: {\n rspack: (config) => {\n const cssPlugin = config.plugins?.find((p) => p instanceof rspack.CssExtractRspackPlugin) as\n | { options?: Record<string, string> }\n | undefined;\n if (cssPlugin) {\n cssPlugin.options ??= {};\n cssPlugin.options.chunkFilename = \"static/css/async/[name].[contenthash].css\";\n }\n Object.assign(config, {\n target: \"web\",\n output: {\n ...config.output,\n publicPath: \"auto\",\n uniqueName: normalizedName,\n chunkFilename: \"static/js/async/[name].[contenthash].js\",\n crossOriginLoading: \"anonymous\",\n },\n resolve: {\n ...config.resolve,\n fallback: { bufferutil: false, \"utf-8-validate\": false },\n },\n infrastructureLogging: { level: \"error\" },\n stats: \"errors-warnings\",\n plugins: [\n ...(config.plugins ?? []),\n TanStackRouterRspack({\n target: \"react\",\n autoCodeSplitting: true,\n routeFileIgnorePattern: \"\\\\.(test|spec)\\\\.(ts|tsx)$\",\n generatedRouteTree: path.join(workspaceRootAbsolute, \"src/routeTree.gen.ts\"),\n ...(routesDirectory ? { routesDirectory } : {}),\n }),\n new FixMfDataUriPlugin(),\n ],\n });\n return config;\n },\n },\n output: {\n // Absolute: the ui source root owns dist even when the build cwd is the\n // parent plugin workspace (folder-form ui sources).\n distPath: {\n root: path.join(workspaceRootAbsolute, \"dist\"),\n css: \"static/css\",\n js: \"static/js\",\n },\n assetPrefix: \"auto\",\n filename: { js: \"[name].js\", css: \"style.css\" },\n copy: [\n ...copy,\n { from: path.join(workspaceRootAbsolute, \"src\", MANIFEST_FILENAME), to: \"./\" },\n ],\n },\n };\n\n // Dev without SSR skips the node environment: it exists for the host's dev\n // SSR container and nothing else. Builds always emit both.\n const includeNodeEnv =\n process.env.BOS_SSR === \"1\" ||\n process.env.DEPLOY === \"true\" ||\n process.env.NODE_ENV !== \"development\";\n\n const nodeEnvironment: EnvironmentConfig = {\n plugins: [\n pluginReact(),\n manifestGen(),\n pluginModuleFederation(\n {\n name: normalizedName,\n filename: uiEntryFilename({ isBuild, server: true }),\n dts: false,\n exposes: nodeExposes,\n shared: uiSharedDeps,\n },\n { target: \"node\", environment: \"node\" },\n ),\n restoreManifestPublicPath(path.resolve(workspaceRootAbsolute, \"dist\", \"ssr\")),\n ...(isBuild\n ? [\n hashArtifactsPlugin({\n entryBase: \"remoteEntry.server\",\n distRoot: path.resolve(workspaceRootAbsolute, \"dist\", \"ssr\"),\n }),\n ]\n : []),\n ],\n source: { entry: { index: nodeEntry } },\n resolve: {\n alias: {\n \"@\": path.join(workspaceRootAbsolute, \"src\"),\n \"@tanstack/react-devtools\": false,\n \"@tanstack/react-router-devtools\": false,\n },\n },\n tools: {\n rspack: (config) => {\n Object.assign(config, {\n output: { ...config.output, uniqueName: `${normalizedName}_server` },\n resolve: {\n ...config.resolve,\n fallback: { bufferutil: false, \"utf-8-validate\": false },\n },\n externals: [/^node:/],\n infrastructureLogging: { level: \"error\" },\n stats: \"errors-warnings\",\n plugins: [\n ...(config.plugins ?? []),\n TanStackRouterRspack({\n target: \"react\",\n autoCodeSplitting: false,\n routeFileIgnorePattern: \"\\\\.(test|spec)\\\\.(ts|tsx)$\",\n generatedRouteTree: NODE_ROUTE_TREE_SCRATCH,\n ...(routesDirectory ? { routesDirectory } : {}),\n }),\n new FixMfDataUriPlugin(),\n ],\n });\n return config;\n },\n },\n // Absolute, like the web dist above — the node container must land in the\n // ui source root's dist/ssr where the host's local container server looks.\n output: { distPath: { root: path.join(workspaceRootAbsolute, \"dist\", \"ssr\") } },\n };\n\n return defineConfig({\n environments: {\n web: webEnvironment,\n ...(includeNodeEnv ? { node: nodeEnvironment } : {}),\n },\n dev: {\n lazyCompilation: false,\n progressBar: false,\n writeToDisk: true,\n client: { overlay: false },\n },\n server: {\n port: Number(process.env.PORT) || devPort,\n printUrls: ({ urls }) => urls.filter((url) => url.includes(\"localhost\")),\n headers: {\n \"Access-Control-Allow-Origin\": \"*\",\n \"Access-Control-Allow-Methods\": \"GET, POST, OPTIONS\",\n \"Access-Control-Allow-Headers\": \"Content-Type\",\n },\n },\n });\n}\n"],"mappings":"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"}
|
package/dist/client.cjs
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
let _orpc_client = require("@orpc/client");
|
|
3
|
+
let _orpc_client_fetch = require("@orpc/client/fetch");
|
|
4
|
+
|
|
5
|
+
//#region src/client.ts
|
|
6
|
+
const RATE_LIMIT_MAX_RETRIES = 3;
|
|
7
|
+
const RATE_LIMIT_RETRY_CAP_MS = 2e3;
|
|
8
|
+
const browserClients = /* @__PURE__ */ new Map();
|
|
9
|
+
async function fetchWithRateLimitRetry(fetchUrl, options) {
|
|
10
|
+
let response = await fetch(fetchUrl, options);
|
|
11
|
+
for (let attempt = 1; attempt <= RATE_LIMIT_MAX_RETRIES && response.status === 429; attempt++) {
|
|
12
|
+
const retryAfterSeconds = Number(response.headers.get("retry-after"));
|
|
13
|
+
const delay = Number.isFinite(retryAfterSeconds) && retryAfterSeconds > 0 ? Math.min(retryAfterSeconds * 1e3, RATE_LIMIT_RETRY_CAP_MS) : 100 * attempt;
|
|
14
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
15
|
+
response = await fetch(fetchUrl, options);
|
|
16
|
+
}
|
|
17
|
+
return response;
|
|
18
|
+
}
|
|
19
|
+
function createRpcLink(config, headers) {
|
|
20
|
+
return new _orpc_client_fetch.RPCLink({
|
|
21
|
+
origin: config.hostUrl,
|
|
22
|
+
url: config.path,
|
|
23
|
+
interceptors: [(0, _orpc_client.onError)((error) => {
|
|
24
|
+
if (typeof globalThis.window === "undefined") return;
|
|
25
|
+
if (error && typeof error === "object" && "message" in error) {
|
|
26
|
+
const message = String(error.message).toLowerCase();
|
|
27
|
+
if (message.includes("fetch") || message.includes("network") || message.includes("failed to fetch")) import("sonner").then(({ toast }) => {
|
|
28
|
+
const message = config.connectionError?.() ?? {
|
|
29
|
+
title: "Unable to connect to API",
|
|
30
|
+
description: "The API is currently unavailable. Please try again later."
|
|
31
|
+
};
|
|
32
|
+
toast.error(message.title, {
|
|
33
|
+
id: "api-connection-error",
|
|
34
|
+
description: message.description
|
|
35
|
+
});
|
|
36
|
+
}).catch(() => {});
|
|
37
|
+
}
|
|
38
|
+
})],
|
|
39
|
+
fetch(fetchUrl, options) {
|
|
40
|
+
return fetchWithRateLimitRetry(fetchUrl, {
|
|
41
|
+
...options,
|
|
42
|
+
credentials: "include",
|
|
43
|
+
headers: headers ? {
|
|
44
|
+
...Object.fromEntries(headers),
|
|
45
|
+
...options?.headers
|
|
46
|
+
} : options?.headers
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
function buildRpcClient(config, headers) {
|
|
52
|
+
if (!config.hostUrl) throw new Error("Missing runtime host URL");
|
|
53
|
+
return (0, _orpc_client.createORPCClient)(createRpcLink(config, headers));
|
|
54
|
+
}
|
|
55
|
+
function createRpcClient(config, headers) {
|
|
56
|
+
if (typeof globalThis.window !== "undefined" && !headers) {
|
|
57
|
+
const key = `${config.hostUrl}${config.path}`;
|
|
58
|
+
const memoized = browserClients.get(key);
|
|
59
|
+
if (memoized) return memoized;
|
|
60
|
+
const client = buildRpcClient(config, headers);
|
|
61
|
+
browserClients.set(key, client);
|
|
62
|
+
return client;
|
|
63
|
+
}
|
|
64
|
+
return buildRpcClient(config, headers);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
//#endregion
|
|
68
|
+
exports.createRpcClient = createRpcClient;
|
|
69
|
+
//# sourceMappingURL=client.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.cjs","names":["RPCLink","onError","createORPCClient"],"sources":["../src/client.ts"],"sourcesContent":["import { createORPCClient, onError } from \"@orpc/client\";\nimport { RPCLink } from \"@orpc/client/fetch\";\nimport type { ContractRouterClient, RouterContract } from \"@orpc/contract\";\n\nexport type RpcConnectionErrorCopy = () => { title: string; description: string };\n\nexport interface RpcClientConfig {\n hostUrl: string;\n path: `/${string}`;\n connectionError?: RpcConnectionErrorCopy;\n}\n\nconst RATE_LIMIT_MAX_RETRIES = 3;\nconst RATE_LIMIT_RETRY_CAP_MS = 2_000;\nconst browserClients = new Map<string, unknown>();\ntype FetchInput = Parameters<typeof fetch>[0];\n\nasync function fetchWithRateLimitRetry(\n fetchUrl: FetchInput,\n options?: RequestInit,\n): Promise<Response> {\n let response = await fetch(fetchUrl, options);\n for (let attempt = 1; attempt <= RATE_LIMIT_MAX_RETRIES && response.status === 429; attempt++) {\n const retryAfterSeconds = Number(response.headers.get(\"retry-after\"));\n const delay =\n Number.isFinite(retryAfterSeconds) && retryAfterSeconds > 0\n ? Math.min(retryAfterSeconds * 1000, RATE_LIMIT_RETRY_CAP_MS)\n : 100 * attempt;\n await new Promise((resolve) => setTimeout(resolve, delay));\n response = await fetch(fetchUrl, options);\n }\n\n return response;\n}\n\nfunction createRpcLink(config: RpcClientConfig, headers?: Headers) {\n return new RPCLink({\n origin: config.hostUrl,\n url: config.path,\n interceptors: [\n onError((error: unknown) => {\n const browserWindow = (globalThis as { window?: unknown }).window;\n if (typeof browserWindow === \"undefined\") {\n return;\n }\n\n if (error && typeof error === \"object\" && \"message\" in error) {\n const message = String(error.message).toLowerCase();\n if (\n message.includes(\"fetch\") ||\n message.includes(\"network\") ||\n message.includes(\"failed to fetch\")\n ) {\n void import(\"sonner\")\n .then(({ toast }) => {\n const message = config.connectionError?.() ?? {\n title: \"Unable to connect to API\",\n description: \"The API is currently unavailable. Please try again later.\",\n };\n toast.error(message.title, {\n id: \"api-connection-error\",\n description: message.description,\n });\n })\n .catch(() => {});\n }\n }\n }),\n ],\n fetch(fetchUrl: FetchInput, options?: RequestInit) {\n return fetchWithRateLimitRetry(fetchUrl, {\n ...options,\n credentials: \"include\",\n headers: headers\n ? { ...Object.fromEntries(headers), ...(options?.headers as Record<string, string>) }\n : options?.headers,\n });\n },\n });\n}\n\nfunction buildRpcClient<T extends RouterContract>(\n config: RpcClientConfig,\n headers?: Headers,\n): ContractRouterClient<T> {\n if (!config.hostUrl) {\n throw new Error(\"Missing runtime host URL\");\n }\n\n return createORPCClient(createRpcLink(config, headers)) as ContractRouterClient<T>;\n}\n\nexport function createRpcClient<T extends RouterContract = RouterContract>(\n config: RpcClientConfig,\n headers?: Headers,\n): ContractRouterClient<T> {\n const browserWindow = (globalThis as { window?: unknown }).window;\n if (typeof browserWindow !== \"undefined\" && !headers) {\n const key = `${config.hostUrl}${config.path}`;\n const memoized = browserClients.get(key);\n if (memoized) {\n return memoized as ContractRouterClient<T>;\n }\n\n const client = buildRpcClient<T>(config, headers);\n browserClients.set(key, client);\n return client;\n }\n\n return buildRpcClient<T>(config, headers);\n}\n"],"mappings":";;;;;AAYA,MAAM,yBAAyB;AAC/B,MAAM,0BAA0B;AAChC,MAAM,iCAAiB,IAAI,IAAqB;AAGhD,eAAe,wBACb,UACA,SACmB;CACnB,IAAI,WAAW,MAAM,MAAM,UAAU,OAAO;CAC5C,KAAK,IAAI,UAAU,GAAG,WAAW,0BAA0B,SAAS,WAAW,KAAK,WAAW;EAC7F,MAAM,oBAAoB,OAAO,SAAS,QAAQ,IAAI,aAAa,CAAC;EACpE,MAAM,QACJ,OAAO,SAAS,iBAAiB,KAAK,oBAAoB,IACtD,KAAK,IAAI,oBAAoB,KAAM,uBAAuB,IAC1D,MAAM;EACZ,MAAM,IAAI,SAAS,YAAY,WAAW,SAAS,KAAK,CAAC;EACzD,WAAW,MAAM,MAAM,UAAU,OAAO;CAC1C;CAEA,OAAO;AACT;AAEA,SAAS,cAAc,QAAyB,SAAmB;CACjE,OAAO,IAAIA,2BAAQ;EACjB,QAAQ,OAAO;EACf,KAAK,OAAO;EACZ,cAAc,KACZC,uBAAS,UAAmB;GAE1B,IAAI,OADmB,WAAoC,WAC9B,aAC3B;GAGF,IAAI,SAAS,OAAO,UAAU,YAAY,aAAa,OAAO;IAC5D,MAAM,UAAU,OAAO,MAAM,OAAO,CAAC,CAAC,YAAY;IAClD,IACE,QAAQ,SAAS,OAAO,KACxB,QAAQ,SAAS,SAAS,KAC1B,QAAQ,SAAS,iBAAiB,GAElC,AAAK,OAAO,SAAS,CAClB,MAAM,EAAE,YAAY;KACnB,MAAM,UAAU,OAAO,kBAAkB,KAAK;MAC5C,OAAO;MACP,aAAa;KACf;KACA,MAAM,MAAM,QAAQ,OAAO;MACzB,IAAI;MACJ,aAAa,QAAQ;KACvB,CAAC;IACH,CAAC,CAAC,CACD,YAAY,CAAC,CAAC;GAErB;EACF,CAAC,CACH;EACA,MAAM,UAAsB,SAAuB;GACjD,OAAO,wBAAwB,UAAU;IACvC,GAAG;IACH,aAAa;IACb,SAAS,UACL;KAAE,GAAG,OAAO,YAAY,OAAO;KAAG,GAAI,SAAS;IAAmC,IAClF,SAAS;GACf,CAAC;EACH;CACF,CAAC;AACH;AAEA,SAAS,eACP,QACA,SACyB;CACzB,IAAI,CAAC,OAAO,SACV,MAAM,IAAI,MAAM,0BAA0B;CAG5C,WAAOC,+BAAiB,cAAc,QAAQ,OAAO,CAAC;AACxD;AAEA,SAAgB,gBACd,QACA,SACyB;CAEzB,IAAI,OADmB,WAAoC,WAC9B,eAAe,CAAC,SAAS;EACpD,MAAM,MAAM,GAAG,OAAO,UAAU,OAAO;EACvC,MAAM,WAAW,eAAe,IAAI,GAAG;EACvC,IAAI,UACF,OAAO;EAGT,MAAM,SAAS,eAAkB,QAAQ,OAAO;EAChD,eAAe,IAAI,KAAK,MAAM;EAC9B,OAAO;CACT;CAEA,OAAO,eAAkB,QAAQ,OAAO;AAC1C"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { ContractRouterClient, RouterContract } from "@orpc/contract";
|
|
2
|
+
//#region src/client.d.ts
|
|
3
|
+
type RpcConnectionErrorCopy = () => {
|
|
4
|
+
title: string;
|
|
5
|
+
description: string;
|
|
6
|
+
};
|
|
7
|
+
interface RpcClientConfig {
|
|
8
|
+
hostUrl: string;
|
|
9
|
+
path: `/${string}`;
|
|
10
|
+
connectionError?: RpcConnectionErrorCopy;
|
|
11
|
+
}
|
|
12
|
+
declare function createRpcClient<T extends RouterContract = RouterContract>(config: RpcClientConfig, headers?: Headers): ContractRouterClient<T>;
|
|
13
|
+
//#endregion
|
|
14
|
+
export { RpcClientConfig, RpcConnectionErrorCopy, createRpcClient };
|
|
15
|
+
//# sourceMappingURL=client.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.cts","names":[],"sources":["../src/client.ts"],"mappings":";;KAIY;EAAiC;EAAe;;UAE3C;EACf;EACA;EACA,kBAAkB;;iBAmFJ,gBAAgB,UAAU,iBAAiB,gBACzD,QAAQ,iBACR,UAAU,UACT,qBAAqB"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { ContractRouterClient, RouterContract } from "@orpc/contract";
|
|
2
|
+
//#region src/client.d.ts
|
|
3
|
+
type RpcConnectionErrorCopy = () => {
|
|
4
|
+
title: string;
|
|
5
|
+
description: string;
|
|
6
|
+
};
|
|
7
|
+
interface RpcClientConfig {
|
|
8
|
+
hostUrl: string;
|
|
9
|
+
path: `/${string}`;
|
|
10
|
+
connectionError?: RpcConnectionErrorCopy;
|
|
11
|
+
}
|
|
12
|
+
declare function createRpcClient<T extends RouterContract = RouterContract>(config: RpcClientConfig, headers?: Headers): ContractRouterClient<T>;
|
|
13
|
+
//#endregion
|
|
14
|
+
export { RpcClientConfig, RpcConnectionErrorCopy, createRpcClient };
|
|
15
|
+
//# sourceMappingURL=client.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.mts","names":[],"sources":["../src/client.ts"],"mappings":";;KAIY;EAAiC;EAAe;;UAE3C;EACf;EACA;EACA,kBAAkB;;iBAmFJ,gBAAgB,UAAU,iBAAiB,gBACzD,QAAQ,iBACR,UAAU,UACT,qBAAqB"}
|
package/dist/client.mjs
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { createORPCClient, onError } from "@orpc/client";
|
|
2
|
+
import { RPCLink } from "@orpc/client/fetch";
|
|
3
|
+
|
|
4
|
+
//#region src/client.ts
|
|
5
|
+
const RATE_LIMIT_MAX_RETRIES = 3;
|
|
6
|
+
const RATE_LIMIT_RETRY_CAP_MS = 2e3;
|
|
7
|
+
const browserClients = /* @__PURE__ */ new Map();
|
|
8
|
+
async function fetchWithRateLimitRetry(fetchUrl, options) {
|
|
9
|
+
let response = await fetch(fetchUrl, options);
|
|
10
|
+
for (let attempt = 1; attempt <= RATE_LIMIT_MAX_RETRIES && response.status === 429; attempt++) {
|
|
11
|
+
const retryAfterSeconds = Number(response.headers.get("retry-after"));
|
|
12
|
+
const delay = Number.isFinite(retryAfterSeconds) && retryAfterSeconds > 0 ? Math.min(retryAfterSeconds * 1e3, RATE_LIMIT_RETRY_CAP_MS) : 100 * attempt;
|
|
13
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
14
|
+
response = await fetch(fetchUrl, options);
|
|
15
|
+
}
|
|
16
|
+
return response;
|
|
17
|
+
}
|
|
18
|
+
function createRpcLink(config, headers) {
|
|
19
|
+
return new RPCLink({
|
|
20
|
+
origin: config.hostUrl,
|
|
21
|
+
url: config.path,
|
|
22
|
+
interceptors: [onError((error) => {
|
|
23
|
+
if (typeof globalThis.window === "undefined") return;
|
|
24
|
+
if (error && typeof error === "object" && "message" in error) {
|
|
25
|
+
const message = String(error.message).toLowerCase();
|
|
26
|
+
if (message.includes("fetch") || message.includes("network") || message.includes("failed to fetch")) import("sonner").then(({ toast }) => {
|
|
27
|
+
const message = config.connectionError?.() ?? {
|
|
28
|
+
title: "Unable to connect to API",
|
|
29
|
+
description: "The API is currently unavailable. Please try again later."
|
|
30
|
+
};
|
|
31
|
+
toast.error(message.title, {
|
|
32
|
+
id: "api-connection-error",
|
|
33
|
+
description: message.description
|
|
34
|
+
});
|
|
35
|
+
}).catch(() => {});
|
|
36
|
+
}
|
|
37
|
+
})],
|
|
38
|
+
fetch(fetchUrl, options) {
|
|
39
|
+
return fetchWithRateLimitRetry(fetchUrl, {
|
|
40
|
+
...options,
|
|
41
|
+
credentials: "include",
|
|
42
|
+
headers: headers ? {
|
|
43
|
+
...Object.fromEntries(headers),
|
|
44
|
+
...options?.headers
|
|
45
|
+
} : options?.headers
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
function buildRpcClient(config, headers) {
|
|
51
|
+
if (!config.hostUrl) throw new Error("Missing runtime host URL");
|
|
52
|
+
return createORPCClient(createRpcLink(config, headers));
|
|
53
|
+
}
|
|
54
|
+
function createRpcClient(config, headers) {
|
|
55
|
+
if (typeof globalThis.window !== "undefined" && !headers) {
|
|
56
|
+
const key = `${config.hostUrl}${config.path}`;
|
|
57
|
+
const memoized = browserClients.get(key);
|
|
58
|
+
if (memoized) return memoized;
|
|
59
|
+
const client = buildRpcClient(config, headers);
|
|
60
|
+
browserClients.set(key, client);
|
|
61
|
+
return client;
|
|
62
|
+
}
|
|
63
|
+
return buildRpcClient(config, headers);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
//#endregion
|
|
67
|
+
export { createRpcClient };
|
|
68
|
+
//# sourceMappingURL=client.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.mjs","names":[],"sources":["../src/client.ts"],"sourcesContent":["import { createORPCClient, onError } from \"@orpc/client\";\nimport { RPCLink } from \"@orpc/client/fetch\";\nimport type { ContractRouterClient, RouterContract } from \"@orpc/contract\";\n\nexport type RpcConnectionErrorCopy = () => { title: string; description: string };\n\nexport interface RpcClientConfig {\n hostUrl: string;\n path: `/${string}`;\n connectionError?: RpcConnectionErrorCopy;\n}\n\nconst RATE_LIMIT_MAX_RETRIES = 3;\nconst RATE_LIMIT_RETRY_CAP_MS = 2_000;\nconst browserClients = new Map<string, unknown>();\ntype FetchInput = Parameters<typeof fetch>[0];\n\nasync function fetchWithRateLimitRetry(\n fetchUrl: FetchInput,\n options?: RequestInit,\n): Promise<Response> {\n let response = await fetch(fetchUrl, options);\n for (let attempt = 1; attempt <= RATE_LIMIT_MAX_RETRIES && response.status === 429; attempt++) {\n const retryAfterSeconds = Number(response.headers.get(\"retry-after\"));\n const delay =\n Number.isFinite(retryAfterSeconds) && retryAfterSeconds > 0\n ? Math.min(retryAfterSeconds * 1000, RATE_LIMIT_RETRY_CAP_MS)\n : 100 * attempt;\n await new Promise((resolve) => setTimeout(resolve, delay));\n response = await fetch(fetchUrl, options);\n }\n\n return response;\n}\n\nfunction createRpcLink(config: RpcClientConfig, headers?: Headers) {\n return new RPCLink({\n origin: config.hostUrl,\n url: config.path,\n interceptors: [\n onError((error: unknown) => {\n const browserWindow = (globalThis as { window?: unknown }).window;\n if (typeof browserWindow === \"undefined\") {\n return;\n }\n\n if (error && typeof error === \"object\" && \"message\" in error) {\n const message = String(error.message).toLowerCase();\n if (\n message.includes(\"fetch\") ||\n message.includes(\"network\") ||\n message.includes(\"failed to fetch\")\n ) {\n void import(\"sonner\")\n .then(({ toast }) => {\n const message = config.connectionError?.() ?? {\n title: \"Unable to connect to API\",\n description: \"The API is currently unavailable. Please try again later.\",\n };\n toast.error(message.title, {\n id: \"api-connection-error\",\n description: message.description,\n });\n })\n .catch(() => {});\n }\n }\n }),\n ],\n fetch(fetchUrl: FetchInput, options?: RequestInit) {\n return fetchWithRateLimitRetry(fetchUrl, {\n ...options,\n credentials: \"include\",\n headers: headers\n ? { ...Object.fromEntries(headers), ...(options?.headers as Record<string, string>) }\n : options?.headers,\n });\n },\n });\n}\n\nfunction buildRpcClient<T extends RouterContract>(\n config: RpcClientConfig,\n headers?: Headers,\n): ContractRouterClient<T> {\n if (!config.hostUrl) {\n throw new Error(\"Missing runtime host URL\");\n }\n\n return createORPCClient(createRpcLink(config, headers)) as ContractRouterClient<T>;\n}\n\nexport function createRpcClient<T extends RouterContract = RouterContract>(\n config: RpcClientConfig,\n headers?: Headers,\n): ContractRouterClient<T> {\n const browserWindow = (globalThis as { window?: unknown }).window;\n if (typeof browserWindow !== \"undefined\" && !headers) {\n const key = `${config.hostUrl}${config.path}`;\n const memoized = browserClients.get(key);\n if (memoized) {\n return memoized as ContractRouterClient<T>;\n }\n\n const client = buildRpcClient<T>(config, headers);\n browserClients.set(key, client);\n return client;\n }\n\n return buildRpcClient<T>(config, headers);\n}\n"],"mappings":";;;;AAYA,MAAM,yBAAyB;AAC/B,MAAM,0BAA0B;AAChC,MAAM,iCAAiB,IAAI,IAAqB;AAGhD,eAAe,wBACb,UACA,SACmB;CACnB,IAAI,WAAW,MAAM,MAAM,UAAU,OAAO;CAC5C,KAAK,IAAI,UAAU,GAAG,WAAW,0BAA0B,SAAS,WAAW,KAAK,WAAW;EAC7F,MAAM,oBAAoB,OAAO,SAAS,QAAQ,IAAI,aAAa,CAAC;EACpE,MAAM,QACJ,OAAO,SAAS,iBAAiB,KAAK,oBAAoB,IACtD,KAAK,IAAI,oBAAoB,KAAM,uBAAuB,IAC1D,MAAM;EACZ,MAAM,IAAI,SAAS,YAAY,WAAW,SAAS,KAAK,CAAC;EACzD,WAAW,MAAM,MAAM,UAAU,OAAO;CAC1C;CAEA,OAAO;AACT;AAEA,SAAS,cAAc,QAAyB,SAAmB;CACjE,OAAO,IAAI,QAAQ;EACjB,QAAQ,OAAO;EACf,KAAK,OAAO;EACZ,cAAc,CACZ,SAAS,UAAmB;GAE1B,IAAI,OADmB,WAAoC,WAC9B,aAC3B;GAGF,IAAI,SAAS,OAAO,UAAU,YAAY,aAAa,OAAO;IAC5D,MAAM,UAAU,OAAO,MAAM,OAAO,CAAC,CAAC,YAAY;IAClD,IACE,QAAQ,SAAS,OAAO,KACxB,QAAQ,SAAS,SAAS,KAC1B,QAAQ,SAAS,iBAAiB,GAElC,AAAK,OAAO,SAAS,CAClB,MAAM,EAAE,YAAY;KACnB,MAAM,UAAU,OAAO,kBAAkB,KAAK;MAC5C,OAAO;MACP,aAAa;KACf;KACA,MAAM,MAAM,QAAQ,OAAO;MACzB,IAAI;MACJ,aAAa,QAAQ;KACvB,CAAC;IACH,CAAC,CAAC,CACD,YAAY,CAAC,CAAC;GAErB;EACF,CAAC,CACH;EACA,MAAM,UAAsB,SAAuB;GACjD,OAAO,wBAAwB,UAAU;IACvC,GAAG;IACH,aAAa;IACb,SAAS,UACL;KAAE,GAAG,OAAO,YAAY,OAAO;KAAG,GAAI,SAAS;IAAmC,IAClF,SAAS;GACf,CAAC;EACH;CACF,CAAC;AACH;AAEA,SAAS,eACP,QACA,SACyB;CACzB,IAAI,CAAC,OAAO,SACV,MAAM,IAAI,MAAM,0BAA0B;CAG5C,OAAO,iBAAiB,cAAc,QAAQ,OAAO,CAAC;AACxD;AAEA,SAAgB,gBACd,QACA,SACyB;CAEzB,IAAI,OADmB,WAAoC,WAC9B,eAAe,CAAC,SAAS;EACpD,MAAM,MAAM,GAAG,OAAO,UAAU,OAAO;EACvC,MAAM,WAAW,eAAe,IAAI,GAAG;EACvC,IAAI,UACF,OAAO;EAGT,MAAM,SAAS,eAAkB,QAAQ,OAAO;EAChD,eAAe,IAAI,KAAK,MAAM;EAC9B,OAAO;CACT;CAEA,OAAO,eAAkB,QAAQ,OAAO;AAC1C"}
|