From 0a67ed0ddedb1673b21aa95cf6200f600e9d812b Mon Sep 17 00:00:00 2001 From: David Festal Date: Fri, 21 Nov 2025 10:15:22 +0100 Subject: [PATCH 01/17] Upgrade to 0.21.6 Signed-off-by: David Festal Assisted-by: Cursor --- .../package.json | 2 +- packages/cli/package.json | 4 +- .../package.json | 6 +- .../report.api.md | 4 +- .../src/loader.ts | 4 +- yarn.lock | 429 +++++++++--------- 6 files changed, 216 insertions(+), 233 deletions(-) diff --git a/packages/backend-dynamic-feature-service/package.json b/packages/backend-dynamic-feature-service/package.json index 9a2e55fcd1..6909c69754 100644 --- a/packages/backend-dynamic-feature-service/package.json +++ b/packages/backend-dynamic-feature-service/package.json @@ -68,7 +68,7 @@ "@backstage/plugin-search-common": "workspace:^", "@backstage/types": "workspace:^", "@manypkg/get-packages": "^1.1.3", - "@module-federation/sdk": "^0.9.0", + "@module-federation/sdk": "^0.21.6", "chokidar": "^3.5.3", "express": "^4.22.0", "express-promise-router": "^4.1.0", diff --git a/packages/cli/package.json b/packages/cli/package.json index 4bc9c91cbe..c5b75e31d7 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -58,7 +58,7 @@ "@backstage/release-manifests": "workspace:^", "@backstage/types": "workspace:^", "@manypkg/get-packages": "^1.1.3", - "@module-federation/enhanced": "^0.9.0", + "@module-federation/enhanced": "^0.21.6", "@octokit/request": "^8.0.0", "@rollup/plugin-commonjs": "^26.0.0", "@rollup/plugin-json": "^6.0.0", @@ -196,7 +196,7 @@ }, "peerDependencies": { "@jest/environment-jsdom-abstract": "^30.0.0", - "@module-federation/enhanced": "^0.9.0", + "@module-federation/enhanced": "^0.21.6", "@pmmmwh/react-refresh-webpack-plugin": "^0.6.0", "esbuild-loader": "^4.0.0", "eslint-webpack-plugin": "^4.2.0", diff --git a/packages/frontend-dynamic-feature-loader/package.json b/packages/frontend-dynamic-feature-loader/package.json index c8771ca154..a323e57840 100644 --- a/packages/frontend-dynamic-feature-loader/package.json +++ b/packages/frontend-dynamic-feature-loader/package.json @@ -34,9 +34,9 @@ "dependencies": { "@backstage/config": "workspace:^", "@backstage/frontend-plugin-api": "workspace:^", - "@module-federation/enhanced": "^0.9.0", - "@module-federation/runtime": "^0.9.0", - "@module-federation/sdk": "^0.9.0", + "@module-federation/enhanced": "^0.21.6", + "@module-federation/runtime": "^0.21.6", + "@module-federation/sdk": "^0.21.6", "cross-fetch": "^4.0.0", "uri-template": "^2.0.0" }, diff --git a/packages/frontend-dynamic-feature-loader/report.api.md b/packages/frontend-dynamic-feature-loader/report.api.md index 3188551bad..a199d0330d 100644 --- a/packages/frontend-dynamic-feature-loader/report.api.md +++ b/packages/frontend-dynamic-feature-loader/report.api.md @@ -3,8 +3,8 @@ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts -import { FederationRuntimePlugin } from '@module-federation/enhanced/runtime'; import { FrontendFeatureLoader } from '@backstage/frontend-plugin-api'; +import { ModuleFederationRuntimePlugin } from '@module-federation/enhanced/runtime'; import { ShareStrategy } from '@module-federation/runtime/types'; import { UserOptions } from '@module-federation/runtime/types'; @@ -18,7 +18,7 @@ export type DynamicFrontendFeaturesLoaderOptions = { moduleFederation: { shared?: UserOptions['shared']; shareStrategy?: ShareStrategy; - plugins?: Array; + plugins?: Array; }; }; ``` diff --git a/packages/frontend-dynamic-feature-loader/src/loader.ts b/packages/frontend-dynamic-feature-loader/src/loader.ts index 9e2585d1fa..8a9597891f 100644 --- a/packages/frontend-dynamic-feature-loader/src/loader.ts +++ b/packages/frontend-dynamic-feature-loader/src/loader.ts @@ -15,7 +15,7 @@ */ import { - FederationRuntimePlugin, + ModuleFederationRuntimePlugin, init, loadRemote, } from '@module-federation/enhanced/runtime'; @@ -39,7 +39,7 @@ export type DynamicFrontendFeaturesLoaderOptions = { moduleFederation: { shared?: UserOptions['shared']; shareStrategy?: ShareStrategy; - plugins?: Array; + plugins?: Array; }; }; diff --git a/yarn.lock b/yarn.lock index 50969a5b03..c1924eb08b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3102,7 +3102,7 @@ __metadata: "@backstage/repo-tools": "workspace:^" "@backstage/types": "workspace:^" "@manypkg/get-packages": "npm:^1.1.3" - "@module-federation/sdk": "npm:^0.9.0" + "@module-federation/sdk": "npm:^0.21.6" "@types/express": "npm:^4.17.6" chokidar: "npm:^3.5.3" express: "npm:^4.22.0" @@ -3300,7 +3300,7 @@ __metadata: "@backstage/types": "workspace:^" "@jest/environment-jsdom-abstract": "npm:^30.0.0" "@manypkg/get-packages": "npm:^1.1.3" - "@module-federation/enhanced": "npm:^0.9.0" + "@module-federation/enhanced": "npm:^0.21.6" "@octokit/request": "npm:^8.0.0" "@pmmmwh/react-refresh-webpack-plugin": "npm:^0.6.0" "@rollup/plugin-commonjs": "npm:^26.0.0" @@ -3418,7 +3418,7 @@ __metadata: zod-validation-error: "npm:^4.0.2" peerDependencies: "@jest/environment-jsdom-abstract": ^30.0.0 - "@module-federation/enhanced": ^0.9.0 + "@module-federation/enhanced": ^0.21.6 "@pmmmwh/react-refresh-webpack-plugin": ^0.6.0 esbuild-loader: ^4.0.0 eslint-webpack-plugin: ^4.2.0 @@ -3890,9 +3890,9 @@ __metadata: "@backstage/config": "workspace:^" "@backstage/frontend-plugin-api": "workspace:^" "@backstage/test-utils": "workspace:^" - "@module-federation/enhanced": "npm:^0.9.0" - "@module-federation/runtime": "npm:^0.9.0" - "@module-federation/sdk": "npm:^0.9.0" + "@module-federation/enhanced": "npm:^0.21.6" + "@module-federation/runtime": "npm:^0.21.6" + "@module-federation/sdk": "npm:^0.21.6" "@testing-library/jest-dom": "npm:^6.0.0" "@testing-library/react": "npm:^16.0.0" "@types/react": "npm:^18.0.0" @@ -11229,46 +11229,61 @@ __metadata: languageName: node linkType: hard -"@module-federation/bridge-react-webpack-plugin@npm:0.9.1": - version: 0.9.1 - resolution: "@module-federation/bridge-react-webpack-plugin@npm:0.9.1" +"@module-federation/bridge-react-webpack-plugin@npm:0.21.6": + version: 0.21.6 + resolution: "@module-federation/bridge-react-webpack-plugin@npm:0.21.6" dependencies: - "@module-federation/sdk": "npm:0.9.1" + "@module-federation/sdk": "npm:0.21.6" "@types/semver": "npm:7.5.8" semver: "npm:7.6.3" - checksum: 10/4ff197741b1bdccf8f9e2236781e5ce3ef434e4207c5462b4b95b044c4c57a3ab3dd4dce48490d9fde5bd06fb855b9918841c7d04306726ee224d3e288074091 + checksum: 10/35762b352875289703b5bdd7f8ec14da4912400bb8408c6d7afccd5d27f9137f98465f000dac08720dc672122f8223600da3b6d643b702ad36598f69af755e48 languageName: node linkType: hard -"@module-federation/data-prefetch@npm:0.9.1": - version: 0.9.1 - resolution: "@module-federation/data-prefetch@npm:0.9.1" +"@module-federation/cli@npm:0.21.6": + version: 0.21.6 + resolution: "@module-federation/cli@npm:0.21.6" dependencies: - "@module-federation/runtime": "npm:0.9.1" - "@module-federation/sdk": "npm:0.9.1" + "@module-federation/dts-plugin": "npm:0.21.6" + "@module-federation/sdk": "npm:0.21.6" + chalk: "npm:3.0.0" + commander: "npm:11.1.0" + jiti: "npm:2.4.2" + bin: + mf: bin/mf.js + checksum: 10/7b982871e817465f0effe0cf43f1c3642f7f7188a084953a3c7776b8ec8ec6aef641b98e18c703071c17145681c3aba88ab14ffc8cb9e7e17434d1088d8d99dc + languageName: node + linkType: hard + +"@module-federation/data-prefetch@npm:0.21.6": + version: 0.21.6 + resolution: "@module-federation/data-prefetch@npm:0.21.6" + dependencies: + "@module-federation/runtime": "npm:0.21.6" + "@module-federation/sdk": "npm:0.21.6" fs-extra: "npm:9.1.0" peerDependencies: react: ">=16.9.0" react-dom: ">=16.9.0" - checksum: 10/a3c0e8d77f4d06e3851d041175ef3f55d47ff4069a526b9ac773c8aba71a520a0490653c87cdcf3761e96f9eb9ea16d45026f3aafdf0851c34ff4db6d71ec113 + checksum: 10/1ae3961aac317f5c63c21a4fd7c640b1ce0be96a0b787af58fd12dc599010087397552b9a2dedb37742ea7544163cbdb6e27b87064b3cf842cfded084c99dccf languageName: node linkType: hard -"@module-federation/dts-plugin@npm:0.9.1": - version: 0.9.1 - resolution: "@module-federation/dts-plugin@npm:0.9.1" +"@module-federation/dts-plugin@npm:0.21.6": + version: 0.21.6 + resolution: "@module-federation/dts-plugin@npm:0.21.6" dependencies: - "@module-federation/error-codes": "npm:0.9.1" - "@module-federation/managers": "npm:0.9.1" - "@module-federation/sdk": "npm:0.9.1" - "@module-federation/third-party-dts-extractor": "npm:0.9.1" + "@module-federation/error-codes": "npm:0.21.6" + "@module-federation/managers": "npm:0.21.6" + "@module-federation/sdk": "npm:0.21.6" + "@module-federation/third-party-dts-extractor": "npm:0.21.6" adm-zip: "npm:^0.5.10" ansi-colors: "npm:^4.1.3" - axios: "npm:^1.7.4" + axios: "npm:^1.12.0" chalk: "npm:3.0.0" fs-extra: "npm:9.1.0" isomorphic-ws: "npm:5.0.0" - koa: "npm:2.15.4" + koa: "npm:3.0.3" lodash.clonedeepwith: "npm:4.5.0" log4js: "npm:6.9.1" node-schedule: "npm:2.1.1" @@ -11280,25 +11295,27 @@ __metadata: peerDependenciesMeta: vue-tsc: optional: true - checksum: 10/e9fd11b150456f2621636587d181f6456fe5cd60a0720843fe1310e350c3ff8ebef02ea87d1bf40dc04a4b4cd65cfb2e9007ca1c20e4e5664142b7c670c4a57d + checksum: 10/abc35da5cb602e9e05d9485d14a1a7a3eed754e123d8b6a703720041bb890fd2ac5045c8d95f3d1720a86ae523d391cf1559e4d7cc385c6915cb8b022cf0b8c7 languageName: node linkType: hard -"@module-federation/enhanced@npm:^0.9.0": - version: 0.9.1 - resolution: "@module-federation/enhanced@npm:0.9.1" +"@module-federation/enhanced@npm:^0.21.6": + version: 0.21.6 + resolution: "@module-federation/enhanced@npm:0.21.6" dependencies: - "@module-federation/bridge-react-webpack-plugin": "npm:0.9.1" - "@module-federation/data-prefetch": "npm:0.9.1" - "@module-federation/dts-plugin": "npm:0.9.1" - "@module-federation/error-codes": "npm:0.9.1" - "@module-federation/inject-external-runtime-core-plugin": "npm:0.9.1" - "@module-federation/managers": "npm:0.9.1" - "@module-federation/manifest": "npm:0.9.1" - "@module-federation/rspack": "npm:0.9.1" - "@module-federation/runtime-tools": "npm:0.9.1" - "@module-federation/sdk": "npm:0.9.1" + "@module-federation/bridge-react-webpack-plugin": "npm:0.21.6" + "@module-federation/cli": "npm:0.21.6" + "@module-federation/data-prefetch": "npm:0.21.6" + "@module-federation/dts-plugin": "npm:0.21.6" + "@module-federation/error-codes": "npm:0.21.6" + "@module-federation/inject-external-runtime-core-plugin": "npm:0.21.6" + "@module-federation/managers": "npm:0.21.6" + "@module-federation/manifest": "npm:0.21.6" + "@module-federation/rspack": "npm:0.21.6" + "@module-federation/runtime-tools": "npm:0.21.6" + "@module-federation/sdk": "npm:0.21.6" btoa: "npm:^1.2.1" + schema-utils: "npm:^4.3.0" upath: "npm:2.0.1" peerDependencies: typescript: ^4.9.0 || ^5.0.0 @@ -11311,7 +11328,16 @@ __metadata: optional: true webpack: optional: true - checksum: 10/a7955711f37ba02a18f3570289dfd8fbed30511b82fcf593e56808559cfd49d8852028aa67950db5e45617d0917536d067d85847892e62c20b68ba6ab40e17c4 + bin: + mf: bin/mf.js + checksum: 10/ee67837a6bbfade36424088d6e2d18518e33f7cfb76303f03a6758bde051060105417e51eb6c10e823510376e195f7b8c4090e905a9ac53f0faa3e87edbe7a4b + languageName: node + linkType: hard + +"@module-federation/error-codes@npm:0.21.6": + version: 0.21.6 + resolution: "@module-federation/error-codes@npm:0.21.6" + checksum: 10/6ded1ecab780f1f9ec46a59adb200e75cdf11580d70aa79dd75d71fbbf276615690da277ea67aa1ceb5bc88386f5708cc1d2ba5526be5c9ff02397a6123e36bf languageName: node linkType: hard @@ -11322,57 +11348,51 @@ __metadata: languageName: node linkType: hard -"@module-federation/error-codes@npm:0.9.1": - version: 0.9.1 - resolution: "@module-federation/error-codes@npm:0.9.1" - checksum: 10/545aecc606a506ee47f061835e0eaa41b8d1b02f6bf71b36ec9ae85a1b0370af1f7b7cf92a8f52c3c4b35da858653244316de5ab06bea5dac5b92995467631cc - languageName: node - linkType: hard - -"@module-federation/inject-external-runtime-core-plugin@npm:0.9.1": - version: 0.9.1 - resolution: "@module-federation/inject-external-runtime-core-plugin@npm:0.9.1" +"@module-federation/inject-external-runtime-core-plugin@npm:0.21.6": + version: 0.21.6 + resolution: "@module-federation/inject-external-runtime-core-plugin@npm:0.21.6" peerDependencies: - "@module-federation/runtime-tools": 0.9.1 - checksum: 10/931eef6292c278450fc8cdb017073fa0b721796461eee12a254fc60a88a2f17e91395b12371f2c8b3b25b4056fc2dd2b76d1022e679be7353947c3d797e75ea5 + "@module-federation/runtime-tools": 0.21.6 + checksum: 10/579d6d1208ff22f5073b6e96c978fc68f9f130d6e12eed94bd2b37905476fad8daa85adae0d655f77ab3cd07c948cb06a78788d1bfbd7de1c3d5e7f08620f84e languageName: node linkType: hard -"@module-federation/managers@npm:0.9.1": - version: 0.9.1 - resolution: "@module-federation/managers@npm:0.9.1" +"@module-federation/managers@npm:0.21.6": + version: 0.21.6 + resolution: "@module-federation/managers@npm:0.21.6" dependencies: - "@module-federation/sdk": "npm:0.9.1" + "@module-federation/sdk": "npm:0.21.6" find-pkg: "npm:2.0.0" fs-extra: "npm:9.1.0" - checksum: 10/32c1666244ba98644ab6eccdc844415d1aece1c105f6ba2ff17a3836866e7cdb2f61e556cb5a2b506b898ec709951f318d397f4d153efeff377067237968462f + checksum: 10/2267a340ae44e62b0cb6f565bb19745996d4840e47a9d16fdf8d1a27273f7f6cb08487b727d03b223e7bfe7cd11254c5f0ab29def369ce25765ae1b20a592024 languageName: node linkType: hard -"@module-federation/manifest@npm:0.9.1": - version: 0.9.1 - resolution: "@module-federation/manifest@npm:0.9.1" +"@module-federation/manifest@npm:0.21.6": + version: 0.21.6 + resolution: "@module-federation/manifest@npm:0.21.6" dependencies: - "@module-federation/dts-plugin": "npm:0.9.1" - "@module-federation/managers": "npm:0.9.1" - "@module-federation/sdk": "npm:0.9.1" + "@module-federation/dts-plugin": "npm:0.21.6" + "@module-federation/managers": "npm:0.21.6" + "@module-federation/sdk": "npm:0.21.6" chalk: "npm:3.0.0" find-pkg: "npm:2.0.0" - checksum: 10/539b86bd5388296fb35a34c7b732b92788600ab6625d53f11588ad67c3a603ac3c1974541d9cf04db2d24635be1610414c29388e849d96bbb812cad3b1c79425 + checksum: 10/957c4642cd54b328740e3f45e84d6c449fbc39969afed169f34ed2b19da13a2d8c029321276500f1212aa78a7853612d2dc945f9d9679012b753708306392be3 languageName: node linkType: hard -"@module-federation/rspack@npm:0.9.1": - version: 0.9.1 - resolution: "@module-federation/rspack@npm:0.9.1" +"@module-federation/rspack@npm:0.21.6": + version: 0.21.6 + resolution: "@module-federation/rspack@npm:0.21.6" dependencies: - "@module-federation/bridge-react-webpack-plugin": "npm:0.9.1" - "@module-federation/dts-plugin": "npm:0.9.1" - "@module-federation/inject-external-runtime-core-plugin": "npm:0.9.1" - "@module-federation/managers": "npm:0.9.1" - "@module-federation/manifest": "npm:0.9.1" - "@module-federation/runtime-tools": "npm:0.9.1" - "@module-federation/sdk": "npm:0.9.1" + "@module-federation/bridge-react-webpack-plugin": "npm:0.21.6" + "@module-federation/dts-plugin": "npm:0.21.6" + "@module-federation/inject-external-runtime-core-plugin": "npm:0.21.6" + "@module-federation/managers": "npm:0.21.6" + "@module-federation/manifest": "npm:0.21.6" + "@module-federation/runtime-tools": "npm:0.21.6" + "@module-federation/sdk": "npm:0.21.6" + btoa: "npm:1.2.1" peerDependencies: "@rspack/core": ">=0.7" typescript: ^4.9.0 || ^5.0.0 @@ -11382,7 +11402,17 @@ __metadata: optional: true vue-tsc: optional: true - checksum: 10/e6deb7236ccc66d7f0475a09916ec714c9855847bfd3d3ec6cdbee991016a222a22f6ae3fd14d71351d55e22e8949140f37ce9ce79dece5416731c6698726096 + checksum: 10/8dd952ee1499a897e30d2ba363c29c2c1eba80f0b712f008a9f1bd84b49a2204e4657033e3086e31afe0452cbf023f132db27fc61b4e9caa66170bca1d78896a + languageName: node + linkType: hard + +"@module-federation/runtime-core@npm:0.21.6": + version: 0.21.6 + resolution: "@module-federation/runtime-core@npm:0.21.6" + dependencies: + "@module-federation/error-codes": "npm:0.21.6" + "@module-federation/sdk": "npm:0.21.6" + checksum: 10/85efa2042d6f3a7cf0e4971b991472d4339d88f6f15684afb6d451f19ed934e225b2510c86b7bb4d2c5f64253ed7b0175f08c17f95bfc2b9929930a8a03fff1e languageName: node linkType: hard @@ -11396,13 +11426,13 @@ __metadata: languageName: node linkType: hard -"@module-federation/runtime-core@npm:0.9.1": - version: 0.9.1 - resolution: "@module-federation/runtime-core@npm:0.9.1" +"@module-federation/runtime-tools@npm:0.21.6": + version: 0.21.6 + resolution: "@module-federation/runtime-tools@npm:0.21.6" dependencies: - "@module-federation/error-codes": "npm:0.9.1" - "@module-federation/sdk": "npm:0.9.1" - checksum: 10/6f9edbe23013395d7896fc2a24cb4055bc78df5a335f090e079df951835c1cf91c567228f19879eee3fddb0b34128abd0b50feaca1cf3fb2828c7b9bacc22169 + "@module-federation/runtime": "npm:0.21.6" + "@module-federation/webpack-bundler-runtime": "npm:0.21.6" + checksum: 10/36e7ccab948e11f310e87397a1a2185b56064e5691e553b34173686e2bc7372ec710e5ad48c026eb28c85b168765788b743aa2111513f3b57118b47636312dd1 languageName: node linkType: hard @@ -11416,13 +11446,14 @@ __metadata: languageName: node linkType: hard -"@module-federation/runtime-tools@npm:0.9.1": - version: 0.9.1 - resolution: "@module-federation/runtime-tools@npm:0.9.1" +"@module-federation/runtime@npm:0.21.6, @module-federation/runtime@npm:^0.21.6": + version: 0.21.6 + resolution: "@module-federation/runtime@npm:0.21.6" dependencies: - "@module-federation/runtime": "npm:0.9.1" - "@module-federation/webpack-bundler-runtime": "npm:0.9.1" - checksum: 10/9436e814a4ab72839b8aed1aa097f32cf7d4d49728dd863c9ce6dc4fb149fe49da6dc9cdeb97814f0023cc91489c9aca06cbfdf9fb4e43d20498ab6ee78c95dd + "@module-federation/error-codes": "npm:0.21.6" + "@module-federation/runtime-core": "npm:0.21.6" + "@module-federation/sdk": "npm:0.21.6" + checksum: 10/93fd9bb284630933cab7e4bc070d648b56272f3636038c05eec7d1e3eeb189be3ccebe5f8ecc450197ee992d2616ed282d54e673ec0acd63adee4faddf80b144 languageName: node linkType: hard @@ -11437,14 +11468,10 @@ __metadata: languageName: node linkType: hard -"@module-federation/runtime@npm:0.9.1, @module-federation/runtime@npm:^0.9.0": - version: 0.9.1 - resolution: "@module-federation/runtime@npm:0.9.1" - dependencies: - "@module-federation/error-codes": "npm:0.9.1" - "@module-federation/runtime-core": "npm:0.9.1" - "@module-federation/sdk": "npm:0.9.1" - checksum: 10/71eb1c3e81b307ebfe06c43ce70bfa56b217e9dfbed27f0b4235d3d0d05cc0fe2eb1dc57fffb3260ed9e0239257ef117ae13924c642b5ff97d9c65bdf48206fe +"@module-federation/sdk@npm:0.21.6, @module-federation/sdk@npm:^0.21.6": + version: 0.21.6 + resolution: "@module-federation/sdk@npm:0.21.6" + checksum: 10/effc4aa932e2f06742bda8f02aaec84e138f5512b50f18c38b051490020b20d3d8edf7ece853fccffc1f78a0b43dec78e69bf02150e7e2801d5ce03c3ee367b9 languageName: node linkType: hard @@ -11455,21 +11482,24 @@ __metadata: languageName: node linkType: hard -"@module-federation/sdk@npm:0.9.1, @module-federation/sdk@npm:^0.9.0": - version: 0.9.1 - resolution: "@module-federation/sdk@npm:0.9.1" - checksum: 10/ea0320feff328a05405e65503d1df28e46a9ad17ef99b77f1428db5c89efbadd2a76ec82d99a54ac1d21286cee6d9ddbba881a9c46748dfe8abdb11e9afef7da - languageName: node - linkType: hard - -"@module-federation/third-party-dts-extractor@npm:0.9.1": - version: 0.9.1 - resolution: "@module-federation/third-party-dts-extractor@npm:0.9.1" +"@module-federation/third-party-dts-extractor@npm:0.21.6": + version: 0.21.6 + resolution: "@module-federation/third-party-dts-extractor@npm:0.21.6" dependencies: find-pkg: "npm:2.0.0" fs-extra: "npm:9.1.0" resolve: "npm:1.22.8" - checksum: 10/68c70c79573cd927212d95879aa7b35490519d0ec9f58dd264c9d61e22fea8d452e45a52a94155128d8378e5cdcaecb229707b5b0f4e4c0d53ae96e2fbac366a + checksum: 10/d9328575d3b2c64711dacae38c8186a38732c900d5b7c63d84ec3d4b42b199aa484cfe69dad228e1197170c33d1b39a1671467d274046780e6bddbe0c68b1e25 + languageName: node + linkType: hard + +"@module-federation/webpack-bundler-runtime@npm:0.21.6": + version: 0.21.6 + resolution: "@module-federation/webpack-bundler-runtime@npm:0.21.6" + dependencies: + "@module-federation/runtime": "npm:0.21.6" + "@module-federation/sdk": "npm:0.21.6" + checksum: 10/a5ceb72ee3867acad5d7d3c654eb568068b1d5288f60ce9301bdc9f56effa5a4c26a732a2cec7176a81b87139566cd51dd8dfbc6112da05d47b870fa3ad3ba1f languageName: node linkType: hard @@ -11483,16 +11513,6 @@ __metadata: languageName: node linkType: hard -"@module-federation/webpack-bundler-runtime@npm:0.9.1": - version: 0.9.1 - resolution: "@module-federation/webpack-bundler-runtime@npm:0.9.1" - dependencies: - "@module-federation/runtime": "npm:0.9.1" - "@module-federation/sdk": "npm:0.9.1" - checksum: 10/430cac0a770b3c46bc195088eb4c1892e1e29a69238dbe72423d64b2b67050afeca2b5026b1a30659b4fe8d9faa038ff97cceba7e2ddf6193b93763f270d9df6 - languageName: node - linkType: hard - "@motionone/animation@npm:^10.12.0": version: 10.16.3 resolution: "@motionone/animation@npm:10.16.3" @@ -21360,14 +21380,7 @@ __metadata: languageName: node linkType: hard -"@types/luxon@npm:^3.0.0": - version: 3.7.1 - resolution: "@types/luxon@npm:3.7.1" - checksum: 10/c7bc164c278393ea0be938f986c74b4cddfab9013b1aff4495b016f771ded1d5b7b7b4825b2c7f0b8799edce19c5f531c28ff434ab3dedf994ac2d99a20fd4c4 - languageName: node - linkType: hard - -"@types/luxon@npm:~3.4.0": +"@types/luxon@npm:^3.0.0, @types/luxon@npm:~3.4.0": version: 3.4.2 resolution: "@types/luxon@npm:3.4.2" checksum: 10/fd89566e3026559f2bc4ddcc1e70a2c16161905ed50be9473ec0cfbbbe919165041408c4f6e06c4bcf095445535052e2c099087c76b1b38e368127e618fc968d @@ -24190,7 +24203,7 @@ __metadata: languageName: node linkType: hard -"accepts@npm:^1.3.5, accepts@npm:^1.3.7, accepts@npm:~1.3.4, accepts@npm:~1.3.8": +"accepts@npm:^1.3.7, accepts@npm:^1.3.8, accepts@npm:~1.3.4, accepts@npm:~1.3.8": version: 1.3.8 resolution: "accepts@npm:1.3.8" dependencies: @@ -25258,7 +25271,7 @@ __metadata: languageName: node linkType: hard -"axios@npm:1.13.2, axios@npm:^1.0.0, axios@npm:^1.11.0, axios@npm:^1.12.2, axios@npm:^1.13.0, axios@npm:^1.7.4": +"axios@npm:1.13.2, axios@npm:^1.0.0, axios@npm:^1.11.0, axios@npm:^1.12.0, axios@npm:^1.12.2, axios@npm:^1.13.0, axios@npm:^1.7.4": version: 1.13.2 resolution: "axios@npm:1.13.2" dependencies: @@ -26010,7 +26023,7 @@ __metadata: languageName: node linkType: hard -"btoa@npm:^1.2.1": +"btoa@npm:1.2.1, btoa@npm:^1.2.1": version: 1.2.1 resolution: "btoa@npm:1.2.1" bin: @@ -26252,16 +26265,6 @@ __metadata: languageName: node linkType: hard -"cache-content-type@npm:^1.0.0": - version: 1.0.1 - resolution: "cache-content-type@npm:1.0.1" - dependencies: - mime-types: "npm:^2.1.18" - ylru: "npm:^1.2.0" - checksum: 10/18db4d59452669ccbfd7146a1510a37eb28e9eccf18ca7a4eb603dff2edc5cccdca7498fc3042a2978f76f11151fba486eb9eb69d9afa3fb124957870aef4fd3 - languageName: node - linkType: hard - "cacheable-lookup@npm:^5.0.3": version: 5.0.3 resolution: "cacheable-lookup@npm:5.0.3" @@ -27177,6 +27180,13 @@ __metadata: languageName: node linkType: hard +"commander@npm:11.1.0, commander@npm:^11.0.0": + version: 11.1.0 + resolution: "commander@npm:11.1.0" + checksum: 10/66bd2d8a0547f6cb1d34022efb25f348e433b0e04ad76a65279b1b09da108f59a4d3001ca539c60a7a46ea38bcf399fc17d91adad76a8cf43845d8dcbaf5cda1 + languageName: node + linkType: hard + "commander@npm:7.1.0": version: 7.1.0 resolution: "commander@npm:7.1.0" @@ -27205,13 +27215,6 @@ __metadata: languageName: node linkType: hard -"commander@npm:^11.0.0": - version: 11.1.0 - resolution: "commander@npm:11.1.0" - checksum: 10/66bd2d8a0547f6cb1d34022efb25f348e433b0e04ad76a65279b1b09da108f59a4d3001ca539c60a7a46ea38bcf399fc17d91adad76a8cf43845d8dcbaf5cda1 - languageName: node - linkType: hard - "commander@npm:^12.0.0, commander@npm:^12.1.0": version: 12.1.0 resolution: "commander@npm:12.1.0" @@ -27499,7 +27502,7 @@ __metadata: languageName: node linkType: hard -"content-disposition@npm:^0.5.3, content-disposition@npm:~0.5.2, content-disposition@npm:~0.5.4": +"content-disposition@npm:^0.5.3, content-disposition@npm:~0.5.4": version: 0.5.4 resolution: "content-disposition@npm:0.5.4" dependencies: @@ -27517,7 +27520,7 @@ __metadata: languageName: node linkType: hard -"content-type@npm:^1.0.4, content-type@npm:^1.0.5, content-type@npm:~1.0.4, content-type@npm:~1.0.5": +"content-type@npm:^1.0.5, content-type@npm:~1.0.4, content-type@npm:~1.0.5": version: 1.0.5 resolution: "content-type@npm:1.0.5" checksum: 10/585847d98dc7fb8035c02ae2cb76c7a9bd7b25f84c447e5ed55c45c2175e83617c8813871b4ee22f368126af6b2b167df655829007b21aa10302873ea9c62662 @@ -27597,7 +27600,7 @@ __metadata: languageName: node linkType: hard -"cookies@npm:~0.9.0": +"cookies@npm:~0.9.1": version: 0.9.1 resolution: "cookies@npm:0.9.1" dependencies: @@ -28819,7 +28822,7 @@ __metadata: languageName: node linkType: hard -"destroy@npm:1.2.0, destroy@npm:^1.0.4, destroy@npm:~1.2.0": +"destroy@npm:1.2.0, destroy@npm:^1.0.4, destroy@npm:^1.2.0, destroy@npm:~1.2.0": version: 1.2.0 resolution: "destroy@npm:1.2.0" checksum: 10/0acb300b7478a08b92d810ab229d5afe0d2f4399272045ab22affa0d99dbaf12637659411530a6fcd597a9bdac718fc94373a61a95b4651bbc7b83684a565e38 @@ -29550,13 +29553,6 @@ __metadata: languageName: node linkType: hard -"encodeurl@npm:^1.0.2, encodeurl@npm:~1.0.2": - version: 1.0.2 - resolution: "encodeurl@npm:1.0.2" - checksum: 10/e50e3d508cdd9c4565ba72d2012e65038e5d71bdc9198cb125beb6237b5b1ade6c0d343998da9e170fb2eae52c1bed37d4d6d98a46ea423a0cddbed5ac3f780c - languageName: node - linkType: hard - "encodeurl@npm:^2.0.0, encodeurl@npm:~2.0.0": version: 2.0.0 resolution: "encodeurl@npm:2.0.0" @@ -29564,6 +29560,13 @@ __metadata: languageName: node linkType: hard +"encodeurl@npm:~1.0.2": + version: 1.0.2 + resolution: "encodeurl@npm:1.0.2" + checksum: 10/e50e3d508cdd9c4565ba72d2012e65038e5d71bdc9198cb125beb6237b5b1ade6c0d343998da9e170fb2eae52c1bed37d4d6d98a46ea423a0cddbed5ac3f780c + languageName: node + linkType: hard + "encoding@npm:^0.1.12, encoding@npm:^0.1.13": version: 0.1.13 resolution: "encoding@npm:0.1.13" @@ -33606,7 +33609,7 @@ __metadata: languageName: node linkType: hard -"http-assert@npm:^1.3.0": +"http-assert@npm:^1.5.0": version: 1.5.0 resolution: "http-assert@npm:1.5.0" dependencies: @@ -33665,19 +33668,6 @@ __metadata: languageName: node linkType: hard -"http-errors@npm:^1.6.3, http-errors@npm:~1.8.0": - version: 1.8.1 - resolution: "http-errors@npm:1.8.1" - dependencies: - depd: "npm:~1.1.2" - inherits: "npm:2.0.4" - setprototypeof: "npm:1.2.0" - statuses: "npm:>= 1.5.0 < 2" - toidentifier: "npm:1.0.1" - checksum: 10/76fc491bd8df2251e21978e080d5dae20d9736cfb29bb72b5b76ec1bcebb1c14f0f58a3a128dd89288934379d2173cfb0421c571d54103e93dd65ef6243d64d8 - languageName: node - linkType: hard - "http-errors@npm:^2.0.0, http-errors@npm:~2.0.0, http-errors@npm:~2.0.1": version: 2.0.1 resolution: "http-errors@npm:2.0.1" @@ -33703,6 +33693,19 @@ __metadata: languageName: node linkType: hard +"http-errors@npm:~1.8.0": + version: 1.8.1 + resolution: "http-errors@npm:1.8.1" + dependencies: + depd: "npm:~1.1.2" + inherits: "npm:2.0.4" + setprototypeof: "npm:1.2.0" + statuses: "npm:>= 1.5.0 < 2" + toidentifier: "npm:1.0.1" + checksum: 10/76fc491bd8df2251e21978e080d5dae20d9736cfb29bb72b5b76ec1bcebb1c14f0f58a3a128dd89288934379d2173cfb0421c571d54103e93dd65ef6243d64d8 + languageName: node + linkType: hard + "http-parser-js@npm:>=0.5.1": version: 0.5.3 resolution: "http-parser-js@npm:0.5.3" @@ -35923,6 +35926,15 @@ __metadata: languageName: node linkType: hard +"jiti@npm:2.4.2": + version: 2.4.2 + resolution: "jiti@npm:2.4.2" + bin: + jiti: lib/jiti-cli.mjs + checksum: 10/e2b07eb2e3fbb245e29ad288dddecab31804967fc84d5e01d39858997d2743b5e248946defcecf99272275a00284ecaf7ec88b8c841331324f0c946d8274414b + languageName: node + linkType: hard + "jiti@npm:^2.0.0, jiti@npm:^2.6.0": version: 2.6.1 resolution: "jiti@npm:2.6.1" @@ -36815,44 +36827,29 @@ __metadata: languageName: node linkType: hard -"koa-convert@npm:^2.0.0": - version: 2.0.0 - resolution: "koa-convert@npm:2.0.0" +"koa@npm:3.0.3": + version: 3.0.3 + resolution: "koa@npm:3.0.3" dependencies: - co: "npm:^4.6.0" - koa-compose: "npm:^4.1.0" - checksum: 10/7385b3391995f59c1312142e110d5dff677f9850dbfbcf387cd36a7b0af03b5d26e82b811eb9bb008b4f3e661cdab1f8817596e46b1929da2cf6e97a2f7456ed - languageName: node - linkType: hard - -"koa@npm:2.15.4": - version: 2.15.4 - resolution: "koa@npm:2.15.4" - dependencies: - accepts: "npm:^1.3.5" - cache-content-type: "npm:^1.0.0" - content-disposition: "npm:~0.5.2" - content-type: "npm:^1.0.4" - cookies: "npm:~0.9.0" - debug: "npm:^4.3.2" + accepts: "npm:^1.3.8" + content-disposition: "npm:~0.5.4" + content-type: "npm:^1.0.5" + cookies: "npm:~0.9.1" delegates: "npm:^1.0.0" - depd: "npm:^2.0.0" - destroy: "npm:^1.0.4" - encodeurl: "npm:^1.0.2" + destroy: "npm:^1.2.0" + encodeurl: "npm:^2.0.0" escape-html: "npm:^1.0.3" fresh: "npm:~0.5.2" - http-assert: "npm:^1.3.0" - http-errors: "npm:^1.6.3" - is-generator-function: "npm:^1.0.7" + http-assert: "npm:^1.5.0" + http-errors: "npm:^2.0.0" koa-compose: "npm:^4.1.0" - koa-convert: "npm:^2.0.0" - on-finished: "npm:^2.3.0" - only: "npm:~0.0.2" - parseurl: "npm:^1.3.2" - statuses: "npm:^1.5.0" - type-is: "npm:^1.6.16" + mime-types: "npm:^3.0.1" + on-finished: "npm:^2.4.1" + parseurl: "npm:^1.3.3" + statuses: "npm:^2.0.1" + type-is: "npm:^2.0.1" vary: "npm:^1.1.2" - checksum: 10/98de77173822f0a28c0f5d1ebd261ab02f3f905d40602e51957a0c7202122647a60c5b6c59be03361dd24bf6a5685eac97af84b306914efd057751e71f93cb0f + checksum: 10/15df9a7777ad357851253deaba534403dcc97eb81efce263c8a8b30b5bc3e5db7d61e35b7a89ce359ec3cf043b50244996df0efe6f29785adefbc6f691a1eda6 languageName: node linkType: hard @@ -37845,14 +37842,7 @@ __metadata: languageName: node linkType: hard -"luxon@npm:^3.0.0, luxon@npm:^3.2.1, luxon@npm:^3.4.3, luxon@npm:^3.5.0": - version: 3.7.2 - resolution: "luxon@npm:3.7.2" - checksum: 10/b24cd205ed306ce7415991687897dcc4027921ae413c9116590bc33a95f93b86ce52cf74ba72b4f5c5ab1c10090517f54ac8edfb127c049e0bf55b90dc2260be - languageName: node - linkType: hard - -"luxon@npm:~3.5.0": +"luxon@npm:^3.0.0, luxon@npm:^3.2.1, luxon@npm:^3.4.3, luxon@npm:^3.5.0, luxon@npm:~3.5.0": version: 3.5.0 resolution: "luxon@npm:3.5.0" checksum: 10/48f86e6c1c96815139f8559456a3354a276ba79bcef0ae0d4f2172f7652f3ba2be2237b0e103b8ea0b79b47715354ac9fac04eb1db3485dcc72d5110491dd47f @@ -38904,7 +38894,7 @@ __metadata: languageName: node linkType: hard -"mime-types@npm:2.1.35, mime-types@npm:^2.1.12, mime-types@npm:^2.1.18, mime-types@npm:^2.1.27, mime-types@npm:^2.1.31, mime-types@npm:^2.1.35, mime-types@npm:~2.1.17, mime-types@npm:~2.1.24, mime-types@npm:~2.1.34": +"mime-types@npm:2.1.35, mime-types@npm:^2.1.12, mime-types@npm:^2.1.27, mime-types@npm:^2.1.31, mime-types@npm:^2.1.35, mime-types@npm:~2.1.17, mime-types@npm:~2.1.24, mime-types@npm:~2.1.34": version: 2.1.35 resolution: "mime-types@npm:2.1.35" dependencies: @@ -40680,7 +40670,7 @@ __metadata: languageName: node linkType: hard -"on-finished@npm:2.4.1, on-finished@npm:^2.3.0, on-finished@npm:^2.4.1, on-finished@npm:~2.4.1": +"on-finished@npm:2.4.1, on-finished@npm:^2.4.1, on-finished@npm:~2.4.1": version: 2.4.1 resolution: "on-finished@npm:2.4.1" dependencies: @@ -40759,13 +40749,6 @@ __metadata: languageName: node linkType: hard -"only@npm:~0.0.2": - version: 0.0.2 - resolution: "only@npm:0.0.2" - checksum: 10/e2ad03e486534dc6bfb983393be83125a4669052b4a19a353eb00475b46971fb238a18223f2b609fe0d1bcb61ff8373964ccac64d05cbf970865299f655ed0ba - languageName: node - linkType: hard - "ono@npm:^7.1.3": version: 7.1.3 resolution: "ono@npm:7.1.3" @@ -41523,7 +41506,7 @@ __metadata: languageName: node linkType: hard -"parseurl@npm:^1.3.2, parseurl@npm:^1.3.3, parseurl@npm:~1.3.2, parseurl@npm:~1.3.3": +"parseurl@npm:^1.3.3, parseurl@npm:~1.3.2, parseurl@npm:~1.3.3": version: 1.3.3 resolution: "parseurl@npm:1.3.3" checksum: 10/407cee8e0a3a4c5cd472559bca8b6a45b82c124e9a4703302326e9ab60fc1081442ada4e02628efef1eb16197ddc7f8822f5a91fd7d7c86b51f530aedb17dfa2 @@ -46990,7 +46973,7 @@ __metadata: languageName: node linkType: hard -"statuses@npm:>= 1.4.0 < 2, statuses@npm:>= 1.5.0 < 2, statuses@npm:^1.5.0, statuses@npm:~1.5.0": +"statuses@npm:>= 1.4.0 < 2, statuses@npm:>= 1.5.0 < 2, statuses@npm:~1.5.0": version: 1.5.0 resolution: "statuses@npm:1.5.0" checksum: 10/c469b9519de16a4bb19600205cffb39ee471a5f17b82589757ca7bd40a8d92ebb6ed9f98b5a540c5d302ccbc78f15dc03cc0280dd6e00df1335568a5d5758a5c @@ -48914,7 +48897,7 @@ __metadata: languageName: node linkType: hard -"type-is@npm:^1.6.16, type-is@npm:^1.6.18, type-is@npm:~1.6.18": +"type-is@npm:^1.6.18, type-is@npm:~1.6.18": version: 1.6.18 resolution: "type-is@npm:1.6.18" dependencies: @@ -51180,7 +51163,7 @@ __metadata: languageName: node linkType: hard -"ylru@npm:^1.2.0, ylru@npm:^1.3.2": +"ylru@npm:^1.3.2": version: 1.4.0 resolution: "ylru@npm:1.4.0" checksum: 10/5437f8eb2fb5dd515845c657dde3cecaa9f6bd4c6386d2a5212d3fafe02189c7d8ebfdfc84940a7811607cb3524eb362ce95d3180d355cd5deb610aa8c82c9bc From c324bf71be57d74aeed9f9de689f9e8950d8baf0 Mon Sep 17 00:00:00 2001 From: David Festal Date: Tue, 16 Sep 2025 21:32:03 +0200 Subject: [PATCH 02/17] Move module federation enablement in `app-next` at runtime. Signed-off-by: David Festal Assisted-by: Cursor --- packages/cli/package.json | 1 + .../commands/package/start/startFrontend.ts | 13 +- .../src/modules/build/lib/buildFrontend.ts | 15 +- .../src/modules/build/lib/bundler/bundle.ts | 14 +- .../src/modules/build/lib/bundler/config.ts | 121 +-- .../src/modules/build/lib/bundler/index.ts | 2 +- .../build/lib/bundler/moduleFederation.ts | 132 ++- .../src/modules/build/lib/bundler/server.ts | 39 +- .../src/modules/build/lib/bundler/types.ts | 15 +- .../package.json | 1 + .../report.api.md | 8 +- .../src/loader.test.tsx | 761 ++++++++++++++---- .../src/loader.ts | 80 +- .../module-federation-common/.eslintrc.js | 1 + packages/module-federation-common/README.md | 11 + .../catalog-info.yaml | 10 + .../module-federation-common/package.json | 70 ++ .../module-federation-common/report.api.md | 50 ++ .../src/defaults.test.ts | 44 + .../module-federation-common/src/defaults.ts | 155 ++++ .../module-federation-common/src/index.ts | 33 + .../src/runtime.test.ts | 523 ++++++++++++ .../module-federation-common/src/runtime.ts | 112 +++ .../module-federation-common/src/types.ts | 69 ++ yarn.lock | 43 +- 25 files changed, 1992 insertions(+), 331 deletions(-) create mode 100644 packages/module-federation-common/.eslintrc.js create mode 100644 packages/module-federation-common/README.md create mode 100644 packages/module-federation-common/catalog-info.yaml create mode 100644 packages/module-federation-common/package.json create mode 100644 packages/module-federation-common/report.api.md create mode 100644 packages/module-federation-common/src/defaults.test.ts create mode 100644 packages/module-federation-common/src/defaults.ts create mode 100644 packages/module-federation-common/src/index.ts create mode 100644 packages/module-federation-common/src/runtime.test.ts create mode 100644 packages/module-federation-common/src/runtime.ts create mode 100644 packages/module-federation-common/src/types.ts diff --git a/packages/cli/package.json b/packages/cli/package.json index c5b75e31d7..6e1fc0b10f 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -55,6 +55,7 @@ "@backstage/errors": "workspace:^", "@backstage/eslint-plugin": "workspace:^", "@backstage/integration": "workspace:^", + "@backstage/module-federation-common": "workspace:^", "@backstage/release-manifests": "workspace:^", "@backstage/types": "workspace:^", "@manypkg/get-packages": "^1.1.3", diff --git a/packages/cli/src/modules/build/commands/package/start/startFrontend.ts b/packages/cli/src/modules/build/commands/package/start/startFrontend.ts index 1fa439f4ea..027dbf68e3 100644 --- a/packages/cli/src/modules/build/commands/package/start/startFrontend.ts +++ b/packages/cli/src/modules/build/commands/package/start/startFrontend.ts @@ -17,7 +17,7 @@ import { readJson } from 'fs-extra'; import { resolve as resolvePath } from 'node:path'; import { - getModuleFederationOptions, + getModuleFederationRemoteOptions, serveBundle, } from '../../../../build/lib/bundler'; import { paths } from '../../../../../lib/paths'; @@ -55,11 +55,12 @@ export async function startFrontend(options: StartAppOptions) { verifyVersions: options.verifyVersions, skipOpenBrowser: options.skipOpenBrowser, linkedWorkspace: options.linkedWorkspace, - moduleFederation: await getModuleFederationOptions( - packageJson, - resolvePath(paths.targetDir), - options.isModuleFederationRemote, - ), + moduleFederationRemote: options.isModuleFederationRemote + ? await getModuleFederationRemoteOptions( + packageJson, + resolvePath(paths.targetDir), + ) + : undefined, }); await waitForExit(); diff --git a/packages/cli/src/modules/build/lib/buildFrontend.ts b/packages/cli/src/modules/build/lib/buildFrontend.ts index 554b90306d..7b0955a519 100644 --- a/packages/cli/src/modules/build/lib/buildFrontend.ts +++ b/packages/cli/src/modules/build/lib/buildFrontend.ts @@ -16,7 +16,7 @@ import fs from 'fs-extra'; import { resolve as resolvePath } from 'node:path'; -import { buildBundle, getModuleFederationOptions } from './bundler'; +import { buildBundle, getModuleFederationRemoteOptions } from './bundler'; import { getEnvironmentParallelism } from '../../../lib/parallel'; import { loadCliConfig } from '../../config/lib/config'; import { BackstagePackageJson } from '@backstage/cli-node'; @@ -25,7 +25,7 @@ interface BuildAppOptions { targetDir: string; writeStats: boolean; configPaths: string[]; - isModuleFederationRemote?: true; + isModuleFederationRemote?: boolean; webpack?: typeof import('webpack'); } @@ -39,11 +39,12 @@ export async function buildFrontend(options: BuildAppOptions) { entry: 'src/index', parallelism: getEnvironmentParallelism(), statsJsonEnabled: writeStats, - moduleFederation: await getModuleFederationOptions( - packageJson, - resolvePath(targetDir), - options.isModuleFederationRemote, - ), + moduleFederationRemote: options.isModuleFederationRemote + ? await getModuleFederationRemoteOptions( + packageJson, + resolvePath(targetDir), + ) + : undefined, ...(await loadCliConfig({ args: configPaths, fromPackage: packageJson.name, diff --git a/packages/cli/src/modules/build/lib/bundler/bundle.ts b/packages/cli/src/modules/build/lib/bundler/bundle.ts index 6235d9b214..17ee660735 100644 --- a/packages/cli/src/modules/build/lib/bundler/bundle.ts +++ b/packages/cli/src/modules/build/lib/bundler/bundle.ts @@ -28,6 +28,7 @@ import { BuildOptions } from './types'; import { resolveBundlingPaths, resolveOptionalBundlingPaths } from './paths'; import chalk from 'chalk'; import { createDetectedModulesEntryPoint } from './packageDetection'; +import { createRuntimeSharedDependeciesEntryPoint } from './moduleFederation'; // TODO(Rugvip): Limits from CRA, we might want to tweak these though. const WARN_AFTER_BUNDLE_GZIP_SIZE = 512 * 1024; @@ -55,8 +56,7 @@ export async function buildBundle(options: BuildOptions) { }; const configs: Configuration[] = []; - - if (options.moduleFederation?.mode === 'remote') { + if (options.moduleFederationRemote) { // Package detection is disabled for remote bundles configs.push(await createConfig(paths, commonConfigOptions)); } else { @@ -65,10 +65,18 @@ export async function buildBundle(options: BuildOptions) { targetPath: paths.targetPath, }); + const moduleFederationSharedDependenciesEntryPoint = + await createRuntimeSharedDependeciesEntryPoint({ + targetPath: paths.targetPath, + }); + configs.push( await createConfig(paths, { ...commonConfigOptions, - additionalEntryPoints: detectedModulesEntryPoint, + additionalEntryPoints: [ + ...detectedModulesEntryPoint, + ...moduleFederationSharedDependenciesEntryPoint, + ], appMode: publicPaths ? 'protected' : 'public', }), ); diff --git a/packages/cli/src/modules/build/lib/bundler/config.ts b/packages/cli/src/modules/build/lib/bundler/config.ts index e68ce9588d..278f6a3b69 100644 --- a/packages/cli/src/modules/build/lib/bundler/config.ts +++ b/packages/cli/src/modules/build/lib/bundler/config.ts @@ -14,8 +14,8 @@ * limitations under the License. */ -import { BundlingOptions, ModuleFederationOptions } from './types'; import { resolve as resolvePath } from 'node:path'; +import { BundlingOptions, ModuleFederationRemoteOptions } from './types'; import { rspack, Configuration } from '@rspack/core'; import { BundlingPaths } from './paths'; @@ -39,14 +39,13 @@ import { ConfigInjectingHtmlWebpackPlugin } from './ConfigInjectingHtmlWebpackPl export function resolveBaseUrl( config: Config, - moduleFederation?: ModuleFederationOptions, + moduleFederationRemote?: ModuleFederationRemoteOptions, ): URL { const baseUrl = config.getOptionalString('app.baseUrl'); - const defaultBaseUrl = - moduleFederation?.mode === 'remote' - ? `http://localhost:${process.env.PORT ?? '3000'}` - : 'http://localhost:3000'; + const defaultBaseUrl = moduleFederationRemote + ? `http://localhost:${process.env.PORT ?? '3000'}` + : 'http://localhost:3000'; try { return new URL(baseUrl ?? '/', defaultBaseUrl); @@ -57,12 +56,12 @@ export function resolveBaseUrl( export function resolveEndpoint( config: Config, - moduleFederation?: ModuleFederationOptions, + moduleFederationRemote?: ModuleFederationRemoteOptions, ): { host: string; port: number; } { - const url = resolveBaseUrl(config, moduleFederation); + const url = resolveBaseUrl(config, moduleFederationRemote); return { host: config.getOptionalString('app.listen.host') ?? url.hostname, @@ -117,7 +116,7 @@ export async function createConfig( checksEnabled, isDev, frontendConfig, - moduleFederation, + moduleFederationRemote, publicSubPath = '', webpack, } = options; @@ -126,7 +125,7 @@ export async function createConfig( // Any package that is part of the monorepo but outside the monorepo root dir need // separate resolution logic. - const validBaseUrl = resolveBaseUrl(frontendConfig, moduleFederation); + const validBaseUrl = resolveBaseUrl(frontendConfig, moduleFederationRemote); let publicPath = validBaseUrl.pathname.replace(/\/$/, ''); if (publicSubPath) { publicPath = `${publicPath}${publicSubPath}`.replace('//', '/'); @@ -135,7 +134,7 @@ export async function createConfig( if (isDev) { const { host, port } = resolveEndpoint( options.frontendConfig, - options.moduleFederation, + options.moduleFederationRemote, ); const refreshOptions = { @@ -186,7 +185,7 @@ export async function createConfig( }), ); - if (options.moduleFederation?.mode !== 'remote') { + if (!options.moduleFederationRemote) { const templateOptions = { meta: { 'backstage-app-mode': options?.appMode ?? 'public', @@ -231,20 +230,17 @@ export async function createConfig( ); } - if (options.moduleFederation) { - const isRemote = options.moduleFederation?.mode === 'remote'; - + if (options.moduleFederationRemote) { const AdaptedModuleFederationPlugin = webpack ? (require('@module-federation/enhanced/webpack') .ModuleFederationPlugin as unknown as typeof ModuleFederationPlugin) : ModuleFederationPlugin; - const exposes = options.moduleFederation?.exposes + const exposes = options.moduleFederationRemote.exposes ? Object.fromEntries( - Object.entries(options.moduleFederation?.exposes).map(([k, v]) => [ - k, - resolvePath(paths.targetPath, v), - ]), + Object.entries(options.moduleFederationRemote?.exposes).map( + ([k, v]) => [k, resolvePath(paths.targetPath, v)], + ), ) : { '.': paths.targetEntry, @@ -252,66 +248,28 @@ export async function createConfig( plugins.push( new AdaptedModuleFederationPlugin({ - ...(isRemote && { - filename: 'remoteEntry.js', - exposes, - }), - name: options.moduleFederation.name, + filename: 'remoteEntry.js', + exposes, + name: options.moduleFederationRemote.name, runtime: false, - shared: { - // React - react: { - singleton: true, - requiredVersion: '*', - eager: !isRemote, - ...(isRemote && { import: false }), - }, - 'react-dom': { - singleton: true, - requiredVersion: '*', - eager: !isRemote, - ...(isRemote && { import: false }), - }, - // React Router - 'react-router': { - singleton: true, - requiredVersion: '*', - eager: !isRemote, - ...(isRemote && { import: false }), - }, - 'react-router-dom': { - singleton: true, - requiredVersion: '*', - eager: !isRemote, - ...(isRemote && { import: false }), - }, - // MUI v4 - // not setting import: false for MUI packages as this - // will break once Backstage moves to BUI - '@material-ui/core/styles': { - singleton: true, - requiredVersion: '*', - eager: !isRemote, - }, - '@material-ui/styles': { - singleton: true, - requiredVersion: '*', - eager: !isRemote, - }, - // MUI v5 - // not setting import: false for MUI packages as this - // will break once Backstage moves to BUI - '@mui/material/styles/': { - singleton: true, - requiredVersion: '*', - eager: !isRemote, - }, - '@emotion/react': { - singleton: true, - requiredVersion: '*', - eager: !isRemote, - }, - }, + shared: Object.fromEntries( + Object.entries(options.moduleFederationRemote.sharedDependencies).map( + ([name, p]) => [ + name, + { + ...(p.version === undefined ? {} : { version: p.version }), + ...(p.requiredVersion === undefined + ? {} + : { requiredVersion: p.requiredVersion }), + ...(p.singleton === undefined + ? {} + : { singleton: p.singleton }), + ...(p.import === undefined ? {} : { import: p.import }), + eager: false, + }, + ], + ), + ), }), ); } @@ -426,10 +384,9 @@ export async function createConfig( rules: loaders, }, output: { - uniqueName: options.moduleFederation?.name, + uniqueName: options.moduleFederationRemote?.name, path: paths.targetDist, - publicPath: - options.moduleFederation?.mode === 'remote' ? 'auto' : `${publicPath}/`, + publicPath: options.moduleFederationRemote ? 'auto' : `${publicPath}/`, filename: isDev ? '[name].js' : 'static/[name].[contenthash:8].js', chunkFilename: isDev ? '[name].chunk.js' diff --git a/packages/cli/src/modules/build/lib/bundler/index.ts b/packages/cli/src/modules/build/lib/bundler/index.ts index d8dd6ed0d6..7cb05e3cf0 100644 --- a/packages/cli/src/modules/build/lib/bundler/index.ts +++ b/packages/cli/src/modules/build/lib/bundler/index.ts @@ -15,5 +15,5 @@ */ export { buildBundle } from './bundle'; -export { getModuleFederationOptions } from './moduleFederation'; +export { getModuleFederationRemoteOptions } from './moduleFederation'; export { serveBundle } from './server'; diff --git a/packages/cli/src/modules/build/lib/bundler/moduleFederation.ts b/packages/cli/src/modules/build/lib/bundler/moduleFederation.ts index 0bc606f82a..a92192f50f 100644 --- a/packages/cli/src/modules/build/lib/bundler/moduleFederation.ts +++ b/packages/cli/src/modules/build/lib/bundler/moduleFederation.ts @@ -14,36 +14,34 @@ * limitations under the License. */ -import chalk from 'chalk'; -import { ModuleFederationOptions } from './types'; +import { ModuleFederationRemoteOptions } from './types'; import { BackstagePackageJson } from '@backstage/cli-node'; import { readEntryPoints } from '../../../../lib/entryPoints'; import { createTypeDistProject, getEntryPointDefaultFeatureType, } from '../../../../lib/typeDistProject'; +import { + SharedDependencies, + Host, + prepareRuntimeSharedDependenciesScript, + defaultRemoteSharedDependencies, + defaultHostSharedDependencies, +} from '@backstage/module-federation-common'; +import { dirname, join as joinPath, resolve as resolvePath } from 'path'; +import fs from 'fs-extra'; +import chokidar from 'chokidar'; +import PQueue from 'p-queue'; -export async function getModuleFederationOptions( +// Remote modules management utilities + +export async function getModuleFederationRemoteOptions( packageJson: BackstagePackageJson, packageDir: string, - isModuleFederationRemote?: boolean, -): Promise { - if ( - !isModuleFederationRemote && - !process.env.EXPERIMENTAL_MODULE_FEDERATION - ) { - return undefined; - } - - console.log( - chalk.yellow( - `⚠️ WARNING: Module federation is experimental and will receive immediate breaking changes in the future.`, - ), - ); - - let exposes: ModuleFederationOptions['exposes']; +): Promise { + let exposes: ModuleFederationRemoteOptions['exposes']; const packageRole = packageJson.backstage?.role; - if (isModuleFederationRemote && packageJson.exports && packageRole) { + if (packageJson.exports && packageRole) { const project = await createTypeDistProject(); exposes = Object.fromEntries( readEntryPoints(packageJson) @@ -70,7 +68,6 @@ export async function getModuleFederationOptions( } return { - mode: isModuleFederationRemote ? 'remote' : 'host', // The default output mode requires the name to be a usable as a code // symbol, there might be better options here but for now we need to // sanitize the name. @@ -79,5 +76,98 @@ export async function getModuleFederationOptions( .replaceAll('/', '__') .replaceAll('-', '_'), exposes, + sharedDependencies: defaultRemoteSharedDependencies(), }; } + +// Module federation host management utilities + +const RUNTIME_SHARED_DEPENDENCIES_MODULE_NAME = + '__backstage-module-federation-runtime-shared-dependencies__'; + +// Make sure we're not issuing multiple writes at the same time, which can cause partial overwrites +const writeQueue = new PQueue({ concurrency: 1 }); + +async function writeRuntimeSharedDependenciesModule( + targetPath: string, + runtimeSharedDependencies: SharedDependencies, +) { + const script = prepareRuntimeSharedDependenciesScript( + runtimeSharedDependencies, + ); + + await writeQueue.add(async () => { + const path = joinPath( + targetPath, + 'node_modules', + `${RUNTIME_SHARED_DEPENDENCIES_MODULE_NAME}.js`, + ); + + await fs.ensureDir(dirname(path)); + await fs.writeFile(path, script); + }); +} + +function resolveSharedDependencyVersions( + targetPath: string, + hostSharedDependencies: SharedDependencies, +): SharedDependencies { + return Object.fromEntries( + Object.entries(hostSharedDependencies) + .filter(([_, sharedDep]) => sharedDep !== undefined) + .map(([name, sharedDep]) => { + // Use require.resolve to find the package + // For scoped modules, keep the scope and the module name, but remove any sub-folder + const nameParts = name.split('/'); + const moduleName = + nameParts[0].startsWith('@') && nameParts.length > 1 + ? `${nameParts[0]}/${nameParts[1]}` + : nameParts[0]; + let packagePath: string; + try { + packagePath = require.resolve(`${moduleName}/package.json`, { + paths: [targetPath], + }); + } catch (e) { + throw new Error( + `Failed to resolve package.json for module federation shared dependency '${name}': ${e}`, + ); + } + const packageJson = require(packagePath); + + if (sharedDep.version && packageJson.version !== sharedDep.version) { + throw new Error( + `Version mismatch for module federation shared dependency '${name}': '${sharedDep.version}' vs '${packageJson.version}' found in '${packagePath}'.`, + ); + } + + return [ + name, + { ...sharedDep, version: sharedDep.version ?? packageJson.version }, + ]; + }), + ); +} + +export async function createRuntimeSharedDependeciesEntryPoint(options: { + targetPath: string; + watch?: () => void; +}): Promise { + const { targetPath, watch } = options; + + const doWriteSharedDependenciesModule = async () => { + const sharedDependencies = defaultHostSharedDependencies(); + await writeRuntimeSharedDependenciesModule( + targetPath, + resolveSharedDependencyVersions(targetPath, sharedDependencies), + ); + }; + + if (watch) { + const watcher = chokidar.watch(resolvePath(targetPath, 'package.json')); + watcher.on('change', doWriteSharedDependenciesModule); + } + await doWriteSharedDependenciesModule(); + + return [RUNTIME_SHARED_DEPENDENCIES_MODULE_NAME]; +} diff --git a/packages/cli/src/modules/build/lib/bundler/server.ts b/packages/cli/src/modules/build/lib/bundler/server.ts index 0f287c0713..a7cc0be8c5 100644 --- a/packages/cli/src/modules/build/lib/bundler/server.ts +++ b/packages/cli/src/modules/build/lib/bundler/server.ts @@ -28,6 +28,7 @@ import { createConfig, resolveBaseUrl, resolveEndpoint } from './config'; import { createDetectedModulesEntryPoint } from './packageDetection'; import { resolveBundlingPaths, resolveOptionalBundlingPaths } from './paths'; import { ServeOptions } from './types'; +import { createRuntimeSharedDependeciesEntryPoint } from './moduleFederation'; export async function serveBundle(options: ServeOptions) { const paths = resolveBundlingPaths(options); @@ -108,10 +109,10 @@ DEPRECATION WARNING: React Router Beta is deprecated and support for it will be } const { frontendConfig, fullConfig } = cliConfig; - const url = resolveBaseUrl(frontendConfig, options.moduleFederation); + const url = resolveBaseUrl(frontendConfig, options.moduleFederationRemote); const { host, port } = resolveEndpoint( frontendConfig, - options.moduleFederation, + options.moduleFederationRemote, ); const detectedModulesEntryPoint = await createDetectedModulesEntryPoint({ @@ -122,6 +123,14 @@ DEPRECATION WARNING: React Router Beta is deprecated and support for it will be }, }); + const moduleFederationSharedDependenciesEntryPoint = + await createRuntimeSharedDependeciesEntryPoint({ + targetPath: paths.targetPath, + watch() { + triggerReload(); + }, + }); + const webpack = process.env.LEGACY_WEBPACK_BUILD ? (require('webpack') as typeof import('webpack')) : undefined; @@ -140,8 +149,11 @@ DEPRECATION WARNING: React Router Beta is deprecated and support for it will be const config = await createConfig(paths, { ...commonConfigOptions, - additionalEntryPoints: detectedModulesEntryPoint, - moduleFederation: options.moduleFederation, + additionalEntryPoints: [ + ...detectedModulesEntryPoint, + ...moduleFederationSharedDependenciesEntryPoint, + ], + moduleFederationRemote: options.moduleFederationRemote, }); const bundler = (webpack ?? rspack) as typeof rspack; @@ -181,17 +193,16 @@ DEPRECATION WARNING: React Router Beta is deprecated and support for it will be directory: paths.targetPublic, } : undefined, - historyApiFallback: - options.moduleFederation?.mode === 'remote' - ? false - : { - // Paths with dots should still use the history fallback. - // See https://github.com/facebookincubator/create-react-app/issues/387. - disableDotRule: true, + historyApiFallback: options.moduleFederationRemote + ? false + : { + // Paths with dots should still use the history fallback. + // See https://github.com/facebookincubator/create-react-app/issues/387. + disableDotRule: true, - // The index needs to be rewritten relative to the new public path, including subroutes. - index: `${config.output?.publicPath}index.html`, - }, + // The index needs to be rewritten relative to the new public path, including subroutes. + index: `${config.output?.publicPath}index.html`, + }, server: url.protocol === 'https:' ? { diff --git a/packages/cli/src/modules/build/lib/bundler/types.ts b/packages/cli/src/modules/build/lib/bundler/types.ts index 59b0dcb70d..835b92e180 100644 --- a/packages/cli/src/modules/build/lib/bundler/types.ts +++ b/packages/cli/src/modules/build/lib/bundler/types.ts @@ -17,18 +17,21 @@ import { AppConfig, Config } from '@backstage/config'; import { BundlingPathsOptions } from './paths'; import { ConfigSchema } from '@backstage/config-loader'; +import { + SharedDependencies, + Remote, +} from '@backstage/module-federation-common'; -export type ModuleFederationOptions = { +export type ModuleFederationRemoteOptions = { // Unique name for this module federation bundle name: string; - // Whether this is a host or remote bundle - mode: 'host' | 'remote'; exposes?: { /** * Modules that should be exposed by this container. */ [k: string]: string; }; + sharedDependencies: SharedDependencies; }; export type BundlingOptions = { @@ -44,7 +47,7 @@ export type BundlingOptions = { appMode?: string; // An external linked workspace to include in the bundling linkedWorkspace?: string; - moduleFederation?: ModuleFederationOptions; + moduleFederationRemote?: ModuleFederationRemoteOptions; webpack?: typeof import('webpack'); }; @@ -54,7 +57,7 @@ export type ServeOptions = BundlingPathsOptions & { configPaths: string[]; verifyVersions?: boolean; skipOpenBrowser?: boolean; - moduleFederation?: ModuleFederationOptions; + moduleFederationRemote?: ModuleFederationRemoteOptions; // An external linked workspace to include in the bundling linkedWorkspace?: string; }; @@ -68,7 +71,7 @@ export type BuildOptions = BundlingPathsOptions & { frontendConfig: Config; frontendAppConfigs: AppConfig[]; fullConfig: Config; - moduleFederation?: ModuleFederationOptions; + moduleFederationRemote?: ModuleFederationRemoteOptions; webpack?: typeof import('webpack'); }; diff --git a/packages/frontend-dynamic-feature-loader/package.json b/packages/frontend-dynamic-feature-loader/package.json index a323e57840..f2a807757a 100644 --- a/packages/frontend-dynamic-feature-loader/package.json +++ b/packages/frontend-dynamic-feature-loader/package.json @@ -34,6 +34,7 @@ "dependencies": { "@backstage/config": "workspace:^", "@backstage/frontend-plugin-api": "workspace:^", + "@backstage/module-federation-common": "workspace:^", "@module-federation/enhanced": "^0.21.6", "@module-federation/runtime": "^0.21.6", "@module-federation/sdk": "^0.21.6", diff --git a/packages/frontend-dynamic-feature-loader/report.api.md b/packages/frontend-dynamic-feature-loader/report.api.md index a199d0330d..53934e3de8 100644 --- a/packages/frontend-dynamic-feature-loader/report.api.md +++ b/packages/frontend-dynamic-feature-loader/report.api.md @@ -4,6 +4,7 @@ ```ts import { FrontendFeatureLoader } from '@backstage/frontend-plugin-api'; +import { ModuleFederation } from '@module-federation/enhanced/runtime'; import { ModuleFederationRuntimePlugin } from '@module-federation/enhanced/runtime'; import { ShareStrategy } from '@module-federation/runtime/types'; import { UserOptions } from '@module-federation/runtime/types'; @@ -16,9 +17,12 @@ export function dynamicFrontendFeaturesLoader( // @public (undocumented) export type DynamicFrontendFeaturesLoaderOptions = { moduleFederation: { - shared?: UserOptions['shared']; shareStrategy?: ShareStrategy; - plugins?: Array; + shared?: UserOptions['shared'] | (() => Promise); + plugins?: + | Array + | (() => Promise>); + instance?: ModuleFederation | (() => Promise); }; }; ``` diff --git a/packages/frontend-dynamic-feature-loader/src/loader.test.tsx b/packages/frontend-dynamic-feature-loader/src/loader.test.tsx index c0bf5822cc..c496890361 100644 --- a/packages/frontend-dynamic-feature-loader/src/loader.test.tsx +++ b/packages/frontend-dynamic-feature-loader/src/loader.test.tsx @@ -15,21 +15,48 @@ */ import { mockApis, registerMswTestHooks } from '@backstage/test-utils'; -import { - DynamicFrontendFeaturesLoaderOptions, - dynamicFrontendFeaturesLoader, -} from './loader'; +import { dynamicFrontendFeaturesLoader } from './loader'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; +import { + createInstance, + ModuleFederationRuntimePlugin, +} from '@module-federation/enhanced/runtime'; import { RemoteEntryExports } from '@module-federation/runtime/types'; import { Module } from '@module-federation/sdk'; import { createFrontendPlugin } from '@backstage/frontend-plugin-api'; // eslint-disable-next-line @backstage/no-relative-monorepo-imports import { InternalFrontendFeatureLoader } from '../../frontend-plugin-api/src/wiring/createFrontendFeatureLoader'; import { resetFederationGlobalInfo } from '@module-federation/runtime/core'; +import { Config } from '@backstage/config'; const baseUrl = 'http://localhost:7007'; +function mockDefaultConfig(): Config { + return mockApis.config({ + data: { + app: { + packages: { + include: [], + }, + }, + backend: { + baseUrl, + }, + dynamicPlugins: {}, + }, + }); +} + +const globalSpy = jest.fn(); +Object.defineProperty( + global, + '__backstage-module-federation-shared-dependencies__', + { + get: globalSpy, + }, +); + describe('dynamicFrontendFeaturesLoader', () => { const server = setupServer(); registerMswTestHooks(server); @@ -46,31 +73,27 @@ describe('dynamicFrontendFeaturesLoader', () => { }, }; - const getCommonOptions = (): DynamicFrontendFeaturesLoaderOptions => ({ - moduleFederation: { + const testModuleFederationPlugins: ModuleFederationRuntimePlugin[] = [ + { // We add this module federation plugin to mock the // effective retrieval of the remote content, since it // normally requires a host application built with module federation support, // and won't work by default in Jest tests. - plugins: [ - { - name: 'load-entry-mock', - loadEntry: async args => { - return { - get: (id: string) => async () => { - return await mocks.federation.get({ - name: args.remoteInfo.name, - id, - }); - }, - init: async () => {}, - } as RemoteEntryExports; + name: 'load-entry-mock', + loadEntry: async args => { + return { + get: (id: string) => async () => { + return await mocks.federation.get({ + name: args.remoteInfo.name, + id, + }); }, - onLoad: mocks.federation.onLoad, - }, - ], + init: async () => {}, + } as RemoteEntryExports; + }, + onLoad: mocks.federation.onLoad, }, - }); + ]; const manifestDummyData = { metaData: { @@ -104,9 +127,73 @@ describe('dynamicFrontendFeaturesLoader', () => { mocks.console.debug.mockReset(); mocks.federation.get.mockReset(); mocks.federation.onLoad.mockReset(); + globalSpy.mockReset(); resetFederationGlobalInfo(); }); + const mockedDefaultSharedDependencies = { + react: { + version: '18.3.1', + requiredVersion: '*', + singleton: true, + eager: true, + module: () => ({ default: {} }), + }, + 'react-dom': { + version: '18.3.1', + requiredVersion: '*', + singleton: true, + eager: true, + module: () => ({ default: {} }), + }, + 'react-router': { + version: '6.28.2', + requiredVersion: '*', + singleton: true, + eager: true, + module: () => ({ default: {} }), + }, + 'react-router-dom': { + version: '6.28.2', + requiredVersion: '*', + singleton: true, + eager: true, + module: () => ({ default: {} }), + }, + '@material-ui/core/styles': { + version: '4.12.4', + requiredVersion: '*', + singleton: true, + eager: true, + module: () => ({ default: {} }), + }, + '@material-ui/styles': { + version: '4.11.5', + requiredVersion: '*', + singleton: true, + eager: true, + module: () => ({ default: {} }), + }, + '@mui/material/styles/': { + version: '5.16.14', + requiredVersion: '*', + singleton: true, + eager: true, + module: () => ({ default: {} }), + }, + '@emotion/react': { + version: '11.13.5', + requiredVersion: '*', + singleton: true, + eager: true, + module: () => ({ default: {} }), + }, + }; + + beforeEach(() => { + globalSpy.mockReturnValue(mockedDefaultSharedDependencies); + }); + it('should return immediately if dynamic plugins are not enabled in config', async () => { let manifestsEndpointCalled = false; server.use( @@ -121,7 +208,9 @@ describe('dynamicFrontendFeaturesLoader', () => { const features = await ( dynamicFrontendFeaturesLoader({ - ...getCommonOptions(), + moduleFederation: { + plugins: testModuleFederationPlugins, + }, }) as InternalFrontendFeatureLoader ).loader({ config: mockApis.config({ @@ -196,22 +285,12 @@ describe('dynamicFrontendFeaturesLoader', () => { const features = await ( dynamicFrontendFeaturesLoader({ - ...getCommonOptions(), + moduleFederation: { + plugins: testModuleFederationPlugins, + }, }) as InternalFrontendFeatureLoader ).loader({ - config: mockApis.config({ - data: { - app: { - packages: { - include: [], - }, - }, - backend: { - baseUrl, - }, - dynamicPlugins: {}, - }, - }), + config: mockDefaultConfig(), }); const errorCalls = mocks.console.error.mock.calls.flatMap(e => e[0]); @@ -320,22 +399,12 @@ describe('dynamicFrontendFeaturesLoader', () => { const features = await ( dynamicFrontendFeaturesLoader({ - ...getCommonOptions(), + moduleFederation: { + plugins: testModuleFederationPlugins, + }, }) as InternalFrontendFeatureLoader ).loader({ - config: mockApis.config({ - data: { - app: { - packages: { - include: [], - }, - }, - backend: { - baseUrl, - }, - dynamicPlugins: {}, - }, - }), + config: mockDefaultConfig(), }); const errorCalls = mocks.console.error.mock.calls.flatMap(e => e[0]); @@ -435,22 +504,12 @@ describe('dynamicFrontendFeaturesLoader', () => { const features = await ( dynamicFrontendFeaturesLoader({ - ...getCommonOptions(), + moduleFederation: { + plugins: testModuleFederationPlugins, + }, }) as InternalFrontendFeatureLoader ).loader({ - config: mockApis.config({ - data: { - app: { - packages: { - include: [], - }, - }, - backend: { - baseUrl, - }, - dynamicPlugins: {}, - }, - }), + config: mockDefaultConfig(), }); const errorCalls = mocks.console.error.mock.calls.flatMap(e => e[0]); @@ -526,22 +585,12 @@ describe('dynamicFrontendFeaturesLoader', () => { const features = await ( dynamicFrontendFeaturesLoader({ - ...getCommonOptions(), + moduleFederation: { + plugins: testModuleFederationPlugins, + }, }) as InternalFrontendFeatureLoader ).loader({ - config: mockApis.config({ - data: { - app: { - packages: { - include: [], - }, - }, - backend: { - baseUrl, - }, - dynamicPlugins: {}, - }, - }), + config: mockDefaultConfig(), }); const errorCalls = mocks.console.error.mock.calls.flatMap(e => e[0]); @@ -588,22 +637,12 @@ describe('dynamicFrontendFeaturesLoader', () => { const features = await ( dynamicFrontendFeaturesLoader({ - ...getCommonOptions(), + moduleFederation: { + plugins: testModuleFederationPlugins, + }, }) as InternalFrontendFeatureLoader ).loader({ - config: mockApis.config({ - data: { - app: { - packages: { - include: [], - }, - }, - backend: { - baseUrl, - }, - dynamicPlugins: {}, - }, - }), + config: mockDefaultConfig(), }); const errorCalls = mocks.console.error.mock.calls.flatMap(e => e[0]); @@ -635,22 +674,12 @@ describe('dynamicFrontendFeaturesLoader', () => { const features = await ( dynamicFrontendFeaturesLoader({ - ...getCommonOptions(), + moduleFederation: { + plugins: testModuleFederationPlugins, + }, }) as InternalFrontendFeatureLoader ).loader({ - config: mockApis.config({ - data: { - app: { - packages: { - include: [], - }, - }, - backend: { - baseUrl, - }, - dynamicPlugins: {}, - }, - }), + config: mockDefaultConfig(), }); const errorCalls = mocks.console.error.mock.calls.flatMap(e => e[0]); @@ -739,22 +768,12 @@ describe('dynamicFrontendFeaturesLoader', () => { const features = await ( dynamicFrontendFeaturesLoader({ - ...getCommonOptions(), + moduleFederation: { + plugins: testModuleFederationPlugins, + }, }) as InternalFrontendFeatureLoader ).loader({ - config: mockApis.config({ - data: { - app: { - packages: { - include: [], - }, - }, - backend: { - baseUrl, - }, - dynamicPlugins: {}, - }, - }), + config: mockDefaultConfig(), }); const errorCalls = mocks.console.error.mock.calls.flatMap(e => e[0]); @@ -867,22 +886,12 @@ describe('dynamicFrontendFeaturesLoader', () => { const features = await ( dynamicFrontendFeaturesLoader({ - ...getCommonOptions(), + moduleFederation: { + plugins: testModuleFederationPlugins, + }, }) as InternalFrontendFeatureLoader ).loader({ - config: mockApis.config({ - data: { - app: { - packages: { - include: [], - }, - }, - backend: { - baseUrl, - }, - dynamicPlugins: {}, - }, - }), + config: mockDefaultConfig(), }); const errorCalls = mocks.console.error.mock.calls.flatMap(e => e[0]); @@ -978,30 +987,26 @@ describe('dynamicFrontendFeaturesLoader', () => { const features = await ( dynamicFrontendFeaturesLoader({ - ...getCommonOptions(), + moduleFederation: { + plugins: testModuleFederationPlugins, + }, }) as InternalFrontendFeatureLoader ).loader({ - config: mockApis.config({ - data: { - app: { - packages: { - include: [], - }, - }, - backend: { - baseUrl, - }, - dynamicPlugins: {}, - }, - }), + config: mockDefaultConfig(), }); const errorCalls = mocks.console.error.mock.calls.flatMap(e => e[0]); - expect(errorCalls).toEqual([ - "Failed loading remote module 'plugin_1' of dynamic plugin 'plugin-1': Error: [ Federation Runtime ]: [ Federation Runtime ]: [ Federation Runtime ]: http://localhost:7007/.backstage/dynamic-features/remotes/plugin-1/mf-manifest.json is not a federation manifest", - ]); const warnCalls = mocks.console.warn.mock.calls.flatMap(e => e[0]); - expect(warnCalls).toEqual([]); + + // eslint-disable-next-line no-console + console.log(warnCalls); + // eslint-disable-next-line no-console + console.log(errorCalls); + + expect(warnCalls).toEqual(['[ Federation Runtime ]']); + expect(errorCalls).toEqual([ + "Failed loading remote module 'plugin_1' of dynamic plugin 'plugin-1': Error: [ Federation Runtime ]: http://localhost:7007/.backstage/dynamic-features/remotes/plugin-1/mf-manifest.json is not a federation manifest", + ]); expect(features).toMatchObject([ { $$type: '@backstage/FrontendPlugin', @@ -1086,30 +1091,20 @@ describe('dynamicFrontendFeaturesLoader', () => { const features = await ( dynamicFrontendFeaturesLoader({ - ...getCommonOptions(), + moduleFederation: { + plugins: testModuleFederationPlugins, + }, }) as InternalFrontendFeatureLoader ).loader({ - config: mockApis.config({ - data: { - app: { - packages: { - include: [], - }, - }, - backend: { - baseUrl, - }, - dynamicPlugins: {}, - }, - }), + config: mockDefaultConfig(), }); const errorCalls = mocks.console.error.mock.calls.flatMap(e => e[0]); - expect(errorCalls).toEqual([ - "Failed loading remote module 'plugin_1' of dynamic plugin 'plugin-1': Error: [ Federation Runtime ]: [ Federation Runtime ]: [ Federation Runtime ]: http://localhost:7007/.backstage/dynamic-features/remotes/plugin-1/mf-manifest.json is not a federation manifest", - ]); const warnCalls = mocks.console.warn.mock.calls.flatMap(e => e[0]); - expect(warnCalls).toEqual([]); + expect(warnCalls).toEqual(['[ Federation Runtime ]']); + expect(errorCalls).toEqual([ + "Failed loading remote module 'plugin_1' of dynamic plugin 'plugin-1': Error: [ Federation Runtime ]: http://localhost:7007/.backstage/dynamic-features/remotes/plugin-1/mf-manifest.json is not a federation manifest", + ]); expect(features).toMatchObject([ { $$type: '@backstage/FrontendPlugin', @@ -1133,4 +1128,426 @@ describe('dynamicFrontendFeaturesLoader', () => { }, ]); }); + + it('should initialize module federation with resolved shared dependencies', async () => { + server.use( + rest.get( + `${baseUrl}/.backstage/dynamic-features/remotes`, + (_, res, ctx) => res(ctx.json([])), + ), + ); + + const spyInit = jest.fn(); + await ( + dynamicFrontendFeaturesLoader({ + moduleFederation: { + plugins: [ + { + name: 'spy-init', + init: args => { + spyInit(args); + return args; + }, + }, + ...testModuleFederationPlugins, + ], + }, + }) as InternalFrontendFeatureLoader + ).loader({ + config: mockDefaultConfig(), + }); + + expect(spyInit).toHaveBeenCalledTimes(1); + expect(spyInit.mock.calls[0][0].options).toMatchObject({ + shared: Object.fromEntries( + Object.entries(mockedDefaultSharedDependencies).map( + ([name, shared]) => [ + name, + [ + { + version: shared.version, + shareConfig: { + singleton: shared.singleton, + requiredVersion: shared.requiredVersion, + eager: shared.eager, + }, + strategy: 'version-first', + }, + ], + ], + ), + ), + }); + }); + + it('should initialize module federation with shareStrategy option', async () => { + server.use( + rest.get( + `${baseUrl}/.backstage/dynamic-features/remotes`, + (_, res, ctx) => res(ctx.json([])), + ), + ); + + const spyInit = jest.fn(); + await ( + dynamicFrontendFeaturesLoader({ + moduleFederation: { + shareStrategy: 'loaded-first', + plugins: [ + { + name: 'spy-init', + init: args => { + spyInit(args); + return args; + }, + }, + ...testModuleFederationPlugins, + ], + }, + }) as InternalFrontendFeatureLoader + ).loader({ + config: mockDefaultConfig(), + }); + + const errorCalls = mocks.console.error.mock.calls.flatMap(e => e[0]); + expect(errorCalls).toEqual([]); + const warnCalls = mocks.console.warn.mock.calls.flatMap(e => e[0]); + expect(warnCalls).toEqual([]); + const infoCalls = mocks.console.info.mock.calls.flatMap(e => e[0]); + expect(infoCalls).toEqual([]); + const debugCalls = mocks.console.debug.mock.calls.flatMap(e => e[0]); + expect(debugCalls).toEqual([]); + expect(spyInit).toHaveBeenCalledTimes(1); + expect(spyInit.mock.calls[0][0].options).toMatchObject({ + shareStrategy: 'loaded-first', + shared: { + react: [ + { + version: '18.3.1', + shareConfig: { + singleton: true, + requiredVersion: '*', + }, + strategy: 'loaded-first', + }, + ], + }, + }); + }); + + it('should initialize module federation with shared as function', async () => { + server.use( + rest.get( + `${baseUrl}/.backstage/dynamic-features/remotes`, + (_, res, ctx) => res(ctx.json([])), + ), + ); + + const spyInit = jest.fn(); + await ( + dynamicFrontendFeaturesLoader({ + moduleFederation: { + shared: async () => ({ + react: { + version: '19.0.0', + lib: () => ({ default: {} }), + shareConfig: { + singleton: true, + requiredVersion: '*', + }, + strategy: 'loaded-first', + }, + newDep: { + version: '1.2.3', + lib: () => ({ default: {} }), + shareConfig: { + singleton: true, + requiredVersion: '*', + }, + }, + }), + plugins: [ + { + name: 'spy-init', + init: args => { + spyInit(args); + return args; + }, + }, + ...testModuleFederationPlugins, + ], + }, + }) as InternalFrontendFeatureLoader + ).loader({ + config: mockDefaultConfig(), + }); + + const errorCalls = mocks.console.error.mock.calls.flatMap(e => e[0]); + expect(errorCalls).toEqual([]); + const warnCalls = mocks.console.warn.mock.calls.flatMap(e => e[0]); + expect(warnCalls).toEqual([]); + const infoCalls = mocks.console.info.mock.calls.flatMap(e => e[0]); + expect(infoCalls).toEqual([]); + const debugCalls = mocks.console.debug.mock.calls.flatMap(e => e[0]); + expect(debugCalls).toEqual([]); + expect(spyInit.mock.calls[0][0].options.shared).toMatchObject({ + react: [ + { + version: '18.3.1', + shareConfig: { + singleton: true, + requiredVersion: '*', + }, + strategy: 'version-first', + }, + { + version: '19.0.0', + shareConfig: { + singleton: true, + requiredVersion: '*', + }, + strategy: 'loaded-first', + }, + ], + newDep: [ + { + version: '1.2.3', + shareConfig: { + singleton: true, + requiredVersion: '*', + }, + strategy: 'version-first', + }, + ], + }); + }); + + it('should use a provided module federation instance provided as an async function, and complete it', async () => { + server.use( + rest.get( + `${baseUrl}/.backstage/dynamic-features/remotes`, + (_, res, ctx) => + res( + ctx.json([ + { + packageName: 'plugin-test-dynamic', + exposedModules: ['.'], + remoteInfo: { + name: 'test_plugin', + entry: `${baseUrl}/.backstage/dynamic-features/remotes/plugin-test-dynamic/mf-manifest.json`, + }, + }, + ]), + ), + ), + rest.get( + `${baseUrl}/.backstage/dynamic-features/remotes/plugin-test-dynamic/mf-manifest.json`, + (_, res, ctx) => + res( + ctx.json({ + name: 'test_plugin', + ...manifestDummyData, + exposes: [ + { + id: 'test_plugin:.', + name: '.', + path: '.', + ...manifestExposedRemoteDummyData, + }, + ], + }), + ), + ), + ); + + mocks.federation.get.mockReturnValue({ + default: createFrontendPlugin({ + pluginId: 'test-plugin', + extensions: [], + }), + }); + + const spyInit = jest.fn(); + await ( + dynamicFrontendFeaturesLoader({ + moduleFederation: { + instance: async () => + Promise.resolve( + createInstance({ + name: 'MyExternalInstance', + remotes: [ + { + name: 'myApplicationRemote', + entry: 'myApplicationRemote.js', + }, + ], + }), + ), + shared: async () => ({ + react: { + version: '19.0.0', + lib: () => ({ default: {} }), + shareConfig: { + singleton: true, + requiredVersion: '*', + }, + strategy: 'loaded-first', + }, + newDep: { + version: '1.2.3', + lib: () => ({ default: {} }), + shareConfig: { + singleton: true, + requiredVersion: '*', + }, + }, + }), + plugins: [ + { + name: 'spy-init', + init: args => { + spyInit(args); + return args; + }, + }, + ...testModuleFederationPlugins, + ], + }, + }) as InternalFrontendFeatureLoader + ).loader({ + config: mockDefaultConfig(), + }); + + const errorCalls = mocks.console.error.mock.calls.flatMap(e => e[0]); + expect(errorCalls).toEqual([]); + const warnCalls = mocks.console.warn.mock.calls.flatMap(e => e[0]); + expect(warnCalls).toEqual([]); + const infoCalls = mocks.console.info.mock.calls.flatMap(e => e[0]); + expect(infoCalls).toEqual([ + "Remote module 'test_plugin' of dynamic plugin 'plugin-test-dynamic' loaded from http://localhost:7007/.backstage/dynamic-features/remotes/plugin-test-dynamic/mf-manifest.json", + ]); + const debugCalls = mocks.console.debug.mock.calls.flatMap(e => e[0]); + expect(debugCalls).toEqual([ + "Loading dynamic plugin 'plugin-test-dynamic' from 'http://localhost:7007/.backstage/dynamic-features/remotes/plugin-test-dynamic/mf-manifest.json'", + ]); + expect(mocks.federation.get.mock.calls.flatMap(e => e[0])).toEqual([ + { + id: '.', + name: 'test_plugin', + }, + ]); + expect(spyInit.mock.calls[0][0].options).toMatchObject({ + name: 'MyExternalInstance', + remotes: [ + { + entry: 'http://localhost/myApplicationRemote.js', + name: 'myApplicationRemote', + shareScope: 'default', + type: 'global', + }, + { + alias: 'plugin-test-dynamic', + entry: + 'http://localhost:7007/.backstage/dynamic-features/remotes/plugin-test-dynamic/mf-manifest.json', + name: 'test_plugin', + shareScope: 'default', + type: 'global', + }, + ], + shared: { + react: [ + { + version: '19.0.0', + shareConfig: { + singleton: true, + requiredVersion: '*', + }, + strategy: 'loaded-first', + }, + ], + newDep: [ + { + version: '1.2.3', + shareConfig: { + singleton: true, + requiredVersion: '*', + }, + strategy: 'version-first', + }, + ], + }, + }); + }); + + it('should return an empty list of features if module federation initialization fails', async () => { + server.use( + rest.get( + `${baseUrl}/.backstage/dynamic-features/remotes`, + (_, res, ctx) => + res( + ctx.json([ + { + packageName: 'plugin-test-dynamic', + exposedModules: ['.'], + remoteInfo: { + name: 'test_plugin', + entry: `${baseUrl}/.backstage/dynamic-features/remotes/plugin-test-dynamic/mf-manifest.json`, + }, + }, + ]), + ), + ), + rest.get( + `${baseUrl}/.backstage/dynamic-features/remotes/plugin-test-dynamic/mf-manifest.json`, + (_, res, ctx) => + res( + ctx.json({ + name: 'test_plugin', + ...manifestDummyData, + exposes: [ + { + id: 'test_plugin:.', + name: '.', + path: '.', + ...manifestExposedRemoteDummyData, + }, + ], + }), + ), + ), + ); + + mocks.federation.get.mockReturnValue({ + default: createFrontendPlugin({ + pluginId: 'test-plugin', + extensions: [], + }), + }); + + const features = await ( + dynamicFrontendFeaturesLoader({ + moduleFederation: { + shared: async () => { + throw new Error('An initialization error'); + }, + plugins: testModuleFederationPlugins, + }, + }) as InternalFrontendFeatureLoader + ).loader({ + config: mockDefaultConfig(), + }); + + const errorCalls = mocks.console.error.mock.calls.flatMap(e => e[0]); + expect(errorCalls).toEqual([ + 'Failed initializing module federation: Error: An initialization error', + ]); + const warnCalls = mocks.console.warn.mock.calls.flatMap(e => e[0]); + expect(warnCalls).toEqual([]); + const infoCalls = mocks.console.info.mock.calls.flatMap(e => e[0]); + expect(infoCalls).toEqual([]); + const debugCalls = mocks.console.debug.mock.calls.flatMap(e => e[0]); + expect(debugCalls).toEqual([]); + expect(mocks.federation.get.mock.calls.flatMap(e => e[0])).toEqual([]); + expect(features).toEqual([]); + }); }); diff --git a/packages/frontend-dynamic-feature-loader/src/loader.ts b/packages/frontend-dynamic-feature-loader/src/loader.ts index 8a9597891f..b5f6c65069 100644 --- a/packages/frontend-dynamic-feature-loader/src/loader.ts +++ b/packages/frontend-dynamic-feature-loader/src/loader.ts @@ -16,8 +16,8 @@ import { ModuleFederationRuntimePlugin, - init, - loadRemote, + createInstance, + ModuleFederation, } from '@module-federation/enhanced/runtime'; import { Module } from '@module-federation/sdk'; import { DefaultApiClient, Remote } from './schema/openapi'; @@ -27,6 +27,7 @@ import { createFrontendFeatureLoader, } from '@backstage/frontend-plugin-api'; import { ShareStrategy, UserOptions } from '@module-federation/runtime/types'; +import { buildRuntimeSharedUserOption } from '@backstage/module-federation-common'; /** * @@ -37,9 +38,12 @@ export type DynamicFrontendFeaturesLoaderOptions = { * Additional module federation arguments for the Module Federation runtime initialization. */ moduleFederation: { - shared?: UserOptions['shared']; shareStrategy?: ShareStrategy; - plugins?: Array; + shared?: UserOptions['shared'] | (() => Promise); + plugins?: + | Array + | (() => Promise>); + instance?: ModuleFederation | (() => Promise); }; }; @@ -98,18 +102,62 @@ export function dynamicFrontendFeaturesLoader( return []; } + let instance: ModuleFederation; try { - init({ - ...options?.moduleFederation, - name: appPackageName - .replaceAll('@', '') - .replaceAll('/', '__') - .replaceAll('-', '_'), - remotes: frontendPluginRemotes.map(remote => ({ - alias: remote.packageName, - ...remote.remoteInfo, - })), - }); + if (options?.moduleFederation?.instance) { + if (typeof options.moduleFederation.instance === 'function') { + instance = await options.moduleFederation.instance(); + } else { + instance = options.moduleFederation.instance; + } + } else { + const { shared, errors } = await buildRuntimeSharedUserOption(); + for (const err of errors) { + error(err.message, err.cause); + } + + const createOptions: UserOptions = { + name: appPackageName + .replaceAll('@', '') + .replaceAll('/', '__') + .replaceAll('-', '_'), + shared, + remotes: [], + }; + if (options?.moduleFederation?.shareStrategy) { + createOptions.shareStrategy = + options.moduleFederation.shareStrategy; + } + instance = createInstance(createOptions); + } + + const userOptions: UserOptions = { + name: instance.name, + remotes: [], + }; + + if (options?.moduleFederation?.plugins) { + if (typeof options.moduleFederation.plugins === 'function') { + userOptions.plugins = await options.moduleFederation.plugins(); + } else { + userOptions.plugins = options.moduleFederation.plugins; + } + } + if (options?.moduleFederation?.shareStrategy) { + userOptions.shareStrategy = options.moduleFederation.shareStrategy; + } + if (options?.moduleFederation?.shared) { + if (typeof options.moduleFederation.shared === 'function') { + userOptions.shared = await options.moduleFederation.shared(); + } else { + userOptions.shared = options.moduleFederation.shared; + } + } + userOptions.remotes = frontendPluginRemotes.map(remote => ({ + alias: remote.packageName, + ...remote.remoteInfo, + })); + instance.initOptions(userOptions); } catch (err) { error(`Failed initializing module federation`, err); return []; @@ -131,7 +179,7 @@ export function dynamicFrontendFeaturesLoader( : `${remote.remoteInfo.name}/${exposedModuleName}`; let module: Module; try { - module = await loadRemote(remoteModuleName); + module = await instance.loadRemote(remoteModuleName); } catch (err) { error( `Failed loading remote module '${remoteModuleName}' of dynamic plugin '${remote.packageName}'`, diff --git a/packages/module-federation-common/.eslintrc.js b/packages/module-federation-common/.eslintrc.js new file mode 100644 index 0000000000..e2a53a6ad2 --- /dev/null +++ b/packages/module-federation-common/.eslintrc.js @@ -0,0 +1 @@ +module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); diff --git a/packages/module-federation-common/README.md b/packages/module-federation-common/README.md new file mode 100644 index 0000000000..512c3dc5b0 --- /dev/null +++ b/packages/module-federation-common/README.md @@ -0,0 +1,11 @@ +# @backstage/module-federation-common + +This package provides a helper library for module federation, enabling a consistent management of shared dependencies +in both the module federation host (frontend application) at runtime, and remote modules at build-time through the CLI. + +It provides: + +- TypeScript types for both host and remote shared dependency definitions, +- a default list of shared dependencies (React, React Router, Material-UI, Backstage core packages, etc.) for both the host and remote modules, +- utilities used by the CLI to resolve versions of the shared dependencies for the host at build-time, +- utilities available for the frontend application to provide the list of resolved shared dependencies at runtime. diff --git a/packages/module-federation-common/catalog-info.yaml b/packages/module-federation-common/catalog-info.yaml new file mode 100644 index 0000000000..a5843ad116 --- /dev/null +++ b/packages/module-federation-common/catalog-info.yaml @@ -0,0 +1,10 @@ +apiVersion: backstage.io/v1alpha1 +kind: Component +metadata: + name: backstage-module-federation-common + title: '@backstage/module-federation-common' + description: Helper library for module federation +spec: + lifecycle: experimental + type: backstage-common-library + owner: framework-maintainers diff --git a/packages/module-federation-common/package.json b/packages/module-federation-common/package.json new file mode 100644 index 0000000000..15acc57fbd --- /dev/null +++ b/packages/module-federation-common/package.json @@ -0,0 +1,70 @@ +{ + "name": "@backstage/module-federation-common", + "version": "0.0.0", + "description": "Helper library for module federation", + "backstage": { + "role": "common-library" + }, + "publishConfig": { + "access": "public", + "main": "dist/index.cjs.js", + "module": "dist/index.esm.js", + "types": "dist/index.d.ts" + }, + "keywords": [ + "backstage" + ], + "homepage": "https://backstage.io", + "repository": { + "type": "git", + "url": "https://github.com/backstage/backstage", + "directory": "packages/module-federation-common" + }, + "license": "Apache-2.0", + "sideEffects": false, + "main": "src/index.ts", + "types": "src/index.ts", + "files": [ + "dist" + ], + "scripts": { + "build": "backstage-cli package build", + "clean": "backstage-cli package clean", + "lint": "backstage-cli package lint", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "test": "backstage-cli package test" + }, + "dependencies": { + "@backstage/config": "workspace:^", + "@backstage/errors": "workspace:^", + "@backstage/types": "workspace:^", + "@module-federation/runtime": "^0.21.6", + "serialize-javascript": "^6.0.0" + }, + "devDependencies": { + "@backstage/cli": "workspace:^", + "@backstage/test-utils": "workspace:^", + "@types/react": "^18.0.0", + "@types/serialize-javascript": "^5.0.4", + "react": "^18.0.2", + "react-dom": "^18.0.2", + "react-router-dom": "^6.3.0" + }, + "peerDependencies": { + "@emotion/react": "^11.10.5", + "@material-ui/core": "^4.12.2", + "@material-ui/styles": "^4.10.0", + "@mui/material": "^5.12.2", + "@types/react": "^17.0.0 || ^18.0.0", + "react": "^17.0.0 || ^18.0.0", + "react-dom": "^17.0.0 || ^18.0.0", + "react-router": "^6.3.0", + "react-router-dom": "^6.3.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } +} diff --git a/packages/module-federation-common/report.api.md b/packages/module-federation-common/report.api.md new file mode 100644 index 0000000000..ec0fb25394 --- /dev/null +++ b/packages/module-federation-common/report.api.md @@ -0,0 +1,50 @@ +## API Report File for "@backstage/module-federation-common" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +import { ForwardedError } from '@backstage/errors'; +import type { UserOptions } from '@module-federation/runtime/types'; + +// @public +export function buildRuntimeSharedUserOption(): Promise<{ + shared: UserOptions['shared']; + errors: ForwardedError[]; +}>; + +// @public +export function defaultHostSharedDependencies(): SharedDependencies; + +// @public +export function defaultRemoteSharedDependencies(): SharedDependencies; + +// @public +export type Host = { + eager?: boolean; + requiredVersion: false | string; + version?: string; +}; + +// @public +export function prepareRuntimeSharedDependenciesScript( + hostSharedDependencies: SharedDependencies< + Host & { + version: string; + } + >, +): string; + +// @public +export type Remote = { + import?: false | string; + requiredVersion?: false | string; + version?: false | string; +}; + +// @public +export type SharedDependencies = { + [name: string]: { + singleton?: boolean; + } & ContextFields; +}; +``` diff --git a/packages/module-federation-common/src/defaults.test.ts b/packages/module-federation-common/src/defaults.test.ts new file mode 100644 index 0000000000..cc84c82e09 --- /dev/null +++ b/packages/module-federation-common/src/defaults.test.ts @@ -0,0 +1,44 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + defaultHostSharedDependencies, + defaultRemoteSharedDependencies, +} from './defaults'; + +describe('defaultHostSharedDependencies', () => { + it('should return shared dependencies with the host-only eager property', () => { + const result = defaultHostSharedDependencies(); + + expect(result.react).toEqual({ + requiredVersion: '*', + singleton: true, + eager: true, + }); + }); +}); + +describe('defaultRemoteSharedDependencies', () => { + it('should return shared dependencies with the remote-only import property', () => { + const result = defaultRemoteSharedDependencies(); + + expect(result.react).toEqual({ + requiredVersion: '*', + singleton: true, + import: false, + }); + }); +}); diff --git a/packages/module-federation-common/src/defaults.ts b/packages/module-federation-common/src/defaults.ts new file mode 100644 index 0000000000..8197f5eb98 --- /dev/null +++ b/packages/module-federation-common/src/defaults.ts @@ -0,0 +1,155 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Host, Remote, SharedDependencies } from './types'; + +/** + * The list of default shared dependencies, expected to be the same + * for both the module federation host and remotes. + * + * @internal + */ +const defaultSharedDependencies: SharedDependencies<{ + host: Host; + remote: Remote; +}> = { + // React + react: { + singleton: true, + host: { + eager: true, + requiredVersion: '*', + }, + remote: { + import: false, + requiredVersion: '*', + }, + }, + 'react-dom': { + singleton: true, + host: { + eager: true, + requiredVersion: '*', + }, + remote: { + import: false, + requiredVersion: '*', + }, + }, + // React Router + 'react-router': { + singleton: true, + host: { + eager: true, + requiredVersion: '*', + }, + remote: { + import: false, + requiredVersion: '*', + }, + }, + 'react-router-dom': { + singleton: true, + host: { + eager: true, + requiredVersion: '*', + }, + remote: { + import: false, + requiredVersion: '*', + }, + }, + // MUI v4 + // not setting import: false for MUI packages as this + // will break once Backstage moves to BUI + '@material-ui/core/styles': { + singleton: true, + host: { + eager: true, + requiredVersion: '*', + }, + remote: { + requiredVersion: '*', + }, + }, + '@material-ui/styles': { + singleton: true, + host: { + eager: true, + requiredVersion: '*', + }, + remote: { + requiredVersion: '*', + }, + }, + // MUI v5 + // not setting import: false for MUI packages as this + // will break once Backstage moves to BUI + '@mui/material/styles/': { + singleton: true, + host: { + eager: true, + requiredVersion: '*', + }, + remote: { + requiredVersion: '*', + }, + }, + '@emotion/react': { + singleton: true, + host: { + eager: true, + requiredVersion: '*', + }, + remote: { + requiredVersion: '*', + }, + }, +}; + +/** + * Returns the list of default shared dependencies for the host, with host-only properties. + * + * @public + */ +export function defaultHostSharedDependencies(): SharedDependencies { + return Object.fromEntries( + Object.entries(defaultSharedDependencies).map(([name, p]) => [ + name, + { + singleton: p.singleton, + ...p.host, + }, + ]), + ); +} + +/** + * Returns the list of default shared dependencies for the remote, with remote-only properties. + * + * @public + */ +export function defaultRemoteSharedDependencies(): SharedDependencies { + return Object.fromEntries( + Object.entries(defaultSharedDependencies).map(([name, p]) => [ + name, + { + singleton: p.singleton, + ...p.remote, + }, + ]), + ); +} diff --git a/packages/module-federation-common/src/index.ts b/packages/module-federation-common/src/index.ts new file mode 100644 index 0000000000..cc79a20c6e --- /dev/null +++ b/packages/module-federation-common/src/index.ts @@ -0,0 +1,33 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Helper library for module federation, enabling a consistent management of shared dependencies + * in both the module federation host (frontend application) at runtime, + * and remote modules at build time through the CLI. + * + * @packageDocumentation + */ + +export { + prepareRuntimeSharedDependenciesScript, + buildRuntimeSharedUserOption, +} from './runtime'; +export { + defaultHostSharedDependencies, + defaultRemoteSharedDependencies, +} from './defaults'; +export type { Host, Remote, SharedDependencies } from './types'; diff --git a/packages/module-federation-common/src/runtime.test.ts b/packages/module-federation-common/src/runtime.test.ts new file mode 100644 index 0000000000..fb73b866fa --- /dev/null +++ b/packages/module-federation-common/src/runtime.test.ts @@ -0,0 +1,523 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + prepareRuntimeSharedDependenciesScript, + buildRuntimeSharedUserOption, +} from './runtime'; +import { ForwardedError } from '@backstage/errors'; + +describe('prepareRuntimeSharedDependenciesScript', () => { + it('should generate script with minimal required properties', () => { + const sharedDependencies = { + react: { + version: '18.2.0', + requiredVersion: '*', + }, + }; + + const result = prepareRuntimeSharedDependenciesScript(sharedDependencies); + + expect(result) + .toBe(`window['__backstage-module-federation-shared-dependencies__'] = { + "react": { + "version": "18.2.0", + "requiredVersion": "*", + "module": () => import('react') + } +};`); + }); + + it('should handle multiple shared dependencies', () => { + const sharedDependencies = { + react: { + version: '18.2.0', + requiredVersion: '*', + }, + 'react-dom': { + version: '18.2.0', + requiredVersion: '*', + }, + lodash: { + version: '4.17.21', + requiredVersion: '*', + }, + }; + + const result = prepareRuntimeSharedDependenciesScript(sharedDependencies); + + expect(result) + .toBe(`window['__backstage-module-federation-shared-dependencies__'] = { + "react": { + "version": "18.2.0", + "requiredVersion": "*", + "module": () => import('react') + }, + "react-dom": { + "version": "18.2.0", + "requiredVersion": "*", + "module": () => import('react-dom') + }, + "lodash": { + "version": "4.17.21", + "requiredVersion": "*", + "module": () => import('lodash') + } +};`); + }); + + it('should include requiredVersion when provided', () => { + const sharedDependencies = { + react: { + version: '18.2.0', + requiredVersion: '^18.0.0', + }, + }; + + const result = prepareRuntimeSharedDependenciesScript(sharedDependencies); + + expect(result) + .toBe(`window['__backstage-module-federation-shared-dependencies__'] = { + "react": { + "version": "18.2.0", + "requiredVersion": "^18.0.0", + "module": () => import('react') + } +};`); + }); + + it('should include requiredVersion when set to false', () => { + const sharedDependencies = { + react: { + version: '18.2.0', + requiredVersion: false as const, + }, + }; + + const result = prepareRuntimeSharedDependenciesScript(sharedDependencies); + + expect(result) + .toBe(`window['__backstage-module-federation-shared-dependencies__'] = { + "react": { + "version": "18.2.0", + "requiredVersion": false, + "module": () => import('react') + } +};`); + }); + + it('should include singleton when true', () => { + const sharedDependencies = { + react: { + version: '18.2.0', + requiredVersion: '*', + singleton: true, + }, + }; + + const result = prepareRuntimeSharedDependenciesScript(sharedDependencies); + + expect(result) + .toBe(`window['__backstage-module-federation-shared-dependencies__'] = { + "react": { + "version": "18.2.0", + "requiredVersion": "*", + "singleton": true, + "module": () => import('react') + } +};`); + }); + + it('should include singleton when false', () => { + const sharedDependencies = { + lodash: { + version: '4.17.21', + requiredVersion: '*', + singleton: false, + }, + }; + + const result = prepareRuntimeSharedDependenciesScript(sharedDependencies); + + expect(result) + .toBe(`window['__backstage-module-federation-shared-dependencies__'] = { + "lodash": { + "version": "4.17.21", + "requiredVersion": "*", + "singleton": false, + "module": () => import('lodash') + } +};`); + }); + + it('should include eager when true', () => { + const sharedDependencies = { + react: { + version: '18.2.0', + requiredVersion: '*', + eager: true, + }, + }; + + const result = prepareRuntimeSharedDependenciesScript(sharedDependencies); + + expect(result) + .toBe(`window['__backstage-module-federation-shared-dependencies__'] = { + "react": { + "version": "18.2.0", + "requiredVersion": "*", + "eager": true, + "module": () => import('react') + } +};`); + }); + + it('should include eager when false', () => { + const sharedDependencies = { + lodash: { + version: '4.17.21', + requiredVersion: '*', + eager: false, + }, + }; + + const result = prepareRuntimeSharedDependenciesScript(sharedDependencies); + + expect(result) + .toBe(`window['__backstage-module-federation-shared-dependencies__'] = { + "lodash": { + "version": "4.17.21", + "requiredVersion": "*", + "eager": false, + "module": () => import('lodash') + } +};`); + }); + + it('should handle all properties together', () => { + const sharedDependencies = { + react: { + version: '18.2.0', + requiredVersion: '^18.0.0', + singleton: true, + eager: false, + }, + }; + + const result = prepareRuntimeSharedDependenciesScript(sharedDependencies); + + expect(result) + .toBe(`window['__backstage-module-federation-shared-dependencies__'] = { + "react": { + "version": "18.2.0", + "requiredVersion": "^18.0.0", + "singleton": true, + "eager": false, + "module": () => import('react') + } +};`); + }); + + it('should handle empty object', () => { + const sharedDependencies = {}; + + const result = prepareRuntimeSharedDependenciesScript(sharedDependencies); + + expect(result).toBe( + `window['__backstage-module-federation-shared-dependencies__'] = {};`, + ); + }); + + it('should handle scoped package names and special characters', () => { + const sharedDependencies = { + '@backstage/core-plugin-api': { + version: '1.0.0', + requiredVersion: '*', + }, + }; + + const result = prepareRuntimeSharedDependenciesScript(sharedDependencies); + + expect(result) + .toBe(`window['__backstage-module-federation-shared-dependencies__'] = { + "@backstage/core-plugin-api": { + "version": "1.0.0", + "requiredVersion": "*", + "module": () => import('@backstage/core-plugin-api') + } +};`); + }); +}); + +const globalSpy = jest.fn(); +Object.defineProperty( + global, + '__backstage-module-federation-shared-dependencies__', + { + get: globalSpy, + }, +); + +describe('getRuntimeSharedDependencies', () => { + afterEach(jest.resetAllMocks); + + it('should get runtime shared dependencies with minimal required properties', async () => { + const reactMock = { default: { React: 'react' } }; + const reactDomMock = { default: { ReactDom: 'react-dom' } }; + + globalSpy.mockReturnValue({ + react: { + version: '18.2.0', + requiredVersion: '*', + module: async () => reactMock, + }, + 'react-dom': { + version: '18.2.0', + requiredVersion: '*', + module: async () => reactDomMock, + }, + }); + const result = await buildRuntimeSharedUserOption(); + + expect(result.errors).toEqual([]); + expect(result.shared).toEqual({ + react: { + version: '18.2.0', + lib: expect.any(Function), + shareConfig: { + requiredVersion: '*', + }, + }, + 'react-dom': { + version: '18.2.0', + lib: expect.any(Function), + shareConfig: { + requiredVersion: '*', + }, + }, + }); + + // Test that lib functions return the correct modules + expect((result?.shared?.react as { lib: () => any }).lib()).toBe(reactMock); + expect((result?.shared?.['react-dom'] as { lib: () => any }).lib()).toBe( + reactDomMock, + ); + }); + + it('should get runtime shared dependencies with custom version and requiredVersion', async () => { + globalSpy.mockReturnValue({ + react: { + module: async () => ({ default: {} }), + version: '18.2.0', + requiredVersion: '^18.0.0', + }, + lodash: { + module: async () => ({ default: {} }), + version: '4.17.21', + requiredVersion: '^4.17.0', + }, + }); + const result = await buildRuntimeSharedUserOption(); + + expect(result.errors).toEqual([]); + expect(result.shared).toEqual({ + react: { + version: '18.2.0', + lib: expect.any(Function), + shareConfig: { + requiredVersion: '^18.0.0', + }, + }, + lodash: { + version: '4.17.21', + lib: expect.any(Function), + shareConfig: { + requiredVersion: '^4.17.0', + }, + }, + }); + }); + + it('should handle eager', async () => { + globalSpy.mockReturnValue({ + react: { + version: '18.2.0', + requiredVersion: '*', + eager: false, + module: async () => ({ default: {} }), + }, + lodash: { + version: '4.17.21', + requiredVersion: '*', + eager: true, + module: async () => ({ default: {} }), + }, + }); + const result = await buildRuntimeSharedUserOption(); + + expect(result.errors).toEqual([]); + expect(result.shared).toEqual({ + react: { + version: '18.2.0', + lib: expect.any(Function), + shareConfig: { + requiredVersion: '*', + eager: false, + }, + }, + lodash: { + version: '4.17.21', + lib: expect.any(Function), + shareConfig: { + requiredVersion: '*', + eager: true, + }, + }, + }); + }); + + it('should handle singleton', async () => { + globalSpy.mockReturnValue({ + react: { + module: async () => ({ default: {} }), + version: '18.2.0', + requiredVersion: '*', + singleton: true, + }, + lodash: { + module: async () => ({ default: {} }), + version: '4.17.21', + requiredVersion: '*', + singleton: false, + }, + }); + const result = await buildRuntimeSharedUserOption(); + + expect(result.errors).toEqual([]); + expect(result.shared).toEqual({ + react: { + version: '18.2.0', + lib: expect.any(Function), + shareConfig: { + requiredVersion: '*', + singleton: true, + }, + }, + lodash: { + version: '4.17.21', + lib: expect.any(Function), + shareConfig: { + requiredVersion: '*', + singleton: false, + }, + }, + }); + }); + + it('should handle an empty object', async () => { + globalSpy.mockReturnValue({}); + const result = await buildRuntimeSharedUserOption(); + + expect(result.errors).toEqual([]); + expect(result.shared).toEqual({}); + }); + + it('should handle module import failures and collect errors', async () => { + const mockError = new Error('Module import failed'); + const reactMock = { default: { React: 'react' } }; + const lodashMock = { default: { _: 'lodash' } }; + + globalSpy.mockReturnValue({ + react: { + module: async () => reactMock, + version: '18.2.0', + requiredVersion: '^18.0.0', + }, + 'failing-module': { + module: async () => { + throw mockError; + }, + }, + lodash: { + module: async () => lodashMock, + version: '4.17.21', + requiredVersion: '^4.17.0', + }, + }); + + const result = await buildRuntimeSharedUserOption(); + + expect(result.errors).toHaveLength(1); + expect(result.errors[0]).toBeInstanceOf(ForwardedError); + expect(result.errors[0].message).toContain( + 'Failed to dynamically import "failing-module" and add it to module federation shared dependencies:', + ); + expect(result.errors[0].cause).toBe(mockError); + + // Should still include successful modules + expect(result.shared).toEqual({ + react: { + version: '18.2.0', + lib: expect.any(Function), + shareConfig: { + requiredVersion: '^18.0.0', + }, + }, + lodash: { + version: '4.17.21', + lib: expect.any(Function), + shareConfig: { + requiredVersion: '^4.17.0', + }, + }, + }); + + // Test that lib functions work correctly + expect((result?.shared?.react as { lib: () => any }).lib()).toBe(reactMock); + expect((result?.shared?.lodash as { lib: () => any }).lib()).toBe( + lodashMock, + ); + }); + + it('should handle multiple module import failures', async () => { + const mockError1 = new Error('First module failed'); + const mockError2 = new Error('Second module failed'); + globalSpy.mockReturnValue({ + 'failing-module-1': { + module: async () => { + throw mockError1; + }, + }, + 'failing-module-2': { + module: async () => { + throw mockError2; + }, + }, + }); + + const result = await buildRuntimeSharedUserOption(); + + expect(result.errors).toHaveLength(2); + expect(result.errors[0]).toBeInstanceOf(ForwardedError); + expect(result.errors[0].message).toContain('failing-module-1'); + expect(result.errors[0].cause).toBe(mockError1); + expect(result.errors[1]).toBeInstanceOf(ForwardedError); + expect(result.errors[1].message).toContain('failing-module-2'); + expect(result.errors[1].cause).toBe(mockError2); + + expect(result.shared).toEqual({}); + }); +}); diff --git a/packages/module-federation-common/src/runtime.ts b/packages/module-federation-common/src/runtime.ts new file mode 100644 index 0000000000..1670d8c941 --- /dev/null +++ b/packages/module-federation-common/src/runtime.ts @@ -0,0 +1,112 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Host, Runtime, SharedDependencies } from './types'; +import { default as serialize } from 'serialize-javascript'; +import type { UserOptions } from '@module-federation/runtime/types'; +import { ForwardedError } from '@backstage/errors'; + +const BACKSTAGE_RUNTIME_SHARED_DEPENDENCIES_GLOBAL = + '__backstage-module-federation-shared-dependencies__'; + +/** + * Prepares the runtime shared dependencies script for the module federation host, + * which will be written by the CLI into a Javascript file added as an additional entry point for the frontend bundler. + * This script is used in the browser to build the list of shared dependencies provided to the module federation runtime. + * + * @see {@link buildRuntimeSharedUserOption} + * + * @param hostSharedDependencies - The shared dependencies for the module federation host. + * @returns The runtime shared dependencies script. + * + * @public + */ +export function prepareRuntimeSharedDependenciesScript( + hostSharedDependencies: SharedDependencies, +) { + const runtimeSharedDependencies: SharedDependencies = + Object.fromEntries( + Object.entries(hostSharedDependencies).map(([name, sharedDep]) => [ + name, + { + version: sharedDep.version, + requiredVersion: sharedDep.requiredVersion, + ...(sharedDep.singleton !== undefined + ? { singleton: sharedDep.singleton } + : {}), + ...(sharedDep.eager !== undefined ? { eager: sharedDep.eager } : {}), + // eslint-disable-next-line no-new-func + module: new Function( + `return () => import('${name}')`, + )() as () => Promise, + }, + ]), + ); + + return `window['${BACKSTAGE_RUNTIME_SHARED_DEPENDENCIES_GLOBAL}'] = ${serialize( + runtimeSharedDependencies, + { + space: 2, + unsafe: true, + }, + )};`; +} + +/** + * Builds the list of shared dependencies provided to the module federation runtime. + * It uses the runtime shared dependencies script prepared by {@link prepareRuntimeSharedDependenciesScript}. + * + * @public + */ +export async function buildRuntimeSharedUserOption(): Promise<{ + shared: UserOptions['shared']; + errors: ForwardedError[]; +}> { + const runtimeSharedDependencies = + ( + window as { + [BACKSTAGE_RUNTIME_SHARED_DEPENDENCIES_GLOBAL]?: SharedDependencies< + Host & Runtime + >; + } + )[BACKSTAGE_RUNTIME_SHARED_DEPENDENCIES_GLOBAL] ?? {}; + + const result: UserOptions['shared'] = {}; + const errors: ForwardedError[] = []; + for (const [name, sharedDep] of Object.entries(runtimeSharedDependencies)) { + try { + const module = await sharedDep.module(); + result[name] = { + version: sharedDep.version, + lib: () => module, + shareConfig: { + singleton: sharedDep.singleton, + requiredVersion: sharedDep.requiredVersion, + eager: sharedDep.eager, + }, + }; + } catch (e) { + errors.push( + new ForwardedError( + `Failed to dynamically import "${name}" and add it to module federation shared dependencies:`, + e, + ), + ); + } + } + + return { shared: result, errors }; +} diff --git a/packages/module-federation-common/src/types.ts b/packages/module-federation-common/src/types.ts new file mode 100644 index 0000000000..e8070990df --- /dev/null +++ b/packages/module-federation-common/src/types.ts @@ -0,0 +1,69 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Generic type for shared dependencies configuration in module federation. + * + * The ContextFields type parameter is used to provide additional fields + * to the shared dependencies configuration according to the context. + * + * @public + */ +export type SharedDependencies = { + [name: string]: { + /** Whether this dependency should be a singleton */ + singleton?: boolean; + } & ContextFields; +}; + +/** + * Specific fields for shared dependencies configured in module federation remote modules. + * + * @public + */ +export type Remote = { + /** Provided module for fallback. Set to false to not provide a fallback, or a custom import path. */ + import?: false | string; + /** Required version range. Optional for remotes - can be auto-filled from package.json at build time. */ + requiredVersion?: false | string; + /** Version of the shared dependency. Will be resolved at build time by default but can be overridden, but not completely removed. */ + version?: false | string; +}; + +/** + * Specific fields for shared dependencies configured in the module federation host. + * + * @public + */ +export type Host = { + /** Whether to load this dependency eagerly */ + eager?: boolean; + /** Required version range. Required for host. */ + requiredVersion: false | string; + /** Version of the shared dependency. Will be resolved at build time by default but can be overridden, but not completely removed. */ + version?: string; +}; + +/** + * Specific fields for shared dependencies configured when bootstrapping the module federation host at runtime. + * + * @internal + */ +export type Runtime = { + // version is always expected for runtime host dependencies + version: string; + module: () => Promise; +}; diff --git a/yarn.lock b/yarn.lock index c1924eb08b..7dcfbd2512 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3289,6 +3289,7 @@ __metadata: "@backstage/errors": "workspace:^" "@backstage/eslint-plugin": "workspace:^" "@backstage/integration": "workspace:^" + "@backstage/module-federation-common": "workspace:^" "@backstage/plugin-auth-backend": "workspace:^" "@backstage/plugin-auth-backend-module-guest-provider": "workspace:^" "@backstage/plugin-catalog-node": "workspace:^" @@ -3889,6 +3890,7 @@ __metadata: "@backstage/cli": "workspace:^" "@backstage/config": "workspace:^" "@backstage/frontend-plugin-api": "workspace:^" + "@backstage/module-federation-common": "workspace:^" "@backstage/test-utils": "workspace:^" "@module-federation/enhanced": "npm:^0.21.6" "@module-federation/runtime": "npm:^0.21.6" @@ -4046,6 +4048,38 @@ __metadata: languageName: unknown linkType: soft +"@backstage/module-federation-common@workspace:^, @backstage/module-federation-common@workspace:packages/module-federation-common": + version: 0.0.0-use.local + resolution: "@backstage/module-federation-common@workspace:packages/module-federation-common" + dependencies: + "@backstage/cli": "workspace:^" + "@backstage/config": "workspace:^" + "@backstage/errors": "workspace:^" + "@backstage/test-utils": "workspace:^" + "@backstage/types": "workspace:^" + "@module-federation/runtime": "npm:^0.21.6" + "@types/react": "npm:^18.0.0" + "@types/serialize-javascript": "npm:^5.0.4" + react: "npm:^18.0.2" + react-dom: "npm:^18.0.2" + react-router-dom: "npm:^6.3.0" + serialize-javascript: "npm:^6.0.0" + peerDependencies: + "@emotion/react": ^11.10.5 + "@material-ui/core": ^4.12.2 + "@material-ui/styles": ^4.10.0 + "@mui/material": ^5.12.2 + "@types/react": ^17.0.0 || ^18.0.0 + react: ^17.0.0 || ^18.0.0 + react-dom: ^17.0.0 || ^18.0.0 + react-router: ^6.3.0 + react-router-dom: ^6.3.0 + peerDependenciesMeta: + "@types/react": + optional: true + languageName: unknown + linkType: soft + "@backstage/plugin-api-docs-module-protoc-gen-doc@workspace:plugins/api-docs-module-protoc-gen-doc": version: 0.0.0-use.local resolution: "@backstage/plugin-api-docs-module-protoc-gen-doc@workspace:plugins/api-docs-module-protoc-gen-doc" @@ -22016,6 +22050,13 @@ __metadata: languageName: node linkType: hard +"@types/serialize-javascript@npm:^5.0.4": + version: 5.0.4 + resolution: "@types/serialize-javascript@npm:5.0.4" + checksum: 10/c342a4d151736c1ba4913e6d9b00537bcf62401a06e3489dcf96b7d51a4ab147efcf3fe20ca9491b1349ee7e55c6d69606682e1630f2e076e2828eaee3764f94 + languageName: node + linkType: hard + "@types/serve-handler@npm:^6.1.0": version: 6.1.4 resolution: "@types/serve-handler@npm:6.1.4" @@ -46020,7 +46061,7 @@ __metadata: languageName: node linkType: hard -"serialize-javascript@npm:^6.0.2": +"serialize-javascript@npm:^6.0.0, serialize-javascript@npm:^6.0.2": version: 6.0.2 resolution: "serialize-javascript@npm:6.0.2" dependencies: From 1a656db5301c07f084d869bcdf5f5d1826c1ff92 Mon Sep 17 00:00:00 2001 From: David Festal Date: Wed, 5 Nov 2025 16:52:42 +0100 Subject: [PATCH 03/17] Add CLI --module-federation flag to build frontend plugins as remotes Signed-off-by: David Festal Assisted-by: Cursor --- packages/cli/cli-report.md | 1 + .../modules/build/commands/package/build/command.ts | 12 ++++++++++-- packages/cli/src/modules/build/index.ts | 8 ++++++++ 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/packages/cli/cli-report.md b/packages/cli/cli-report.md index 8979e91a82..0948954ff7 100644 --- a/packages/cli/cli-report.md +++ b/packages/cli/cli-report.md @@ -260,6 +260,7 @@ Usage: program [options] Options: --config --minify + --module-federation --role --skip-build-dependencies --stats diff --git a/packages/cli/src/modules/build/commands/package/build/command.ts b/packages/cli/src/modules/build/commands/package/build/command.ts index 378fd31896..101e91ad42 100644 --- a/packages/cli/src/modules/build/commands/package/build/command.ts +++ b/packages/cli/src/modules/build/commands/package/build/command.ts @@ -55,18 +55,26 @@ export async function command(opts: OptionValues): Promise { }); } - // experimental + let isModuleFederationRemote: boolean | undefined = undefined; if ((role as string) === 'frontend-dynamic-container') { console.log( chalk.yellow( `⚠️ WARNING: The 'frontend-dynamic-container' package role is experimental and will receive immediate breaking changes in the future.`, ), ); + isModuleFederationRemote = true; + } + if (opts.moduleFederation) { + isModuleFederationRemote = true; + } + + if (isModuleFederationRemote) { + console.log('Building package as a module federation remote'); return buildFrontend({ targetDir: paths.targetDir, configPaths: [], writeStats: Boolean(opts.stats), - isModuleFederationRemote: true, + isModuleFederationRemote, webpack, }); } diff --git a/packages/cli/src/modules/build/index.ts b/packages/cli/src/modules/build/index.ts index 5382adfec9..9b37efaa8b 100644 --- a/packages/cli/src/modules/build/index.ts +++ b/packages/cli/src/modules/build/index.ts @@ -42,6 +42,10 @@ export function registerPackageCommands(command: Command) { (opt: string, opts: string[]) => (opts ? [...opts, opt] : [opt]), Array(), ) + .option( + '--module-federation', + 'Build a package as a module federation remote. Applies to frontend plugin packages only.', + ) .action(lazy(() => import('./commands/package/build'), 'command')); } @@ -77,6 +81,10 @@ export const buildPlugin = createCliPlugin({ (opt: string, opts: string[]) => (opts ? [...opts, opt] : [opt]), Array(), ) + .option( + '--module-federation', + 'Build a package as a module federation remote. Applies to frontend plugin packages only.', + ) .action(lazy(() => import('./commands/package/build'), 'command')); await defaultCommand.parseAsync(args, { from: 'user' }); }, From 86bb4321a9e00941a940183607dfdcddc739582c Mon Sep 17 00:00:00 2001 From: David Festal Date: Thu, 6 Nov 2025 15:44:22 +0100 Subject: [PATCH 04/17] Add and update documentation Signed-off-by: David Festal Assisted-by: Cursor --- .../building-apps/07-module-federation.md | 173 ++++++++++++++++++ docs/tooling/cli/02-build-system.md | 6 + docs/tooling/cli/03-commands.md | 1 + microsite/sidebars.ts | 1 + 4 files changed, 181 insertions(+) create mode 100644 docs/frontend-system/building-apps/07-module-federation.md diff --git a/docs/frontend-system/building-apps/07-module-federation.md b/docs/frontend-system/building-apps/07-module-federation.md new file mode 100644 index 0000000000..2a75163790 --- /dev/null +++ b/docs/frontend-system/building-apps/07-module-federation.md @@ -0,0 +1,173 @@ +--- +id: module-federation +title: Module Federation +sidebar_label: Module Federation +description: Using Module Federation in Backstage +--- + +## Introduction + +Module Federation is a feature that enables sharing code and dependencies between separately built JavaScript applications at runtime. In Backstage, module federation support allows you to: + +- Build your frontend application as a **module federation host** that can load remote modules at runtime +- Package individual plugins or bundles of several plugins as **module federation remotes** that can be loaded dynamically +- Share dependencies efficiently between the host and remotes to avoid code duplication + +This guide explains how to configure and build both module federation hosts and remotes in Backstage, and how to initialize module federation at runtime using the standard Module Federation Runtime API. + +## Overview + +### Module Federation Host vs Remotes + +In module federation terminology: + +- **Host**: The main frontend application that loads and consumes remote modules. In Backstage, this is your app package (typically `packages/app-next`). +- **Remote**: A separately built module that can be loaded by the host at runtime. In Backstage, these are typically plugin packages built as module federation remotes. + +### Shared Dependencies + +A critical aspect of module federation is **shared dependencies**. When a host loads remote modules, both need to share common dependencies (like React, React Router, Material-UI) to: + +- Avoid loading the same dependency multiple times +- Ensure singleton dependencies (like React) only have one instance +- Enable context sharing between host and remotes + +Backstage provides a list of default shared dependencies for common packages like React, React Router, and Material-UI. At build-time the `version` field is automatically resolved from your `package.json` files. + +## Building the Module Federation Host + +The module federation host is your main frontend application. By default, Backstage frontend applications include a default list of module federation shared dependencies. + +When building and bundling the frontend application, the CLI automatically: + +1. Resolves versions of the shared dependencies based on the monorepo dependencies +2. Adds an additional entrypoint to the frontend application bundle with the list of resolved runtime shared dependencies + +## Building Module Federation Remotes + +Plugin packages can be built as module federation remotes, allowing them to be loaded dynamically by a host application. + +### Using the CLI + +To build a plugin as a module federation remote, use the `--module-federation` option with the `package build` command: + +```bash +cd plugins/my-plugin +yarn build --module-federation +``` + +### Build Output + +When building a plugin as a module federation remote, the CLI: + +1. Resolves versions of the shared dependencies based on the monorepo dependencies (done automatically by the Rspack/Webpack module federation plugin) +2. Produces the bundle assets in the `dist` folder, including: + - a `mf-manifest.json` file which contains the module federation manifest + - a `remoteEntry.js` file which is the main entrypoint for the remote module + +## Runtime Usage + +To use module federation in your Backstage app, you need to initialize the Module Federation Runtime with the shared dependencies configuration. + +### Basic Usage + +Here's how to initialize module federation in your app, and load remote modules: + +```typescript title="packages/app/src/moduleFederation.ts" +import { + createInstance, + ModuleFederation, +} from '@module-federation/enhanced/runtime'; +import { buildRuntimeSharedUserOption } from '@backstage/module-federation-common'; + +export async function initializeModuleFederation(): Promise { + // Build the shared dependencies configuration + const { shared, errors } = await buildRuntimeSharedUserOption(); + + // Log any errors loading shared dependencies + if (errors.length > 0) { + for (const err of errors) { + console.error(err.message, err.cause); + } + } + + // Initialize Module Federation Runtime + return createInstance({ + name: 'app-next', + remotes: [ + { + name: 'my_plugin', + entry: 'http://localhost:3001/mf-manifest.json', + }, + ], + shared, + }); +} + +export async function loadRemote( + instance: ModuleFederation, + name: string, +): Promise { + return await instance.loadRemote(name); +} +``` + +### Integration with Feature Loaders + +Integration with frontend feature loaders is straightforward: + +```typescript title="packages/app/src/App.tsx" +import { createInstance } from '@module-federation/enhanced/runtime'; +import { buildRuntimeSharedUserOption } from '@backstage/module-federation-common'; +import { createFrontendFeatureLoader } from '@backstage/frontend-plugin-api'; + +const moduleFederationInstance = createInstance({ + name: 'app-next', + remotes: [], +}); + +const moduleFederationLoader = createFrontendFeatureLoader({ + async loader() { + moduleFederationInstance.registerShared( + (await buildRuntimeSharedUserOption()).shared, + ); + moduleFederationInstance.registerRemotes([ + { + name: 'myFirstRemoteWith2ExposedModules', + entry: + 'https://someCDN.org/myFirstRemoteWith2ExposedModules/mf-manifest.json', + }, + { + name: 'mySecondRemote', + entry: 'https://someCDN.org/mySecondRemote/mf-manifest.json', + }, + ]); + const myFirstRemoteModule1 = await moduleFederationInstance.loadRemote( + 'myFirstRemoteWith2Exposes/module1', + ); + const myFirstRemoteModule2 = await moduleFederationInstance.loadRemote( + 'myFirstRemoteWith2Exposes/module2', + ); + const mySecondRemoteModule = await moduleFederationInstance.loadRemote( + 'mySecondRemote', + ); + return [ + myFirstRemoteModule1.default, + myFirstRemoteModule2.default, + mySecondRemoteModule.default, + ]; + }, +}); + +const app = createApp({ + features: [moduleFederationLoader], +}); + +export default app.createRoot(); +``` + +The [`dynamicFrontendFeaturesLoader`](https://github.com/backstage/backstage/blob/master/packages/frontend-dynamic-feature-loader/src/loader.ts) provided in the [`@backstage/frontend-dynamic-feature-loader`](https://github.com/backstage/backstage/blob/master/packages/frontend-dynamic-feature-loader/README.md) package, which provides an integrated solution to load module federation remotes as dynamic frontend plugins, is a more complete example of a feature loader based on the module federation support. + +## Default Shared Dependencies + +Default shared dependencies are the same for both the host and remotes, and the list can be found in the [`@backstage/module-federation-common`](https://github.com/backstage/backstage/blob/master/packages/module-federation-common/src/defaults.ts) package. diff --git a/docs/tooling/cli/02-build-system.md b/docs/tooling/cli/02-build-system.md index c896aa1399..2c7826a149 100644 --- a/docs/tooling/cli/02-build-system.md +++ b/docs/tooling/cli/02-build-system.md @@ -270,6 +270,12 @@ that are exported from the package, leaving a much cleaner type definition file and making sure that the type definitions are in sync with the generated JavaScript. +### Building Module Federation Remotes + +Frontend plugin packages can be built as module federation remotes, which allows them to be loaded dynamically at runtime by a module federation host (typically your main frontend app). To build a package as a module federation remote, use the `--module-federation` option with the `package build` command. + +More details are given in the [Module Federation](../../frontend-system/building-apps/07-module-federation.md#building-module-federation-remotes) documentation. + ## Bundling The goal of the bundling process is to combine multiple packages together into a diff --git a/docs/tooling/cli/03-commands.md b/docs/tooling/cli/03-commands.md index 07f6dee879..b2d84ed09c 100644 --- a/docs/tooling/cli/03-commands.md +++ b/docs/tooling/cli/03-commands.md @@ -200,6 +200,7 @@ Options: --skip-build-dependencies Skip the automatic building of local dependencies. Applies to backend packages only. --stats If bundle stats are available, write them to the output directory. Applies to app packages only. --config Config files to load instead of app-config.yaml. Applies to app packages only. (default: []) + --module-federation Build a package as a module federation remote. Applies to frontend plugin packages only. ``` ## package lint diff --git a/microsite/sidebars.ts b/microsite/sidebars.ts index 5432edd6db..495b6fa469 100644 --- a/microsite/sidebars.ts +++ b/microsite/sidebars.ts @@ -583,6 +583,7 @@ export default { 'frontend-system/building-apps/configuring-extensions', 'frontend-system/building-apps/built-in-extensions', 'frontend-system/building-apps/plugin-conversion', + 'frontend-system/building-apps/module-federation', 'frontend-system/building-apps/migrating', ], ), From ce12decce04a32d59bb84d6ca89d8546abcde250 Mon Sep 17 00:00:00 2001 From: David Festal Date: Tue, 16 Sep 2025 22:04:45 +0200 Subject: [PATCH 05/17] Add changeset Signed-off-by: David Festal --- .changeset/small-ravens-add.md | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 .changeset/small-ravens-add.md diff --git a/.changeset/small-ravens-add.md b/.changeset/small-ravens-add.md new file mode 100644 index 0000000000..bec57e94fe --- /dev/null +++ b/.changeset/small-ravens-add.md @@ -0,0 +1,10 @@ +--- +'@backstage/backend-dynamic-feature-service': patch +'@backstage/frontend-dynamic-feature-loader': patch +'@backstage/module-federation-common': patch +'@backstage/cli': patch +--- + +Enable Module Federation support in the frontend application (Module Federation host) through API only, without using the ModuleFederationPlugin at build time, nor producing specific generated bundled assets. +Module federation remotes still use ModuleFederationPlugin at build time to provide module-federation enabled remote modules, like plugin bundles or dynamic frontend plugins. +Default shared dependencies are provided for both the frontend application (Module Federation host), and Module Federation remotes, maintaining consistency between both sides. From 22c50722685876db3b1f9dd863d2e4998616d773 Mon Sep 17 00:00:00 2001 From: David Festal Date: Mon, 15 Dec 2025 18:01:54 +0100 Subject: [PATCH 06/17] Fix function naming Signed-off-by: David Festal --- packages/cli/src/modules/build/lib/bundler/bundle.ts | 4 ++-- .../cli/src/modules/build/lib/bundler/moduleFederation.ts | 2 +- packages/cli/src/modules/build/lib/bundler/server.ts | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/cli/src/modules/build/lib/bundler/bundle.ts b/packages/cli/src/modules/build/lib/bundler/bundle.ts index 17ee660735..8e500ba808 100644 --- a/packages/cli/src/modules/build/lib/bundler/bundle.ts +++ b/packages/cli/src/modules/build/lib/bundler/bundle.ts @@ -28,7 +28,7 @@ import { BuildOptions } from './types'; import { resolveBundlingPaths, resolveOptionalBundlingPaths } from './paths'; import chalk from 'chalk'; import { createDetectedModulesEntryPoint } from './packageDetection'; -import { createRuntimeSharedDependeciesEntryPoint } from './moduleFederation'; +import { createRuntimeSharedDependenciesEntryPoint } from './moduleFederation'; // TODO(Rugvip): Limits from CRA, we might want to tweak these though. const WARN_AFTER_BUNDLE_GZIP_SIZE = 512 * 1024; @@ -66,7 +66,7 @@ export async function buildBundle(options: BuildOptions) { }); const moduleFederationSharedDependenciesEntryPoint = - await createRuntimeSharedDependeciesEntryPoint({ + await createRuntimeSharedDependenciesEntryPoint({ targetPath: paths.targetPath, }); diff --git a/packages/cli/src/modules/build/lib/bundler/moduleFederation.ts b/packages/cli/src/modules/build/lib/bundler/moduleFederation.ts index a92192f50f..854cad0246 100644 --- a/packages/cli/src/modules/build/lib/bundler/moduleFederation.ts +++ b/packages/cli/src/modules/build/lib/bundler/moduleFederation.ts @@ -149,7 +149,7 @@ function resolveSharedDependencyVersions( ); } -export async function createRuntimeSharedDependeciesEntryPoint(options: { +export async function createRuntimeSharedDependenciesEntryPoint(options: { targetPath: string; watch?: () => void; }): Promise { diff --git a/packages/cli/src/modules/build/lib/bundler/server.ts b/packages/cli/src/modules/build/lib/bundler/server.ts index a7cc0be8c5..b2d480f061 100644 --- a/packages/cli/src/modules/build/lib/bundler/server.ts +++ b/packages/cli/src/modules/build/lib/bundler/server.ts @@ -28,7 +28,7 @@ import { createConfig, resolveBaseUrl, resolveEndpoint } from './config'; import { createDetectedModulesEntryPoint } from './packageDetection'; import { resolveBundlingPaths, resolveOptionalBundlingPaths } from './paths'; import { ServeOptions } from './types'; -import { createRuntimeSharedDependeciesEntryPoint } from './moduleFederation'; +import { createRuntimeSharedDependenciesEntryPoint } from './moduleFederation'; export async function serveBundle(options: ServeOptions) { const paths = resolveBundlingPaths(options); @@ -124,7 +124,7 @@ DEPRECATION WARNING: React Router Beta is deprecated and support for it will be }); const moduleFederationSharedDependenciesEntryPoint = - await createRuntimeSharedDependeciesEntryPoint({ + await createRuntimeSharedDependenciesEntryPoint({ targetPath: paths.targetPath, watch() { triggerReload(); From 5f23e9439783d321bedb14614787e83f782fb9a1 Mon Sep 17 00:00:00 2001 From: David Festal Date: Mon, 15 Dec 2025 18:02:23 +0100 Subject: [PATCH 07/17] Remove function types in module federation options Signed-off-by: David Festal --- .../report.api.md | 8 +- .../src/loader.test.tsx | 262 +----------------- .../src/loader.ts | 26 +- 3 files changed, 19 insertions(+), 277 deletions(-) diff --git a/packages/frontend-dynamic-feature-loader/report.api.md b/packages/frontend-dynamic-feature-loader/report.api.md index 53934e3de8..fb14cb7c57 100644 --- a/packages/frontend-dynamic-feature-loader/report.api.md +++ b/packages/frontend-dynamic-feature-loader/report.api.md @@ -17,12 +17,10 @@ export function dynamicFrontendFeaturesLoader( // @public (undocumented) export type DynamicFrontendFeaturesLoaderOptions = { moduleFederation: { + shared?: UserOptions['shared']; shareStrategy?: ShareStrategy; - shared?: UserOptions['shared'] | (() => Promise); - plugins?: - | Array - | (() => Promise>); - instance?: ModuleFederation | (() => Promise); + plugins?: Array; + instance?: ModuleFederation; }; }; ``` diff --git a/packages/frontend-dynamic-feature-loader/src/loader.test.tsx b/packages/frontend-dynamic-feature-loader/src/loader.test.tsx index c496890361..37a5785f50 100644 --- a/packages/frontend-dynamic-feature-loader/src/loader.test.tsx +++ b/packages/frontend-dynamic-feature-loader/src/loader.test.tsx @@ -18,10 +18,7 @@ import { mockApis, registerMswTestHooks } from '@backstage/test-utils'; import { dynamicFrontendFeaturesLoader } from './loader'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; -import { - createInstance, - ModuleFederationRuntimePlugin, -} from '@module-federation/enhanced/runtime'; +import { ModuleFederationRuntimePlugin } from '@module-federation/enhanced/runtime'; import { RemoteEntryExports } from '@module-federation/runtime/types'; import { Module } from '@module-federation/sdk'; import { createFrontendPlugin } from '@backstage/frontend-plugin-api'; @@ -1235,250 +1232,6 @@ describe('dynamicFrontendFeaturesLoader', () => { }); }); - it('should initialize module federation with shared as function', async () => { - server.use( - rest.get( - `${baseUrl}/.backstage/dynamic-features/remotes`, - (_, res, ctx) => res(ctx.json([])), - ), - ); - - const spyInit = jest.fn(); - await ( - dynamicFrontendFeaturesLoader({ - moduleFederation: { - shared: async () => ({ - react: { - version: '19.0.0', - lib: () => ({ default: {} }), - shareConfig: { - singleton: true, - requiredVersion: '*', - }, - strategy: 'loaded-first', - }, - newDep: { - version: '1.2.3', - lib: () => ({ default: {} }), - shareConfig: { - singleton: true, - requiredVersion: '*', - }, - }, - }), - plugins: [ - { - name: 'spy-init', - init: args => { - spyInit(args); - return args; - }, - }, - ...testModuleFederationPlugins, - ], - }, - }) as InternalFrontendFeatureLoader - ).loader({ - config: mockDefaultConfig(), - }); - - const errorCalls = mocks.console.error.mock.calls.flatMap(e => e[0]); - expect(errorCalls).toEqual([]); - const warnCalls = mocks.console.warn.mock.calls.flatMap(e => e[0]); - expect(warnCalls).toEqual([]); - const infoCalls = mocks.console.info.mock.calls.flatMap(e => e[0]); - expect(infoCalls).toEqual([]); - const debugCalls = mocks.console.debug.mock.calls.flatMap(e => e[0]); - expect(debugCalls).toEqual([]); - expect(spyInit.mock.calls[0][0].options.shared).toMatchObject({ - react: [ - { - version: '18.3.1', - shareConfig: { - singleton: true, - requiredVersion: '*', - }, - strategy: 'version-first', - }, - { - version: '19.0.0', - shareConfig: { - singleton: true, - requiredVersion: '*', - }, - strategy: 'loaded-first', - }, - ], - newDep: [ - { - version: '1.2.3', - shareConfig: { - singleton: true, - requiredVersion: '*', - }, - strategy: 'version-first', - }, - ], - }); - }); - - it('should use a provided module federation instance provided as an async function, and complete it', async () => { - server.use( - rest.get( - `${baseUrl}/.backstage/dynamic-features/remotes`, - (_, res, ctx) => - res( - ctx.json([ - { - packageName: 'plugin-test-dynamic', - exposedModules: ['.'], - remoteInfo: { - name: 'test_plugin', - entry: `${baseUrl}/.backstage/dynamic-features/remotes/plugin-test-dynamic/mf-manifest.json`, - }, - }, - ]), - ), - ), - rest.get( - `${baseUrl}/.backstage/dynamic-features/remotes/plugin-test-dynamic/mf-manifest.json`, - (_, res, ctx) => - res( - ctx.json({ - name: 'test_plugin', - ...manifestDummyData, - exposes: [ - { - id: 'test_plugin:.', - name: '.', - path: '.', - ...manifestExposedRemoteDummyData, - }, - ], - }), - ), - ), - ); - - mocks.federation.get.mockReturnValue({ - default: createFrontendPlugin({ - pluginId: 'test-plugin', - extensions: [], - }), - }); - - const spyInit = jest.fn(); - await ( - dynamicFrontendFeaturesLoader({ - moduleFederation: { - instance: async () => - Promise.resolve( - createInstance({ - name: 'MyExternalInstance', - remotes: [ - { - name: 'myApplicationRemote', - entry: 'myApplicationRemote.js', - }, - ], - }), - ), - shared: async () => ({ - react: { - version: '19.0.0', - lib: () => ({ default: {} }), - shareConfig: { - singleton: true, - requiredVersion: '*', - }, - strategy: 'loaded-first', - }, - newDep: { - version: '1.2.3', - lib: () => ({ default: {} }), - shareConfig: { - singleton: true, - requiredVersion: '*', - }, - }, - }), - plugins: [ - { - name: 'spy-init', - init: args => { - spyInit(args); - return args; - }, - }, - ...testModuleFederationPlugins, - ], - }, - }) as InternalFrontendFeatureLoader - ).loader({ - config: mockDefaultConfig(), - }); - - const errorCalls = mocks.console.error.mock.calls.flatMap(e => e[0]); - expect(errorCalls).toEqual([]); - const warnCalls = mocks.console.warn.mock.calls.flatMap(e => e[0]); - expect(warnCalls).toEqual([]); - const infoCalls = mocks.console.info.mock.calls.flatMap(e => e[0]); - expect(infoCalls).toEqual([ - "Remote module 'test_plugin' of dynamic plugin 'plugin-test-dynamic' loaded from http://localhost:7007/.backstage/dynamic-features/remotes/plugin-test-dynamic/mf-manifest.json", - ]); - const debugCalls = mocks.console.debug.mock.calls.flatMap(e => e[0]); - expect(debugCalls).toEqual([ - "Loading dynamic plugin 'plugin-test-dynamic' from 'http://localhost:7007/.backstage/dynamic-features/remotes/plugin-test-dynamic/mf-manifest.json'", - ]); - expect(mocks.federation.get.mock.calls.flatMap(e => e[0])).toEqual([ - { - id: '.', - name: 'test_plugin', - }, - ]); - expect(spyInit.mock.calls[0][0].options).toMatchObject({ - name: 'MyExternalInstance', - remotes: [ - { - entry: 'http://localhost/myApplicationRemote.js', - name: 'myApplicationRemote', - shareScope: 'default', - type: 'global', - }, - { - alias: 'plugin-test-dynamic', - entry: - 'http://localhost:7007/.backstage/dynamic-features/remotes/plugin-test-dynamic/mf-manifest.json', - name: 'test_plugin', - shareScope: 'default', - type: 'global', - }, - ], - shared: { - react: [ - { - version: '19.0.0', - shareConfig: { - singleton: true, - requiredVersion: '*', - }, - strategy: 'loaded-first', - }, - ], - newDep: [ - { - version: '1.2.3', - shareConfig: { - singleton: true, - requiredVersion: '*', - }, - strategy: 'version-first', - }, - ], - }, - }); - }); - it('should return an empty list of features if module federation initialization fails', async () => { server.use( rest.get( @@ -1527,10 +1280,15 @@ describe('dynamicFrontendFeaturesLoader', () => { const features = await ( dynamicFrontendFeaturesLoader({ moduleFederation: { - shared: async () => { - throw new Error('An initialization error'); - }, - plugins: testModuleFederationPlugins, + plugins: [ + ...testModuleFederationPlugins, + { + name: 'fail-init', + init: () => { + throw new Error('An initialization error'); + }, + }, + ], }, }) as InternalFrontendFeatureLoader ).loader({ diff --git a/packages/frontend-dynamic-feature-loader/src/loader.ts b/packages/frontend-dynamic-feature-loader/src/loader.ts index b5f6c65069..616481ae95 100644 --- a/packages/frontend-dynamic-feature-loader/src/loader.ts +++ b/packages/frontend-dynamic-feature-loader/src/loader.ts @@ -38,12 +38,10 @@ export type DynamicFrontendFeaturesLoaderOptions = { * Additional module federation arguments for the Module Federation runtime initialization. */ moduleFederation: { + shared?: UserOptions['shared']; shareStrategy?: ShareStrategy; - shared?: UserOptions['shared'] | (() => Promise); - plugins?: - | Array - | (() => Promise>); - instance?: ModuleFederation | (() => Promise); + plugins?: Array; + instance?: ModuleFederation; }; }; @@ -105,11 +103,7 @@ export function dynamicFrontendFeaturesLoader( let instance: ModuleFederation; try { if (options?.moduleFederation?.instance) { - if (typeof options.moduleFederation.instance === 'function') { - instance = await options.moduleFederation.instance(); - } else { - instance = options.moduleFederation.instance; - } + instance = options.moduleFederation.instance; } else { const { shared, errors } = await buildRuntimeSharedUserOption(); for (const err of errors) { @@ -137,21 +131,13 @@ export function dynamicFrontendFeaturesLoader( }; if (options?.moduleFederation?.plugins) { - if (typeof options.moduleFederation.plugins === 'function') { - userOptions.plugins = await options.moduleFederation.plugins(); - } else { - userOptions.plugins = options.moduleFederation.plugins; - } + userOptions.plugins = options.moduleFederation.plugins; } if (options?.moduleFederation?.shareStrategy) { userOptions.shareStrategy = options.moduleFederation.shareStrategy; } if (options?.moduleFederation?.shared) { - if (typeof options.moduleFederation.shared === 'function') { - userOptions.shared = await options.moduleFederation.shared(); - } else { - userOptions.shared = options.moduleFederation.shared; - } + userOptions.shared = options.moduleFederation.shared; } userOptions.remotes = frontendPluginRemotes.map(remote => ({ alias: remote.packageName, From 1f5dc0b787db8d94f64991db39784a2f0ebab89a Mon Sep 17 00:00:00 2001 From: David Festal Date: Mon, 15 Dec 2025 18:26:14 +0100 Subject: [PATCH 08/17] Replace `serialize-javascript` by `JSON.serialize` Signed-off-by: David Festal --- .../module-federation-common/package.json | 4 +--- .../module-federation-common/src/runtime.ts | 20 +++++++++---------- yarn.lock | 11 +--------- 3 files changed, 11 insertions(+), 24 deletions(-) diff --git a/packages/module-federation-common/package.json b/packages/module-federation-common/package.json index 15acc57fbd..31a03b686f 100644 --- a/packages/module-federation-common/package.json +++ b/packages/module-federation-common/package.json @@ -39,14 +39,12 @@ "@backstage/config": "workspace:^", "@backstage/errors": "workspace:^", "@backstage/types": "workspace:^", - "@module-federation/runtime": "^0.21.6", - "serialize-javascript": "^6.0.0" + "@module-federation/runtime": "^0.21.6" }, "devDependencies": { "@backstage/cli": "workspace:^", "@backstage/test-utils": "workspace:^", "@types/react": "^18.0.0", - "@types/serialize-javascript": "^5.0.4", "react": "^18.0.2", "react-dom": "^18.0.2", "react-router-dom": "^6.3.0" diff --git a/packages/module-federation-common/src/runtime.ts b/packages/module-federation-common/src/runtime.ts index 1670d8c941..dada9dcf46 100644 --- a/packages/module-federation-common/src/runtime.ts +++ b/packages/module-federation-common/src/runtime.ts @@ -15,7 +15,6 @@ */ import { Host, Runtime, SharedDependencies } from './types'; -import { default as serialize } from 'serialize-javascript'; import type { UserOptions } from '@module-federation/runtime/types'; import { ForwardedError } from '@backstage/errors'; @@ -37,7 +36,8 @@ const BACKSTAGE_RUNTIME_SHARED_DEPENDENCIES_GLOBAL = export function prepareRuntimeSharedDependenciesScript( hostSharedDependencies: SharedDependencies, ) { - const runtimeSharedDependencies: SharedDependencies = + type StringModule = Omit & { module: string }; + const runtimeSharedDependencies: SharedDependencies = Object.fromEntries( Object.entries(hostSharedDependencies).map(([name, sharedDep]) => [ name, @@ -48,20 +48,18 @@ export function prepareRuntimeSharedDependenciesScript( ? { singleton: sharedDep.singleton } : {}), ...(sharedDep.eager !== undefined ? { eager: sharedDep.eager } : {}), - // eslint-disable-next-line no-new-func - module: new Function( - `return () => import('${name}')`, - )() as () => Promise, + module: `() => import('${name}')`, }, ]), ); - return `window['${BACKSTAGE_RUNTIME_SHARED_DEPENDENCIES_GLOBAL}'] = ${serialize( + return `window['${BACKSTAGE_RUNTIME_SHARED_DEPENDENCIES_GLOBAL}'] = ${JSON.stringify( runtimeSharedDependencies, - { - space: 2, - unsafe: true, - }, + null, + 2, + ).replace( + /(^\s+"module":\s*)"([^"]+)"$/gm, + (_, start, unquoted) => `${start}${unquoted}`, )};`; } diff --git a/yarn.lock b/yarn.lock index 7dcfbd2512..8135ad7473 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4059,11 +4059,9 @@ __metadata: "@backstage/types": "workspace:^" "@module-federation/runtime": "npm:^0.21.6" "@types/react": "npm:^18.0.0" - "@types/serialize-javascript": "npm:^5.0.4" react: "npm:^18.0.2" react-dom: "npm:^18.0.2" react-router-dom: "npm:^6.3.0" - serialize-javascript: "npm:^6.0.0" peerDependencies: "@emotion/react": ^11.10.5 "@material-ui/core": ^4.12.2 @@ -22050,13 +22048,6 @@ __metadata: languageName: node linkType: hard -"@types/serialize-javascript@npm:^5.0.4": - version: 5.0.4 - resolution: "@types/serialize-javascript@npm:5.0.4" - checksum: 10/c342a4d151736c1ba4913e6d9b00537bcf62401a06e3489dcf96b7d51a4ab147efcf3fe20ca9491b1349ee7e55c6d69606682e1630f2e076e2828eaee3764f94 - languageName: node - linkType: hard - "@types/serve-handler@npm:^6.1.0": version: 6.1.4 resolution: "@types/serve-handler@npm:6.1.4" @@ -46061,7 +46052,7 @@ __metadata: languageName: node linkType: hard -"serialize-javascript@npm:^6.0.0, serialize-javascript@npm:^6.0.2": +"serialize-javascript@npm:^6.0.2": version: 6.0.2 resolution: "serialize-javascript@npm:6.0.2" dependencies: From 95693a951b0a18d8941345a32543d8b6f76c8e60 Mon Sep 17 00:00:00 2001 From: David Festal Date: Mon, 15 Dec 2025 19:08:16 +0100 Subject: [PATCH 09/17] Complete docs Signed-off-by: David Festal --- docs/frontend-system/building-apps/07-module-federation.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/frontend-system/building-apps/07-module-federation.md b/docs/frontend-system/building-apps/07-module-federation.md index 2a75163790..8b11e6c245 100644 --- a/docs/frontend-system/building-apps/07-module-federation.md +++ b/docs/frontend-system/building-apps/07-module-federation.md @@ -114,7 +114,8 @@ export async function loadRemote( ### Integration with Feature Loaders -Integration with frontend feature loaders is straightforward: +Standard Module Federation runtime API integrates very well with frontend feature loaders, +as shown in the example below: ```typescript title="packages/app/src/App.tsx" import { createInstance } from '@module-federation/enhanced/runtime'; @@ -166,7 +167,9 @@ const app = createApp({ export default app.createRoot(); ``` -The [`dynamicFrontendFeaturesLoader`](https://github.com/backstage/backstage/blob/master/packages/frontend-dynamic-feature-loader/src/loader.ts) provided in the [`@backstage/frontend-dynamic-feature-loader`](https://github.com/backstage/backstage/blob/master/packages/frontend-dynamic-feature-loader/README.md) package, which provides an integrated solution to load module federation remotes as dynamic frontend plugins, is a more complete example of a feature loader based on the module federation support. +Note that, on top of the standard API, we plan to provide a more simplified way to configure module federation remotes. + +Additionally, the [`dynamicFrontendFeaturesLoader`](https://github.com/backstage/backstage/blob/master/packages/frontend-dynamic-feature-loader/src/loader.ts) provided in the [`@backstage/frontend-dynamic-feature-loader`](https://github.com/backstage/backstage/blob/master/packages/frontend-dynamic-feature-loader/README.md) package, which provides an integrated solution to load module federation remotes as dynamic frontend plugins, is a more complete example of a feature loader based on the module federation support. ## Default Shared Dependencies From 595b9e49baf438260b0f6dcc77dc4132cf099eb0 Mon Sep 17 00:00:00 2001 From: David Festal Date: Fri, 23 Jan 2026 15:48:45 +0100 Subject: [PATCH 10/17] Remove debugging output in `loader.test.tsx` Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Signed-off-by: David Festal --- packages/frontend-dynamic-feature-loader/src/loader.test.tsx | 5 ----- 1 file changed, 5 deletions(-) diff --git a/packages/frontend-dynamic-feature-loader/src/loader.test.tsx b/packages/frontend-dynamic-feature-loader/src/loader.test.tsx index 37a5785f50..b24aea0fdd 100644 --- a/packages/frontend-dynamic-feature-loader/src/loader.test.tsx +++ b/packages/frontend-dynamic-feature-loader/src/loader.test.tsx @@ -995,11 +995,6 @@ describe('dynamicFrontendFeaturesLoader', () => { const errorCalls = mocks.console.error.mock.calls.flatMap(e => e[0]); const warnCalls = mocks.console.warn.mock.calls.flatMap(e => e[0]); - // eslint-disable-next-line no-console - console.log(warnCalls); - // eslint-disable-next-line no-console - console.log(errorCalls); - expect(warnCalls).toEqual(['[ Federation Runtime ]']); expect(errorCalls).toEqual([ "Failed loading remote module 'plugin_1' of dynamic plugin 'plugin-1': Error: [ Federation Runtime ]: http://localhost:7007/.backstage/dynamic-features/remotes/plugin-1/mf-manifest.json is not a federation manifest", From cf09e3ad42c79efe0bb8d2bdcb09e9fac6f816d8 Mon Sep 17 00:00:00 2001 From: David Festal Date: Fri, 23 Jan 2026 15:49:45 +0100 Subject: [PATCH 11/17] Fix review comment on `README.md` Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Signed-off-by: David Festal --- packages/module-federation-common/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/module-federation-common/README.md b/packages/module-federation-common/README.md index 512c3dc5b0..fcf1f5726c 100644 --- a/packages/module-federation-common/README.md +++ b/packages/module-federation-common/README.md @@ -6,6 +6,6 @@ in both the module federation host (frontend application) at runtime, and remote It provides: - TypeScript types for both host and remote shared dependency definitions, -- a default list of shared dependencies (React, React Router, Material-UI, Backstage core packages, etc.) for both the host and remote modules, +- a default list of shared dependencies (React, React Router, Material-UI, etc.) for both the host and remote modules, - utilities used by the CLI to resolve versions of the shared dependencies for the host at build-time, - utilities available for the frontend application to provide the list of resolved shared dependencies at runtime. From 00638e4145b223a10b228043e2fe57d86f22fc12 Mon Sep 17 00:00:00 2001 From: David Festal Date: Fri, 23 Jan 2026 15:53:26 +0100 Subject: [PATCH 12/17] Fix review comment on `07-module-federation.md` Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Signed-off-by: David Festal --- docs/frontend-system/building-apps/07-module-federation.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/frontend-system/building-apps/07-module-federation.md b/docs/frontend-system/building-apps/07-module-federation.md index 8b11e6c245..bb88275a91 100644 --- a/docs/frontend-system/building-apps/07-module-federation.md +++ b/docs/frontend-system/building-apps/07-module-federation.md @@ -144,10 +144,10 @@ const moduleFederationLoader = createFrontendFeatureLoader({ }, ]); const myFirstRemoteModule1 = await moduleFederationInstance.loadRemote( - 'myFirstRemoteWith2Exposes/module1', + 'myFirstRemoteWith2ExposedModules/module1', ); const myFirstRemoteModule2 = await moduleFederationInstance.loadRemote( - 'myFirstRemoteWith2Exposes/module2', + 'myFirstRemoteWith2ExposedModules/module2', ); const mySecondRemoteModule = await moduleFederationInstance.loadRemote( 'mySecondRemote', From 3fdda3384e458b1919bab51039335e2fd3afdbad Mon Sep 17 00:00:00 2001 From: David Festal Date: Tue, 27 Jan 2026 14:44:54 +0100 Subject: [PATCH 13/17] Apply review comment suggestion Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Signed-off-by: David Festal --- .../cli/src/modules/build/lib/bundler/moduleFederation.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/cli/src/modules/build/lib/bundler/moduleFederation.ts b/packages/cli/src/modules/build/lib/bundler/moduleFederation.ts index 854cad0246..becf438c34 100644 --- a/packages/cli/src/modules/build/lib/bundler/moduleFederation.ts +++ b/packages/cli/src/modules/build/lib/bundler/moduleFederation.ts @@ -165,7 +165,10 @@ export async function createRuntimeSharedDependenciesEntryPoint(options: { if (watch) { const watcher = chokidar.watch(resolvePath(targetPath, 'package.json')); - watcher.on('change', doWriteSharedDependenciesModule); + watcher.on('change', async () => { + await doWriteSharedDependenciesModule(); + watch(); + }); } await doWriteSharedDependenciesModule(); From 94e05532be9446410776e9a75c991ddfb93231b9 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Thu, 12 Feb 2026 23:20:05 +0100 Subject: [PATCH 14/17] Apply suggestions from code review Signed-off-by: Patrik Oldsberg --- .../frontend-system/building-apps/07-module-federation.md | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/docs/frontend-system/building-apps/07-module-federation.md b/docs/frontend-system/building-apps/07-module-federation.md index bb88275a91..81d2dde7d6 100644 --- a/docs/frontend-system/building-apps/07-module-federation.md +++ b/docs/frontend-system/building-apps/07-module-federation.md @@ -21,16 +21,12 @@ This guide explains how to configure and build both module federation hosts and In module federation terminology: -- **Host**: The main frontend application that loads and consumes remote modules. In Backstage, this is your app package (typically `packages/app-next`). +- **Host**: The main frontend application that loads and consumes remote modules. In Backstage, this is your app package (typically `packages/app`). - **Remote**: A separately built module that can be loaded by the host at runtime. In Backstage, these are typically plugin packages built as module federation remotes. ### Shared Dependencies -A critical aspect of module federation is **shared dependencies**. When a host loads remote modules, both need to share common dependencies (like React, React Router, Material-UI) to: - -- Avoid loading the same dependency multiple times -- Ensure singleton dependencies (like React) only have one instance -- Enable context sharing between host and remotes +A critical aspect of module federation is **shared dependencies**. When a host loads remote modules, both need to share common dependencies (like React, React Router, Material-UI) in order to ensure singleton dependencies only have one instance. Backstage provides a list of default shared dependencies for common packages like React, React Router, and Material-UI. At build-time the `version` field is automatically resolved from your `package.json` files. From 94f2884a0cfc2f5112c7f4ef74cf780883bb012c Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Thu, 12 Feb 2026 23:37:18 +0100 Subject: [PATCH 15/17] yarn.lock: resolve conflict Signed-off-by: Patrik Oldsberg --- yarn.lock | 1260 +++++++++++++++++++++++++++-------------------------- 1 file changed, 633 insertions(+), 627 deletions(-) diff --git a/yarn.lock b/yarn.lock index 8135ad7473..1531d505eb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -765,7 +765,7 @@ __metadata: languageName: node linkType: hard -"@aws-sdk/client-sesv2@npm:^3.839.0, @aws-sdk/client-sesv2@npm:^3.911.0": +"@aws-sdk/client-sesv2@npm:^3.911.0": version: 3.946.0 resolution: "@aws-sdk/client-sesv2@npm:3.946.0" dependencies: @@ -8459,14 +8459,14 @@ __metadata: linkType: hard "@codemirror/view@npm:^6.0.0, @codemirror/view@npm:^6.23.0": - version: 6.39.11 - resolution: "@codemirror/view@npm:6.39.11" + version: 6.39.12 + resolution: "@codemirror/view@npm:6.39.12" dependencies: "@codemirror/state": "npm:^6.5.0" crelt: "npm:^1.0.6" style-mod: "npm:^4.1.0" w3c-keyname: "npm:^2.2.4" - checksum: 10/691825e783a1ac720411f59fface596fe1ba0fbf0344ed61af84937c7dd4337298b1a91fbff93cee076dc1b1c5c6f7bd73b8660fa417fb484f157946ecac9986 + checksum: 10/acd476d485914095fe38009bb29c7a6ac4cf3de2d3921172e27fc40639eb5bce0534766fd6e093c94aa60f076f263ce90a670a8052e220244bf4065f95c064bb languageName: node linkType: hard @@ -9045,7 +9045,7 @@ __metadata: languageName: node linkType: hard -"@eslint-community/eslint-utils@npm:^4.2.0, @eslint-community/eslint-utils@npm:^4.4.0, @eslint-community/eslint-utils@npm:^4.7.0, @eslint-community/eslint-utils@npm:^4.9.1": +"@eslint-community/eslint-utils@npm:^4.2.0, @eslint-community/eslint-utils@npm:^4.4.0, @eslint-community/eslint-utils@npm:^4.9.1": version: 4.9.1 resolution: "@eslint-community/eslint-utils@npm:4.9.1" dependencies: @@ -9056,10 +9056,10 @@ __metadata: languageName: node linkType: hard -"@eslint-community/regexpp@npm:^4.10.0, @eslint-community/regexpp@npm:^4.6.1": - version: 4.12.1 - resolution: "@eslint-community/regexpp@npm:4.12.1" - checksum: 10/c08f1dd7dd18fbb60bdd0d85820656d1374dd898af9be7f82cb00451313402a22d5e30569c150315b4385907cdbca78c22389b2a72ab78883b3173be317620cc +"@eslint-community/regexpp@npm:^4.12.2, @eslint-community/regexpp@npm:^4.6.1": + version: 4.12.2 + resolution: "@eslint-community/regexpp@npm:4.12.2" + checksum: 10/049b280fddf71dd325514e0a520024969431dc3a8b02fa77476e6820e9122f28ab4c9168c11821f91a27982d2453bcd7a66193356ea84e84fb7c8d793be1ba0c languageName: node linkType: hard @@ -9087,15 +9087,15 @@ __metadata: languageName: node linkType: hard -"@exodus/bytes@npm:^1.6.0": - version: 1.8.0 - resolution: "@exodus/bytes@npm:1.8.0" +"@exodus/bytes@npm:^1.11.0, @exodus/bytes@npm:^1.6.0": + version: 1.11.0 + resolution: "@exodus/bytes@npm:1.11.0" peerDependencies: - "@exodus/crypto": ^1.0.0-rc.4 + "@noble/hashes": ^1.8.0 || ^2.0.0 peerDependenciesMeta: - "@exodus/crypto": + "@noble/hashes": optional: true - checksum: 10/aed2f77fbdfbadfc686ee66be68c192dd9138677daa65d368b8aaee006432518fec1098b4319073692d9cce52c50e0269b700801c1cb13a694f8dd04a2e1c5ec + checksum: 10/a8c815fc15a6f16e05ae2da11b210c3bec7d75c7595478c4b8bb8f3a7bc7fde4b44dc9f160b15c9d7a5b064abd6f38731d7817c132c9da60a4164038601ff54f languageName: node linkType: hard @@ -9383,8 +9383,8 @@ __metadata: linkType: hard "@google-cloud/storage@npm:^7.0.0": - version: 7.18.0 - resolution: "@google-cloud/storage@npm:7.18.0" + version: 7.19.0 + resolution: "@google-cloud/storage@npm:7.19.0" dependencies: "@google-cloud/paginator": "npm:^5.0.0" "@google-cloud/projectify": "npm:^4.0.0" @@ -9392,7 +9392,7 @@ __metadata: abort-controller: "npm:^3.0.0" async-retry: "npm:^1.3.3" duplexify: "npm:^4.1.3" - fast-xml-parser: "npm:^4.4.1" + fast-xml-parser: "npm:^5.3.4" gaxios: "npm:^6.0.2" google-auth-library: "npm:^9.6.3" html-entities: "npm:^2.5.2" @@ -9401,7 +9401,7 @@ __metadata: retry-request: "npm:^7.0.0" teeny-request: "npm:^9.0.0" uuid: "npm:^8.0.0" - checksum: 10/29ca208cf88770dd60ac7868ec69bffa43e3cba03cbb49dd7064593f777e66181a8cba6f1993f36193f009be07bc02129d0ecac9f9f09f8a8b6a8d90a9e5ba86 + checksum: 10/6fa0621ff702f3e8e8e4edd25c1f7582b5f2a0b44866ad0b94cd3f074ff58b9164d1c470222bf9c29fcf54c27fabb4ff6706ee073a706c6a67673a8e19b17c30 languageName: node linkType: hard @@ -11230,8 +11230,8 @@ __metadata: linkType: hard "@modelcontextprotocol/sdk@npm:^1.25.2": - version: 1.25.3 - resolution: "@modelcontextprotocol/sdk@npm:1.25.3" + version: 1.26.0 + resolution: "@modelcontextprotocol/sdk@npm:1.26.0" dependencies: "@hono/node-server": "npm:^1.19.9" ajv: "npm:^8.17.1" @@ -11241,14 +11241,15 @@ __metadata: cross-spawn: "npm:^7.0.5" eventsource: "npm:^3.0.2" eventsource-parser: "npm:^3.0.0" - express: "npm:^5.0.1" - express-rate-limit: "npm:^7.5.0" - jose: "npm:^6.1.1" + express: "npm:^5.2.1" + express-rate-limit: "npm:^8.2.1" + hono: "npm:^4.11.4" + jose: "npm:^6.1.3" json-schema-typed: "npm:^8.0.2" pkce-challenge: "npm:^5.0.0" raw-body: "npm:^3.0.0" zod: "npm:^3.25 || ^4.0" - zod-to-json-schema: "npm:^3.25.0" + zod-to-json-schema: "npm:^3.25.1" peerDependencies: "@cfworker/json-schema": ^4.1.1 zod: ^3.25 || ^4.0 @@ -11257,7 +11258,7 @@ __metadata: optional: true zod: optional: false - checksum: 10/e4e38845ecfeaee124860ac2dfe378d2a4e8a09bd085b77124c9047b944826cff1776f97c11eaa56b0d83e164518a064f19c0be3046fa4307ba05dbe2ec325a1 + checksum: 10/a206b2a4d61a23be8b8f4c886528dd9348d11b17ce36013b350edf5c082b1c1f07941d52ea098f721daf3828085b6f6276bb844c484a0e9913edbc028517a3d5 languageName: node linkType: hard @@ -13051,7 +13052,7 @@ __metadata: languageName: node linkType: hard -"@opentelemetry/core@npm:2.2.0, @opentelemetry/core@npm:^2.0.0": +"@opentelemetry/core@npm:2.2.0": version: 2.2.0 resolution: "@opentelemetry/core@npm:2.2.0" dependencies: @@ -13062,6 +13063,17 @@ __metadata: languageName: node linkType: hard +"@opentelemetry/core@npm:2.5.0, @opentelemetry/core@npm:^2.0.0": + version: 2.5.0 + resolution: "@opentelemetry/core@npm:2.5.0" + dependencies: + "@opentelemetry/semantic-conventions": "npm:^1.29.0" + peerDependencies: + "@opentelemetry/api": ">=1.0.0 <1.10.0" + checksum: 10/62cb4721af697fe61b6a227fe1675e2e9a440ad6b04e2af6e1f60ca6b714fcd432bdf1cc2595b105fdf2a4223bc5d3ff37a7b2af67b4ea2513e6b99c3e10a709 + languageName: node + linkType: hard + "@opentelemetry/core@npm:^1.29.0": version: 1.30.1 resolution: "@opentelemetry/core@npm:1.30.1" @@ -13902,7 +13914,7 @@ __metadata: languageName: node linkType: hard -"@opentelemetry/resources@npm:2.2.0, @opentelemetry/resources@npm:^2.0.0": +"@opentelemetry/resources@npm:2.2.0": version: 2.2.0 resolution: "@opentelemetry/resources@npm:2.2.0" dependencies: @@ -13914,6 +13926,18 @@ __metadata: languageName: node linkType: hard +"@opentelemetry/resources@npm:^2.0.0": + version: 2.5.0 + resolution: "@opentelemetry/resources@npm:2.5.0" + dependencies: + "@opentelemetry/core": "npm:2.5.0" + "@opentelemetry/semantic-conventions": "npm:^1.29.0" + peerDependencies: + "@opentelemetry/api": ">=1.3.0 <1.10.0" + checksum: 10/0400e5db66c2bab05424b6701badd891cba61cf0a4c07a9c01d74ff131d27f5ea55846d2ae59af2eb9c3fb48e71097eacb529224f2c6498a0a2306dd8a890bbb + languageName: node + linkType: hard + "@opentelemetry/sdk-logs@npm:0.208.0": version: 0.208.0 resolution: "@opentelemetry/sdk-logs@npm:0.208.0" @@ -14340,13 +14364,13 @@ __metadata: linkType: hard "@playwright/test@npm:^1.32.3": - version: 1.57.0 - resolution: "@playwright/test@npm:1.57.0" + version: 1.58.2 + resolution: "@playwright/test@npm:1.58.2" dependencies: - playwright: "npm:1.57.0" + playwright: "npm:1.58.2" bin: playwright: cli.js - checksum: 10/07f5ba4841b2db1dea70d821004c5156b692488e13523c096ce3487d30f95f34ccf30ba6467ece60c86faac27ae382213b7eacab48a695550981b2e811e5e579 + checksum: 10/58bf90139280a0235eeeb6049e9fb4db6425e98be1bf0cc17913b068eef616cf67be57bfb36dc4cb56bcf116f498ffd0225c4916e85db404b343ea6c5efdae13 languageName: node linkType: hard @@ -17084,92 +17108,92 @@ __metadata: languageName: node linkType: hard -"@rspack/binding-darwin-arm64@npm:1.7.3": - version: 1.7.3 - resolution: "@rspack/binding-darwin-arm64@npm:1.7.3" +"@rspack/binding-darwin-arm64@npm:1.7.5": + version: 1.7.5 + resolution: "@rspack/binding-darwin-arm64@npm:1.7.5" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"@rspack/binding-darwin-x64@npm:1.7.3": - version: 1.7.3 - resolution: "@rspack/binding-darwin-x64@npm:1.7.3" +"@rspack/binding-darwin-x64@npm:1.7.5": + version: 1.7.5 + resolution: "@rspack/binding-darwin-x64@npm:1.7.5" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"@rspack/binding-linux-arm64-gnu@npm:1.7.3": - version: 1.7.3 - resolution: "@rspack/binding-linux-arm64-gnu@npm:1.7.3" +"@rspack/binding-linux-arm64-gnu@npm:1.7.5": + version: 1.7.5 + resolution: "@rspack/binding-linux-arm64-gnu@npm:1.7.5" conditions: os=linux & cpu=arm64 & libc=glibc languageName: node linkType: hard -"@rspack/binding-linux-arm64-musl@npm:1.7.3": - version: 1.7.3 - resolution: "@rspack/binding-linux-arm64-musl@npm:1.7.3" +"@rspack/binding-linux-arm64-musl@npm:1.7.5": + version: 1.7.5 + resolution: "@rspack/binding-linux-arm64-musl@npm:1.7.5" conditions: os=linux & cpu=arm64 & libc=musl languageName: node linkType: hard -"@rspack/binding-linux-x64-gnu@npm:1.7.3": - version: 1.7.3 - resolution: "@rspack/binding-linux-x64-gnu@npm:1.7.3" +"@rspack/binding-linux-x64-gnu@npm:1.7.5": + version: 1.7.5 + resolution: "@rspack/binding-linux-x64-gnu@npm:1.7.5" conditions: os=linux & cpu=x64 & libc=glibc languageName: node linkType: hard -"@rspack/binding-linux-x64-musl@npm:1.7.3": - version: 1.7.3 - resolution: "@rspack/binding-linux-x64-musl@npm:1.7.3" +"@rspack/binding-linux-x64-musl@npm:1.7.5": + version: 1.7.5 + resolution: "@rspack/binding-linux-x64-musl@npm:1.7.5" conditions: os=linux & cpu=x64 & libc=musl languageName: node linkType: hard -"@rspack/binding-wasm32-wasi@npm:1.7.3": - version: 1.7.3 - resolution: "@rspack/binding-wasm32-wasi@npm:1.7.3" +"@rspack/binding-wasm32-wasi@npm:1.7.5": + version: 1.7.5 + resolution: "@rspack/binding-wasm32-wasi@npm:1.7.5" dependencies: "@napi-rs/wasm-runtime": "npm:1.0.7" conditions: cpu=wasm32 languageName: node linkType: hard -"@rspack/binding-win32-arm64-msvc@npm:1.7.3": - version: 1.7.3 - resolution: "@rspack/binding-win32-arm64-msvc@npm:1.7.3" +"@rspack/binding-win32-arm64-msvc@npm:1.7.5": + version: 1.7.5 + resolution: "@rspack/binding-win32-arm64-msvc@npm:1.7.5" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"@rspack/binding-win32-ia32-msvc@npm:1.7.3": - version: 1.7.3 - resolution: "@rspack/binding-win32-ia32-msvc@npm:1.7.3" +"@rspack/binding-win32-ia32-msvc@npm:1.7.5": + version: 1.7.5 + resolution: "@rspack/binding-win32-ia32-msvc@npm:1.7.5" conditions: os=win32 & cpu=ia32 languageName: node linkType: hard -"@rspack/binding-win32-x64-msvc@npm:1.7.3": - version: 1.7.3 - resolution: "@rspack/binding-win32-x64-msvc@npm:1.7.3" +"@rspack/binding-win32-x64-msvc@npm:1.7.5": + version: 1.7.5 + resolution: "@rspack/binding-win32-x64-msvc@npm:1.7.5" conditions: os=win32 & cpu=x64 languageName: node linkType: hard -"@rspack/binding@npm:1.7.3": - version: 1.7.3 - resolution: "@rspack/binding@npm:1.7.3" +"@rspack/binding@npm:1.7.5": + version: 1.7.5 + resolution: "@rspack/binding@npm:1.7.5" dependencies: - "@rspack/binding-darwin-arm64": "npm:1.7.3" - "@rspack/binding-darwin-x64": "npm:1.7.3" - "@rspack/binding-linux-arm64-gnu": "npm:1.7.3" - "@rspack/binding-linux-arm64-musl": "npm:1.7.3" - "@rspack/binding-linux-x64-gnu": "npm:1.7.3" - "@rspack/binding-linux-x64-musl": "npm:1.7.3" - "@rspack/binding-wasm32-wasi": "npm:1.7.3" - "@rspack/binding-win32-arm64-msvc": "npm:1.7.3" - "@rspack/binding-win32-ia32-msvc": "npm:1.7.3" - "@rspack/binding-win32-x64-msvc": "npm:1.7.3" + "@rspack/binding-darwin-arm64": "npm:1.7.5" + "@rspack/binding-darwin-x64": "npm:1.7.5" + "@rspack/binding-linux-arm64-gnu": "npm:1.7.5" + "@rspack/binding-linux-arm64-musl": "npm:1.7.5" + "@rspack/binding-linux-x64-gnu": "npm:1.7.5" + "@rspack/binding-linux-x64-musl": "npm:1.7.5" + "@rspack/binding-wasm32-wasi": "npm:1.7.5" + "@rspack/binding-win32-arm64-msvc": "npm:1.7.5" + "@rspack/binding-win32-ia32-msvc": "npm:1.7.5" + "@rspack/binding-win32-x64-msvc": "npm:1.7.5" dependenciesMeta: "@rspack/binding-darwin-arm64": optional: true @@ -17191,38 +17215,61 @@ __metadata: optional: true "@rspack/binding-win32-x64-msvc": optional: true - checksum: 10/295c59c22370f71e0f8543fca9819d7d13741e02ef340f1fdda84789d800e324a91d7e54c5119ec0e2a64d4074efff7d2a7f989522bef2d8cb12fb7abffbb5d5 + checksum: 10/3e66805d4dae5f2051f10c5a9126e5bf25926d2a6ccb1c794af2aa49c15e4fdcb9e362bd015a9afef1e788a3272dfe7a28a3c866713badda34579896d736ed4f languageName: node linkType: hard "@rspack/core@npm:^1.4.11": - version: 1.7.3 - resolution: "@rspack/core@npm:1.7.3" + version: 1.7.5 + resolution: "@rspack/core@npm:1.7.5" dependencies: "@module-federation/runtime-tools": "npm:0.22.0" - "@rspack/binding": "npm:1.7.3" + "@rspack/binding": "npm:1.7.5" "@rspack/lite-tapable": "npm:1.1.0" peerDependencies: "@swc/helpers": ">=0.5.1" peerDependenciesMeta: "@swc/helpers": optional: true - checksum: 10/cd6a4d8dea6eb2fe8fd97b1266ef3ab0bdefd02970f70f0154b20c7ba3b4235cb92e712cf7f9f42bf64786663422ee46e85917b15fe06b563da22bc39ca5f35e + checksum: 10/c17d93ef1e7e0728b74bf527150642d9bf072cabb63964ebd32c82da94d6d2f9eac7ff2cc13031bbd376c0c03710899f549e61d2bcfc0a6638a9f3bc8620b7ce languageName: node linkType: hard "@rspack/dev-server@npm:^1.1.4": - version: 1.1.5 - resolution: "@rspack/dev-server@npm:1.1.5" + version: 1.2.1 + resolution: "@rspack/dev-server@npm:1.2.1" dependencies: + "@types/bonjour": "npm:^3.5.13" + "@types/connect-history-api-fallback": "npm:^1.5.4" + "@types/express": "npm:^4.17.25" + "@types/express-serve-static-core": "npm:^4.17.21" + "@types/serve-index": "npm:^1.9.4" + "@types/serve-static": "npm:^1.15.5" + "@types/sockjs": "npm:^0.3.36" + "@types/ws": "npm:^8.5.10" + ansi-html-community: "npm:^0.0.8" + bonjour-service: "npm:^1.2.1" chokidar: "npm:^3.6.0" + colorette: "npm:^2.0.10" + compression: "npm:^1.8.1" + connect-history-api-fallback: "npm:^2.0.0" + express: "npm:^4.22.1" + graceful-fs: "npm:^4.2.6" http-proxy-middleware: "npm:^2.0.9" + ipaddr.js: "npm:^2.1.0" + launch-editor: "npm:^2.6.1" + open: "npm:^10.0.3" p-retry: "npm:^6.2.0" - webpack-dev-server: "npm:5.2.2" + schema-utils: "npm:^4.2.0" + selfsigned: "npm:^2.4.1" + serve-index: "npm:^1.9.1" + sockjs: "npm:^0.3.24" + spdy: "npm:^4.0.2" + webpack-dev-middleware: "npm:^7.4.2" ws: "npm:^8.18.0" peerDependencies: "@rspack/core": "*" - checksum: 10/67a747d998f9a2449cb1c6c5791ffc812c9d99a7219595359ce960063f344fde9f8f2000bbc9633dc490082f69b74a20b8f319697bd19beca65bd108f5dff5e5 + checksum: 10/154808faef8079dc1d6eae1712455864cc7bc1ec686f3020f7117ad3e5f2906940f27ec514eb40230276132371570ecdf6b47f7ab117ad209462bcba7c2b0692 languageName: node linkType: hard @@ -19047,8 +19094,8 @@ __metadata: linkType: hard "@stoplight/spectral-core@npm:^1.18.0, @stoplight/spectral-core@npm:^1.18.3, @stoplight/spectral-core@npm:^1.19.2, @stoplight/spectral-core@npm:^1.19.4, @stoplight/spectral-core@npm:^1.8.1": - version: 1.20.0 - resolution: "@stoplight/spectral-core@npm:1.20.0" + version: 1.21.0 + resolution: "@stoplight/spectral-core@npm:1.21.0" dependencies: "@stoplight/better-ajv-errors": "npm:1.0.3" "@stoplight/json": "npm:~3.21.0" @@ -19064,14 +19111,14 @@ __metadata: ajv-formats: "npm:~2.1.1" es-aggregate-error: "npm:^1.0.7" jsonpath-plus: "npm:^10.3.0" - lodash: "npm:~4.17.21" + lodash: "npm:~4.17.23" lodash.topath: "npm:^4.5.2" minimatch: "npm:3.1.2" nimma: "npm:0.2.3" pony-cause: "npm:^1.1.1" simple-eval: "npm:1.0.1" tslib: "npm:^2.8.1" - checksum: 10/63628dcf4b1556db166a020dd78d17033908fa7d1c67c62739e35848e5d0e095714524b4c142aa7d6524fe556152f4dbb8cb388b36bc6e37026bf07c31a0e69b + checksum: 10/1ee71d19c810e716ada542c4e838bbc8b20e7bdc46518739c16c2edbc446a34fcf4e977d79b89d68d1a41e295ef9abee6449e2260cbf5ed1c2ae486229e3bdfb languageName: node linkType: hard @@ -19240,46 +19287,46 @@ __metadata: linkType: hard "@storybook/addon-a11y@npm:^10.2.0-alpha.7": - version: 10.2.0-alpha.7 - resolution: "@storybook/addon-a11y@npm:10.2.0-alpha.7" + version: 10.2.8 + resolution: "@storybook/addon-a11y@npm:10.2.8" dependencies: "@storybook/global": "npm:^5.0.0" axe-core: "npm:^4.2.0" peerDependencies: - storybook: ^10.2.0-alpha.7 - checksum: 10/f531e8d2bbde53343734ac1b1e0a36aef65188b8acfa188eb1b3feda603932a525f1fa76503e04e300cb5953ff8a58c810f88d6f9d56cfdd0c8dd23973dfa110 + storybook: ^10.2.8 + checksum: 10/92cf09e98e517e5e10139c85a5f006ec1a552d3b28934dba6e0bf60729500f81ea03af6858268e0415e0604b5ea30ad0952399e151b36b3e7868f6a6d00a4cea languageName: node linkType: hard "@storybook/addon-docs@npm:^10.2.0-alpha.7": - version: 10.2.0-alpha.7 - resolution: "@storybook/addon-docs@npm:10.2.0-alpha.7" + version: 10.2.8 + resolution: "@storybook/addon-docs@npm:10.2.8" dependencies: "@mdx-js/react": "npm:^3.0.0" - "@storybook/csf-plugin": "npm:10.2.0-alpha.7" - "@storybook/icons": "npm:^2.0.0" - "@storybook/react-dom-shim": "npm:10.2.0-alpha.7" + "@storybook/csf-plugin": "npm:10.2.8" + "@storybook/icons": "npm:^2.0.1" + "@storybook/react-dom-shim": "npm:10.2.8" react: "npm:^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" react-dom: "npm:^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" ts-dedent: "npm:^2.0.0" peerDependencies: - storybook: ^10.2.0-alpha.7 - checksum: 10/cc7142cd187f1f0a50ad7277ba2555e10e6d0ff57e29d699a5c260237c96b4a246aad1d51d960c56ed814a2d80638dcf67318d57644f0e4b63f0b869e8dbe379 + storybook: ^10.2.8 + checksum: 10/e9fd99ba12e556126038a06430b6848006741111d0d12b8bde276227fbb2a97c6a4ec88c6bfa578911026f5944f0365efe9e546ca7c40974fbeed9361532fada languageName: node linkType: hard "@storybook/addon-links@npm:^10.2.0-alpha.7": - version: 10.2.0-alpha.7 - resolution: "@storybook/addon-links@npm:10.2.0-alpha.7" + version: 10.2.8 + resolution: "@storybook/addon-links@npm:10.2.8" dependencies: "@storybook/global": "npm:^5.0.0" peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - storybook: ^10.2.0-alpha.7 + storybook: ^10.2.8 peerDependenciesMeta: react: optional: true - checksum: 10/bc868268f21766fdc274399558598d6c95400f00c15b964cd2a239581a4b8cd4ad1454d2ba018471df5c7a372f66ee1724e32f99f246d0d852995782e01e4631 + checksum: 10/0619754455f5a98f072cdf3e8aa7a929475bb061d3c91f2b4daf4571136f7b1db59f29c5d09cdf82f89dc2b509adf35788d82b7f8c2345030f7def5a447819ce languageName: node linkType: hard @@ -19299,27 +19346,27 @@ __metadata: linkType: hard "@storybook/addon-themes@npm:^10.2.0-alpha.7": - version: 10.2.0-alpha.7 - resolution: "@storybook/addon-themes@npm:10.2.0-alpha.7" + version: 10.2.8 + resolution: "@storybook/addon-themes@npm:10.2.8" dependencies: ts-dedent: "npm:^2.0.0" peerDependencies: - storybook: ^10.2.0-alpha.7 - checksum: 10/85d3be25d89ae1b66702093fafd14f3b4ea810b6875540017d40b8d67febd2f3a6e139d9a5fa1fae38271d6a7c387ff625d0c023482d0ca39b7500fca71f23b7 + storybook: ^10.2.8 + checksum: 10/ebccf0e4a68573b8aa7d37ac68a935fd4f0a035bd1bb1a504849744b23557b9cbb58d707341bc64c7bc1b74b92a876d95c675af49546025f2514e29de172f07e languageName: node linkType: hard "@storybook/addon-vitest@npm:^10.2.0-alpha.7": - version: 10.2.0-alpha.7 - resolution: "@storybook/addon-vitest@npm:10.2.0-alpha.7" + version: 10.2.8 + resolution: "@storybook/addon-vitest@npm:10.2.8" dependencies: "@storybook/global": "npm:^5.0.0" - "@storybook/icons": "npm:^2.0.0" + "@storybook/icons": "npm:^2.0.1" peerDependencies: "@vitest/browser": ^3.0.0 || ^4.0.0 "@vitest/browser-playwright": ^4.0.0 "@vitest/runner": ^3.0.0 || ^4.0.0 - storybook: ^10.2.0-alpha.7 + storybook: ^10.2.8 vitest: ^3.0.0 || ^4.0.0 peerDependenciesMeta: "@vitest/browser": @@ -19330,33 +19377,32 @@ __metadata: optional: true vitest: optional: true - checksum: 10/983b887326ab7fe21c3eb6c017659edbdf06f710327b060a15d45f9769759071a011b6f0e33bf8e02714334091fa5b715936cb23caa61050636e2691373e07fc + checksum: 10/3ddeb8927f96a625877bb75ab412eda2b923f836036dc5779205784b13404b645f5796109924090c7bfd2f8f3e6261feeeb07fa245a0bf78aeb3d81fbcdf6814 languageName: node linkType: hard -"@storybook/builder-vite@npm:10.2.0-alpha.7": - version: 10.2.0-alpha.7 - resolution: "@storybook/builder-vite@npm:10.2.0-alpha.7" +"@storybook/builder-vite@npm:10.2.8": + version: 10.2.8 + resolution: "@storybook/builder-vite@npm:10.2.8" dependencies: - "@storybook/csf-plugin": "npm:10.2.0-alpha.7" - "@vitest/mocker": "npm:3.2.4" + "@storybook/csf-plugin": "npm:10.2.8" ts-dedent: "npm:^2.0.0" peerDependencies: - storybook: ^10.2.0-alpha.7 + storybook: ^10.2.8 vite: ^5.0.0 || ^6.0.0 || ^7.0.0 - checksum: 10/df83a6d775fa5f6e9e8e84bad4b66fb2039f534ad95b6d7643eff02285ad77367c16a0b9122281344a8ac16ec2bed1b140820be672807e7358630d0576d3ed41 + checksum: 10/9ddbb7f25eb8667b53e35e9982a300ca6f323f6cdd13067141327d285e2e967deb1214c0b4880998620a46e477f8fad4ccce1719282e11a6b757d5a368e38903 languageName: node linkType: hard -"@storybook/csf-plugin@npm:10.2.0-alpha.7": - version: 10.2.0-alpha.7 - resolution: "@storybook/csf-plugin@npm:10.2.0-alpha.7" +"@storybook/csf-plugin@npm:10.2.8": + version: 10.2.8 + resolution: "@storybook/csf-plugin@npm:10.2.8" dependencies: unplugin: "npm:^2.3.5" peerDependencies: esbuild: "*" rollup: "*" - storybook: ^10.2.0-alpha.7 + storybook: ^10.2.8 vite: "*" webpack: "*" peerDependenciesMeta: @@ -19368,7 +19414,7 @@ __metadata: optional: true webpack: optional: true - checksum: 10/7efb9d56a21eaf26ffd0971b0d3b8d525d0227fbced7e7391cf8329eb354f9d717cdc04a156391c62b57d53ebdba6ef3e3897014cad029725dc5c68fdbf3ce3e + checksum: 10/e468ed2749b6f6a99784357727b73da57912e00d95bc9a95c96d664189f0e7f6b3660340fbec072eb2edd14d21007b47f9253712069703c2a28ec8c7e99251e0 languageName: node linkType: hard @@ -19379,7 +19425,7 @@ __metadata: languageName: node linkType: hard -"@storybook/icons@npm:^2.0.0": +"@storybook/icons@npm:^2.0.1": version: 2.0.1 resolution: "@storybook/icons@npm:2.0.1" peerDependencies: @@ -19401,25 +19447,25 @@ __metadata: languageName: node linkType: hard -"@storybook/react-dom-shim@npm:10.2.0-alpha.7": - version: 10.2.0-alpha.7 - resolution: "@storybook/react-dom-shim@npm:10.2.0-alpha.7" +"@storybook/react-dom-shim@npm:10.2.8": + version: 10.2.8 + resolution: "@storybook/react-dom-shim@npm:10.2.8" peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - storybook: ^10.2.0-alpha.7 - checksum: 10/088262c61b2a138e02ae3619df3f3a62328dd7fc764b1d843bc1464e613d4d34b16c83d24aea54771fe90eb7882f9699d9d045f206a4f6302a4b7b6b5f3f5080 + storybook: ^10.2.8 + checksum: 10/385b27a633f41c5923806502863b458bdc29c2948b306020a8598734edcc92bd95648b2d0e285f17a3e3d140b79dce5a871d6ddc786525eb1beac269a05a17b2 languageName: node linkType: hard "@storybook/react-vite@npm:^10.2.0-alpha.7": - version: 10.2.0-alpha.7 - resolution: "@storybook/react-vite@npm:10.2.0-alpha.7" + version: 10.2.8 + resolution: "@storybook/react-vite@npm:10.2.8" dependencies: "@joshwooding/vite-plugin-react-docgen-typescript": "npm:^0.6.3" "@rollup/pluginutils": "npm:^5.0.2" - "@storybook/builder-vite": "npm:10.2.0-alpha.7" - "@storybook/react": "npm:10.2.0-alpha.7" + "@storybook/builder-vite": "npm:10.2.8" + "@storybook/react": "npm:10.2.8" empathic: "npm:^2.0.0" magic-string: "npm:^0.30.0" react-docgen: "npm:^8.0.0" @@ -19428,28 +19474,28 @@ __metadata: peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - storybook: ^10.2.0-alpha.7 + storybook: ^10.2.8 vite: ^5.0.0 || ^6.0.0 || ^7.0.0 - checksum: 10/495c2955fe68549f9be3a39dbf60b68cd9e0ed016de5eabd98c40725bd3c3cfd1a8c493ac5906bf8119ce16b75a1f997d721492cad4110673e62da8d8e6fe1a3 + checksum: 10/84e75f41f480147437f207ff153457d43d13b5b1cef07c13a355d88f3515e665a127158012f03988f5a4e33f1eeb3d1cd31e825eba13f6519697afa5fc924fc0 languageName: node linkType: hard -"@storybook/react@npm:10.2.0-alpha.7": - version: 10.2.0-alpha.7 - resolution: "@storybook/react@npm:10.2.0-alpha.7" +"@storybook/react@npm:10.2.8": + version: 10.2.8 + resolution: "@storybook/react@npm:10.2.8" dependencies: "@storybook/global": "npm:^5.0.0" - "@storybook/react-dom-shim": "npm:10.2.0-alpha.7" + "@storybook/react-dom-shim": "npm:10.2.8" react-docgen: "npm:^8.0.2" peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - storybook: ^10.2.0-alpha.7 + storybook: ^10.2.8 typescript: ">= 4.9.x" peerDependenciesMeta: typescript: optional: true - checksum: 10/f0240fa8d72fc9b54380a9f50145b66a4285fdf3b69c51b042e45d2080f845580a4473614f2cd3ee472022cacb6a4ccc71b54a2a61382d86767d57604075b5ae + checksum: 10/8365c47a3ab9b191c367aedfa2c2737d2e90d575c9ea096d70bc4f680d579b4687afdd6b0512558522b593aeb83a3b7cb535cc05dc4a140b0e8429ff6f9e4d8e languageName: node linkType: hard @@ -21412,7 +21458,14 @@ __metadata: languageName: node linkType: hard -"@types/luxon@npm:^3.0.0, @types/luxon@npm:~3.4.0": +"@types/luxon@npm:^3.0.0": + version: 3.7.1 + resolution: "@types/luxon@npm:3.7.1" + checksum: 10/c7bc164c278393ea0be938f986c74b4cddfab9013b1aff4495b016f771ded1d5b7b7b4825b2c7f0b8799edce19c5f531c28ff434ab3dedf994ac2d99a20fd4c4 + languageName: node + linkType: hard + +"@types/luxon@npm:~3.4.0": version: 3.4.2 resolution: "@types/luxon@npm:3.4.2" checksum: 10/fd89566e3026559f2bc4ddcc1e70a2c16161905ed50be9473ec0cfbbbe919165041408c4f6e06c4bcf095445535052e2c099087c76b1b38e368127e618fc968d @@ -21612,12 +21665,11 @@ __metadata: linkType: hard "@types/nodemailer@npm:^7.0.0": - version: 7.0.5 - resolution: "@types/nodemailer@npm:7.0.5" + version: 7.0.9 + resolution: "@types/nodemailer@npm:7.0.9" dependencies: - "@aws-sdk/client-sesv2": "npm:^3.839.0" "@types/node": "npm:*" - checksum: 10/2defc792256092b18ee7ca2ef18ba47343ce5239da32ad9d5219f8f6d57279fa1540415219105ce690f5fb9bf343288e81c315d41deb3e3e8f293d91c382ab4f + checksum: 10/6bfca388af668a05a68e750a7acbd5736a3dcdf96f34f23bf4211ab152572d55008fd813e38bf03f944c6edbd002a7f98d6cee048343b8e840b3b91a00befac9 languageName: node linkType: hard @@ -22419,65 +22471,51 @@ __metadata: linkType: hard "@typescript-eslint/eslint-plugin@npm:^8.17.0": - version: 8.48.1 - resolution: "@typescript-eslint/eslint-plugin@npm:8.48.1" + version: 8.54.0 + resolution: "@typescript-eslint/eslint-plugin@npm:8.54.0" dependencies: - "@eslint-community/regexpp": "npm:^4.10.0" - "@typescript-eslint/scope-manager": "npm:8.48.1" - "@typescript-eslint/type-utils": "npm:8.48.1" - "@typescript-eslint/utils": "npm:8.48.1" - "@typescript-eslint/visitor-keys": "npm:8.48.1" - graphemer: "npm:^1.4.0" - ignore: "npm:^7.0.0" + "@eslint-community/regexpp": "npm:^4.12.2" + "@typescript-eslint/scope-manager": "npm:8.54.0" + "@typescript-eslint/type-utils": "npm:8.54.0" + "@typescript-eslint/utils": "npm:8.54.0" + "@typescript-eslint/visitor-keys": "npm:8.54.0" + ignore: "npm:^7.0.5" natural-compare: "npm:^1.4.0" - ts-api-utils: "npm:^2.1.0" + ts-api-utils: "npm:^2.4.0" peerDependencies: - "@typescript-eslint/parser": ^8.48.1 + "@typescript-eslint/parser": ^8.54.0 eslint: ^8.57.0 || ^9.0.0 typescript: ">=4.8.4 <6.0.0" - checksum: 10/3ccf420805fb8adb2f3059fa26eb9c6211c0624966d8c8654a1bd586bf87f30be0c62524dfd785185ef573bedd91c42ec3c98c23aed5d60cb9ac583dd9334bc8 + checksum: 10/8f1c74ac77d7a84ae3f201bb09cb67271662befed036266af1eaa0653d09b545353441640516c1c86e0a94939887d32f0473c61a642488b14d46533742bfbd1b languageName: node linkType: hard "@typescript-eslint/parser@npm:^8.16.0": - version: 8.48.1 - resolution: "@typescript-eslint/parser@npm:8.48.1" + version: 8.54.0 + resolution: "@typescript-eslint/parser@npm:8.54.0" dependencies: - "@typescript-eslint/scope-manager": "npm:8.48.1" - "@typescript-eslint/types": "npm:8.48.1" - "@typescript-eslint/typescript-estree": "npm:8.48.1" - "@typescript-eslint/visitor-keys": "npm:8.48.1" - debug: "npm:^4.3.4" + "@typescript-eslint/scope-manager": "npm:8.54.0" + "@typescript-eslint/types": "npm:8.54.0" + "@typescript-eslint/typescript-estree": "npm:8.54.0" + "@typescript-eslint/visitor-keys": "npm:8.54.0" + debug: "npm:^4.4.3" peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: ">=4.8.4 <6.0.0" - checksum: 10/d8409c9ede4b1cd2ad0e10e94bb00c54f79352f7d54c97bf24419cb983c19b9f6097e6c31b217ce7ec5cfc9a48117e732d9f88ce0cb8c0ccf7fc3faecdf854a3 + checksum: 10/d2e09462c9966ef3deeba71d9e41d1d4876c61eea65888c93a3db6fba48b89a2165459c6519741d40e969da05ed98d3f4c87a7f56c5521ab5699743cc315f6cb languageName: node linkType: hard -"@typescript-eslint/project-service@npm:8.48.1": - version: 8.48.1 - resolution: "@typescript-eslint/project-service@npm:8.48.1" +"@typescript-eslint/project-service@npm:8.54.0": + version: 8.54.0 + resolution: "@typescript-eslint/project-service@npm:8.54.0" dependencies: - "@typescript-eslint/tsconfig-utils": "npm:^8.48.1" - "@typescript-eslint/types": "npm:^8.48.1" - debug: "npm:^4.3.4" - peerDependencies: - typescript: ">=4.8.4 <6.0.0" - checksum: 10/66ecc7ef9572748860517cde7fbfc335d05ca8c99dcf13ac6d728ac93388d90cdc3ebe2ff33a85c0a03487b3c1c4e36c6e3fe413ee16d8fb003621cb58e65e52 - languageName: node - linkType: hard - -"@typescript-eslint/project-service@npm:8.52.0": - version: 8.52.0 - resolution: "@typescript-eslint/project-service@npm:8.52.0" - dependencies: - "@typescript-eslint/tsconfig-utils": "npm:^8.52.0" - "@typescript-eslint/types": "npm:^8.52.0" + "@typescript-eslint/tsconfig-utils": "npm:^8.54.0" + "@typescript-eslint/types": "npm:^8.54.0" debug: "npm:^4.4.3" peerDependencies: typescript: ">=4.8.4 <6.0.0" - checksum: 10/bfa786007ed4a603fb8f31c6e354f0ba0cca576b03e402584ae3cf0d674f07adfbde9e976a5bf165fa44c484d4b4f310bd18b34d1b0e75b4210253edbdaabb87 + checksum: 10/93f0483f6bbcf7cf776a53a130f7606f597fba67cf111e1897873bf1531efaa96e4851cfd461da0f0cc93afbdb51e47bcce11cf7dd4fb68b7030c7f9f240b92f languageName: node linkType: hard @@ -22491,57 +22529,38 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/scope-manager@npm:8.48.1": - version: 8.48.1 - resolution: "@typescript-eslint/scope-manager@npm:8.48.1" +"@typescript-eslint/scope-manager@npm:8.54.0, @typescript-eslint/scope-manager@npm:^8.51.0": + version: 8.54.0 + resolution: "@typescript-eslint/scope-manager@npm:8.54.0" dependencies: - "@typescript-eslint/types": "npm:8.48.1" - "@typescript-eslint/visitor-keys": "npm:8.48.1" - checksum: 10/5040246220f9872ec47633297b7896ed5587af3163e06ddcb7ca0dcf1e171f359bd4f1c82f794a6adfecbccfb5ef437d51b522321034603c93ba1993c407bdf2 + "@typescript-eslint/types": "npm:8.54.0" + "@typescript-eslint/visitor-keys": "npm:8.54.0" + checksum: 10/3474f3197e8647754393dee62b3145c9de71eaa66c8a68f61c8283aa332141803885db9c96caa6a51f78128ad9ef92f774a90361655e57bd951d5b57eb76f914 languageName: node linkType: hard -"@typescript-eslint/scope-manager@npm:8.52.0, @typescript-eslint/scope-manager@npm:^8.51.0": - version: 8.52.0 - resolution: "@typescript-eslint/scope-manager@npm:8.52.0" - dependencies: - "@typescript-eslint/types": "npm:8.52.0" - "@typescript-eslint/visitor-keys": "npm:8.52.0" - checksum: 10/89d9c04cd2567e6aa9adcbe85e2eab24fbc64bde5a33c688764e7c896e9a02c06aad2ec88e8bdc4d5bfabadbc510906a0cb4f3e0b73a5b80d10218f7a6a4ea27 - languageName: node - linkType: hard - -"@typescript-eslint/tsconfig-utils@npm:8.48.1": - version: 8.48.1 - resolution: "@typescript-eslint/tsconfig-utils@npm:8.48.1" +"@typescript-eslint/tsconfig-utils@npm:8.54.0, @typescript-eslint/tsconfig-utils@npm:^8.54.0": + version: 8.54.0 + resolution: "@typescript-eslint/tsconfig-utils@npm:8.54.0" peerDependencies: typescript: ">=4.8.4 <6.0.0" - checksum: 10/830bcd0e7628441f91899e8e24aaed66d32a239babcc205aba1d08c08ff5a636d8c04f96d9873578df59d7468fc4c5df032667764b3b2ee0a733af36fca21c4a + checksum: 10/e9d6b29538716f007919bfcee94f09b7f8e7d2b684ad43d1a3c8d43afb9f0539c7707f84a34f42054e31c8c056b0ccf06575d89e860b4d34632ffefaefafe1fc languageName: node linkType: hard -"@typescript-eslint/tsconfig-utils@npm:8.52.0, @typescript-eslint/tsconfig-utils@npm:^8.48.1, @typescript-eslint/tsconfig-utils@npm:^8.52.0": - version: 8.52.0 - resolution: "@typescript-eslint/tsconfig-utils@npm:8.52.0" - peerDependencies: - typescript: ">=4.8.4 <6.0.0" - checksum: 10/5b26227ab549e20a6b15725a4f8373acb70ae1c83570c8d670e242bfcd22ac0c9111d4d28ea16ee3939572caacce50e113388ce943f238fc2ca17f6c5a040cd2 - languageName: node - linkType: hard - -"@typescript-eslint/type-utils@npm:8.48.1": - version: 8.48.1 - resolution: "@typescript-eslint/type-utils@npm:8.48.1" +"@typescript-eslint/type-utils@npm:8.54.0": + version: 8.54.0 + resolution: "@typescript-eslint/type-utils@npm:8.54.0" dependencies: - "@typescript-eslint/types": "npm:8.48.1" - "@typescript-eslint/typescript-estree": "npm:8.48.1" - "@typescript-eslint/utils": "npm:8.48.1" - debug: "npm:^4.3.4" - ts-api-utils: "npm:^2.1.0" + "@typescript-eslint/types": "npm:8.54.0" + "@typescript-eslint/typescript-estree": "npm:8.54.0" + "@typescript-eslint/utils": "npm:8.54.0" + debug: "npm:^4.4.3" + ts-api-utils: "npm:^2.4.0" peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: ">=4.8.4 <6.0.0" - checksum: 10/6cf9370ac5437e2d64c71964646aed9e6c1ea3c7bb473258b50ae422106461d290f4215b9435b892a2dd563e3c31feb3169532375513b56b7e48f4a425283091 + checksum: 10/60e92fb32274abd70165ce6f4187e4cffa55416374c63731d7de8fdcfb7a558b4dd48909ff1ad38ac39d2ea1248ec54d6ce38dbc065fd34529a217fc2450d5b1 languageName: node linkType: hard @@ -22552,17 +22571,10 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/types@npm:8.48.1": - version: 8.48.1 - resolution: "@typescript-eslint/types@npm:8.48.1" - checksum: 10/1aa1e3f25b429bcebd9eb45b5252d950f1b24dbc6014a47dff8d00547e2e1ac47f351846fb996b6ebd49da37a85394051d36191cbbbf2c431b8db9d95afd198d - languageName: node - linkType: hard - -"@typescript-eslint/types@npm:8.52.0, @typescript-eslint/types@npm:^8.48.1, @typescript-eslint/types@npm:^8.52.0": - version: 8.52.0 - resolution: "@typescript-eslint/types@npm:8.52.0" - checksum: 10/05a630c5d25cce74d1bfa51027f1232f2e8a97a8f483ce0274e928373b4633cdf713be53eca39926f0372d52a3335f13786c7910d2edfd546a0cf1d66b3bcf51 +"@typescript-eslint/types@npm:8.54.0, @typescript-eslint/types@npm:^8.54.0": + version: 8.54.0 + resolution: "@typescript-eslint/types@npm:8.54.0" + checksum: 10/c25cc0bdf90fb150cf6ce498897f43fe3adf9e872562159118f34bd91a9bfab5f720cb1a41f3cdf253b2e840145d7d372089b7cef5156624ef31e98d34f91b31 languageName: node linkType: hard @@ -22585,33 +22597,14 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/typescript-estree@npm:8.48.1": - version: 8.48.1 - resolution: "@typescript-eslint/typescript-estree@npm:8.48.1" +"@typescript-eslint/typescript-estree@npm:8.54.0, @typescript-eslint/typescript-estree@npm:^8.23.0": + version: 8.54.0 + resolution: "@typescript-eslint/typescript-estree@npm:8.54.0" dependencies: - "@typescript-eslint/project-service": "npm:8.48.1" - "@typescript-eslint/tsconfig-utils": "npm:8.48.1" - "@typescript-eslint/types": "npm:8.48.1" - "@typescript-eslint/visitor-keys": "npm:8.48.1" - debug: "npm:^4.3.4" - minimatch: "npm:^9.0.4" - semver: "npm:^7.6.0" - tinyglobby: "npm:^0.2.15" - ts-api-utils: "npm:^2.1.0" - peerDependencies: - typescript: ">=4.8.4 <6.0.0" - checksum: 10/485aa44d22453396dbe61c560c6f583bf876f971d9e70773093cd729279f88184cf5793bf706033bbd8465cce6f9d045b63574727d58d5996519c29e1adbbfe5 - languageName: node - linkType: hard - -"@typescript-eslint/typescript-estree@npm:8.52.0, @typescript-eslint/typescript-estree@npm:^8.23.0": - version: 8.52.0 - resolution: "@typescript-eslint/typescript-estree@npm:8.52.0" - dependencies: - "@typescript-eslint/project-service": "npm:8.52.0" - "@typescript-eslint/tsconfig-utils": "npm:8.52.0" - "@typescript-eslint/types": "npm:8.52.0" - "@typescript-eslint/visitor-keys": "npm:8.52.0" + "@typescript-eslint/project-service": "npm:8.54.0" + "@typescript-eslint/tsconfig-utils": "npm:8.54.0" + "@typescript-eslint/types": "npm:8.54.0" + "@typescript-eslint/visitor-keys": "npm:8.54.0" debug: "npm:^4.4.3" minimatch: "npm:^9.0.5" semver: "npm:^7.7.3" @@ -22619,37 +22612,22 @@ __metadata: ts-api-utils: "npm:^2.4.0" peerDependencies: typescript: ">=4.8.4 <6.0.0" - checksum: 10/4e699f44a05e9c487531557a1eaf6412a97f370ec946a03596c8d445f584c3d17e9aa34cde5ce8998ae9d6908c1daffb2c9b523cb07e5988cf249eae6dea50fd + checksum: 10/3a545037c6f9319251d3ba44cf7a3216b1372422469e27f7ed3415244ebf42553da1ab4644da42d3f0ae2706a8cad12529ffebcb2e75406f74e3b30b812d010d languageName: node linkType: hard -"@typescript-eslint/utils@npm:8.48.1": - version: 8.48.1 - resolution: "@typescript-eslint/utils@npm:8.48.1" - dependencies: - "@eslint-community/eslint-utils": "npm:^4.7.0" - "@typescript-eslint/scope-manager": "npm:8.48.1" - "@typescript-eslint/types": "npm:8.48.1" - "@typescript-eslint/typescript-estree": "npm:8.48.1" - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: ">=4.8.4 <6.0.0" - checksum: 10/34afe5cf78020b682473e6529d6268eb8015bdb020a3c5303c4abb230d4d7c39e6fc8b9df58d1f0f35a1ceeb5d6182e71e42fe7a28dde8ffc31f8560f2dacc7c - languageName: node - linkType: hard - -"@typescript-eslint/utils@npm:^6.0.0 || ^7.0.0 || ^8.0.0, @typescript-eslint/utils@npm:^8.51.0, @typescript-eslint/utils@npm:^8.8.1": - version: 8.52.0 - resolution: "@typescript-eslint/utils@npm:8.52.0" +"@typescript-eslint/utils@npm:8.54.0, @typescript-eslint/utils@npm:^6.0.0 || ^7.0.0 || ^8.0.0, @typescript-eslint/utils@npm:^8.48.0, @typescript-eslint/utils@npm:^8.51.0": + version: 8.54.0 + resolution: "@typescript-eslint/utils@npm:8.54.0" dependencies: "@eslint-community/eslint-utils": "npm:^4.9.1" - "@typescript-eslint/scope-manager": "npm:8.52.0" - "@typescript-eslint/types": "npm:8.52.0" - "@typescript-eslint/typescript-estree": "npm:8.52.0" + "@typescript-eslint/scope-manager": "npm:8.54.0" + "@typescript-eslint/types": "npm:8.54.0" + "@typescript-eslint/typescript-estree": "npm:8.54.0" peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: ">=4.8.4 <6.0.0" - checksum: 10/11a02ab0fd26bb1284dfa8c02d40c54cabd3aa795e82ab26b060ea3839998c28a41822b075f9d23fb51e291e465147213166c8ddaf3c8d5807e70b0a4345d967 + checksum: 10/9f88a2a7ab3e11aa0ff7f99c0e66a0cf2cba10b640def4c64a4f4ef427fecfb22f28dbe5697535915eb01f6507515ac43e45e0ff384bf82856e3420194d9ffdd languageName: node linkType: hard @@ -22677,23 +22655,13 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/visitor-keys@npm:8.48.1": - version: 8.48.1 - resolution: "@typescript-eslint/visitor-keys@npm:8.48.1" +"@typescript-eslint/visitor-keys@npm:8.54.0": + version: 8.54.0 + resolution: "@typescript-eslint/visitor-keys@npm:8.54.0" dependencies: - "@typescript-eslint/types": "npm:8.48.1" + "@typescript-eslint/types": "npm:8.54.0" eslint-visitor-keys: "npm:^4.2.1" - checksum: 10/63aa165c57e6b38700adf84da2e90537577cdeb69d05031e3e70785fa412d96d539dc4c1696a0b7bc93284613f8b92fb1bb40f6068bb75347a942120b246ac60 - languageName: node - linkType: hard - -"@typescript-eslint/visitor-keys@npm:8.52.0": - version: 8.52.0 - resolution: "@typescript-eslint/visitor-keys@npm:8.52.0" - dependencies: - "@typescript-eslint/types": "npm:8.52.0" - eslint-visitor-keys: "npm:^4.2.1" - checksum: 10/4d841402cc65e876382ede464b68cf167c7d24905b15225c472516bb759140abbef02f250c6335ca35327f7328975ff3b28c3249a5183319cfd01f1d5541e3c1 + checksum: 10/cca5380ee30250302ee1459e5a0a38de8c16213026dbbff3d167fa7d71d012f31d60ac4483ad45ebd13f2ac963d1ca52dd5f22759a68d4ee57626e421769187a languageName: node linkType: hard @@ -23119,25 +23087,6 @@ __metadata: languageName: node linkType: hard -"@vitest/mocker@npm:3.2.4": - version: 3.2.4 - resolution: "@vitest/mocker@npm:3.2.4" - dependencies: - "@vitest/spy": "npm:3.2.4" - estree-walker: "npm:^3.0.3" - magic-string: "npm:^0.30.17" - peerDependencies: - msw: ^2.4.9 - vite: ^5.0.0 || ^6.0.0 || ^7.0.0-0 - peerDependenciesMeta: - msw: - optional: true - vite: - optional: true - checksum: 10/5e92431b6ed9fc1679060e4caef3e4623f4750542a5d7cd944774f8217c4d231e273202e8aea00bab33260a5a9222ecb7005d80da0348c3c829bd37d123071a8 - languageName: node - linkType: hard - "@vitest/pretty-format@npm:3.2.4": version: 3.2.4 resolution: "@vitest/pretty-format@npm:3.2.4" @@ -25261,10 +25210,10 @@ __metadata: languageName: node linkType: hard -"aws-ssl-profiles@npm:^1.1.1": - version: 1.1.1 - resolution: "aws-ssl-profiles@npm:1.1.1" - checksum: 10/7293640f29d7b9baf62bcc4e36228c0b7cd435053bbe5535a367dc7fcd76ffdf7f1c7078181147f5d666cc316abb65ce098e64e403f882a49937a4942080a8ea +"aws-ssl-profiles@npm:^1.1.2": + version: 1.1.2 + resolution: "aws-ssl-profiles@npm:1.1.2" + checksum: 10/af9e5c5e6e343e0f299106acaf03106a7458be69772d004f3e4cf0e3649bb41131b594126fcbc997ad89d73752d9e1d72886c72fcc8649ac5d590459d6b75827 languageName: node linkType: hard @@ -25303,7 +25252,7 @@ __metadata: languageName: node linkType: hard -"axios@npm:1.13.2, axios@npm:^1.0.0, axios@npm:^1.11.0, axios@npm:^1.12.0, axios@npm:^1.12.2, axios@npm:^1.13.0, axios@npm:^1.7.4": +"axios@npm:1.13.2": version: 1.13.2 resolution: "axios@npm:1.13.2" dependencies: @@ -25314,6 +25263,17 @@ __metadata: languageName: node linkType: hard +"axios@npm:^1.0.0, axios@npm:^1.11.0, axios@npm:^1.12.0, axios@npm:^1.12.2, axios@npm:^1.13.0, axios@npm:^1.7.4": + version: 1.13.5 + resolution: "axios@npm:1.13.5" + dependencies: + follow-redirects: "npm:^1.15.11" + form-data: "npm:^4.0.5" + proxy-from-env: "npm:^1.1.0" + checksum: 10/db726d09902565ef9a0632893530028310e2ec2b95b727114eca1b101450b00014133dfc3871cffc87983fb922bca7e4874d7e2826d1550a377a157cdf3f05b6 + languageName: node + linkType: hard + "axobject-query@npm:^4.1.0": version: 4.1.0 resolution: "axobject-query@npm:4.1.0" @@ -25596,12 +25556,12 @@ __metadata: languageName: node linkType: hard -"baseline-browser-mapping@npm:^2.8.25": - version: 2.9.8 - resolution: "baseline-browser-mapping@npm:2.9.8" +"baseline-browser-mapping@npm:^2.9.0": + version: 2.9.19 + resolution: "baseline-browser-mapping@npm:2.9.19" bin: baseline-browser-mapping: dist/cli.js - checksum: 10/1c9cf2fb0cc008ba86d5f1bd1f1a771d6f508dbd6124d173549c650734d6d305eba49622e8bc0160beea9ecafcd2f5f104ffdc92f4a815a4926b74a2d7a6d986 + checksum: 10/8d7bbb7fe3d1ad50e04b127c819ba6d059c01ed0d2a7a5fc3327e23a8c42855fa3a8b510550c1fe1e37916147e6a390243566d3ef85bf6130c8ddfe5cc3db530 languageName: node linkType: hard @@ -25814,20 +25774,20 @@ __metadata: languageName: node linkType: hard -"body-parser@npm:^2.2.0": - version: 2.2.0 - resolution: "body-parser@npm:2.2.0" +"body-parser@npm:^2.2.1": + version: 2.2.2 + resolution: "body-parser@npm:2.2.2" dependencies: bytes: "npm:^3.1.2" content-type: "npm:^1.0.5" - debug: "npm:^4.4.0" + debug: "npm:^4.4.3" http-errors: "npm:^2.0.0" - iconv-lite: "npm:^0.6.3" + iconv-lite: "npm:^0.7.0" on-finished: "npm:^2.4.1" - qs: "npm:^6.14.0" - raw-body: "npm:^3.0.0" - type-is: "npm:^2.0.0" - checksum: 10/e9d844b036bd15970df00a16f373c7ed28e1ef870974a0a1d4d6ef60d70e01087cc20a0dbb2081c49a88e3c08ce1d87caf1e2898c615dffa193f63e8faa8a84e + qs: "npm:^6.14.1" + raw-body: "npm:^3.0.1" + type-is: "npm:^2.0.1" + checksum: 10/69671f67d4d5ae5974593901a92d639757231da1725ed6de4d35e86cde9ce7650afdf1cd28df9b6f7892ea7f9eb03ccb30c70fe27d679275ae4cb4aae5ce1b21 languageName: node linkType: hard @@ -26024,18 +25984,18 @@ __metadata: languageName: node linkType: hard -"browserslist@npm:^4.0.0, browserslist@npm:^4.16.0, browserslist@npm:^4.16.6, browserslist@npm:^4.18.1, browserslist@npm:^4.24.0, browserslist@npm:^4.26.3": - version: 4.28.0 - resolution: "browserslist@npm:4.28.0" +"browserslist@npm:^4.0.0, browserslist@npm:^4.16.0, browserslist@npm:^4.16.6, browserslist@npm:^4.18.1, browserslist@npm:^4.24.0, browserslist@npm:^4.26.3, browserslist@npm:^4.28.1": + version: 4.28.1 + resolution: "browserslist@npm:4.28.1" dependencies: - baseline-browser-mapping: "npm:^2.8.25" - caniuse-lite: "npm:^1.0.30001754" - electron-to-chromium: "npm:^1.5.249" + baseline-browser-mapping: "npm:^2.9.0" + caniuse-lite: "npm:^1.0.30001759" + electron-to-chromium: "npm:^1.5.263" node-releases: "npm:^2.0.27" - update-browserslist-db: "npm:^1.1.4" + update-browserslist-db: "npm:^1.2.0" bin: browserslist: cli.js - checksum: 10/59dc88f8d950e44a064361cb874f486e532a8ba932e0cf549aee8b36dd2b791da2bc11f36c1cf820ebb9c1f3250b100f8c56364dd6e86dbc90495af424100e19 + checksum: 10/64f2a97de4bce8473c0e5ae0af8d76d1ead07a5b05fc6bc87b848678bb9c3a91ae787b27aa98cdd33fc00779607e6c156000bed58fefb9cf8e4c5a183b994cdb languageName: node linkType: hard @@ -26452,10 +26412,10 @@ __metadata: languageName: node linkType: hard -"caniuse-lite@npm:^1.0.0, caniuse-lite@npm:^1.0.30001754": - version: 1.0.30001760 - resolution: "caniuse-lite@npm:1.0.30001760" - checksum: 10/ac5c13d00b946c3ace331d25379ed9d85743b1028aba79ae80402cb128b4b491122585144898fefb836d4d9879c13c717a081ae241a00420cbbc7e1b934ec685 +"caniuse-lite@npm:^1.0.0, caniuse-lite@npm:^1.0.30001759": + version: 1.0.30001769 + resolution: "caniuse-lite@npm:1.0.30001769" + checksum: 10/4b7d087832d4330a8b1fa02cd9455bdb068ea67f1735f2aa6324d5b64b24f5079cf6349b13d209f268ffa59644b9f4f784266b780bafd877ceb83c9797ca80ba languageName: node linkType: hard @@ -27597,13 +27557,6 @@ __metadata: languageName: node linkType: hard -"cookie-signature@npm:1.0.7, cookie-signature@npm:~1.0.6": - version: 1.0.7 - resolution: "cookie-signature@npm:1.0.7" - checksum: 10/1a62808cd30d15fb43b70e19829b64d04b0802d8ef00275b57d152de4ae6a3208ca05c197b6668d104c4d9de389e53ccc2d3bc6bcaaffd9602461417d8c40710 - languageName: node - linkType: hard - "cookie-signature@npm:^1.2.1, cookie-signature@npm:^1.2.2": version: 1.2.2 resolution: "cookie-signature@npm:1.2.2" @@ -27611,7 +27564,14 @@ __metadata: languageName: node linkType: hard -"cookie@npm:0.7.2, cookie@npm:^0.7.0, cookie@npm:^0.7.1, cookie@npm:^0.7.2, cookie@npm:~0.7.1": +"cookie-signature@npm:~1.0.6, cookie-signature@npm:~1.0.7": + version: 1.0.7 + resolution: "cookie-signature@npm:1.0.7" + checksum: 10/1a62808cd30d15fb43b70e19829b64d04b0802d8ef00275b57d152de4ae6a3208ca05c197b6668d104c4d9de389e53ccc2d3bc6bcaaffd9602461417d8c40710 + languageName: node + linkType: hard + +"cookie@npm:0.7.2, cookie@npm:^0.7.0, cookie@npm:^0.7.1, cookie@npm:^0.7.2, cookie@npm:~0.7.1, cookie@npm:~0.7.2": version: 0.7.2 resolution: "cookie@npm:0.7.2" checksum: 10/24b286c556420d4ba4e9bc09120c9d3db7d28ace2bd0f8ccee82422ce42322f73c8312441271e5eefafbead725980e5996cc02766dbb89a90ac7f5636ede608f @@ -27666,9 +27626,9 @@ __metadata: linkType: hard "core-js@npm:^3.6.5": - version: 3.47.0 - resolution: "core-js@npm:3.47.0" - checksum: 10/c02dc6a091c7e6799e3527dc06a428c44bbcff7f8f6ee700ff818b90aa2ebaf1f17b0234146e692811da97cda5a39a6095ecadec9fd1a74b1135103eb0e96cb1 + version: 3.48.0 + resolution: "core-js@npm:3.48.0" + checksum: 10/08bb3cc9b3225b905e72370c18257a14bb5563946d9eb7496799e0ee4f13231768b980ffe98434df7dbd0f8209bd2c19519938a2fa94846b2c82c2d5aa804037 languageName: node linkType: hard @@ -27687,12 +27647,12 @@ __metadata: linkType: hard "cors@npm:^2.8.4, cors@npm:^2.8.5": - version: 2.8.5 - resolution: "cors@npm:2.8.5" + version: 2.8.6 + resolution: "cors@npm:2.8.6" dependencies: object-assign: "npm:^4" vary: "npm:^1" - checksum: 10/66e88e08edee7cbce9d92b4d28a2028c88772a4c73e02f143ed8ca76789f9b59444eed6b1c167139e76fa662998c151322720093ba229f9941365ada5a6fc2c6 + checksum: 10/aa7174305b21ceb90f9c84f4eaa32f04432d333addbfdc0d1eb7310393c48902e5364aada5ac2f5d054528d63b3179238444475426fcb74e1e345077de485727 languageName: node linkType: hard @@ -28495,7 +28455,7 @@ __metadata: languageName: node linkType: hard -"debug@npm:2.6.9, debug@npm:^2.6.0": +"debug@npm:2.6.9, debug@npm:^2.6.0, debug@npm:~2.6.9": version: 2.6.9 resolution: "debug@npm:2.6.9" dependencies: @@ -28885,9 +28845,9 @@ __metadata: linkType: hard "detect-libc@npm:^2.0.0, detect-libc@npm:^2.0.3": - version: 2.0.3 - resolution: "detect-libc@npm:2.0.3" - checksum: 10/b4ea018d623e077bd395f168a9e81db77370dde36a5b01d067f2ad7989924a81d31cb547ff764acb2aa25d50bb7fdde0b0a93bec02212b0cb430621623246d39 + version: 2.1.2 + resolution: "detect-libc@npm:2.1.2" + checksum: 10/b736c8d97d5d46164c0d1bed53eb4e6a3b1d8530d460211e2d52f1c552875e706c58a5376854e4e54f8b828c9cada58c855288c968522eb93ac7696d65970766 languageName: node linkType: hard @@ -29505,10 +29465,10 @@ __metadata: languageName: node linkType: hard -"electron-to-chromium@npm:^1.5.249": - version: 1.5.263 - resolution: "electron-to-chromium@npm:1.5.263" - checksum: 10/c74c6fedc38a0a5d823f4ed168efb6961972a30df443caa44265c85231087936673cdfbccfa0c14ba6f1a0fd6c634ef43b046fbdd3cdfce6c73523408d86caee +"electron-to-chromium@npm:^1.5.263": + version: 1.5.286 + resolution: "electron-to-chromium@npm:1.5.286" + checksum: 10/530ae36571f3f737431dc1f97ab176d9ec38d78e7a14a78fff78540769ef139e9011200a886864111ee26d64e647136531ff004f368f5df8cdd755c45ad97649 languageName: node linkType: hard @@ -29626,13 +29586,13 @@ __metadata: languageName: node linkType: hard -"enhanced-resolve@npm:^5.17.3, enhanced-resolve@npm:^5.18.0": - version: 5.18.3 - resolution: "enhanced-resolve@npm:5.18.3" +"enhanced-resolve@npm:^5.17.3, enhanced-resolve@npm:^5.17.4, enhanced-resolve@npm:^5.18.0": + version: 5.19.0 + resolution: "enhanced-resolve@npm:5.19.0" dependencies: graceful-fs: "npm:^4.2.4" - tapable: "npm:^2.2.0" - checksum: 10/a4d0a1eacba3079f617b68c8f7e17583c3cbc572055c2edca41c0fa0230a49f6e9b2c6ffd4128cc5f84e15ea6cc313ae2b01e1057fcd252fabef70220a5d9f6a + tapable: "npm:^2.3.0" + checksum: 10/b537d52173bf1ba903c623f96a43ea3b51466ee2b606b2fcca30d73d453fd79c8683dccbb83523de27cd02763c906f11486e2591a4335e6afe49fa5ad6e67b83 languageName: node linkType: hard @@ -29866,6 +29826,13 @@ __metadata: languageName: node linkType: hard +"es-module-lexer@npm:^2.0.0": + version: 2.0.0 + resolution: "es-module-lexer@npm:2.0.0" + checksum: 10/b075855289b5f40ee496f3d7525c5c501d029c3da15c22298a0030d625bf36d1da0768b26278f7f4bada2a602459b505888e20b77c414fba5da5619b0e84dbd1 + languageName: node + linkType: hard + "es-object-atoms@npm:^1.0.0, es-object-atoms@npm:^1.1.1": version: 1.1.1 resolution: "es-object-atoms@npm:1.1.1" @@ -30350,14 +30317,14 @@ __metadata: linkType: hard "eslint-plugin-storybook@npm:^10.2.0-alpha.7": - version: 10.2.0-alpha.7 - resolution: "eslint-plugin-storybook@npm:10.2.0-alpha.7" + version: 10.2.8 + resolution: "eslint-plugin-storybook@npm:10.2.8" dependencies: - "@typescript-eslint/utils": "npm:^8.8.1" + "@typescript-eslint/utils": "npm:^8.48.0" peerDependencies: eslint: ">=8" - storybook: ^10.2.0-alpha.7 - checksum: 10/69e45c19a3d9e83a9e2454382dee4fe8f02ca8708d0bb485eb5ed6f55d1a854b106b9c2c280e56886be97913d8d468fda24e6c147de5a9bd385a3c597f205211 + storybook: ^10.2.8 + checksum: 10/c1d0c6b94a39a6deb1e23dc7ddb48614f7f7a6699600c751ac87b52c852fccb5d396f5937fbe22f72a5eb586bc454c50cbd9eea9e8813a57c5e1550dfa9d82be languageName: node linkType: hard @@ -30603,15 +30570,6 @@ __metadata: languageName: node linkType: hard -"estree-walker@npm:^3.0.3": - version: 3.0.3 - resolution: "estree-walker@npm:3.0.3" - dependencies: - "@types/estree": "npm:^1.0.0" - checksum: 10/a65728d5727b71de172c5df323385755a16c0fdab8234dc756c3854cfee343261ddfbb72a809a5660fac8c75d960bb3e21aa898c2d7e9b19bb298482ca58a3af - languageName: node - linkType: hard - "esutils@npm:^2.0.2": version: 2.0.3 resolution: "esutils@npm:2.0.3" @@ -31075,23 +31033,34 @@ __metadata: languageName: node linkType: hard -"express-session@npm:^1.17.1, express-session@npm:^1.17.3": - version: 1.18.2 - resolution: "express-session@npm:1.18.2" +"express-rate-limit@npm:^8.2.1": + version: 8.2.1 + resolution: "express-rate-limit@npm:8.2.1" dependencies: - cookie: "npm:0.7.2" - cookie-signature: "npm:1.0.7" - debug: "npm:2.6.9" - depd: "npm:~2.0.0" - on-headers: "npm:~1.1.0" - parseurl: "npm:~1.3.3" - safe-buffer: "npm:5.2.1" - uid-safe: "npm:~2.1.5" - checksum: 10/1a89a4d3e579e1d2a729dc604c254c3e942b24a279681371c2d8042b1080f9e6de4ca787a091ec1a9178c9f2cc5c19bcb9f3929632d44db8972263e26c2cc4b8 + ip-address: "npm:10.0.1" + peerDependencies: + express: ">= 4.11" + checksum: 10/7cbf70df2e88e590e463d2d8f93380775b2ea181d97f2c50c2ff9f2c666c247f83109a852b21d9c99ccc5762119101f281f54a27252a2f1a0a918be6d71f955b languageName: node linkType: hard -"express@npm:^4.14.0, express@npm:^4.21.0, express@npm:^4.21.2, express@npm:^4.22.0, express@npm:^4.22.1": +"express-session@npm:^1.17.1, express-session@npm:^1.17.3": + version: 1.19.0 + resolution: "express-session@npm:1.19.0" + dependencies: + cookie: "npm:~0.7.2" + cookie-signature: "npm:~1.0.7" + debug: "npm:~2.6.9" + depd: "npm:~2.0.0" + on-headers: "npm:~1.1.0" + parseurl: "npm:~1.3.3" + safe-buffer: "npm:~5.2.1" + uid-safe: "npm:~2.1.5" + checksum: 10/5f36b51d344ec40adb5b9cd8a915fd694cdaf64832632411d4f6e6de8e9a83d873a20389e9c3cce966fece76a18c0384c5f2763b3ac089f801e8d6e92cb543e6 + languageName: node + linkType: hard + +"express@npm:^4.14.0, express@npm:^4.21.0, express@npm:^4.22.0, express@npm:^4.22.1": version: 4.22.1 resolution: "express@npm:4.22.1" dependencies: @@ -31130,17 +31099,18 @@ __metadata: languageName: node linkType: hard -"express@npm:^5.0.1": - version: 5.1.0 - resolution: "express@npm:5.1.0" +"express@npm:^5.2.1": + version: 5.2.1 + resolution: "express@npm:5.2.1" dependencies: accepts: "npm:^2.0.0" - body-parser: "npm:^2.2.0" + body-parser: "npm:^2.2.1" content-disposition: "npm:^1.0.0" content-type: "npm:^1.0.5" cookie: "npm:^0.7.1" cookie-signature: "npm:^1.2.1" debug: "npm:^4.4.0" + depd: "npm:^2.0.0" encodeurl: "npm:^2.0.0" escape-html: "npm:^1.0.3" etag: "npm:^1.8.1" @@ -31161,7 +31131,7 @@ __metadata: statuses: "npm:^2.0.1" type-is: "npm:^2.0.1" vary: "npm:^1.1.2" - checksum: 10/6dba00bbdf308f43a84ed3f07a7e9870d5208f2a0b8f60f39459dda089750379747819863fad250849d3c9163833f33f94ce69d73938df31e0c5a430800d7e56 + checksum: 10/4aa545d89702ac83f645c77abda1b57bcabe288f0b380fb5580fac4e323ea0eb533005c8e666b4e19152fb16d4abf11ba87b22aa9a10857a0485cd86b94639bd languageName: node linkType: hard @@ -31346,6 +31316,17 @@ __metadata: languageName: node linkType: hard +"fast-xml-parser@npm:^5.3.4": + version: 5.3.5 + resolution: "fast-xml-parser@npm:5.3.5" + dependencies: + strnum: "npm:^2.1.2" + bin: + fxparser: src/cli/cli.js + checksum: 10/913363c2cf9ab8038bd2b666698d99d44b977725f0198f3dfff3a5d34c3109ef49d3a163a0f390f69ed00ad33b81355112dec8be5e79a13f8e6c7aaf146204b8 + languageName: node + linkType: hard + "fastest-stable-stringify@npm:^2.0.2": version: 2.0.2 resolution: "fastest-stable-stringify@npm:2.0.2" @@ -31780,13 +31761,13 @@ __metadata: languageName: node linkType: hard -"follow-redirects@npm:^1.0.0, follow-redirects@npm:^1.15.6": - version: 1.15.6 - resolution: "follow-redirects@npm:1.15.6" +"follow-redirects@npm:^1.0.0, follow-redirects@npm:^1.15.11, follow-redirects@npm:^1.15.6": + version: 1.15.11 + resolution: "follow-redirects@npm:1.15.11" peerDependenciesMeta: debug: optional: true - checksum: 10/70c7612c4cab18e546e36b991bbf8009a1a41cf85354afe04b113d1117569abf760269409cb3eb842d9f7b03d62826687086b081c566ea7b1e6613cf29030bf7 + checksum: 10/07372fd74b98c78cf4d417d68d41fdaa0be4dcacafffb9e67b1e3cf090bc4771515e65020651528faab238f10f9b9c0d9707d6c1574a6c0387c5de1042cde9ba languageName: node linkType: hard @@ -33503,6 +33484,13 @@ __metadata: languageName: node linkType: hard +"hono@npm:^4.11.4": + version: 4.11.7 + resolution: "hono@npm:4.11.7" + checksum: 10/16f5a715f70430bd4050b250207adf7c567774c1d91386d5454577fbc191fc4a50b912628845ce8392fae0e3fd9f364a947412961e3747a9f0b2f714790b738e + languageName: node + linkType: hard + "hookified@npm:^1.10.0": version: 1.12.2 resolution: "hookified@npm:1.12.2" @@ -33945,7 +33933,7 @@ __metadata: languageName: node linkType: hard -"iconv-lite@npm:0.6.3, iconv-lite@npm:^0.6.2, iconv-lite@npm:^0.6.3": +"iconv-lite@npm:0.6.3, iconv-lite@npm:^0.6.2": version: 0.6.3 resolution: "iconv-lite@npm:0.6.3" dependencies: @@ -33954,12 +33942,12 @@ __metadata: languageName: node linkType: hard -"iconv-lite@npm:^0.7.0": - version: 0.7.0 - resolution: "iconv-lite@npm:0.7.0" +"iconv-lite@npm:^0.7.0, iconv-lite@npm:^0.7.2, iconv-lite@npm:~0.7.0": + version: 0.7.2 + resolution: "iconv-lite@npm:0.7.2" dependencies: safer-buffer: "npm:>= 2.1.2 < 3.0.0" - checksum: 10/5bfc897fedfb7e29991ae5ef1c061ed4f864005f8c6d61ef34aba6a3885c04bd207b278c0642b041383aeac2d11645b4319d0ca7b863b0be4be0cde1c9238ca7 + checksum: 10/24c937b532f868e938386b62410b303b7c767ce3d08dc2829cbe59464d5a26ef86ae5ad1af6b34eec43ddfea39e7d101638644b0178d67262fa87015d59f983a languageName: node linkType: hard @@ -34045,7 +34033,7 @@ __metadata: languageName: node linkType: hard -"ignore@npm:^7.0.0": +"ignore@npm:^7.0.5": version: 7.0.5 resolution: "ignore@npm:7.0.5" checksum: 10/f134b96a4de0af419196f52c529d5c6120c4456ff8a6b5a14ceaaa399f883e15d58d2ce651c9b69b9388491d4669dda47285d307e827de9304a53a1824801bc6 @@ -34373,6 +34361,13 @@ __metadata: languageName: node linkType: hard +"ip-address@npm:10.0.1": + version: 10.0.1 + resolution: "ip-address@npm:10.0.1" + checksum: 10/09731acda32cd8e14c46830c137e7e5940f47b36d63ffb87c737331270287d631cf25aa95570907a67d3f919fdb25f4470c404eda21e62f22e0a55927f4dd0fb + languageName: node + linkType: hard + "ip-address@npm:^9.0.5": version: 9.0.5 resolution: "ip-address@npm:9.0.5" @@ -34553,7 +34548,7 @@ __metadata: languageName: node linkType: hard -"is-core-module@npm:^2.13.0, is-core-module@npm:^2.16.0, is-core-module@npm:^2.16.1": +"is-core-module@npm:^2.13.0, is-core-module@npm:^2.16.1": version: 2.16.1 resolution: "is-core-module@npm:2.16.1" dependencies: @@ -35249,8 +35244,8 @@ __metadata: linkType: hard "isomorphic-git@npm:^1.23.0": - version: 1.36.1 - resolution: "isomorphic-git@npm:1.36.1" + version: 1.36.3 + resolution: "isomorphic-git@npm:1.36.3" dependencies: async-lock: "npm:^1.4.1" clean-git-ref: "npm:^2.0.1" @@ -35265,7 +35260,7 @@ __metadata: simple-get: "npm:^4.0.1" bin: isogit: cli.cjs - checksum: 10/f68670b53c5216284afe785f5327dcedffb99dcbe947b338e1f3b20338382506561ef178b77391d2ce95f16912eb8035b2b4d3d52d832cf1cd86ceabc9b9174a + checksum: 10/b6295326773ed3ba4b0f7abb7470c65f11de8b9e19ff0b8e58d85575491a461fae600a579e5de91c15398144eefec3f95c99082ac2c866abbc66e0dd225273c8 languageName: node linkType: hard @@ -36004,7 +35999,7 @@ __metadata: languageName: node linkType: hard -"jose@npm:^6.0.10, jose@npm:^6.1.1": +"jose@npm:^6.0.10, jose@npm:^6.1.3": version: 6.1.3 resolution: "jose@npm:6.1.3" checksum: 10/9626c51e8c3792b505e954f3094698c182208617b62dfb27269230f31e57560b083985ed8128b8a9753aa92daf18d3a2341cc826d149503f14569abe87d42389 @@ -36730,11 +36725,11 @@ __metadata: linkType: hard "keyv@npm:*, keyv@npm:^5.2.1": - version: 5.5.5 - resolution: "keyv@npm:5.5.5" + version: 5.6.0 + resolution: "keyv@npm:5.6.0" dependencies: "@keyv/serialize": "npm:^1.1.1" - checksum: 10/4bbc2119151d67bfc04d3a08fc98f4efac5e171e8c99519fc7bc9ae9e05df4d1c6c835a5d133d563ed109a20db4688f3f9738400cbd3674f6303cdfc4490d429 + checksum: 10/f1de999fdf635d703d091981a0a3844fb20081e01d45c6743ada7d01f3a6570dc47d1882e10d0a98d31075b342db8e62b4ebe4f5bf473dcd0903064d718709c1 languageName: node linkType: hard @@ -36827,8 +36822,8 @@ __metadata: linkType: hard "knip@npm:^5.42.0": - version: 5.82.1 - resolution: "knip@npm:5.82.1" + version: 5.83.1 + resolution: "knip@npm:5.83.1" dependencies: "@nodelib/fs.walk": "npm:^1.2.3" fast-glob: "npm:^3.3.3" @@ -36848,7 +36843,7 @@ __metadata: bin: knip: bin/knip.js knip-bun: bin/knip-bun.js - checksum: 10/e41549af9dc9b8921b393cab881f848ce06c7fd915214cb1806ee01aec7155b4e045684bc8d1a396a588e8fe284693912a50edc5680312b1859a1f949dd4c37a + checksum: 10/d4783b22eacbcb726790211cb6e7cfb966cbb42c4737ae71fbe766523add2e9b8c7eb389a14f9418742d7722f26b107b036c6f0e1af4b56d86a7097f62172a54 languageName: node linkType: hard @@ -36949,12 +36944,12 @@ __metadata: linkType: hard "ldapts@npm:^8.0.6": - version: 8.1.3 - resolution: "ldapts@npm:8.1.3" + version: 8.1.5 + resolution: "ldapts@npm:8.1.5" dependencies: strict-event-emitter-types: "npm:2.0.0" - whatwg-url: "npm:15.1.0" - checksum: 10/8a1071c02e93e6d8530b4d24a5e3e6022d4b84a5b153b86f2cc34be9593ac7b3de9122a681bfc5b700a866de8bc89da23136c9649ae6c99ea4ecfbbb342edc13 + whatwg-url: "npm:16.0.0" + checksum: 10/82805610977948f59f5def1daf7953a69aa0c776b443fbb7bab97dab3d801276f4f859594263a903db064b309a1811c6adfdefdb843e455cdce76da5c66260aa languageName: node linkType: hard @@ -37026,99 +37021,99 @@ __metadata: languageName: node linkType: hard -"lightningcss-android-arm64@npm:1.30.2": - version: 1.30.2 - resolution: "lightningcss-android-arm64@npm:1.30.2" +"lightningcss-android-arm64@npm:1.31.1": + version: 1.31.1 + resolution: "lightningcss-android-arm64@npm:1.31.1" conditions: os=android & cpu=arm64 languageName: node linkType: hard -"lightningcss-darwin-arm64@npm:1.30.2": - version: 1.30.2 - resolution: "lightningcss-darwin-arm64@npm:1.30.2" +"lightningcss-darwin-arm64@npm:1.31.1": + version: 1.31.1 + resolution: "lightningcss-darwin-arm64@npm:1.31.1" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"lightningcss-darwin-x64@npm:1.30.2": - version: 1.30.2 - resolution: "lightningcss-darwin-x64@npm:1.30.2" +"lightningcss-darwin-x64@npm:1.31.1": + version: 1.31.1 + resolution: "lightningcss-darwin-x64@npm:1.31.1" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"lightningcss-freebsd-x64@npm:1.30.2": - version: 1.30.2 - resolution: "lightningcss-freebsd-x64@npm:1.30.2" +"lightningcss-freebsd-x64@npm:1.31.1": + version: 1.31.1 + resolution: "lightningcss-freebsd-x64@npm:1.31.1" conditions: os=freebsd & cpu=x64 languageName: node linkType: hard -"lightningcss-linux-arm-gnueabihf@npm:1.30.2": - version: 1.30.2 - resolution: "lightningcss-linux-arm-gnueabihf@npm:1.30.2" +"lightningcss-linux-arm-gnueabihf@npm:1.31.1": + version: 1.31.1 + resolution: "lightningcss-linux-arm-gnueabihf@npm:1.31.1" conditions: os=linux & cpu=arm languageName: node linkType: hard -"lightningcss-linux-arm64-gnu@npm:1.30.2": - version: 1.30.2 - resolution: "lightningcss-linux-arm64-gnu@npm:1.30.2" +"lightningcss-linux-arm64-gnu@npm:1.31.1": + version: 1.31.1 + resolution: "lightningcss-linux-arm64-gnu@npm:1.31.1" conditions: os=linux & cpu=arm64 & libc=glibc languageName: node linkType: hard -"lightningcss-linux-arm64-musl@npm:1.30.2": - version: 1.30.2 - resolution: "lightningcss-linux-arm64-musl@npm:1.30.2" +"lightningcss-linux-arm64-musl@npm:1.31.1": + version: 1.31.1 + resolution: "lightningcss-linux-arm64-musl@npm:1.31.1" conditions: os=linux & cpu=arm64 & libc=musl languageName: node linkType: hard -"lightningcss-linux-x64-gnu@npm:1.30.2": - version: 1.30.2 - resolution: "lightningcss-linux-x64-gnu@npm:1.30.2" +"lightningcss-linux-x64-gnu@npm:1.31.1": + version: 1.31.1 + resolution: "lightningcss-linux-x64-gnu@npm:1.31.1" conditions: os=linux & cpu=x64 & libc=glibc languageName: node linkType: hard -"lightningcss-linux-x64-musl@npm:1.30.2": - version: 1.30.2 - resolution: "lightningcss-linux-x64-musl@npm:1.30.2" +"lightningcss-linux-x64-musl@npm:1.31.1": + version: 1.31.1 + resolution: "lightningcss-linux-x64-musl@npm:1.31.1" conditions: os=linux & cpu=x64 & libc=musl languageName: node linkType: hard -"lightningcss-win32-arm64-msvc@npm:1.30.2": - version: 1.30.2 - resolution: "lightningcss-win32-arm64-msvc@npm:1.30.2" +"lightningcss-win32-arm64-msvc@npm:1.31.1": + version: 1.31.1 + resolution: "lightningcss-win32-arm64-msvc@npm:1.31.1" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"lightningcss-win32-x64-msvc@npm:1.30.2": - version: 1.30.2 - resolution: "lightningcss-win32-x64-msvc@npm:1.30.2" +"lightningcss-win32-x64-msvc@npm:1.31.1": + version: 1.31.1 + resolution: "lightningcss-win32-x64-msvc@npm:1.31.1" conditions: os=win32 & cpu=x64 languageName: node linkType: hard "lightningcss@npm:^1.29.1": - version: 1.30.2 - resolution: "lightningcss@npm:1.30.2" + version: 1.31.1 + resolution: "lightningcss@npm:1.31.1" dependencies: detect-libc: "npm:^2.0.3" - lightningcss-android-arm64: "npm:1.30.2" - lightningcss-darwin-arm64: "npm:1.30.2" - lightningcss-darwin-x64: "npm:1.30.2" - lightningcss-freebsd-x64: "npm:1.30.2" - lightningcss-linux-arm-gnueabihf: "npm:1.30.2" - lightningcss-linux-arm64-gnu: "npm:1.30.2" - lightningcss-linux-arm64-musl: "npm:1.30.2" - lightningcss-linux-x64-gnu: "npm:1.30.2" - lightningcss-linux-x64-musl: "npm:1.30.2" - lightningcss-win32-arm64-msvc: "npm:1.30.2" - lightningcss-win32-x64-msvc: "npm:1.30.2" + lightningcss-android-arm64: "npm:1.31.1" + lightningcss-darwin-arm64: "npm:1.31.1" + lightningcss-darwin-x64: "npm:1.31.1" + lightningcss-freebsd-x64: "npm:1.31.1" + lightningcss-linux-arm-gnueabihf: "npm:1.31.1" + lightningcss-linux-arm64-gnu: "npm:1.31.1" + lightningcss-linux-arm64-musl: "npm:1.31.1" + lightningcss-linux-x64-gnu: "npm:1.31.1" + lightningcss-linux-x64-musl: "npm:1.31.1" + lightningcss-win32-arm64-msvc: "npm:1.31.1" + lightningcss-win32-x64-msvc: "npm:1.31.1" dependenciesMeta: lightningcss-android-arm64: optional: true @@ -37142,7 +37137,7 @@ __metadata: optional: true lightningcss-win32-x64-msvc: optional: true - checksum: 10/d6cc06d9bac295589a49446e9c45a241dfa16f4f81a7318c26cbc0be3e189003ec0da5d9a0fd9bdffc63a3ce05878cc7329277eaac77a826e8b68c73dc96cfda + checksum: 10/3c2b2c2f648b12d9cba623d2e558f74fcce35911077e3d33f97ed521e0ad7a84e2c814628f6e16f64095c4483f6b180dee7b2e441b3ff5f44d142a510785a0c6 languageName: node linkType: hard @@ -37629,7 +37624,7 @@ __metadata: languageName: node linkType: hard -"lodash@npm:^4.15.0, lodash@npm:^4.16.4, lodash@npm:^4.17.10, lodash@npm:^4.17.11, lodash@npm:^4.17.14, lodash@npm:^4.17.15, lodash@npm:^4.17.20, lodash@npm:^4.17.21, lodash@npm:^4.17.4, lodash@npm:~4.17.15, lodash@npm:~4.17.21": +"lodash@npm:^4.15.0, lodash@npm:^4.16.4, lodash@npm:^4.17.10, lodash@npm:^4.17.11, lodash@npm:^4.17.14, lodash@npm:^4.17.15, lodash@npm:^4.17.20, lodash@npm:^4.17.21, lodash@npm:^4.17.4, lodash@npm:~4.17.15, lodash@npm:~4.17.21, lodash@npm:~4.17.23": version: 4.17.23 resolution: "lodash@npm:4.17.23" checksum: 10/82504c88250f58da7a5a4289f57a4f759c44946c005dd232821c7688b5fcfbf4a6268f6a6cdde4b792c91edd2f3b5398c1d2a0998274432cff76def48735e233 @@ -37733,10 +37728,10 @@ __metadata: languageName: node linkType: hard -"long@npm:^5.0.0, long@npm:^5.2.1": - version: 5.2.3 - resolution: "long@npm:5.2.3" - checksum: 10/9167ec6947a825b827c30da169a7384eec6c0c9ec2f0b9c74da2e93d81159bbe39fb09c3f13dae9721d4b807ccfa09797a7dd1012f5d478e3e33ca3c78b608e6 +"long@npm:^5.0.0, long@npm:^5.3.2": + version: 5.3.2 + resolution: "long@npm:5.3.2" + checksum: 10/b6b55ddae56fcce2864d37119d6b02fe28f6dd6d9e44fd22705f86a9254b9321bd69e9ffe35263b4846d54aba197c64882adcb8c543f2383c1e41284b321ea64 languageName: node linkType: hard @@ -37860,7 +37855,7 @@ __metadata: languageName: node linkType: hard -"lru.min@npm:^1.0.0, lru.min@npm:^1.1.0": +"lru.min@npm:^1.1.0, lru.min@npm:^1.1.3": version: 1.1.3 resolution: "lru.min@npm:1.1.3" checksum: 10/b741bf51e6f2620f35f66657c31a37bb4e6aaa3d7f4dfd8a657cd4e6a4d75be881057d71f54a907a4938d5993677d92cdfa71203054a73af6978514ba73767ee @@ -37874,7 +37869,14 @@ __metadata: languageName: node linkType: hard -"luxon@npm:^3.0.0, luxon@npm:^3.2.1, luxon@npm:^3.4.3, luxon@npm:^3.5.0, luxon@npm:~3.5.0": +"luxon@npm:^3.0.0, luxon@npm:^3.2.1, luxon@npm:^3.4.3, luxon@npm:^3.5.0": + version: 3.7.2 + resolution: "luxon@npm:3.7.2" + checksum: 10/b24cd205ed306ce7415991687897dcc4027921ae413c9116590bc33a95f93b86ce52cf74ba72b4f5c5ab1c10090517f54ac8edfb127c049e0bf55b90dc2260be + languageName: node + linkType: hard + +"luxon@npm:~3.5.0": version: 3.5.0 resolution: "luxon@npm:3.5.0" checksum: 10/48f86e6c1c96815139f8559456a3354a276ba79bcef0ae0d4f2172f7652f3ba2be2237b0e103b8ea0b79b47715354ac9fac04eb1db3485dcc72d5110491dd47f @@ -39649,19 +39651,19 @@ __metadata: linkType: hard "mysql2@npm:^3.0.0": - version: 3.16.1 - resolution: "mysql2@npm:3.16.1" + version: 3.16.2 + resolution: "mysql2@npm:3.16.2" dependencies: - aws-ssl-profiles: "npm:^1.1.1" + aws-ssl-profiles: "npm:^1.1.2" denque: "npm:^2.1.0" generate-function: "npm:^2.3.1" - iconv-lite: "npm:^0.7.0" - long: "npm:^5.2.1" - lru.min: "npm:^1.0.0" + iconv-lite: "npm:^0.7.2" + long: "npm:^5.3.2" + lru.min: "npm:^1.1.3" named-placeholders: "npm:^1.1.6" seq-queue: "npm:^0.0.5" - sqlstring: "npm:^2.3.2" - checksum: 10/c4e61df1e7855161966f2efd83f08322403e876194d9bc514606e1be2a91326e94d7d18b9d398c625df91a5df1e5ba73ff44c2a54c5238e1b04c00b876072215 + sqlstring: "npm:^2.3.3" + checksum: 10/b44cff80bb804b56eec422cce65555ea3879d8bb1ccc0e1e26df09c8300167a123396e8591da09c1f8769d16d498f9aa454d0b0a11e53235cfd403f0f6597ba2 languageName: node linkType: hard @@ -40215,9 +40217,9 @@ __metadata: linkType: hard "nodemailer@npm:^7.0.7": - version: 7.0.12 - resolution: "nodemailer@npm:7.0.12" - checksum: 10/31a2713be588fb6849d05698cb355a88902a64e17e63b1a5c8a10db3acc4349c329c3bbd83bc5bdefda92f8df5e0297364502f93042c0bae87c48e5652b663b7 + version: 7.0.13 + resolution: "nodemailer@npm:7.0.13" + checksum: 10/4ae37bfb6896f1555de150c1098a7c1b28eb1da240a4c7adede81a8af0dcc184298cfbf804930599c076ea574428e0c18c6b28f0dc2072cebb30c1da5fd0b688 languageName: node linkType: hard @@ -41909,10 +41911,10 @@ __metadata: languageName: node linkType: hard -"pg-connection-string@npm:^2.10.1, pg-connection-string@npm:^2.3.0, pg-connection-string@npm:^2.5.0": - version: 2.10.1 - resolution: "pg-connection-string@npm:2.10.1" - checksum: 10/8785cfac30f64a48f47031c24d7c5c53241fabb336d5be8f30ca06af0e16aea8d9647b645b4b44ed931717a47a0afb95ddb57e60b6af103767a4d8606dec22dc +"pg-connection-string@npm:^2.11.0, pg-connection-string@npm:^2.3.0, pg-connection-string@npm:^2.5.0": + version: 2.11.0 + resolution: "pg-connection-string@npm:2.11.0" + checksum: 10/0333bb1b7ddeac6fa5262920f82a983222c600d21ef14fdc5254b0d3cbb1763030d20c1e8e3c20fa767a6eda8f4b4773550954c06f3e072e5288b6fa9e9cae13 languageName: node linkType: hard @@ -41960,11 +41962,11 @@ __metadata: linkType: hard "pg@npm:^8.11.3, pg@npm:^8.9.0": - version: 8.17.2 - resolution: "pg@npm:8.17.2" + version: 8.18.0 + resolution: "pg@npm:8.18.0" dependencies: pg-cloudflare: "npm:^1.3.0" - pg-connection-string: "npm:^2.10.1" + pg-connection-string: "npm:^2.11.0" pg-pool: "npm:^3.11.0" pg-protocol: "npm:^1.11.0" pg-types: "npm:2.2.0" @@ -41977,7 +41979,7 @@ __metadata: peerDependenciesMeta: pg-native: optional: true - checksum: 10/0f0b70f1310791b263f970f8235ab054de26a94861e73727def8df1b976ab9dda7e9c34ecffb78260fe8569521798f8e811da6369b79601023a07ea0f5e7167a + checksum: 10/91c622f179f60df08ab7aa9b05a890567ea47f2d7984377b64e88e1eba1c42787324b7fc5ff00e109a757f3329dc4b57c73502603ae2765d1827b2082abbdcfa languageName: node linkType: hard @@ -42196,27 +42198,27 @@ __metadata: languageName: node linkType: hard -"playwright-core@npm:1.57.0": - version: 1.57.0 - resolution: "playwright-core@npm:1.57.0" +"playwright-core@npm:1.58.2": + version: 1.58.2 + resolution: "playwright-core@npm:1.58.2" bin: playwright-core: cli.js - checksum: 10/ec066602f0196f036006caee14a30d0a57533a76673bb9a0c609ef56e21decf018f0e8d402ba2fb18251393be6a1c9e193c83266f1670fe50838c5340e220de0 + checksum: 10/8a98fcf122167e8703d525db2252de0e3da4ab9110ab6ea9951247e52d846310eb25ea2c805e1b7ccb54b4010c44e5adc3a76aae6da02f34324ccc3e76683bb1 languageName: node linkType: hard -"playwright@npm:1.57.0": - version: 1.57.0 - resolution: "playwright@npm:1.57.0" +"playwright@npm:1.58.2": + version: 1.58.2 + resolution: "playwright@npm:1.58.2" dependencies: fsevents: "npm:2.3.2" - playwright-core: "npm:1.57.0" + playwright-core: "npm:1.58.2" dependenciesMeta: fsevents: optional: true bin: playwright: cli.js - checksum: 10/241559210f98ef11b6bd6413f2d29da7ef67c7865b72053192f0d164fab9e0d3bd47913b3351d5de6433a8aff2d8424d4b8bd668df420bf4dda7ae9fcd37b942 + checksum: 10/d89d6c8a32388911b9aff9ee0f1a90076219f15c804f2b287db048b9e9cde182aea3131fac1959051d25189ed4218ec4272b137c83cd7f9cd24781cbc77edd86 languageName: node linkType: hard @@ -43496,15 +43498,15 @@ __metadata: languageName: node linkType: hard -"raw-body@npm:^3.0.0": - version: 3.0.0 - resolution: "raw-body@npm:3.0.0" +"raw-body@npm:^3.0.0, raw-body@npm:^3.0.1": + version: 3.0.2 + resolution: "raw-body@npm:3.0.2" dependencies: - bytes: "npm:3.1.2" - http-errors: "npm:2.0.0" - iconv-lite: "npm:0.6.3" - unpipe: "npm:1.0.0" - checksum: 10/2443429bbb2f9ae5c50d3d2a6c342533dfbde6b3173740b70fa0302b30914ff400c6d31a46b3ceacbe7d0925dc07d4413928278b494b04a65736fc17ca33e30c + bytes: "npm:~3.1.2" + http-errors: "npm:~2.0.1" + iconv-lite: "npm:~0.7.0" + unpipe: "npm:~1.0.0" + checksum: 10/4168c82157bd69175d5bd960e59b74e253e237b358213694946a427a6f750a18b8e150f036fed3421b3e83294b071a4e2bb01037a79ccacdac05360c63d3ebba languageName: node linkType: hard @@ -45061,15 +45063,15 @@ __metadata: linkType: hard "resolve@npm:^1.1.6, resolve@npm:^1.17.0, resolve@npm:^1.19.0, resolve@npm:^1.20.0, resolve@npm:^1.22.1, resolve@npm:^1.22.10, resolve@npm:^1.22.4, resolve@npm:^1.22.8, resolve@npm:~1.22.1, resolve@npm:~1.22.2": - version: 1.22.10 - resolution: "resolve@npm:1.22.10" + version: 1.22.11 + resolution: "resolve@npm:1.22.11" dependencies: - is-core-module: "npm:^2.16.0" + is-core-module: "npm:^2.16.1" path-parse: "npm:^1.0.7" supports-preserve-symlinks-flag: "npm:^1.0.0" bin: resolve: bin/resolve - checksum: 10/0a398b44da5c05e6e421d70108822c327675febb880eebe905587628de401854c61d5df02866ff34fc4cb1173a51c9f0e84a94702738df3611a62e2acdc68181 + checksum: 10/e1b2e738884a08de03f97ee71494335eba8c2b0feb1de9ae065e82c48997f349f77a2b10e8817e147cf610bfabc4b1cb7891ee8eaf5bf80d4ad514a34c4fab0a languageName: node linkType: hard @@ -45100,15 +45102,15 @@ __metadata: linkType: hard "resolve@patch:resolve@npm%3A^1.1.6#optional!builtin, resolve@patch:resolve@npm%3A^1.17.0#optional!builtin, resolve@patch:resolve@npm%3A^1.19.0#optional!builtin, resolve@patch:resolve@npm%3A^1.20.0#optional!builtin, resolve@patch:resolve@npm%3A^1.22.1#optional!builtin, resolve@patch:resolve@npm%3A^1.22.10#optional!builtin, resolve@patch:resolve@npm%3A^1.22.4#optional!builtin, resolve@patch:resolve@npm%3A^1.22.8#optional!builtin, resolve@patch:resolve@npm%3A~1.22.1#optional!builtin, resolve@patch:resolve@npm%3A~1.22.2#optional!builtin": - version: 1.22.10 - resolution: "resolve@patch:resolve@npm%3A1.22.10#optional!builtin::version=1.22.10&hash=c3c19d" + version: 1.22.11 + resolution: "resolve@patch:resolve@npm%3A1.22.11#optional!builtin::version=1.22.11&hash=c3c19d" dependencies: - is-core-module: "npm:^2.16.0" + is-core-module: "npm:^2.16.1" path-parse: "npm:^1.0.7" supports-preserve-symlinks-flag: "npm:^1.0.0" bin: resolve: bin/resolve - checksum: 10/d4d878bfe3702d215ea23e75e0e9caf99468e3db76f5ca100d27ebdc527366fee3877e54bce7d47cc72ca8952fc2782a070d238bfa79a550eeb0082384c3b81a + checksum: 10/fd342cad25e52cd6f4f3d1716e189717f2522bfd6641109fe7aa372f32b5714a296ed7c238ddbe7ebb0c1ddfe0b7f71c9984171024c97cf1b2073e3e40ff71a8 languageName: node linkType: hard @@ -45660,7 +45662,7 @@ __metadata: languageName: node linkType: hard -"safe-buffer@npm:5.2.1, safe-buffer@npm:>=5.1.0, safe-buffer@npm:^5.0.1, safe-buffer@npm:^5.1.0, safe-buffer@npm:^5.1.1, safe-buffer@npm:^5.1.2, safe-buffer@npm:^5.2.1, safe-buffer@npm:~5.2.0": +"safe-buffer@npm:5.2.1, safe-buffer@npm:>=5.1.0, safe-buffer@npm:^5.0.1, safe-buffer@npm:^5.1.0, safe-buffer@npm:^5.1.1, safe-buffer@npm:^5.1.2, safe-buffer@npm:^5.2.1, safe-buffer@npm:~5.2.0, safe-buffer@npm:~5.2.1": version: 5.2.1 resolution: "safe-buffer@npm:5.2.1" checksum: 10/32872cd0ff68a3ddade7a7617b8f4c2ae8764d8b7d884c651b74457967a9e0e886267d3ecc781220629c44a865167b61c375d2da6c720c840ecd73f45d5d9451 @@ -45957,7 +45959,7 @@ __metadata: languageName: node linkType: hard -"semver@npm:^7.0.0, semver@npm:^7.1.1, semver@npm:^7.1.2, semver@npm:^7.1.3, semver@npm:^7.3.2, semver@npm:^7.3.4, semver@npm:^7.3.5, semver@npm:^7.3.8, semver@npm:^7.5.3, semver@npm:^7.5.4, semver@npm:^7.6.0, semver@npm:^7.6.2, semver@npm:^7.7.2, semver@npm:^7.7.3": +"semver@npm:^7.0.0, semver@npm:^7.1.1, semver@npm:^7.1.2, semver@npm:^7.1.3, semver@npm:^7.3.2, semver@npm:^7.3.4, semver@npm:^7.3.5, semver@npm:^7.3.8, semver@npm:^7.5.3, semver@npm:^7.5.4, semver@npm:^7.6.0, semver@npm:^7.7.2, semver@npm:^7.7.3": version: 7.7.3 resolution: "semver@npm:7.7.3" bin: @@ -46852,10 +46854,10 @@ __metadata: languageName: node linkType: hard -"sqlstring@npm:^2.3.2": - version: 2.3.2 - resolution: "sqlstring@npm:2.3.2" - checksum: 10/56fd2851ce6054f1185722bf7da4dbbd1ed24af64073ce58f142d5f6c62451d4a6dbad80999880debcdf764b37340f8f93155d641983e619a13abe5531849255 +"sqlstring@npm:^2.3.3": + version: 2.3.3 + resolution: "sqlstring@npm:2.3.3" + checksum: 10/4e5a25af2d77a031fe00694034bf9fd822ddc3a483c9383124b120aa6b9ae9ab71e173cd29fba9c653998ebfef9e97be668957839960b9b3dc1afcb45f1ddb64 languageName: node linkType: hard @@ -47037,11 +47039,11 @@ __metadata: linkType: hard "storybook@npm:^10.2.0-alpha.7": - version: 10.2.0-alpha.8 - resolution: "storybook@npm:10.2.0-alpha.8" + version: 10.2.8 + resolution: "storybook@npm:10.2.8" dependencies: "@storybook/global": "npm:^5.0.0" - "@storybook/icons": "npm:^2.0.0" + "@storybook/icons": "npm:^2.0.1" "@testing-library/jest-dom": "npm:^6.6.3" "@testing-library/user-event": "npm:^14.6.1" "@vitest/expect": "npm:3.2.4" @@ -47049,7 +47051,7 @@ __metadata: esbuild: "npm:^0.18.0 || ^0.19.0 || ^0.20.0 || ^0.21.0 || ^0.22.0 || ^0.23.0 || ^0.24.0 || ^0.25.0 || ^0.26.0 || ^0.27.0" open: "npm:^10.2.0" recast: "npm:^0.23.5" - semver: "npm:^7.6.2" + semver: "npm:^7.7.3" use-sync-external-store: "npm:^1.5.0" ws: "npm:^8.18.0" peerDependencies: @@ -47059,7 +47061,7 @@ __metadata: optional: true bin: storybook: ./dist/bin/dispatcher.js - checksum: 10/bf7c2797b832ccb21efa68ae901ca3202e572762bd66b4a51ae2b2505dcc259402b7c81363b67675a7c81086bb90ca6e234965e10c4237f5cea1ab6739c88f39 + checksum: 10/2a401ee42c303f44199f0bb5be2983a22c0a3c8962cba31401bb6a3f75eefc909238c32d4a2bc2040df853f4f813432c9e6ac7223740cdc7d4e83b5f76c3c2cd languageName: node linkType: hard @@ -47512,10 +47514,10 @@ __metadata: languageName: node linkType: hard -"strnum@npm:^2.1.0": - version: 2.1.1 - resolution: "strnum@npm:2.1.1" - checksum: 10/d5fe6e4333cddc17569331048e403e876ffcf629989815f0359b0caf05dae9441b7eef3d7dd07427313ac8b3f05a8f60abc1f61efc15f97245dbc24028362bc9 +"strnum@npm:^2.1.0, strnum@npm:^2.1.2": + version: 2.1.2 + resolution: "strnum@npm:2.1.2" + checksum: 10/7d894dff385e3a5c5b29c012cf0a7ea7962a92c6a299383c3d6db945ad2b6f3e770511356a9774dbd54444c56af1dc7c435dad6466c47293c48173274dd6c631 languageName: node linkType: hard @@ -47836,14 +47838,14 @@ __metadata: linkType: hard "swr@npm:^2.0.0, swr@npm:^2.2.5": - version: 2.3.8 - resolution: "swr@npm:2.3.8" + version: 2.4.0 + resolution: "swr@npm:2.4.0" dependencies: dequal: "npm:^2.0.3" use-sync-external-store: "npm:^1.6.0" peerDependencies: react: ^16.11.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - checksum: 10/fc4c992902da13bc2c82f066131cdf0b73147d6a590984c0b746704ad7ac8e40ac72afab679c47ad3abc7c09789a31964ffbb963904ec6c29e650790991b0eac + checksum: 10/3536db25748b49659d87450ed40e391b0a8c2cfe387e41224ee505a18ae739477bd60caba1d8ff7bd961db923cf3d6771e4aee13de822855436a7bca9e343ccc languageName: node linkType: hard @@ -47952,15 +47954,15 @@ __metadata: linkType: hard "tar@npm:^7.4.3, tar@npm:^7.5.6": - version: 7.5.6 - resolution: "tar@npm:7.5.6" + version: 7.5.7 + resolution: "tar@npm:7.5.7" dependencies: "@isaacs/fs-minipass": "npm:^4.0.0" chownr: "npm:^3.0.0" minipass: "npm:^7.1.2" minizlib: "npm:^3.1.0" yallist: "npm:^5.0.0" - checksum: 10/cf4a84d79b9327fcf765f2ea16de4702b9b8dd7dc6b1840b16e0f999628d96b81b2c7efbf83d4eb42b0164856f1db887a5a61ffef97d36cdb77cac742219f9ee + checksum: 10/0d6938dd32fe5c0f17c8098d92bd9889ee0ed9d11f12381b8146b6e8c87bb5aa49feec7abc42463f0597503d8e89e4c4c0b42bff1a5a38444e918b4878b7fd21 languageName: node linkType: hard @@ -48061,7 +48063,7 @@ __metadata: languageName: node linkType: hard -"terser-webpack-plugin@npm:*, terser-webpack-plugin@npm:^5.1.3, terser-webpack-plugin@npm:^5.3.11": +"terser-webpack-plugin@npm:*, terser-webpack-plugin@npm:^5.1.3, terser-webpack-plugin@npm:^5.3.11, terser-webpack-plugin@npm:^5.3.16": version: 5.3.16 resolution: "terser-webpack-plugin@npm:5.3.16" dependencies: @@ -48606,7 +48608,7 @@ __metadata: languageName: node linkType: hard -"ts-api-utils@npm:^2.1.0, ts-api-utils@npm:^2.4.0": +"ts-api-utils@npm:^2.4.0": version: 2.4.0 resolution: "ts-api-utils@npm:2.4.0" peerDependencies: @@ -48939,7 +48941,7 @@ __metadata: languageName: node linkType: hard -"type-is@npm:^2.0.0, type-is@npm:^2.0.1": +"type-is@npm:^2.0.1": version: 2.0.1 resolution: "type-is@npm:2.0.1" dependencies: @@ -49311,9 +49313,9 @@ __metadata: linkType: hard "undici@npm:^7.16.0, undici@npm:^7.2.3": - version: 7.19.0 - resolution: "undici@npm:7.19.0" - checksum: 10/5a60b11ed23b2eea74e71123595ffe2b91005b80295051e1ba89119ee9b547ea09c395fd992d7609e0507452177853a8c0405d1a9e7938b2e17292b7aeaba6b0 + version: 7.20.0 + resolution: "undici@npm:7.20.0" + checksum: 10/09ca3e1255cf05f3c76e6dff2ae760131ea5bba57290b9b184bd94f5167939548e7ea73292c524c25eb91f5a2152623394d4c6124e222d34fcd53ef733c6b156 languageName: node linkType: hard @@ -49532,7 +49534,7 @@ __metadata: languageName: node linkType: hard -"unpipe@npm:1.0.0, unpipe@npm:~1.0.0": +"unpipe@npm:~1.0.0": version: 1.0.0 resolution: "unpipe@npm:1.0.0" checksum: 10/4fa18d8d8d977c55cb09715385c203197105e10a6d220087ec819f50cb68870f02942244f1017565484237f1f8c5d3cd413631b1ae104d3096f24fdfde1b4aa2 @@ -49649,9 +49651,9 @@ __metadata: languageName: node linkType: hard -"update-browserslist-db@npm:^1.1.4": - version: 1.1.4 - resolution: "update-browserslist-db@npm:1.1.4" +"update-browserslist-db@npm:^1.2.0": + version: 1.2.3 + resolution: "update-browserslist-db@npm:1.2.3" dependencies: escalade: "npm:^3.2.0" picocolors: "npm:^1.1.1" @@ -49659,7 +49661,7 @@ __metadata: browserslist: ">= 4.21.0" bin: update-browserslist-db: cli.js - checksum: 10/79b2c0a31e9b837b49dc55d5cb7b77f44a69502847c7be352a44b1d35ac2032bf0e1bb7543f992809ed427bf9d32aa3f7ad41cef96198fa959c1666870174c06 + checksum: 10/059f774300efb4b084a49293143c511f3ae946d40397b5c30914e900cd5691a12b8e61b41dd54ed73d3b56c8204165a0333107dd784ccf8f8c81790bcc423175 languageName: node linkType: hard @@ -50228,14 +50230,14 @@ __metadata: linkType: hard "vm2@npm:^3.10.0": - version: 3.10.0 - resolution: "vm2@npm:3.10.0" + version: 3.10.3 + resolution: "vm2@npm:3.10.3" dependencies: acorn: "npm:^8.14.1" acorn-walk: "npm:^8.3.4" bin: vm2: bin/vm2 - checksum: 10/ba8000037f2bed73aef6271a6a65a5db1c5d40046b920bc495a871fbeb3869908628e4e50feb1ec005bb43a17bd04fcf90638cff7db29ff2cb8070d879e61f18 + checksum: 10/015edd8adda9530b081dacc0eff1e1c7118a03a204337b7ab4b708f435c625aedb0b95637a171fe1022b434ca655dc2b92372784b2c26347d3fc57264fab5824 languageName: node linkType: hard @@ -50382,10 +50384,10 @@ __metadata: languageName: node linkType: hard -"webidl-conversions@npm:^8.0.0": - version: 8.0.0 - resolution: "webidl-conversions@npm:8.0.0" - checksum: 10/8138d1b291c8f311d93de680653b13b04560aa35d83f9606642e746fca39d7dab9cddd9282ade21774115ea332b8b11f008106b82d4a0125e98a49479381aeee +"webidl-conversions@npm:^8.0.0, webidl-conversions@npm:^8.0.1": + version: 8.0.1 + resolution: "webidl-conversions@npm:8.0.1" + checksum: 10/0f7007311f1fc257a8e406dd236f13b61fb57cf0fddb476aec33457d2d0add2d012d6df0eeb00934399238e3f3b9dad30f59dc6ac83024ae0ebd5a518bf365e8 languageName: node linkType: hard @@ -50408,51 +50410,6 @@ __metadata: languageName: node linkType: hard -"webpack-dev-server@npm:5.2.2": - version: 5.2.2 - resolution: "webpack-dev-server@npm:5.2.2" - dependencies: - "@types/bonjour": "npm:^3.5.13" - "@types/connect-history-api-fallback": "npm:^1.5.4" - "@types/express": "npm:^4.17.21" - "@types/express-serve-static-core": "npm:^4.17.21" - "@types/serve-index": "npm:^1.9.4" - "@types/serve-static": "npm:^1.15.5" - "@types/sockjs": "npm:^0.3.36" - "@types/ws": "npm:^8.5.10" - ansi-html-community: "npm:^0.0.8" - bonjour-service: "npm:^1.2.1" - chokidar: "npm:^3.6.0" - colorette: "npm:^2.0.10" - compression: "npm:^1.7.4" - connect-history-api-fallback: "npm:^2.0.0" - express: "npm:^4.21.2" - graceful-fs: "npm:^4.2.6" - http-proxy-middleware: "npm:^2.0.9" - ipaddr.js: "npm:^2.1.0" - launch-editor: "npm:^2.6.1" - open: "npm:^10.0.3" - p-retry: "npm:^6.2.0" - schema-utils: "npm:^4.2.0" - selfsigned: "npm:^2.4.1" - serve-index: "npm:^1.9.1" - sockjs: "npm:^0.3.24" - spdy: "npm:^4.0.2" - webpack-dev-middleware: "npm:^7.4.2" - ws: "npm:^8.18.0" - peerDependencies: - webpack: ^5.0.0 - peerDependenciesMeta: - webpack: - optional: true - webpack-cli: - optional: true - bin: - webpack-dev-server: bin/webpack-dev-server.js - checksum: 10/59517409cd38c01a875a03b9658f3d20d492b5b8bead9ded4a0f3d33e6857daf2d352fe89f0181dcaea6d0fbe84b0494cb4750a87120fe81cdbb3c32b499451c - languageName: node - linkType: hard - "webpack-dev-server@npm:^5.0.0": version: 5.2.3 resolution: "webpack-dev-server@npm:5.2.3" @@ -50522,7 +50479,45 @@ __metadata: languageName: node linkType: hard -"webpack@npm:^5, webpack@npm:~5.103.0": +"webpack@npm:^5": + version: 5.104.1 + resolution: "webpack@npm:5.104.1" + dependencies: + "@types/eslint-scope": "npm:^3.7.7" + "@types/estree": "npm:^1.0.8" + "@types/json-schema": "npm:^7.0.15" + "@webassemblyjs/ast": "npm:^1.14.1" + "@webassemblyjs/wasm-edit": "npm:^1.14.1" + "@webassemblyjs/wasm-parser": "npm:^1.14.1" + acorn: "npm:^8.15.0" + acorn-import-phases: "npm:^1.0.3" + browserslist: "npm:^4.28.1" + chrome-trace-event: "npm:^1.0.2" + enhanced-resolve: "npm:^5.17.4" + es-module-lexer: "npm:^2.0.0" + eslint-scope: "npm:5.1.1" + events: "npm:^3.2.0" + glob-to-regexp: "npm:^0.4.1" + graceful-fs: "npm:^4.2.11" + json-parse-even-better-errors: "npm:^2.3.1" + loader-runner: "npm:^4.3.1" + mime-types: "npm:^2.1.27" + neo-async: "npm:^2.6.2" + schema-utils: "npm:^4.3.3" + tapable: "npm:^2.3.0" + terser-webpack-plugin: "npm:^5.3.16" + watchpack: "npm:^2.4.4" + webpack-sources: "npm:^3.3.3" + peerDependenciesMeta: + webpack-cli: + optional: true + bin: + webpack: bin/webpack.js + checksum: 10/c22b58fdf41d993971516154cb621d13b7b61dd744b7e2c6be972e9afcc9942694a8aaa322c07fba46448c69d663023ff53d0aeeb00eb0b125d83ace5ca8fa3c + languageName: node + linkType: hard + +"webpack@npm:~5.103.0": version: 5.103.0 resolution: "webpack@npm:5.103.0" dependencies: @@ -50601,13 +50596,14 @@ __metadata: languageName: node linkType: hard -"whatwg-url@npm:15.1.0, whatwg-url@npm:^15.0.0, whatwg-url@npm:^15.1.0": - version: 15.1.0 - resolution: "whatwg-url@npm:15.1.0" +"whatwg-url@npm:16.0.0": + version: 16.0.0 + resolution: "whatwg-url@npm:16.0.0" dependencies: + "@exodus/bytes": "npm:^1.11.0" tr46: "npm:^6.0.0" - webidl-conversions: "npm:^8.0.0" - checksum: 10/9ae5ce70060f2a9ea73799062af6e796ec2477f44bf1a886953b405700e3ab11d15aa0fe7088c4215f839e56a845d5d1c44584ed292a832837a8c8549c566886 + webidl-conversions: "npm:^8.0.1" + checksum: 10/f57a668adcd98fc21a8da88905ac23da3feba2aea2fb484caab20980504a32c16fd9e3c3313131eacade802505118967631cea3e48e5c3c272ba76521babe355 languageName: node linkType: hard @@ -50621,6 +50617,16 @@ __metadata: languageName: node linkType: hard +"whatwg-url@npm:^15.0.0, whatwg-url@npm:^15.1.0": + version: 15.1.0 + resolution: "whatwg-url@npm:15.1.0" + dependencies: + tr46: "npm:^6.0.0" + webidl-conversions: "npm:^8.0.0" + checksum: 10/9ae5ce70060f2a9ea73799062af6e796ec2477f44bf1a886953b405700e3ab11d15aa0fe7088c4215f839e56a845d5d1c44584ed292a832837a8c8549c566886 + languageName: node + linkType: hard + "whatwg-url@npm:^5.0.0": version: 5.0.0 resolution: "whatwg-url@npm:5.0.0" @@ -50688,8 +50694,8 @@ __metadata: linkType: hard "which-typed-array@npm:^1.1.13, which-typed-array@npm:^1.1.16, which-typed-array@npm:^1.1.19, which-typed-array@npm:^1.1.2": - version: 1.1.19 - resolution: "which-typed-array@npm:1.1.19" + version: 1.1.20 + resolution: "which-typed-array@npm:1.1.20" dependencies: available-typed-arrays: "npm:^1.0.7" call-bind: "npm:^1.0.8" @@ -50698,7 +50704,7 @@ __metadata: get-proto: "npm:^1.0.1" gopd: "npm:^1.2.0" has-tostringtag: "npm:^1.0.2" - checksum: 10/12be30fb88567f9863186bee1777f11bea09dd59ed8b3ce4afa7dd5cade75e2f4cc56191a2da165113cc7cf79987ba021dac1e22b5b62aa7e5c56949f2469a68 + checksum: 10/e56da3fc995d330ff012f682476f7883c16b12d36c6717c87c7ca23eb5a5ef957fa89115dacb389b11a9b4e99d5dbe2d12689b4d5d08c050b5aed0eae385b840 languageName: node linkType: hard @@ -51274,7 +51280,7 @@ __metadata: languageName: node linkType: hard -"zod-to-json-schema@npm:^3.25.0, zod-to-json-schema@npm:^3.25.1": +"zod-to-json-schema@npm:^3.25.1": version: 3.25.1 resolution: "zod-to-json-schema@npm:3.25.1" peerDependencies: @@ -51300,9 +51306,9 @@ __metadata: linkType: hard "zod@npm:^3.25 || ^4.0, zod@npm:^4.1.11": - version: 4.1.13 - resolution: "zod@npm:4.1.13" - checksum: 10/0679190318928f69fcb07751063719de232c663b13955fcdb55db59839569d39f3f29b955cb0cba7af0b724233f88c06b3e84c550397ad4e68f8088fa6799d88 + version: 4.3.6 + resolution: "zod@npm:4.3.6" + checksum: 10/25fc0f62e01b557b4644bf0b393bbaf47542ab30877c37837ea8caf314a8713d220c7d7fe51f68ffa72f0e1018ddfa34d96f1973d23033f5a2a5a9b6b9d9da01 languageName: node linkType: hard From b377707685bf6811a007c2a0617ea0f79d8f7b7b Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Thu, 12 Feb 2026 23:38:34 +0100 Subject: [PATCH 16/17] yarn.lock: resolve latest conflict Signed-off-by: Patrik Oldsberg --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 1531d505eb..c464e325b4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9107,9 +9107,9 @@ __metadata: linkType: hard "@faker-js/faker@npm:^10.0.0": - version: 10.2.0 - resolution: "@faker-js/faker@npm:10.2.0" - checksum: 10/5b1b9690ff3339405cf32e2a1ae6f98305ffd118fb84c2d16daae7f2759408cba1e4f264ba95a7e5fb473a07fd492e4077ec38f0280baddcb43f901fa5653a5c + version: 10.3.0 + resolution: "@faker-js/faker@npm:10.3.0" + checksum: 10/ae06502156d918beed43bc939ad4a2b2b4696c5335ac6cfa52290cee23ffbcc4967c69a149118b3ec5c44d8cd7da690851fea4a93467e02d91b5281e3a6a8b60 languageName: node linkType: hard From a326fe580ebd20dc6c397574e220a0230600c24c Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Fri, 13 Feb 2026 00:26:54 +0100 Subject: [PATCH 17/17] module-federation-common: fix RR dep Signed-off-by: Patrik Oldsberg --- packages/module-federation-common/package.json | 6 +++--- yarn.lock | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/module-federation-common/package.json b/packages/module-federation-common/package.json index 31a03b686f..dfed332525 100644 --- a/packages/module-federation-common/package.json +++ b/packages/module-federation-common/package.json @@ -47,7 +47,7 @@ "@types/react": "^18.0.0", "react": "^18.0.2", "react-dom": "^18.0.2", - "react-router-dom": "^6.3.0" + "react-router-dom": "^6.30.2" }, "peerDependencies": { "@emotion/react": "^11.10.5", @@ -57,8 +57,8 @@ "@types/react": "^17.0.0 || ^18.0.0", "react": "^17.0.0 || ^18.0.0", "react-dom": "^17.0.0 || ^18.0.0", - "react-router": "^6.3.0", - "react-router-dom": "^6.3.0" + "react-router": "^6.30.2", + "react-router-dom": "^6.30.2" }, "peerDependenciesMeta": { "@types/react": { diff --git a/yarn.lock b/yarn.lock index c582548556..bc198d3dbc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4095,7 +4095,7 @@ __metadata: "@types/react": "npm:^18.0.0" react: "npm:^18.0.2" react-dom: "npm:^18.0.2" - react-router-dom: "npm:^6.3.0" + react-router-dom: "npm:^6.30.2" peerDependencies: "@emotion/react": ^11.10.5 "@material-ui/core": ^4.12.2 @@ -4104,8 +4104,8 @@ __metadata: "@types/react": ^17.0.0 || ^18.0.0 react: ^17.0.0 || ^18.0.0 react-dom: ^17.0.0 || ^18.0.0 - react-router: ^6.3.0 - react-router-dom: ^6.3.0 + react-router: ^6.30.2 + react-router-dom: ^6.30.2 peerDependenciesMeta: "@types/react": optional: true @@ -44523,7 +44523,7 @@ __metadata: languageName: node linkType: hard -"react-router-dom@npm:^6.3.0, react-router-dom@npm:^6.30.2": +"react-router-dom@npm:^6.30.2": version: 6.30.3 resolution: "react-router-dom@npm:6.30.3" dependencies: