create-interview-cockpit 0.16.0 → 0.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/template/client/package-lock.json +75 -2
- package/template/client/package.json +3 -1
- package/template/client/src/browserSecurityTemplates.ts +75 -72
- package/template/client/src/components/CodeRunnerModal.tsx +406 -22
- package/template/client/src/reactLab.ts +374 -152
- package/template/cockpit.json +1 -1
- package/template/server/src/index.ts +134 -47
package/package.json
CHANGED
|
@@ -7,7 +7,9 @@
|
|
|
7
7
|
"name": "interview-cockpit-client",
|
|
8
8
|
"dependencies": {
|
|
9
9
|
"@ai-sdk/react": "^3.0.170",
|
|
10
|
+
"@monaco-editor/react": "^4.7.0",
|
|
10
11
|
"@types/prismjs": "^1.26.6",
|
|
12
|
+
"@typescript/ata": "^0.9.8",
|
|
11
13
|
"ai": "^6.0.168",
|
|
12
14
|
"lucide-react": "^0.460.0",
|
|
13
15
|
"mermaid": "^11.4.0",
|
|
@@ -32,7 +34,7 @@
|
|
|
32
34
|
"autoprefixer": "^10.4.0",
|
|
33
35
|
"postcss": "^8.4.0",
|
|
34
36
|
"tailwindcss": "^3.4.0",
|
|
35
|
-
"typescript": "^5.
|
|
37
|
+
"typescript": "^5.9.3",
|
|
36
38
|
"vite": "^6.0.0"
|
|
37
39
|
}
|
|
38
40
|
},
|
|
@@ -978,6 +980,29 @@
|
|
|
978
980
|
"langium": "^4.0.0"
|
|
979
981
|
}
|
|
980
982
|
},
|
|
983
|
+
"node_modules/@monaco-editor/loader": {
|
|
984
|
+
"version": "1.7.0",
|
|
985
|
+
"resolved": "https://registry.npmjs.org/@monaco-editor/loader/-/loader-1.7.0.tgz",
|
|
986
|
+
"integrity": "sha512-gIwR1HrJrrx+vfyOhYmCZ0/JcWqG5kbfG7+d3f/C1LXk2EvzAbHSg3MQ5lO2sMlo9izoAZ04shohfKLVT6crVA==",
|
|
987
|
+
"license": "MIT",
|
|
988
|
+
"dependencies": {
|
|
989
|
+
"state-local": "^1.0.6"
|
|
990
|
+
}
|
|
991
|
+
},
|
|
992
|
+
"node_modules/@monaco-editor/react": {
|
|
993
|
+
"version": "4.7.0",
|
|
994
|
+
"resolved": "https://registry.npmjs.org/@monaco-editor/react/-/react-4.7.0.tgz",
|
|
995
|
+
"integrity": "sha512-cyzXQCtO47ydzxpQtCGSQGOC8Gk3ZUeBXFAxD+CWXYFo5OqZyZUonFl0DwUlTyAfRHntBfw2p3w4s9R6oe1eCA==",
|
|
996
|
+
"license": "MIT",
|
|
997
|
+
"dependencies": {
|
|
998
|
+
"@monaco-editor/loader": "^1.5.0"
|
|
999
|
+
},
|
|
1000
|
+
"peerDependencies": {
|
|
1001
|
+
"monaco-editor": ">= 0.25.0 < 1",
|
|
1002
|
+
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
|
|
1003
|
+
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
|
1004
|
+
}
|
|
1005
|
+
},
|
|
981
1006
|
"node_modules/@nodelib/fs.scandir": {
|
|
982
1007
|
"version": "2.1.5",
|
|
983
1008
|
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
|
|
@@ -1801,6 +1826,15 @@
|
|
|
1801
1826
|
"integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==",
|
|
1802
1827
|
"license": "MIT"
|
|
1803
1828
|
},
|
|
1829
|
+
"node_modules/@typescript/ata": {
|
|
1830
|
+
"version": "0.9.8",
|
|
1831
|
+
"resolved": "https://registry.npmjs.org/@typescript/ata/-/ata-0.9.8.tgz",
|
|
1832
|
+
"integrity": "sha512-+M815CeDRJS5H5ciWfhFCKp25nNfF+LFWawWAaBhNlquFb2wS5IIMDI+2bKWN3GuU6mpj+FzySsOD29M4nG8Xg==",
|
|
1833
|
+
"license": "MIT",
|
|
1834
|
+
"peerDependencies": {
|
|
1835
|
+
"typescript": ">=4.4.4"
|
|
1836
|
+
}
|
|
1837
|
+
},
|
|
1804
1838
|
"node_modules/@ungap/structured-clone": {
|
|
1805
1839
|
"version": "1.3.0",
|
|
1806
1840
|
"resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz",
|
|
@@ -4563,6 +4597,40 @@
|
|
|
4563
4597
|
"ufo": "^1.6.3"
|
|
4564
4598
|
}
|
|
4565
4599
|
},
|
|
4600
|
+
"node_modules/monaco-editor": {
|
|
4601
|
+
"version": "0.55.1",
|
|
4602
|
+
"resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.55.1.tgz",
|
|
4603
|
+
"integrity": "sha512-jz4x+TJNFHwHtwuV9vA9rMujcZRb0CEilTEwG2rRSpe/A7Jdkuj8xPKttCgOh+v/lkHy7HsZ64oj+q3xoAFl9A==",
|
|
4604
|
+
"license": "MIT",
|
|
4605
|
+
"peer": true,
|
|
4606
|
+
"dependencies": {
|
|
4607
|
+
"dompurify": "3.2.7",
|
|
4608
|
+
"marked": "14.0.0"
|
|
4609
|
+
}
|
|
4610
|
+
},
|
|
4611
|
+
"node_modules/monaco-editor/node_modules/dompurify": {
|
|
4612
|
+
"version": "3.2.7",
|
|
4613
|
+
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.2.7.tgz",
|
|
4614
|
+
"integrity": "sha512-WhL/YuveyGXJaerVlMYGWhvQswa7myDG17P7Vu65EWC05o8vfeNbvNf4d/BOvH99+ZW+LlQsc1GDKMa1vNK6dw==",
|
|
4615
|
+
"license": "(MPL-2.0 OR Apache-2.0)",
|
|
4616
|
+
"peer": true,
|
|
4617
|
+
"optionalDependencies": {
|
|
4618
|
+
"@types/trusted-types": "^2.0.7"
|
|
4619
|
+
}
|
|
4620
|
+
},
|
|
4621
|
+
"node_modules/monaco-editor/node_modules/marked": {
|
|
4622
|
+
"version": "14.0.0",
|
|
4623
|
+
"resolved": "https://registry.npmjs.org/marked/-/marked-14.0.0.tgz",
|
|
4624
|
+
"integrity": "sha512-uIj4+faQ+MgHgwUW1l2PsPglZLOLOT1uErt06dAPtx2kjteLAkbsd/0FiYg/MGS+i7ZKLb7w2WClxHkzOOuryQ==",
|
|
4625
|
+
"license": "MIT",
|
|
4626
|
+
"peer": true,
|
|
4627
|
+
"bin": {
|
|
4628
|
+
"marked": "bin/marked.js"
|
|
4629
|
+
},
|
|
4630
|
+
"engines": {
|
|
4631
|
+
"node": ">= 18"
|
|
4632
|
+
}
|
|
4633
|
+
},
|
|
4566
4634
|
"node_modules/ms": {
|
|
4567
4635
|
"version": "2.1.3",
|
|
4568
4636
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
|
@@ -5429,6 +5497,12 @@
|
|
|
5429
5497
|
"url": "https://github.com/sponsors/wooorm"
|
|
5430
5498
|
}
|
|
5431
5499
|
},
|
|
5500
|
+
"node_modules/state-local": {
|
|
5501
|
+
"version": "1.0.7",
|
|
5502
|
+
"resolved": "https://registry.npmjs.org/state-local/-/state-local-1.0.7.tgz",
|
|
5503
|
+
"integrity": "sha512-HTEHMNieakEnoe33shBYcZ7NX83ACUjCu8c40iOGEZsngj9zRnkqS9j1pqQPXwobB0ZcVTk27REb7COQ0UR59w==",
|
|
5504
|
+
"license": "MIT"
|
|
5505
|
+
},
|
|
5432
5506
|
"node_modules/string-width": {
|
|
5433
5507
|
"version": "7.2.0",
|
|
5434
5508
|
"resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz",
|
|
@@ -5785,7 +5859,6 @@
|
|
|
5785
5859
|
"version": "5.9.3",
|
|
5786
5860
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
|
|
5787
5861
|
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
|
5788
|
-
"dev": true,
|
|
5789
5862
|
"license": "Apache-2.0",
|
|
5790
5863
|
"bin": {
|
|
5791
5864
|
"tsc": "bin/tsc",
|
|
@@ -9,7 +9,9 @@
|
|
|
9
9
|
},
|
|
10
10
|
"dependencies": {
|
|
11
11
|
"@ai-sdk/react": "^3.0.170",
|
|
12
|
+
"@monaco-editor/react": "^4.7.0",
|
|
12
13
|
"@types/prismjs": "^1.26.6",
|
|
14
|
+
"@typescript/ata": "^0.9.8",
|
|
13
15
|
"ai": "^6.0.168",
|
|
14
16
|
"lucide-react": "^0.460.0",
|
|
15
17
|
"mermaid": "^11.4.0",
|
|
@@ -34,7 +36,7 @@
|
|
|
34
36
|
"autoprefixer": "^10.4.0",
|
|
35
37
|
"postcss": "^8.4.0",
|
|
36
38
|
"tailwindcss": "^3.4.0",
|
|
37
|
-
"typescript": "^5.
|
|
39
|
+
"typescript": "^5.9.3",
|
|
38
40
|
"vite": "^6.0.0"
|
|
39
41
|
}
|
|
40
42
|
}
|
|
@@ -30,7 +30,7 @@ const MFE_BROWSER_SECURITY_WORKSPACE = (() => {
|
|
|
30
30
|
return {
|
|
31
31
|
...workspace,
|
|
32
32
|
label: "Webpack MF - CSP and XSS Boundaries",
|
|
33
|
-
activeFile: "apps/host/src/App.
|
|
33
|
+
activeFile: "apps/host/src/App.tsx",
|
|
34
34
|
files: {
|
|
35
35
|
...workspace.files,
|
|
36
36
|
"README.md": `# Module Federation Security Lab
|
|
@@ -46,9 +46,9 @@ If any remote renders attacker-controlled HTML with dangerouslySetInnerHTML, tha
|
|
|
46
46
|
## What to inspect
|
|
47
47
|
|
|
48
48
|
- apps/host/webpack.config.js - CSP allowlist for remote origins
|
|
49
|
-
- apps/host/src/App.
|
|
50
|
-
- apps/profile/src/ProfileCard.
|
|
51
|
-
- apps/checkout/src/CheckoutPanel.
|
|
49
|
+
- apps/host/src/App.tsx - host passes one payload to both remotes
|
|
50
|
+
- apps/profile/src/ProfileCard.tsx - safe remote renders payload as text
|
|
51
|
+
- apps/checkout/src/CheckoutPanel.tsx - unsafe remote injects HTML directly
|
|
52
52
|
|
|
53
53
|
## Suggested experiments
|
|
54
54
|
|
|
@@ -57,7 +57,7 @@ If any remote renders attacker-controlled HTML with dangerouslySetInnerHTML, tha
|
|
|
57
57
|
3. Remove one remote origin from script-src in apps/host/webpack.config.js and rerun webpack.
|
|
58
58
|
4. Add a new remote and notice that CSP must be updated before the host can trust it.
|
|
59
59
|
`,
|
|
60
|
-
"apps/host/src/App.
|
|
60
|
+
"apps/host/src/App.tsx": `import React, { Suspense, useMemo, useState } from "react";
|
|
61
61
|
import { makeInspectableLazy } from "../../shared/mfInspector";
|
|
62
62
|
|
|
63
63
|
const ProfileCard = React.lazy(
|
|
@@ -79,7 +79,7 @@ const SAFE_PROMO = "Spring release: 20% off for signed-in teams.";
|
|
|
79
79
|
const ATTACKER_PROMO =
|
|
80
80
|
'<img src="x" onerror="document.getElementById(\\'mf-xss-status\\').textContent=\\'XSS executed inside the unsafe checkout remote\\';document.getElementById(\\'mf-xss-status\\').style.color=\\'#dc2626\\';document.getElementById(\\'mf-xss-status\\').style.fontWeight=\\'700\\';" />';
|
|
81
81
|
|
|
82
|
-
function RemoteBoundary({ title, children }) {
|
|
82
|
+
function RemoteBoundary({ title, children }: { title: string; children: React.ReactNode }) {
|
|
83
83
|
return (
|
|
84
84
|
<div
|
|
85
85
|
style={{
|
|
@@ -303,24 +303,24 @@ const inspectorConfig = {
|
|
|
303
303
|
module.exports = {
|
|
304
304
|
mode: "development",
|
|
305
305
|
devtool: "source-map",
|
|
306
|
-
entry: path.resolve(__dirname, "./src/index.
|
|
306
|
+
entry: path.resolve(__dirname, "./src/index.tsx"),
|
|
307
307
|
output: {
|
|
308
308
|
path: path.resolve(__dirname, "./dist"),
|
|
309
309
|
publicPath: "http://localhost:" + hostPort + "/",
|
|
310
310
|
clean: true,
|
|
311
311
|
},
|
|
312
312
|
resolve: {
|
|
313
|
-
extensions: [".js", ".jsx"],
|
|
313
|
+
extensions: [".js", ".jsx", ".ts", ".tsx"],
|
|
314
314
|
},
|
|
315
315
|
module: {
|
|
316
316
|
rules: [
|
|
317
317
|
{
|
|
318
|
-
test: /\\.(js|jsx)$/,
|
|
318
|
+
test: /\\.(js|jsx|ts|tsx)$/,
|
|
319
319
|
exclude: /node_modules/,
|
|
320
320
|
use: {
|
|
321
321
|
loader: "esbuild-loader",
|
|
322
322
|
options: {
|
|
323
|
-
loader: "
|
|
323
|
+
loader: "tsx",
|
|
324
324
|
jsx: "automatic",
|
|
325
325
|
target: "es2020",
|
|
326
326
|
},
|
|
@@ -366,7 +366,7 @@ module.exports = {
|
|
|
366
366
|
],
|
|
367
367
|
};
|
|
368
368
|
`,
|
|
369
|
-
"apps/profile/src/App.
|
|
369
|
+
"apps/profile/src/App.tsx": `import React from "react";
|
|
370
370
|
import ProfileCard from "./ProfileCard";
|
|
371
371
|
|
|
372
372
|
export default function App() {
|
|
@@ -381,9 +381,9 @@ export default function App() {
|
|
|
381
381
|
);
|
|
382
382
|
}
|
|
383
383
|
`,
|
|
384
|
-
"apps/profile/src/ProfileCard.
|
|
384
|
+
"apps/profile/src/ProfileCard.tsx": `import React from "react";
|
|
385
385
|
|
|
386
|
-
export default function ProfileCard({ promoHtml = "" }) {
|
|
386
|
+
export default function ProfileCard({ promoHtml = "" }: { promoHtml?: string }) {
|
|
387
387
|
return (
|
|
388
388
|
<section>
|
|
389
389
|
<h2 style={{ marginTop: 0, color: "#1e293b" }}>Safe federated profile card</h2>
|
|
@@ -418,7 +418,7 @@ const { createSharedConfig } = require("../shared/buildSharedConfig");
|
|
|
418
418
|
const profilePort = Number(process.env.PROFILE_PORT || 3101);
|
|
419
419
|
const sharedConfig = createSharedConfig(packageJson);
|
|
420
420
|
const exposeConfig = {
|
|
421
|
-
"./ProfileCard": path.resolve(__dirname, "./src/ProfileCard.
|
|
421
|
+
"./ProfileCard": path.resolve(__dirname, "./src/ProfileCard.tsx"),
|
|
422
422
|
"./InspectorBridge": path.resolve(__dirname, "./src/inspectorBridge.js"),
|
|
423
423
|
};
|
|
424
424
|
const inspectorConfig = {
|
|
@@ -430,24 +430,24 @@ const inspectorConfig = {
|
|
|
430
430
|
module.exports = {
|
|
431
431
|
mode: "development",
|
|
432
432
|
devtool: "source-map",
|
|
433
|
-
entry: path.resolve(__dirname, "./src/index.
|
|
433
|
+
entry: path.resolve(__dirname, "./src/index.tsx"),
|
|
434
434
|
output: {
|
|
435
435
|
path: path.resolve(__dirname, "./dist"),
|
|
436
436
|
publicPath: "http://localhost:" + profilePort + "/",
|
|
437
437
|
clean: true,
|
|
438
438
|
},
|
|
439
439
|
resolve: {
|
|
440
|
-
extensions: [".js", ".jsx"],
|
|
440
|
+
extensions: [".js", ".jsx", ".ts", ".tsx"],
|
|
441
441
|
},
|
|
442
442
|
module: {
|
|
443
443
|
rules: [
|
|
444
444
|
{
|
|
445
|
-
test: /\\.(js|jsx)$/,
|
|
445
|
+
test: /\\.(js|jsx|ts|tsx)$/,
|
|
446
446
|
exclude: /node_modules/,
|
|
447
447
|
use: {
|
|
448
448
|
loader: "esbuild-loader",
|
|
449
449
|
options: {
|
|
450
|
-
loader: "
|
|
450
|
+
loader: "tsx",
|
|
451
451
|
jsx: "automatic",
|
|
452
452
|
target: "es2020",
|
|
453
453
|
},
|
|
@@ -481,7 +481,7 @@ module.exports = {
|
|
|
481
481
|
],
|
|
482
482
|
};
|
|
483
483
|
`,
|
|
484
|
-
"apps/checkout/src/App.
|
|
484
|
+
"apps/checkout/src/App.tsx": `import React from "react";
|
|
485
485
|
import CheckoutPanel from "./CheckoutPanel";
|
|
486
486
|
|
|
487
487
|
export default function App() {
|
|
@@ -496,9 +496,9 @@ export default function App() {
|
|
|
496
496
|
);
|
|
497
497
|
}
|
|
498
498
|
`,
|
|
499
|
-
"apps/checkout/src/CheckoutPanel.
|
|
499
|
+
"apps/checkout/src/CheckoutPanel.tsx": `import React from "react";
|
|
500
500
|
|
|
501
|
-
export default function CheckoutPanel({ promoHtml = "" }) {
|
|
501
|
+
export default function CheckoutPanel({ promoHtml = "" }: { promoHtml?: string }) {
|
|
502
502
|
return (
|
|
503
503
|
<section>
|
|
504
504
|
<h2 style={{ marginTop: 0, color: "#7c2d12" }}>Unsafe federated checkout panel</h2>
|
|
@@ -532,7 +532,7 @@ const { createSharedConfig } = require("../shared/buildSharedConfig");
|
|
|
532
532
|
const checkoutPort = Number(process.env.CHECKOUT_PORT || 3102);
|
|
533
533
|
const sharedConfig = createSharedConfig(packageJson);
|
|
534
534
|
const exposeConfig = {
|
|
535
|
-
"./CheckoutPanel": path.resolve(__dirname, "./src/CheckoutPanel.
|
|
535
|
+
"./CheckoutPanel": path.resolve(__dirname, "./src/CheckoutPanel.tsx"),
|
|
536
536
|
"./InspectorBridge": path.resolve(__dirname, "./src/inspectorBridge.js"),
|
|
537
537
|
};
|
|
538
538
|
const inspectorConfig = {
|
|
@@ -544,24 +544,24 @@ const inspectorConfig = {
|
|
|
544
544
|
module.exports = {
|
|
545
545
|
mode: "development",
|
|
546
546
|
devtool: "source-map",
|
|
547
|
-
entry: path.resolve(__dirname, "./src/index.
|
|
547
|
+
entry: path.resolve(__dirname, "./src/index.tsx"),
|
|
548
548
|
output: {
|
|
549
549
|
path: path.resolve(__dirname, "./dist"),
|
|
550
550
|
publicPath: "http://localhost:" + checkoutPort + "/",
|
|
551
551
|
clean: true,
|
|
552
552
|
},
|
|
553
553
|
resolve: {
|
|
554
|
-
extensions: [".js", ".jsx"],
|
|
554
|
+
extensions: [".js", ".jsx", ".ts", ".tsx"],
|
|
555
555
|
},
|
|
556
556
|
module: {
|
|
557
557
|
rules: [
|
|
558
558
|
{
|
|
559
|
-
test: /\\.(js|jsx)$/,
|
|
559
|
+
test: /\\.(js|jsx|ts|tsx)$/,
|
|
560
560
|
exclude: /node_modules/,
|
|
561
561
|
use: {
|
|
562
562
|
loader: "esbuild-loader",
|
|
563
563
|
options: {
|
|
564
|
-
loader: "
|
|
564
|
+
loader: "tsx",
|
|
565
565
|
jsx: "automatic",
|
|
566
566
|
target: "es2020",
|
|
567
567
|
},
|
|
@@ -1582,10 +1582,13 @@ webpack(config, (err, stats) => {
|
|
|
1582
1582
|
"react-dom": "^18.3.1"
|
|
1583
1583
|
},
|
|
1584
1584
|
"devDependencies": {
|
|
1585
|
+
"@types/react": "^18.0.0",
|
|
1586
|
+
"@types/react-dom": "^18.0.0",
|
|
1585
1587
|
"esbuild": "^0.28.0",
|
|
1586
1588
|
"esbuild-loader": "^4.4.3",
|
|
1587
1589
|
"esbuild-register": "^3.6.0",
|
|
1588
1590
|
"html-webpack-plugin": "^5.6.7",
|
|
1591
|
+
"typescript": "^5.6.0",
|
|
1589
1592
|
"webpack": "^5.106.2",
|
|
1590
1593
|
"webpack-cli": "^7.0.2"
|
|
1591
1594
|
}
|
|
@@ -1613,19 +1616,19 @@ module.exports = {
|
|
|
1613
1616
|
publicPath: 'http://localhost:' + port + '/',
|
|
1614
1617
|
clean: true,
|
|
1615
1618
|
},
|
|
1616
|
-
resolve: { extensions: ['.js', '.jsx'] },
|
|
1619
|
+
resolve: { extensions: ['.js', '.jsx', '.ts', '.tsx'] },
|
|
1617
1620
|
module: {
|
|
1618
1621
|
rules: [{
|
|
1619
|
-
test: /\\.jsx
|
|
1622
|
+
test: /\\.(js|jsx|ts|tsx)$/,
|
|
1620
1623
|
exclude: /node_modules/,
|
|
1621
|
-
use: { loader: 'esbuild-loader', options: { loader: '
|
|
1624
|
+
use: { loader: 'esbuild-loader', options: { loader: 'tsx', jsx: 'automatic', target: 'es2020' } },
|
|
1622
1625
|
}],
|
|
1623
1626
|
},
|
|
1624
1627
|
plugins: [
|
|
1625
1628
|
new ModuleFederationPlugin({
|
|
1626
1629
|
name: '${name}',
|
|
1627
1630
|
filename: 'remoteEntry.js',
|
|
1628
|
-
exposes: { './${componentFile}': path.resolve(__dirname, './src/${componentFile}.
|
|
1631
|
+
exposes: { './${componentFile}': path.resolve(__dirname, './src/${componentFile}.tsx') },
|
|
1629
1632
|
shared: {
|
|
1630
1633
|
react: { singleton: true, requiredVersion: '^18.3.1' },
|
|
1631
1634
|
'react-dom': { singleton: true, requiredVersion: '^18.3.1' },
|
|
@@ -1641,7 +1644,7 @@ module.exports = {
|
|
|
1641
1644
|
// This component runs on the server (renderToString) AND in the browser (hydration).
|
|
1642
1645
|
// SSR means the HTML is generated here on the remote's Node server at request time,
|
|
1643
1646
|
// sent to the Next.js host, inserted into the page, then React takes over client-side.
|
|
1644
|
-
export default function ProfileCard({ ssrContext = false }) {
|
|
1647
|
+
export default function ProfileCard({ ssrContext = false }: { ssrContext?: boolean }): React.ReactElement {
|
|
1645
1648
|
return (
|
|
1646
1649
|
<section style={{ fontFamily: 'ui-sans-serif, system-ui, sans-serif' }}>
|
|
1647
1650
|
<div style={{
|
|
@@ -1675,7 +1678,7 @@ export default function ProfileCard({ ssrContext = false }) {
|
|
|
1675
1678
|
|
|
1676
1679
|
// Same SSR pattern as ProfileCard: rendered to HTML string on the remote Node server,
|
|
1677
1680
|
// fetched by the Next.js host during getServerSideProps/page render, then hydrated.
|
|
1678
|
-
export default function CheckoutPanel({ ssrContext = false }) {
|
|
1681
|
+
export default function CheckoutPanel({ ssrContext = false }: { ssrContext?: boolean }): React.ReactElement {
|
|
1679
1682
|
return (
|
|
1680
1683
|
<section style={{ fontFamily: 'ui-sans-serif, system-ui, sans-serif' }}>
|
|
1681
1684
|
<div style={{
|
|
@@ -1718,7 +1721,7 @@ import('./bootstrap');
|
|
|
1718
1721
|
componentName: string,
|
|
1719
1722
|
) => `import React from 'react';
|
|
1720
1723
|
import { createRoot } from 'react-dom/client';
|
|
1721
|
-
import ${componentName} from './${componentName}
|
|
1724
|
+
import ${componentName} from './${componentName}';
|
|
1722
1725
|
|
|
1723
1726
|
// Standalone preview when you open the remote's own URL directly.
|
|
1724
1727
|
const root = document.getElementById('root');
|
|
@@ -1843,14 +1846,14 @@ export default function RootLayout({ children }) {
|
|
|
1843
1846
|
}
|
|
1844
1847
|
`;
|
|
1845
1848
|
|
|
1846
|
-
const HOST_NEXT_CONFIG =
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1849
|
+
const HOST_NEXT_CONFIG = `import type { NextConfig } from 'next';
|
|
1850
|
+
// Allow the Next.js server to make HTTP requests to local remote servers.
|
|
1851
|
+
// In production you'd list your real remote origins here.
|
|
1852
|
+
const nextConfig: NextConfig = {
|
|
1850
1853
|
experimental: {},
|
|
1851
1854
|
};
|
|
1852
1855
|
|
|
1853
|
-
|
|
1856
|
+
export default nextConfig;
|
|
1854
1857
|
`;
|
|
1855
1858
|
|
|
1856
1859
|
const HOST_PACKAGE = `{
|
|
@@ -1997,8 +2000,8 @@ Browser
|
|
|
1997
2000
|
),
|
|
1998
2001
|
"apps/profile/public/index.html": REMOTE_INDEX_HTML("Profile Remote"),
|
|
1999
2002
|
"apps/profile/src/index.js": REMOTE_INDEX_JS,
|
|
2000
|
-
"apps/profile/src/bootstrap.
|
|
2001
|
-
"apps/profile/src/ProfileCard.
|
|
2003
|
+
"apps/profile/src/bootstrap.tsx": REMOTE_BOOTSTRAP("ProfileCard"),
|
|
2004
|
+
"apps/profile/src/ProfileCard.tsx": PROFILE_CARD_JSX,
|
|
2002
2005
|
|
|
2003
2006
|
// checkout remote
|
|
2004
2007
|
"apps/checkout/package.json": REMOTE_PACKAGE("checkout"),
|
|
@@ -2016,12 +2019,12 @@ Browser
|
|
|
2016
2019
|
),
|
|
2017
2020
|
"apps/checkout/public/index.html": REMOTE_INDEX_HTML("Checkout Remote"),
|
|
2018
2021
|
"apps/checkout/src/index.js": REMOTE_INDEX_JS,
|
|
2019
|
-
"apps/checkout/src/bootstrap.
|
|
2020
|
-
"apps/checkout/src/CheckoutPanel.
|
|
2022
|
+
"apps/checkout/src/bootstrap.tsx": REMOTE_BOOTSTRAP("CheckoutPanel"),
|
|
2023
|
+
"apps/checkout/src/CheckoutPanel.tsx": CHECKOUT_PANEL_JSX,
|
|
2021
2024
|
|
|
2022
2025
|
// Next.js host
|
|
2023
2026
|
"apps/host/package.json": HOST_PACKAGE,
|
|
2024
|
-
"apps/host/next.config.
|
|
2027
|
+
"apps/host/next.config.ts": HOST_NEXT_CONFIG,
|
|
2025
2028
|
"apps/host/buildAndServe.js": HOST_BUILD_SERVE,
|
|
2026
2029
|
"apps/host/app/layout.js": HOST_LAYOUT_JS,
|
|
2027
2030
|
"apps/host/app/page.js": HOST_PAGE_JS,
|
|
@@ -2097,18 +2100,18 @@ const MAX_SPANS = 2000;
|
|
|
2097
2100
|
|
|
2098
2101
|
module.exports = {
|
|
2099
2102
|
mode: 'development',
|
|
2100
|
-
entry: path.resolve(__dirname, './src/index.
|
|
2103
|
+
entry: path.resolve(__dirname, './src/index.ts'),
|
|
2101
2104
|
output: {
|
|
2102
2105
|
path: path.resolve(__dirname, './dist'),
|
|
2103
2106
|
publicPath: 'http://localhost:' + HOST_PORT + '/',
|
|
2104
2107
|
clean: true,
|
|
2105
2108
|
},
|
|
2106
|
-
resolve: { extensions: ['.js', '.jsx'] },
|
|
2109
|
+
resolve: { extensions: ['.js', '.jsx', '.ts', '.tsx'] },
|
|
2107
2110
|
module: {
|
|
2108
2111
|
rules: [{
|
|
2109
|
-
test: /\\.jsx
|
|
2112
|
+
test: /\\.(js|jsx|ts|tsx)$/,
|
|
2110
2113
|
exclude: /node_modules/,
|
|
2111
|
-
use: { loader: 'esbuild-loader', options: { loader: '
|
|
2114
|
+
use: { loader: 'esbuild-loader', options: { loader: 'tsx', jsx: 'automatic', target: 'es2020' } },
|
|
2112
2115
|
}],
|
|
2113
2116
|
},
|
|
2114
2117
|
plugins: [
|
|
@@ -2208,8 +2211,8 @@ import('./bootstrap');
|
|
|
2208
2211
|
|
|
2209
2212
|
const HOST_BOOTSTRAP = `import React from 'react';
|
|
2210
2213
|
import { createRoot } from 'react-dom/client';
|
|
2211
|
-
import App from './App
|
|
2212
|
-
createRoot(document.getElementById('root')).render(React.createElement(App));
|
|
2214
|
+
import App from './App';
|
|
2215
|
+
createRoot(document.getElementById('root')!).render(React.createElement(App));
|
|
2213
2216
|
`;
|
|
2214
2217
|
|
|
2215
2218
|
// ── THE KEY FILE ─────────────────────────────────────────────────────
|
|
@@ -2438,8 +2441,8 @@ export function flush() { return _flush(); }
|
|
|
2438
2441
|
// ── App.jsx ──────────────────────────────────────────────────────────
|
|
2439
2442
|
const HOST_APP = `
|
|
2440
2443
|
import React, { useState, useEffect, Suspense } from 'react';
|
|
2441
|
-
import { initTelemetry } from './telemetry
|
|
2442
|
-
import TraceDashboard from './TraceDashboard
|
|
2444
|
+
import { initTelemetry } from './telemetry';
|
|
2445
|
+
import TraceDashboard from './TraceDashboard';
|
|
2443
2446
|
|
|
2444
2447
|
// ── TracerProvider initialisation ────────────────────────────────────────────
|
|
2445
2448
|
// This runs once, synchronously, before any component renders.
|
|
@@ -2862,24 +2865,24 @@ const PROFILE_PORT = Number(process.env.PROFILE_PORT || 3101);
|
|
|
2862
2865
|
|
|
2863
2866
|
module.exports = {
|
|
2864
2867
|
mode: 'development',
|
|
2865
|
-
entry: path.resolve(__dirname, './src/index.
|
|
2868
|
+
entry: path.resolve(__dirname, './src/index.ts'),
|
|
2866
2869
|
output: {
|
|
2867
2870
|
path: path.resolve(__dirname, './dist'),
|
|
2868
2871
|
publicPath: 'http://localhost:' + PROFILE_PORT + '/',
|
|
2869
2872
|
clean: true,
|
|
2870
2873
|
},
|
|
2871
|
-
resolve: { extensions: ['.js', '.jsx'] },
|
|
2874
|
+
resolve: { extensions: ['.js', '.jsx', '.ts', '.tsx'] },
|
|
2872
2875
|
module: {
|
|
2873
2876
|
rules: [{
|
|
2874
|
-
test: /\\.jsx
|
|
2875
|
-
use: { loader: 'esbuild-loader', options: { loader: '
|
|
2877
|
+
test: /\\.(js|jsx|ts|tsx)$/, exclude: /node_modules/,
|
|
2878
|
+
use: { loader: 'esbuild-loader', options: { loader: 'tsx', jsx: 'automatic', target: 'es2020' } },
|
|
2876
2879
|
}],
|
|
2877
2880
|
},
|
|
2878
2881
|
plugins: [
|
|
2879
2882
|
new ModuleFederationPlugin({
|
|
2880
2883
|
name: 'profile',
|
|
2881
2884
|
filename: 'remoteEntry.js',
|
|
2882
|
-
exposes: { './ProfileCard': './src/ProfileCard.
|
|
2885
|
+
exposes: { './ProfileCard': './src/ProfileCard.tsx' },
|
|
2883
2886
|
// Import the host's shared telemetry module so this remote's spans
|
|
2884
2887
|
// are created by the SAME TracerProvider as the host.
|
|
2885
2888
|
remotes: { host: 'host@http://localhost:' + HOST_PORT + '/remoteEntry.js' },
|
|
@@ -2908,7 +2911,7 @@ module.exports = {
|
|
|
2908
2911
|
const REMOTE_BOOTSTRAP = (component: string) => `
|
|
2909
2912
|
import React from 'react';
|
|
2910
2913
|
import { createRoot } from 'react-dom/client';
|
|
2911
|
-
import ${component} from './${component}
|
|
2914
|
+
import ${component} from './${component}';
|
|
2912
2915
|
const root = document.getElementById('root');
|
|
2913
2916
|
if (root) createRoot(root).render(React.createElement(${component}));
|
|
2914
2917
|
`;
|
|
@@ -3007,24 +3010,24 @@ const CHECKOUT_PORT = Number(process.env.CHECKOUT_PORT || 3102);
|
|
|
3007
3010
|
|
|
3008
3011
|
module.exports = {
|
|
3009
3012
|
mode: 'development',
|
|
3010
|
-
entry: path.resolve(__dirname, './src/index.
|
|
3013
|
+
entry: path.resolve(__dirname, './src/index.ts'),
|
|
3011
3014
|
output: {
|
|
3012
3015
|
path: path.resolve(__dirname, './dist'),
|
|
3013
3016
|
publicPath: 'http://localhost:' + CHECKOUT_PORT + '/',
|
|
3014
3017
|
clean: true,
|
|
3015
3018
|
},
|
|
3016
|
-
resolve: { extensions: ['.js', '.jsx'] },
|
|
3019
|
+
resolve: { extensions: ['.js', '.jsx', '.ts', '.tsx'] },
|
|
3017
3020
|
module: {
|
|
3018
3021
|
rules: [{
|
|
3019
|
-
test: /\\.jsx
|
|
3020
|
-
use: { loader: 'esbuild-loader', options: { loader: '
|
|
3022
|
+
test: /\\.(js|jsx|ts|tsx)$/, exclude: /node_modules/,
|
|
3023
|
+
use: { loader: 'esbuild-loader', options: { loader: 'tsx', jsx: 'automatic', target: 'es2020' } },
|
|
3021
3024
|
}],
|
|
3022
3025
|
},
|
|
3023
3026
|
plugins: [
|
|
3024
3027
|
new ModuleFederationPlugin({
|
|
3025
3028
|
name: 'checkout',
|
|
3026
3029
|
filename: 'remoteEntry.js',
|
|
3027
|
-
exposes: { './CheckoutPanel': './src/CheckoutPanel.
|
|
3030
|
+
exposes: { './CheckoutPanel': './src/CheckoutPanel.tsx' },
|
|
3028
3031
|
remotes: { host: 'host@http://localhost:' + HOST_PORT + '/remoteEntry.js' },
|
|
3029
3032
|
shared: {
|
|
3030
3033
|
react: { singleton: true, requiredVersion: '^18.3.1' },
|
|
@@ -3219,23 +3222,23 @@ export default function CheckoutPanel({ deploymentVersion }) {
|
|
|
3219
3222
|
"apps/host/package.json": HOST_PACKAGE,
|
|
3220
3223
|
"apps/host/webpack.config.js": HOST_WEBPACK,
|
|
3221
3224
|
"apps/host/public/index.html": HOST_HTML,
|
|
3222
|
-
"apps/host/src/index.
|
|
3223
|
-
"apps/host/src/bootstrap.
|
|
3225
|
+
"apps/host/src/index.ts": HOST_INDEX_JS,
|
|
3226
|
+
"apps/host/src/bootstrap.tsx": HOST_BOOTSTRAP,
|
|
3224
3227
|
"apps/host/src/telemetry.js": HOST_TELEMETRY,
|
|
3225
|
-
"apps/host/src/App.
|
|
3226
|
-
"apps/host/src/TraceDashboard.
|
|
3228
|
+
"apps/host/src/App.tsx": HOST_APP,
|
|
3229
|
+
"apps/host/src/TraceDashboard.tsx": HOST_TRACE_DASHBOARD,
|
|
3227
3230
|
"apps/profile/package.json": PROFILE_PACKAGE,
|
|
3228
3231
|
"apps/profile/webpack.config.js": PROFILE_WEBPACK,
|
|
3229
3232
|
"apps/profile/public/index.html": REMOTE_HTML("Profile Remote"),
|
|
3230
|
-
"apps/profile/src/index.
|
|
3231
|
-
"apps/profile/src/bootstrap.
|
|
3232
|
-
"apps/profile/src/ProfileCard.
|
|
3233
|
+
"apps/profile/src/index.ts": REMOTE_INDEX,
|
|
3234
|
+
"apps/profile/src/bootstrap.tsx": REMOTE_BOOTSTRAP("ProfileCard"),
|
|
3235
|
+
"apps/profile/src/ProfileCard.tsx": PROFILE_CARD,
|
|
3233
3236
|
"apps/checkout/package.json": CHECKOUT_PACKAGE,
|
|
3234
3237
|
"apps/checkout/webpack.config.js": CHECKOUT_WEBPACK,
|
|
3235
3238
|
"apps/checkout/public/index.html": REMOTE_HTML("Checkout Remote"),
|
|
3236
|
-
"apps/checkout/src/index.
|
|
3237
|
-
"apps/checkout/src/bootstrap.
|
|
3238
|
-
"apps/checkout/src/CheckoutPanel.
|
|
3239
|
+
"apps/checkout/src/index.ts": REMOTE_INDEX,
|
|
3240
|
+
"apps/checkout/src/bootstrap.tsx": REMOTE_BOOTSTRAP("CheckoutPanel"),
|
|
3241
|
+
"apps/checkout/src/CheckoutPanel.tsx": CHECKOUT_PANEL,
|
|
3239
3242
|
};
|
|
3240
3243
|
})(),
|
|
3241
3244
|
},
|