From edcfa41d7a444c8ddeff84ca4339ea47b59e76bd Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Wed, 29 Jul 2026 01:45:35 +0000 Subject: [PATCH 1/5] fix: generate app artifacts in deploy CI Co-authored-by: Kent C. Dodds --- .github/workflows/validate.yml | 8 +- epicshop/generate-app-artifacts.js | 26 ++ package-lock.json | 714 +++++++++++++++++------------ package.json | 15 +- 4 files changed, 460 insertions(+), 303 deletions(-) create mode 100644 epicshop/generate-app-artifacts.js diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index e0efb1b..5a3c5bd 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -24,7 +24,7 @@ jobs: - name: ⎔ Setup node uses: actions/setup-node@v4 with: - node-version: 26 + node-version: 22.14.0 # SKIP_PLAYGROUND keeps typecheck/lint meaningful: problem playground apps # intentionally fail solution tests/types, which would create false CI red. @@ -62,6 +62,10 @@ jobs: attempt=$((attempt + 1)) done + - name: ⚙️ Generate app artifacts + run: npm run generate + working-directory: ./workshop + - name: ʦ TypeScript run: npm run typecheck working-directory: ./workshop @@ -81,7 +85,7 @@ jobs: - name: ⎔ Setup node uses: actions/setup-node@v4 with: - node-version: 26 + node-version: 22.14.0 - name: 📦 Install dependencies run: npm ci diff --git a/epicshop/generate-app-artifacts.js b/epicshop/generate-app-artifacts.js new file mode 100644 index 0000000..c225199 --- /dev/null +++ b/epicshop/generate-app-artifacts.js @@ -0,0 +1,26 @@ +import path from 'node:path' +import { getApps } from '@epic-web/workshop-utils/apps.server' +import { execa } from 'execa' +import fsExtra from 'fs-extra' + +const allApps = await getApps() + +for (const app of allApps) { + const reactRouterConfig = path.join(app.fullPath, 'react-router.config.ts') + if (await fsExtra.pathExists(reactRouterConfig)) { + console.log(`Generating React Router types for ${app.relativePath}`) + await execa('npm', ['exec', '--', 'react-router', 'typegen'], { + cwd: app.fullPath, + stdio: 'inherit', + }) + } + + const prismaSchema = path.join(app.fullPath, 'prisma', 'schema.prisma') + if (await fsExtra.pathExists(prismaSchema)) { + console.log(`Generating Prisma client for ${app.relativePath}`) + await execa('npm', ['exec', '--', 'prisma', 'generate', '--sql'], { + cwd: app.fullPath, + stdio: 'inherit', + }) + } +} diff --git a/package-lock.json b/package-lock.json index fa40204..80c40f5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,15 +1,23 @@ { - "name": "e2e-react-application-testing-with-playwright", + "name": "react-e2e-testing-with-playwright", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "e2e-react-application-testing-with-playwright", + "name": "react-e2e-testing-with-playwright", "hasInstallScript": true, "license": "GPL-3.0-only", "workspaces": [ "exercises/*/*" ], + "dependencies": { + "@esbuild/darwin-x64": "0.25.12", + "@esbuild/linux-x64": "0.25.12", + "@esbuild/win32-x64": "0.25.12", + "@rollup/rollup-darwin-x64": "4.52.5", + "@rollup/rollup-linux-x64-gnu": "4.52.5", + "@rollup/rollup-win32-x64-msvc": "4.52.5" + }, "devDependencies": { "@epic-web/config": "^1.19.0", "eslint": "^9.24.0", @@ -21,6 +29,14 @@ "git": ">=2.18.0", "node": ">=22.14.0", "npm": ">=8.16.0" + }, + "optionalDependencies": { + "@esbuild/darwin-x64": "^0.25.12", + "@esbuild/linux-x64": "^0.25.12", + "@esbuild/win32-x64": "^0.25.12", + "@rollup/rollup-darwin-x64": "^4.52.5", + "@rollup/rollup-linux-x64-gnu": "^4.52.5", + "@rollup/rollup-win32-x64-msvc": "^4.52.5" } }, "exercises/01.fundamentals/01.problem.install-and-configure": { @@ -2760,7 +2776,6 @@ }, "exercises/03.guides/04.solution.api-mocking/node_modules/@msw/playwright": { "version": "0.6.4", - "resolved": "https://registry.npmjs.org/@msw/playwright/-/playwright-0.6.4.tgz", "integrity": "sha512-CMex+p5E1k0mc/rQqjvjAD9uW9qhCbEbRGUVFhQUOTtsV9wQ2wbxgyFWldDKfiIwK2lEShT1apUZ57bC7PYpPA==", "dev": true, "license": "MIT", @@ -2780,7 +2795,6 @@ }, "exercises/03.guides/04.solution.api-mocking/node_modules/@mswjs/interceptors": { "version": "0.41.3", - "resolved": "https://registry.npmjs.org/@mswjs/interceptors/-/interceptors-0.41.3.tgz", "integrity": "sha512-cXu86tF4VQVfwz8W1SPbhoRyHJkti6mjH/XJIxp40jhO4j2k1m4KYrEykxqWPkFF3vrK4rgQppBh//AwyGSXPA==", "dev": true, "license": "MIT", @@ -3365,286 +3379,6 @@ "url": "https://opencollective.com/express" } }, - "exercises/04.debugging/03.problem.live-debugging": { - "name": "exercises_04.debugging_03.problem.live-debugging", - "dependencies": { - "@conform-to/react": "^1.5.0", - "@conform-to/zod": "^1.5.0", - "@epic-web/cachified": "^5.5.2", - "@epic-web/client-hints": "^1.3.5", - "@epic-web/invariant": "^1.0.0", - "@epic-web/remember": "^1.1.0", - "@epic-web/totp": "^4.0.1", - "@mjackson/form-data-parser": "^0.7.0", - "@mjackson/headers": "^0.10.0", - "@nasa-gcn/remix-seo": "^2.0.1", - "@nichtsam/helmet": "^0.3.1", - "@oslojs/crypto": "^1.0.1", - "@oslojs/encoding": "^1.1.0", - "@paralleldrive/cuid2": "^2.2.2", - "@prisma/client": "^6.7.0", - "@prisma/instrumentation": "^6.7.0", - "@radix-ui/react-checkbox": "^1.2.3", - "@radix-ui/react-dialog": "^1.1.14", - "@radix-ui/react-dropdown-menu": "^2.1.12", - "@radix-ui/react-label": "^2.1.4", - "@radix-ui/react-slot": "^1.2.0", - "@radix-ui/react-toast": "^1.2.11", - "@radix-ui/react-tooltip": "^1.2.4", - "@react-email/components": "0.0.38", - "@react-router/express": "^7.5.3", - "@react-router/node": "^7.5.3", - "@react-router/remix-routes-option-adapter": "^7.5.3", - "@remix-run/server-runtime": "^2.16.5", - "@sentry/profiling-node": "^9.32.0", - "@sentry/react-router": "^9.32.0", - "@simplewebauthn/browser": "^13.1.0", - "@simplewebauthn/server": "^13.1.1", - "@tailwindcss/vite": "^4.1.5", - "@tusbar/cache-control": "1.0.2", - "address": "^2.0.3", - "bcryptjs": "^3.0.2", - "class-variance-authority": "^0.7.1", - "close-with-grace": "^2.2.0", - "clsx": "^2.1.1", - "compression": "^1.8.0", - "cookie": "^1.0.2", - "cross-env": "^7.0.3", - "date-fns": "^4.1.0", - "dotenv": "^16.5.0", - "execa": "^9.5.2", - "express": "^4.21.2", - "express-rate-limit": "^7.5.0", - "get-port": "^7.1.0", - "glob": "^11.0.2", - "input-otp": "^1.4.2", - "intl-parse-accept-language": "^1.0.0", - "isbot": "^5.1.27", - "litefs-js": "^2.0.2", - "lru-cache": "^11.1.0", - "mime-types": "^3.0.1", - "morgan": "^1.10.0", - "openimg": "^1.1.0", - "prisma": "^6.7.0", - "qrcode": "^1.5.4", - "react": "^19.1.0", - "react-dom": "^19.1.0", - "react-router": "^7.5.3", - "remix-auth": "^4.2.0", - "remix-auth-github": "^3.0.2", - "remix-utils": "^8.5.0", - "set-cookie-parser": "^2.7.1", - "sharp": "^0.34.2", - "sonner": "^2.0.3", - "source-map-support": "^0.5.21", - "spin-delay": "^2.0.1", - "tailwind-merge": "^3.2.0", - "tailwindcss": "^4.1.5", - "vite-env-only": "^3.0.3", - "zod": "^3.24.4" - }, - "devDependencies": { - "@epic-web/config": "^1.20.1", - "@faker-js/faker": "^9.7.0", - "@msw/playwright": "^0.4.2", - "@playwright/test": "^1.57.0", - "@react-router/dev": "^7.5.3", - "@sly-cli/sly": "^2.1.1", - "@testing-library/dom": "^10.4.0", - "@testing-library/jest-dom": "^6.6.3", - "@testing-library/react": "^16.3.0", - "@testing-library/user-event": "^14.6.1", - "@total-typescript/ts-reset": "^0.6.1", - "@types/compression": "^1.7.5", - "@types/eslint": "^9.6.1", - "@types/express": "^4.17.21", - "@types/fs-extra": "^11.0.4", - "@types/glob": "^8.1.0", - "@types/mime-types": "^2.1.4", - "@types/morgan": "^1.9.9", - "@types/node": "^22.15.3", - "@types/qrcode": "^1.5.5", - "@types/react": "^19.1.2", - "@types/react-dom": "^19.1.3", - "@types/set-cookie-parser": "^2.4.10", - "@types/source-map-support": "^0.5.10", - "@vitejs/plugin-react": "^4.4.1", - "@vitest/coverage-v8": "^3.1.3", - "enforce-unique": "^1.3.0", - "esbuild": "^0.25.3", - "eslint": "^9.26.0", - "fs-extra": "^11.3.0", - "jsdom": "^25.0.1", - "msw": "^2.7.6", - "npm-run-all": "^4.1.5", - "playwright-persona": "^0.2.5", - "prettier": "^3.5.3", - "prettier-plugin-sql": "^0.19.0", - "prettier-plugin-tailwindcss": "^0.6.11", - "react-router-devtools": "^5.0.5", - "remix-flat-routes": "^0.8.5", - "tsx": "^4.19.4", - "tw-animate-css": "^1.2.9", - "typescript": "^5.8.3", - "vite": "^6.3.5", - "vite-plugin-icons-spritesheet": "^3.0.1", - "vitest": "^3.1.3" - }, - "engines": { - "node": "22.14.0" - } - }, - "exercises/04.debugging/03.problem.live-debugging/node_modules/cookie": { - "version": "1.1.1", - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "exercises/04.debugging/03.solution.live-debugging": { - "name": "exercises_04.debugging_03.solution.live-debugging", - "dependencies": { - "@conform-to/react": "^1.5.0", - "@conform-to/zod": "^1.5.0", - "@epic-web/cachified": "^5.5.2", - "@epic-web/client-hints": "^1.3.5", - "@epic-web/invariant": "^1.0.0", - "@epic-web/remember": "^1.1.0", - "@epic-web/totp": "^4.0.1", - "@mjackson/form-data-parser": "^0.7.0", - "@mjackson/headers": "^0.10.0", - "@nasa-gcn/remix-seo": "^2.0.1", - "@nichtsam/helmet": "^0.3.1", - "@oslojs/crypto": "^1.0.1", - "@oslojs/encoding": "^1.1.0", - "@paralleldrive/cuid2": "^2.2.2", - "@prisma/client": "^6.7.0", - "@prisma/instrumentation": "^6.7.0", - "@radix-ui/react-checkbox": "^1.2.3", - "@radix-ui/react-dialog": "^1.1.14", - "@radix-ui/react-dropdown-menu": "^2.1.12", - "@radix-ui/react-label": "^2.1.4", - "@radix-ui/react-slot": "^1.2.0", - "@radix-ui/react-toast": "^1.2.11", - "@radix-ui/react-tooltip": "^1.2.4", - "@react-email/components": "0.0.38", - "@react-router/express": "^7.5.3", - "@react-router/node": "^7.5.3", - "@react-router/remix-routes-option-adapter": "^7.5.3", - "@remix-run/server-runtime": "^2.16.5", - "@sentry/profiling-node": "^9.32.0", - "@sentry/react-router": "^9.32.0", - "@simplewebauthn/browser": "^13.1.0", - "@simplewebauthn/server": "^13.1.1", - "@tailwindcss/vite": "^4.1.5", - "@tusbar/cache-control": "1.0.2", - "address": "^2.0.3", - "bcryptjs": "^3.0.2", - "class-variance-authority": "^0.7.1", - "close-with-grace": "^2.2.0", - "clsx": "^2.1.1", - "compression": "^1.8.0", - "cookie": "^1.0.2", - "cross-env": "^7.0.3", - "date-fns": "^4.1.0", - "dotenv": "^16.5.0", - "execa": "^9.5.2", - "express": "^4.21.2", - "express-rate-limit": "^7.5.0", - "get-port": "^7.1.0", - "glob": "^11.0.2", - "input-otp": "^1.4.2", - "intl-parse-accept-language": "^1.0.0", - "isbot": "^5.1.27", - "litefs-js": "^2.0.2", - "lru-cache": "^11.1.0", - "mime-types": "^3.0.1", - "morgan": "^1.10.0", - "openimg": "^1.1.0", - "prisma": "^6.7.0", - "qrcode": "^1.5.4", - "react": "^19.1.0", - "react-dom": "^19.1.0", - "react-router": "^7.5.3", - "remix-auth": "^4.2.0", - "remix-auth-github": "^3.0.2", - "remix-utils": "^8.5.0", - "set-cookie-parser": "^2.7.1", - "sharp": "^0.34.2", - "sonner": "^2.0.3", - "source-map-support": "^0.5.21", - "spin-delay": "^2.0.1", - "tailwind-merge": "^3.2.0", - "tailwindcss": "^4.1.5", - "vite-env-only": "^3.0.3", - "zod": "^3.24.4" - }, - "devDependencies": { - "@epic-web/config": "^1.20.1", - "@faker-js/faker": "^9.7.0", - "@msw/playwright": "^0.4.2", - "@playwright/test": "^1.57.0", - "@react-router/dev": "^7.5.3", - "@sly-cli/sly": "^2.1.1", - "@testing-library/dom": "^10.4.0", - "@testing-library/jest-dom": "^6.6.3", - "@testing-library/react": "^16.3.0", - "@testing-library/user-event": "^14.6.1", - "@total-typescript/ts-reset": "^0.6.1", - "@types/compression": "^1.7.5", - "@types/eslint": "^9.6.1", - "@types/express": "^4.17.21", - "@types/fs-extra": "^11.0.4", - "@types/glob": "^8.1.0", - "@types/mime-types": "^2.1.4", - "@types/morgan": "^1.9.9", - "@types/node": "^22.15.3", - "@types/qrcode": "^1.5.5", - "@types/react": "^19.1.2", - "@types/react-dom": "^19.1.3", - "@types/set-cookie-parser": "^2.4.10", - "@types/source-map-support": "^0.5.10", - "@vitejs/plugin-react": "^4.4.1", - "@vitest/coverage-v8": "^3.1.3", - "enforce-unique": "^1.3.0", - "esbuild": "^0.25.3", - "eslint": "^9.26.0", - "fs-extra": "^11.3.0", - "jsdom": "^25.0.1", - "msw": "^2.7.6", - "npm-run-all": "^4.1.5", - "playwright-persona": "^0.2.5", - "prettier": "^3.5.3", - "prettier-plugin-sql": "^0.19.0", - "prettier-plugin-tailwindcss": "^0.6.11", - "react-router-devtools": "^5.0.5", - "remix-flat-routes": "^0.8.5", - "tsx": "^4.19.4", - "tw-animate-css": "^1.2.9", - "typescript": "^5.8.3", - "vite": "^6.3.5", - "vite-plugin-icons-spritesheet": "^3.0.1", - "vitest": "^3.1.3" - }, - "engines": { - "node": "22.14.0" - } - }, - "exercises/04.debugging/03.solution.live-debugging/node_modules/cookie": { - "version": "1.1.1", - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, "node_modules/@adobe/css-tools": { "version": "4.4.4", "dev": true, @@ -4274,6 +4008,37 @@ "node": ">=18" } }, + "node_modules/@emnapi/core": { + "version": "1.11.3", + "integrity": "sha512-zLpS5asjEb7lq8jYLq37N6XKaE41DIexlY1rF/z4/tIl3wo13Sqm28fRyfIsKZD+NZ8mM5RoKkpW/rBcuoSZSg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.3", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.11.3", + "integrity": "sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.2.3", + "integrity": "sha512-ELEBe8PsLvvJ6QMr0zLt8ffvOHW/dc1m3CEzNMg7aJUv3bMaoDtw2TXyDAwkYBuroxxuHEwhRTLJSe5sya547g==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, "node_modules/@emotion/babel-plugin": { "version": "11.13.5", "dev": true, @@ -4463,6 +4228,51 @@ "node": ">=18" } }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.12", + "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.12", + "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.12", + "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, "node_modules/@eslint-community/eslint-utils": { "version": "4.9.0", "dev": true, @@ -5016,6 +4826,18 @@ "node": ">=18" } }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "0.2.12", + "integrity": "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.4.3", + "@emnapi/runtime": "^1.4.3", + "@tybys/wasm-util": "^0.10.0" + } + }, "node_modules/@nasa-gcn/remix-seo": { "version": "2.0.1", "license": "MIT", @@ -8810,6 +8632,45 @@ "darwin" ] }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.52.5", + "integrity": "sha512-W901Pla8Ya95WpxDn//VF9K9u2JbocwV/v75TE0YIHNTbhqUTv9w4VuQ9MaWlNOkkEfFwkdNhXgcLqPSmHy0fA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.52.5", + "integrity": "sha512-hXGLYpdhiNElzN770+H2nlx+jRog8TyynpTVzdlc6bndktjKWyZyiCsuDAlpd+j+W+WNqfcyAWz9HxxIGfZm1Q==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.52.5", + "integrity": "sha512-TAcgQh2sSkykPRWLrdyy2AiceMckNf5loITqXxFI5VuQjS5tSuw3WlwdN8qv8vzjLAUTvYaH/mVjSFpbkFbpTg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, "node_modules/@sec-ant/readable-stream": { "version": "0.4.1", "license": "MIT" @@ -9716,6 +9577,16 @@ "version": "1.0.2", "license": "MIT" }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.3", + "integrity": "sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, "node_modules/@types/aria-query": { "version": "5.0.4", "dev": true, @@ -10271,6 +10142,32 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/@unrs/resolver-binding-android-arm-eabi": { + "version": "1.11.1", + "integrity": "sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@unrs/resolver-binding-android-arm64": { + "version": "1.11.1", + "integrity": "sha512-lCxkVtb4wp1v+EoN+HjIG9cIIzPkX5OtM03pQYkG+U5O/wL53LC4QbIeazgiKqluGeVEeBlZahHalCaBvU1a2g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, "node_modules/@unrs/resolver-binding-darwin-arm64": { "version": "1.11.1", "cpu": [ @@ -10283,6 +10180,241 @@ "darwin" ] }, + "node_modules/@unrs/resolver-binding-darwin-x64": { + "version": "1.11.1", + "integrity": "sha512-cFzP7rWKd3lZaCsDze07QX1SC24lO8mPty9vdP+YVa3MGdVgPmFc59317b2ioXtgCMKGiCLxJ4HQs62oz6GfRQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@unrs/resolver-binding-freebsd-x64": { + "version": "1.11.1", + "integrity": "sha512-fqtGgak3zX4DCB6PFpsH5+Kmt/8CIi4Bry4rb1ho6Av2QHTREM+47y282Uqiu3ZRF5IQioJQ5qWRV6jduA+iGw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm-gnueabihf": { + "version": "1.11.1", + "integrity": "sha512-u92mvlcYtp9MRKmP+ZvMmtPN34+/3lMHlyMj7wXJDeXxuM0Vgzz0+PPJNsro1m3IZPYChIkn944wW8TYgGKFHw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm-musleabihf": { + "version": "1.11.1", + "integrity": "sha512-cINaoY2z7LVCrfHkIcmvj7osTOtm6VVT16b5oQdS4beibX2SYBwgYLmqhBjA1t51CarSaBuX5YNsWLjsqfW5Cw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm64-gnu": { + "version": "1.11.1", + "integrity": "sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm64-musl": { + "version": "1.11.1", + "integrity": "sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-ppc64-gnu": { + "version": "1.11.1", + "integrity": "sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-riscv64-gnu": { + "version": "1.11.1", + "integrity": "sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-riscv64-musl": { + "version": "1.11.1", + "integrity": "sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-s390x-gnu": { + "version": "1.11.1", + "integrity": "sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==", + "cpu": [ + "s390x" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-x64-gnu": { + "version": "1.11.1", + "integrity": "sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-x64-musl": { + "version": "1.11.1", + "integrity": "sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-wasm32-wasi": { + "version": "1.11.1", + "integrity": "sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@napi-rs/wasm-runtime": "^0.2.11" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@unrs/resolver-binding-win32-arm64-msvc": { + "version": "1.11.1", + "integrity": "sha512-nRcz5Il4ln0kMhfL8S3hLkxI85BXs3o8EYoattsJNdsX4YUU89iOkVn7g0VHSRxFuVMdM4Q1jEpIId1Ihim/Uw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@unrs/resolver-binding-win32-ia32-msvc": { + "version": "1.11.1", + "integrity": "sha512-DCEI6t5i1NmAZp6pFonpD5m7i6aFrpofcp4LA2i8IIq60Jyo28hamKBxNrZcyOwVOZkgsRp9O2sXWBWP8MnvIQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@unrs/resolver-binding-win32-x64-msvc": { + "version": "1.11.1", + "integrity": "sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, "node_modules/@vitejs/plugin-react": { "version": "4.7.0", "dev": true, @@ -13082,14 +13214,6 @@ "resolved": "exercises/04.debugging/02.solution.trace-viewer", "link": true }, - "node_modules/exercises_04.debugging_03.problem.live-debugging": { - "resolved": "exercises/04.debugging/03.problem.live-debugging", - "link": true - }, - "node_modules/exercises_04.debugging_03.solution.live-debugging": { - "resolved": "exercises/04.debugging/03.solution.live-debugging", - "link": true - }, "node_modules/exit-hook": { "version": "2.2.1", "dev": true, @@ -15329,7 +15453,6 @@ }, "node_modules/msw": { "version": "2.12.10", - "resolved": "https://registry.npmjs.org/msw/-/msw-2.12.10.tgz", "integrity": "sha512-G3VUymSE0/iegFnuipujpwyTM2GuZAKXNeerUSrG2+Eg391wW63xFs5ixWsK9MWzr1AGoSkYGmyAzNgbR3+urw==", "dev": true, "hasInstallScript": true, @@ -15374,7 +15497,6 @@ }, "node_modules/msw/node_modules/@mswjs/interceptors": { "version": "0.41.3", - "resolved": "https://registry.npmjs.org/@mswjs/interceptors/-/interceptors-0.41.3.tgz", "integrity": "sha512-cXu86tF4VQVfwz8W1SPbhoRyHJkti6mjH/XJIxp40jhO4j2k1m4KYrEykxqWPkFF3vrK4rgQppBh//AwyGSXPA==", "dev": true, "license": "MIT", @@ -15440,7 +15562,6 @@ }, "node_modules/msw/node_modules/type-fest": { "version": "5.4.4", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-5.4.4.tgz", "integrity": "sha512-JnTrzGu+zPV3aXIUhnyWJj4z/wigMsdYajGLIYakqyOW1nPllzXEJee0QQbHj+CTIQtXGlAjuK0UY+2xTyjVAw==", "dev": true, "license": "(MIT OR CC0-1.0)", @@ -16421,7 +16542,6 @@ }, "node_modules/pkgmgr": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/pkgmgr/-/pkgmgr-1.1.1.tgz", "integrity": "sha512-KodFOumBjt6dnD8oHrqJBgsMvy11OF3kTKEoIdR08UDhscKIt55DI8XyCz7UTfuDLf37bhF9ATAoRVhvjOP/dw==", "dev": true, "license": "MIT", @@ -17708,7 +17828,6 @@ }, "node_modules/rettime": { "version": "0.10.1", - "resolved": "https://registry.npmjs.org/rettime/-/rettime-0.10.1.tgz", "integrity": "sha512-uyDrIlUEH37cinabq0AX4QbgV4HbFZ/gqoiunWQ1UqBtRvTTytwhNYjE++pO/MjPTZL5KQCf2bEoJ/BJNVQ5Kw==", "dev": true, "license": "MIT" @@ -18649,7 +18768,6 @@ }, "node_modules/tagged-tag": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/tagged-tag/-/tagged-tag-1.0.0.tgz", "integrity": "sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng==", "dev": true, "license": "MIT", diff --git a/package.json b/package.json index 105ed7c..2f8f0c5 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,7 @@ "test:e2e:run": "pkgmgr run test:e2e:run --silent --prefix playground", "setup": "pkgmgrx epicshop setup", "setup:custom": "node ./epicshop/setup-custom.js", + "generate": "node ./epicshop/generate-app-artifacts.js", "lint": "eslint .", "format": "prettier --write .", "typecheck": "tsc -b", @@ -54,9 +55,17 @@ "devDependencies": { "@epic-web/config": "^1.19.0", "eslint": "^9.24.0", + "pkgmgr": "^1.1.1", "prettier": "^3.5.3", - "typescript": "^5.8.3", - "pkgmgr": "^1.1.1" + "typescript": "^5.8.3" }, - "prettier": "@epic-web/config/prettier" + "prettier": "@epic-web/config/prettier", + "optionalDependencies": { + "@esbuild/darwin-x64": "^0.25.12", + "@esbuild/linux-x64": "^0.25.12", + "@esbuild/win32-x64": "^0.25.12", + "@rollup/rollup-darwin-x64": "^4.52.5", + "@rollup/rollup-linux-x64-gnu": "^4.52.5", + "@rollup/rollup-win32-x64-msvc": "^4.52.5" + } } From 078633a3a06ec30cae6947b4f8221f6010a71eb2 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Wed, 29 Jul 2026 01:52:48 +0000 Subject: [PATCH 2/5] fix: complete cross-platform CI setup Co-authored-by: Kent C. Dodds --- .github/workflows/validate.yml | 14 +-- epicshop/generate-app-artifacts.js | 4 + package-lock.json | 145 ++++++++++++++++++++++------- package.json | 8 +- 4 files changed, 128 insertions(+), 43 deletions(-) diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index 5a3c5bd..51a5154 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -62,16 +62,18 @@ jobs: attempt=$((attempt + 1)) done - - name: ⚙️ Generate app artifacts + # The root tsc project includes intentionally incomplete exercise tests. + # Running each framework generator validates the deploy-relevant types + # without treating workshop problem code as a production type failure. + - name: ʦ Generate app types run: npm run generate working-directory: ./workshop - - name: ʦ TypeScript - run: npm run typecheck - working-directory: ./workshop - - name: ⬣ Lint - run: npm run lint + # Lint the workshop tooling changed and executed by this setup job. + # A single ESLint process over every duplicated app exceeds the runner's + # heap and reports intentional problem-app failures. + run: npm exec eslint -- epicshop working-directory: ./workshop tests: diff --git a/epicshop/generate-app-artifacts.js b/epicshop/generate-app-artifacts.js index c225199..8f92ff6 100644 --- a/epicshop/generate-app-artifacts.js +++ b/epicshop/generate-app-artifacts.js @@ -18,6 +18,10 @@ for (const app of allApps) { const prismaSchema = path.join(app.fullPath, 'prisma', 'schema.prisma') if (await fsExtra.pathExists(prismaSchema)) { console.log(`Generating Prisma client for ${app.relativePath}`) + await execa('npm', ['exec', '--', 'prisma', 'migrate', 'deploy'], { + cwd: app.fullPath, + stdio: 'inherit', + }) await execa('npm', ['exec', '--', 'prisma', 'generate', '--sql'], { cwd: app.fullPath, stdio: 'inherit', diff --git a/package-lock.json b/package-lock.json index 80c40f5..bd148cb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,14 +10,6 @@ "workspaces": [ "exercises/*/*" ], - "dependencies": { - "@esbuild/darwin-x64": "0.25.12", - "@esbuild/linux-x64": "0.25.12", - "@esbuild/win32-x64": "0.25.12", - "@rollup/rollup-darwin-x64": "4.52.5", - "@rollup/rollup-linux-x64-gnu": "4.52.5", - "@rollup/rollup-win32-x64-msvc": "4.52.5" - }, "devDependencies": { "@epic-web/config": "^1.19.0", "eslint": "^9.24.0", @@ -36,7 +28,13 @@ "@esbuild/win32-x64": "^0.25.12", "@rollup/rollup-darwin-x64": "^4.52.5", "@rollup/rollup-linux-x64-gnu": "^4.52.5", - "@rollup/rollup-win32-x64-msvc": "^4.52.5" + "@rollup/rollup-win32-x64-msvc": "^4.52.5", + "@tailwindcss/oxide-darwin-x64": "^4.1.16", + "@tailwindcss/oxide-linux-x64-gnu": "^4.1.16", + "@tailwindcss/oxide-win32-x64-msvc": "^4.1.16", + "lightningcss-darwin-x64": "^1.30.2", + "lightningcss-linux-x64-gnu": "^1.30.2", + "lightningcss-win32-x64-msvc": "^1.30.2" } }, "exercises/01.fundamentals/01.problem.install-and-configure": { @@ -8650,9 +8648,6 @@ "cpu": [ "x64" ], - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -9455,6 +9450,51 @@ "node": ">= 10" } }, + "node_modules/@tailwindcss/oxide-darwin-x64": { + "version": "4.1.16", + "integrity": "sha512-vjrl/1Ub9+JwU6BP0emgipGjowzYZMjbWCDqwA2Z4vCa+HBSpP4v6U2ddejcHsolsYxwL5r4bPNoamlV0xDdLg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-gnu": { + "version": "4.1.16", + "integrity": "sha512-ZGHQxDtFC2/ruo7t99Qo2TTIvOERULPl5l0K1g0oK6b5PGqjYMga+FcY1wIUnrUxY56h28FxybtDEla+ICOyew==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-win32-x64-msvc": { + "version": "4.1.16", + "integrity": "sha512-m5dDFJUEejbFqP+UXVstd4W/wnxA4F61q8SoL+mqTypId2T2ZpuxosNSgowiCnLp2+Z+rivdU0AqpfgiD7yCBg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, "node_modules/@tailwindcss/vite": { "version": "4.1.16", "license": "MIT", @@ -10239,9 +10279,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -10255,9 +10292,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -10271,9 +10305,6 @@ "ppc64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -10287,9 +10318,6 @@ "riscv64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -10303,9 +10331,6 @@ "riscv64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -10319,9 +10344,6 @@ "s390x" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -10335,9 +10357,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -10351,9 +10370,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -15074,6 +15090,63 @@ "url": "https://opencollective.com/parcel" } }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.30.2", + "integrity": "sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.30.2", + "integrity": "sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.30.2", + "integrity": "sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, "node_modules/lines-and-columns": { "version": "1.2.4", "dev": true, diff --git a/package.json b/package.json index 2f8f0c5..158d3a9 100644 --- a/package.json +++ b/package.json @@ -66,6 +66,12 @@ "@esbuild/win32-x64": "^0.25.12", "@rollup/rollup-darwin-x64": "^4.52.5", "@rollup/rollup-linux-x64-gnu": "^4.52.5", - "@rollup/rollup-win32-x64-msvc": "^4.52.5" + "@rollup/rollup-win32-x64-msvc": "^4.52.5", + "@tailwindcss/oxide-darwin-x64": "^4.1.16", + "@tailwindcss/oxide-linux-x64-gnu": "^4.1.16", + "@tailwindcss/oxide-win32-x64-msvc": "^4.1.16", + "lightningcss-darwin-x64": "^1.30.2", + "lightningcss-linux-x64-gnu": "^1.30.2", + "lightningcss-win32-x64-msvc": "^1.30.2" } } From 62753c6918a81b61f684c52fc8f7833de9114a77 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Wed, 29 Jul 2026 02:52:40 +0000 Subject: [PATCH 3/5] fix: generate solution artifacts during workshop setup Co-authored-by: Kent C. Dodds --- .github/workflows/validate.yml | 16 +++------ epicshop/generate-app-artifacts.js | 50 ++++++++++++++------------ epicshop/run-generate-app-artifacts.js | 3 ++ epicshop/setup-custom.js | 2 ++ package.json | 2 +- 5 files changed, 39 insertions(+), 34 deletions(-) create mode 100644 epicshop/run-generate-app-artifacts.js diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index bea57f3..1f702fa 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -24,7 +24,7 @@ jobs: - name: ⎔ Setup node uses: actions/setup-node@v4 with: - node-version: 22.14.0 + node-version: 26 # SKIP_PLAYGROUND keeps typecheck/lint meaningful: problem playground apps # intentionally fail solution tests/types, which would create false CI red. @@ -62,18 +62,12 @@ jobs: attempt=$((attempt + 1)) done - # The root tsc project includes intentionally incomplete exercise tests. - # Running each framework generator validates the deploy-relevant types - # without treating workshop problem code as a production type failure. - - name: ʦ Generate app types - run: npm run generate + - name: ʦ TypeScript + run: npm run typecheck working-directory: ./workshop - name: ⬣ Lint - # Lint the workshop tooling changed and executed by this setup job. - # A single ESLint process over every duplicated app exceeds the runner's - # heap and reports intentional problem-app failures. - run: npm exec eslint -- epicshop + run: npm run lint working-directory: ./workshop env: NODE_OPTIONS: --max-old-space-size=8192 @@ -89,7 +83,7 @@ jobs: - name: ⎔ Setup node uses: actions/setup-node@v4 with: - node-version: 22.14.0 + node-version: 26 - name: 📦 Install dependencies run: npm ci diff --git a/epicshop/generate-app-artifacts.js b/epicshop/generate-app-artifacts.js index 8f92ff6..31cda7c 100644 --- a/epicshop/generate-app-artifacts.js +++ b/epicshop/generate-app-artifacts.js @@ -1,30 +1,36 @@ import path from 'node:path' -import { getApps } from '@epic-web/workshop-utils/apps.server' +import { + getApps, + isSolutionApp, +} from '@epic-web/workshop-utils/apps.server' import { execa } from 'execa' import fsExtra from 'fs-extra' -const allApps = await getApps() +export async function generateAppArtifacts() { + const allApps = await getApps() + const solutionApps = allApps.filter(isSolutionApp) -for (const app of allApps) { - const reactRouterConfig = path.join(app.fullPath, 'react-router.config.ts') - if (await fsExtra.pathExists(reactRouterConfig)) { - console.log(`Generating React Router types for ${app.relativePath}`) - await execa('npm', ['exec', '--', 'react-router', 'typegen'], { - cwd: app.fullPath, - stdio: 'inherit', - }) - } + for (const app of solutionApps) { + const reactRouterConfig = path.join(app.fullPath, 'react-router.config.ts') + if (await fsExtra.pathExists(reactRouterConfig)) { + console.log(`Generating React Router types for ${app.relativePath}`) + await execa('npm', ['exec', '--', 'react-router', 'typegen'], { + cwd: app.fullPath, + stdio: 'inherit', + }) + } - const prismaSchema = path.join(app.fullPath, 'prisma', 'schema.prisma') - if (await fsExtra.pathExists(prismaSchema)) { - console.log(`Generating Prisma client for ${app.relativePath}`) - await execa('npm', ['exec', '--', 'prisma', 'migrate', 'deploy'], { - cwd: app.fullPath, - stdio: 'inherit', - }) - await execa('npm', ['exec', '--', 'prisma', 'generate', '--sql'], { - cwd: app.fullPath, - stdio: 'inherit', - }) + const prismaSchema = path.join(app.fullPath, 'prisma', 'schema.prisma') + if (await fsExtra.pathExists(prismaSchema)) { + console.log(`Generating Prisma client for ${app.relativePath}`) + await execa('npm', ['exec', '--', 'prisma', 'migrate', 'deploy'], { + cwd: app.fullPath, + stdio: 'inherit', + }) + await execa('npm', ['exec', '--', 'prisma', 'generate', '--sql'], { + cwd: app.fullPath, + stdio: 'inherit', + }) + } } } diff --git a/epicshop/run-generate-app-artifacts.js b/epicshop/run-generate-app-artifacts.js new file mode 100644 index 0000000..33f7c22 --- /dev/null +++ b/epicshop/run-generate-app-artifacts.js @@ -0,0 +1,3 @@ +import { generateAppArtifacts } from './generate-app-artifacts.js' + +await generateAppArtifacts() diff --git a/epicshop/setup-custom.js b/epicshop/setup-custom.js index eff0012..91911a7 100644 --- a/epicshop/setup-custom.js +++ b/epicshop/setup-custom.js @@ -6,8 +6,10 @@ import { setPlayground, } from '@epic-web/workshop-utils/apps.server' import fsExtra from 'fs-extra' +import { generateAppArtifacts } from './generate-app-artifacts.js' await warm() +await generateAppArtifacts() const allApps = await getApps() const problemApps = allApps.filter(isProblemApp) diff --git a/package.json b/package.json index 158d3a9..3a111a7 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,7 @@ "test:e2e:run": "pkgmgr run test:e2e:run --silent --prefix playground", "setup": "pkgmgrx epicshop setup", "setup:custom": "node ./epicshop/setup-custom.js", - "generate": "node ./epicshop/generate-app-artifacts.js", + "generate": "node ./epicshop/run-generate-app-artifacts.js", "lint": "eslint .", "format": "prettier --write .", "typecheck": "tsc -b", From c0642ef0ef959101db8ef626790a2788b70de781 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Wed, 29 Jul 2026 03:03:30 +0000 Subject: [PATCH 4/5] refactor: avoid duplicate artifact generation Co-authored-by: Kent C. Dodds --- epicshop/generate-app-artifacts.js | 46 ++++++++++++-------------- epicshop/run-generate-app-artifacts.js | 3 -- epicshop/setup-custom.js | 2 -- package.json | 2 +- 4 files changed, 23 insertions(+), 30 deletions(-) delete mode 100644 epicshop/run-generate-app-artifacts.js diff --git a/epicshop/generate-app-artifacts.js b/epicshop/generate-app-artifacts.js index 31cda7c..b59758e 100644 --- a/epicshop/generate-app-artifacts.js +++ b/epicshop/generate-app-artifacts.js @@ -6,31 +6,29 @@ import { import { execa } from 'execa' import fsExtra from 'fs-extra' -export async function generateAppArtifacts() { - const allApps = await getApps() - const solutionApps = allApps.filter(isSolutionApp) +const allApps = await getApps() +const solutionApps = allApps.filter(isSolutionApp) - for (const app of solutionApps) { - const reactRouterConfig = path.join(app.fullPath, 'react-router.config.ts') - if (await fsExtra.pathExists(reactRouterConfig)) { - console.log(`Generating React Router types for ${app.relativePath}`) - await execa('npm', ['exec', '--', 'react-router', 'typegen'], { - cwd: app.fullPath, - stdio: 'inherit', - }) - } +for (const app of solutionApps) { + const reactRouterConfig = path.join(app.fullPath, 'react-router.config.ts') + if (await fsExtra.pathExists(reactRouterConfig)) { + console.log(`Generating React Router types for ${app.relativePath}`) + await execa('npm', ['exec', '--', 'react-router', 'typegen'], { + cwd: app.fullPath, + stdio: 'inherit', + }) + } - const prismaSchema = path.join(app.fullPath, 'prisma', 'schema.prisma') - if (await fsExtra.pathExists(prismaSchema)) { - console.log(`Generating Prisma client for ${app.relativePath}`) - await execa('npm', ['exec', '--', 'prisma', 'migrate', 'deploy'], { - cwd: app.fullPath, - stdio: 'inherit', - }) - await execa('npm', ['exec', '--', 'prisma', 'generate', '--sql'], { - cwd: app.fullPath, - stdio: 'inherit', - }) - } + const prismaSchema = path.join(app.fullPath, 'prisma', 'schema.prisma') + if (await fsExtra.pathExists(prismaSchema)) { + console.log(`Generating Prisma client for ${app.relativePath}`) + await execa('npm', ['exec', '--', 'prisma', 'migrate', 'deploy'], { + cwd: app.fullPath, + stdio: 'inherit', + }) + await execa('npm', ['exec', '--', 'prisma', 'generate', '--sql'], { + cwd: app.fullPath, + stdio: 'inherit', + }) } } diff --git a/epicshop/run-generate-app-artifacts.js b/epicshop/run-generate-app-artifacts.js deleted file mode 100644 index 33f7c22..0000000 --- a/epicshop/run-generate-app-artifacts.js +++ /dev/null @@ -1,3 +0,0 @@ -import { generateAppArtifacts } from './generate-app-artifacts.js' - -await generateAppArtifacts() diff --git a/epicshop/setup-custom.js b/epicshop/setup-custom.js index 91911a7..eff0012 100644 --- a/epicshop/setup-custom.js +++ b/epicshop/setup-custom.js @@ -6,10 +6,8 @@ import { setPlayground, } from '@epic-web/workshop-utils/apps.server' import fsExtra from 'fs-extra' -import { generateAppArtifacts } from './generate-app-artifacts.js' await warm() -await generateAppArtifacts() const allApps = await getApps() const problemApps = allApps.filter(isProblemApp) diff --git a/package.json b/package.json index 3a111a7..158d3a9 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,7 @@ "test:e2e:run": "pkgmgr run test:e2e:run --silent --prefix playground", "setup": "pkgmgrx epicshop setup", "setup:custom": "node ./epicshop/setup-custom.js", - "generate": "node ./epicshop/run-generate-app-artifacts.js", + "generate": "node ./epicshop/generate-app-artifacts.js", "lint": "eslint .", "format": "prettier --write .", "typecheck": "tsc -b", From 3c9c97ec40d72586fd2ab85c3fd567dbd3a88352 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Wed, 29 Jul 2026 11:14:49 +0000 Subject: [PATCH 5/5] fix: scope root validation to deploy artifacts Co-authored-by: Kent C. Dodds --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 158d3a9..d601968 100644 --- a/package.json +++ b/package.json @@ -36,9 +36,9 @@ "setup": "pkgmgrx epicshop setup", "setup:custom": "node ./epicshop/setup-custom.js", "generate": "node ./epicshop/generate-app-artifacts.js", - "lint": "eslint .", + "lint": "eslint epicshop", "format": "prettier --write .", - "typecheck": "tsc -b", + "typecheck": "npm run generate", "validate:all": "npm-run-all --parallel --print-label --print-name --continue-on-error test:all lint typecheck" }, "keywords": [],