diff --git a/.vscode/settings.json b/.vscode/settings.json index aee56f3ff939..4d52d856394e 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -59,4 +59,5 @@ "[javascript]": { "editor.defaultFormatter": "biomejs.biome" }, + "todo-tree.tree.disableCompactFolders": true, } diff --git a/packages/runtime/plugin-runtime/package.json b/packages/runtime/plugin-runtime/package.json index c74515e6302e..254d97a5036e 100644 --- a/packages/runtime/plugin-runtime/package.json +++ b/packages/runtime/plugin-runtime/package.json @@ -232,8 +232,8 @@ "@types/node": "^14", "@types/react-side-effect": "^1.1.1", "jest": "^29", - "react": "^18", - "react-dom": "^18", + "react": "18.3.0-canary-8039e6d0b-20231026", + "react-dom": "18.3.0-canary-8039e6d0b-20231026", "ts-jest": "^29.1.0", "typescript": "^5", "webpack": "^5.93.0" diff --git a/packages/runtime/plugin-runtime/src/cli/index.ts b/packages/runtime/plugin-runtime/src/cli/index.ts index 4b9a65d358e1..27cb7e5a3cfb 100644 --- a/packages/runtime/plugin-runtime/src/cli/index.ts +++ b/packages/runtime/plugin-runtime/src/cli/index.ts @@ -15,7 +15,7 @@ import { generateCode } from './code'; import { builderPluginAlias } from './alias'; export { isRuntimeEntry } from './entry'; -export { statePlugin, ssrPlugin, routerPlugin, documentPlugin }; +export { statePlugin, ssrPlugin, routerPlugin }; export const runtimePlugin = (params?: { plugins?: CliPlugin[]; }): CliPlugin => ({ @@ -32,7 +32,7 @@ export const runtimePlugin = (params?: { ssrPlugin(), routerPlugin(), statePlugin(), - documentPlugin(), + // documentPlugin(), ], setup: api => { return { diff --git a/packages/runtime/plugin-runtime/src/cli/template.ts b/packages/runtime/plugin-runtime/src/cli/template.ts index e21cec93955c..390d9bb57d1e 100644 --- a/packages/runtime/plugin-runtime/src/cli/template.ts +++ b/packages/runtime/plugin-runtime/src/cli/template.ts @@ -68,7 +68,8 @@ export const index = ({ customBootstrap?: string | false; mountId?: string; }) => - `import '@${metaName}/runtime/registry/${entryName}'; + // TODO: remove this + ` ${genRenderCode({ srcDirectory, internalSrcAlias, @@ -166,6 +167,7 @@ import App from '${ customEntry ? entry .replace('entry.tsx', 'App') + .replace('entry.jsx', 'App') .replace(srcDirectory, internalSrcAlias) : entry.replace(srcDirectory, internalSrcAlias).replace('.tsx', ''), ) diff --git a/packages/runtime/plugin-runtime/src/core/server/stream/afterTemplate.ts b/packages/runtime/plugin-runtime/src/core/server/stream/afterTemplate.ts index 4eb5bb9d6f6b..b67603c760d5 100644 --- a/packages/runtime/plugin-runtime/src/core/server/stream/afterTemplate.ts +++ b/packages/runtime/plugin-runtime/src/core/server/stream/afterTemplate.ts @@ -38,7 +38,7 @@ export function buildShellAfterTemplate( async function injectJs(template: string, entryName: string, nonce?: string) { const { routeManifest } = runtimeContext; const { routeAssets } = routeManifest; - const asyncEntry = routeAssets[`async-${entryName}`]; + const asyncEntry = routeAssets?.[`async-${entryName}`]; if (asyncEntry) { const { assets } = asyncEntry; const jsChunkStr = assets diff --git a/packages/runtime/plugin-runtime/src/core/server/stream/createReadableStream.ts b/packages/runtime/plugin-runtime/src/core/server/stream/createReadableStream.ts index 91f672a2fe08..1b053d4cf1c8 100644 --- a/packages/runtime/plugin-runtime/src/core/server/stream/createReadableStream.ts +++ b/packages/runtime/plugin-runtime/src/core/server/stream/createReadableStream.ts @@ -64,15 +64,15 @@ export const createReadableStreamFromElement: CreateReadableStreamFromElement = * So we use the `SHELL_STREAM_END_MARK` to mark the shell content' tail. */ let concatedChunk = chunkVec.join(''); - if (concatedChunk.includes(ESCAPED_SHELL_STREAM_END_MARK)) { - concatedChunk = concatedChunk.replace( - ESCAPED_SHELL_STREAM_END_MARK, - '', - ); - - shellChunkStatus = ShellChunkStatus.FINISH; - this.push(`${shellBefore}${concatedChunk}${shellAfter}`); - } + // if (concatedChunk.includes(ESCAPED_SHELL_STREAM_END_MARK)) { + concatedChunk = concatedChunk.replace( + ESCAPED_SHELL_STREAM_END_MARK, + '', + ); + + shellChunkStatus = ShellChunkStatus.FINISH; + this.push(`${shellBefore}${concatedChunk}${shellAfter}`); + // } } else { this.push(chunk); } diff --git a/packages/solutions/app-tools/src/plugins/analyze/index.ts b/packages/solutions/app-tools/src/plugins/analyze/index.ts index 240f2a1801a4..c834c7bb2857 100644 --- a/packages/solutions/app-tools/src/plugins/analyze/index.ts +++ b/packages/solutions/app-tools/src/plugins/analyze/index.ts @@ -168,7 +168,7 @@ export default ({ builder.onAfterBuild(async ({ stats }) => { const hookRunners = api.useHookRunners(); - await hookRunners.afterBuild({ stats }); + await hookRunners.afterBuild({ stats: stats as any }); await emitResolvedConfig(appContext.appDirectory, normalizedConfig); }); diff --git a/packages/toolkit/utils/src/cli/is/project.ts b/packages/toolkit/utils/src/cli/is/project.ts index 959c0470dc3b..e52dedeea5be 100644 --- a/packages/toolkit/utils/src/cli/is/project.ts +++ b/packages/toolkit/utils/src/cli/is/project.ts @@ -116,7 +116,7 @@ export const isReact18 = (cwd: string = process.cwd()) => { return false; } - return semver.satisfies(semver.minVersion(deps.react)!, '>=18.0.0'); + return semver.gte(semver.minVersion(deps.react)!, '18.0.0'); }; /** diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 37dd9d426351..d7c68d66702d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1009,7 +1009,7 @@ importers: version: 0.2.4(@rspack/core@0.5.1)(esbuild@0.17.19) '@rsdoctor/utils': specifier: ^0.2.4 - version: 0.2.4(@rspack/core@0.5.1)(esbuild@0.17.19) + version: 0.2.4(esbuild@0.17.19) birpc: specifier: 0.2.13 version: 0.2.13 @@ -2858,10 +2858,10 @@ importers: version: 5.15.3(@babel/core@7.24.7) '@loadable/component': specifier: 5.15.3 - version: 5.15.3(react@18.2.0) + version: 5.15.3(react@18.3.0-canary-8039e6d0b-20231026) '@loadable/server': specifier: 5.15.3 - version: 5.15.3(@loadable/component@5.15.3)(react@18.2.0) + version: 5.15.3(@loadable/component@5.15.3)(react@18.3.0-canary-8039e6d0b-20231026) '@modern-js-reduck/plugin-auto-actions': specifier: ^1.1.10 version: 1.1.10(@modern-js-reduck/store@1.1.10) @@ -2876,7 +2876,7 @@ importers: version: 1.1.10(@modern-js-reduck/store@1.1.10) '@modern-js-reduck/react': specifier: ^1.1.10 - version: 1.1.10(@types/react-dom@18.0.6)(@types/react@18.0.21)(react-dom@18.2.0)(react@18.2.0) + version: 1.1.10(@types/react-dom@18.0.6)(@types/react@18.0.21)(react-dom@18.3.0-canary-8039e6d0b-20231026)(react@18.3.0-canary-8039e6d0b-20231026) '@modern-js-reduck/store': specifier: ^1.1.10 version: 1.1.10 @@ -2924,16 +2924,16 @@ importers: version: 3.7.1 react-helmet: specifier: ^6.1.0 - version: 6.1.0(react@18.2.0) + version: 6.1.0(react@18.3.0-canary-8039e6d0b-20231026) react-is: specifier: ^18 version: 18.2.0 react-side-effect: specifier: ^2.1.1 - version: 2.1.2(react@18.2.0) + version: 2.1.2(react@18.3.0-canary-8039e6d0b-20231026) styled-components: specifier: ^5.3.1 - version: 5.3.5(react-dom@18.2.0)(react-is@18.2.0)(react@18.2.0) + version: 5.3.5(react-dom@18.3.0-canary-8039e6d0b-20231026)(react-is@18.2.0)(react@18.3.0-canary-8039e6d0b-20231026) devDependencies: '@modern-js/app-tools': specifier: workspace:* @@ -2955,7 +2955,7 @@ importers: version: link:../../../scripts/jest-config '@testing-library/react': specifier: ^13.4.0 - version: 13.4.0(react-dom@18.2.0)(react@18.2.0) + version: 13.4.0(react-dom@18.3.0-canary-8039e6d0b-20231026)(react@18.3.0-canary-8039e6d0b-20231026) '@types/cookie': specifier: 0.5.1 version: 0.5.1 @@ -2981,11 +2981,11 @@ importers: specifier: ^29 version: 29.5.0(@types/node@14.18.35)(ts-node@10.9.2) react: - specifier: ^18 - version: 18.2.0 + specifier: 18.3.0-canary-8039e6d0b-20231026 + version: 18.3.0-canary-8039e6d0b-20231026 react-dom: - specifier: ^18 - version: 18.2.0(react@18.2.0) + specifier: 18.3.0-canary-8039e6d0b-20231026 + version: 18.3.0-canary-8039e6d0b-20231026(react@18.3.0-canary-8039e6d0b-20231026) ts-jest: specifier: ^29.1.0 version: 29.1.0(@babel/core@7.24.7)(esbuild@0.17.19)(jest@29.5.0)(typescript@5.3.3) @@ -5435,7 +5435,7 @@ importers: version: 18.2.0 react-dom: specifier: ^18 - version: 18.2.0(react@18.2.0) + version: 18.3.1(react@18.2.0) devDependencies: '@modern-js/app-tools': specifier: workspace:* @@ -5608,7 +5608,7 @@ importers: version: 18.2.0 react-dom: specifier: ^18 - version: 18.2.0(react@18.2.0) + version: 18.3.1(react@18.2.0) devDependencies: '@modern-js/app-tools': specifier: workspace:* @@ -5632,6 +5632,134 @@ importers: specifier: ^5 version: 5.3.3 + tests/integration/basic-next-app: + dependencies: + '@modern-js/runtime': + specifier: workspace:* + version: link:../../../packages/runtime/plugin-runtime + date-fns: + specifier: ^2.29.3 + version: 2.29.3 + excerpts: + specifier: 0.0.3 + version: 0.0.3 + marked: + specifier: 4.2.12 + version: 4.2.12 + pg: + specifier: 8.10.0 + version: 8.10.0 + react: + specifier: 18.3.0-canary-8039e6d0b-20231026 + version: 18.3.0-canary-8039e6d0b-20231026 + react-dom: + specifier: 18.3.0-canary-8039e6d0b-20231026 + version: 18.3.0-canary-8039e6d0b-20231026(react@18.3.0-canary-8039e6d0b-20231026) + react-error-boundary: + specifier: 3.1.4 + version: 3.1.4(react@18.3.0-canary-8039e6d0b-20231026) + react-server-dom-webpack: + specifier: 18.3.0-canary-8039e6d0b-20231026 + version: 18.3.0-canary-8039e6d0b-20231026(react-dom@18.3.0-canary-8039e6d0b-20231026)(react@18.3.0-canary-8039e6d0b-20231026)(webpack@5.93.0) + sanitize-html: + specifier: 2.10.0 + version: 2.10.0 + server-only: + specifier: ^0.0.1 + version: 0.0.1 + devDependencies: + '@modern-js/app-tools': + specifier: workspace:* + version: link:../../../packages/solutions/app-tools + '@modern-js/plugin-swc': + specifier: workspace:* + version: link:../../../packages/cli/plugin-swc + '@modern-js/server-core': + specifier: workspace:* + version: link:../../../packages/server/core + '@types/jest': + specifier: ^29 + version: 29.2.6 + '@types/node': + specifier: ^14 + version: 14.18.35 + '@types/pg': + specifier: 8.10.0 + version: 8.10.0 + '@types/react': + specifier: ^18 + version: 18.0.21 + '@types/react-dom': + specifier: ^18 + version: 18.0.6 + typescript: + specifier: ^5 + version: 5.4.5 + + tests/integration/basic-rsc-ssr: + dependencies: + '@modern-js/runtime': + specifier: workspace:* + version: link:../../../packages/runtime/plugin-runtime + date-fns: + specifier: ^2.29.3 + version: 2.29.3 + excerpts: + specifier: 0.0.3 + version: 0.0.3 + marked: + specifier: 4.2.12 + version: 4.2.12 + pg: + specifier: 8.10.0 + version: 8.10.0 + react: + specifier: 18.3.0-canary-8039e6d0b-20231026 + version: 18.3.0-canary-8039e6d0b-20231026 + react-dom: + specifier: 18.3.0-canary-8039e6d0b-20231026 + version: 18.3.0-canary-8039e6d0b-20231026(react@18.3.0-canary-8039e6d0b-20231026) + react-error-boundary: + specifier: 3.1.4 + version: 3.1.4(react@18.3.0-canary-8039e6d0b-20231026) + react-server-dom-webpack: + specifier: 18.3.0-canary-8039e6d0b-20231026 + version: 18.3.0-canary-8039e6d0b-20231026(react-dom@18.3.0-canary-8039e6d0b-20231026)(react@18.3.0-canary-8039e6d0b-20231026)(webpack@5.93.0) + sanitize-html: + specifier: 2.10.0 + version: 2.10.0 + server-only: + specifier: ^0.0.1 + version: 0.0.1 + devDependencies: + '@modern-js/app-tools': + specifier: workspace:* + version: link:../../../packages/solutions/app-tools + '@modern-js/plugin-swc': + specifier: workspace:* + version: link:../../../packages/cli/plugin-swc + '@modern-js/server-core': + specifier: workspace:* + version: link:../../../packages/server/core + '@types/jest': + specifier: ^29 + version: 29.2.6 + '@types/node': + specifier: ^14 + version: 14.18.35 + '@types/pg': + specifier: 8.10.0 + version: 8.10.0 + '@types/react': + specifier: ^18 + version: 18.0.21 + '@types/react-dom': + specifier: ^18 + version: 18.0.6 + typescript: + specifier: ^5 + version: 5.4.5 + tests/integration/bff-express: dependencies: '@modern-js/plugin-bff': @@ -13194,7 +13322,7 @@ packages: '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.24.7) dev: false - /@loadable/component@5.15.3(react@18.2.0): + /@loadable/component@5.15.3(react@18.3.0-canary-8039e6d0b-20231026): resolution: {integrity: sha512-VOgYgCABn6+/7aGIpg7m0Ruj34tGetaJzt4bQ345FwEovDQZ+dua+NWLmuJKv8rWZyxOUSfoJkmGnzyDXH2BAQ==} engines: {node: '>=8'} peerDependencies: @@ -13202,7 +13330,7 @@ packages: dependencies: '@babel/runtime': 7.24.7 hoist-non-react-statics: 3.3.2 - react: 18.2.0 + react: 18.3.0-canary-8039e6d0b-20231026 react-is: 16.13.1 dev: false @@ -13218,16 +13346,16 @@ packages: react-is: 16.13.1 dev: true - /@loadable/server@5.15.3(@loadable/component@5.15.3)(react@18.2.0): + /@loadable/server@5.15.3(@loadable/component@5.15.3)(react@18.3.0-canary-8039e6d0b-20231026): resolution: {integrity: sha512-Bm/BGe+RlChuHDKNNXpQOi4AJ0cKVuSLI+J8U0Q06zTIfT0S1RLoy85qs5RXm3cLIfefygL8+9bcYFgeWcoM8A==} engines: {node: '>=8'} peerDependencies: '@loadable/component': ^5.0.1 react: ^16.3.0 || ^17.0.0 || ^18.0.0 dependencies: - '@loadable/component': 5.15.3(react@18.2.0) + '@loadable/component': 5.15.3(react@18.3.0-canary-8039e6d0b-20231026) lodash: 4.17.21 - react: 18.2.0 + react: 18.3.0-canary-8039e6d0b-20231026 dev: false /@manypkg/find-root@1.1.0: @@ -13403,7 +13531,7 @@ packages: immer: 9.0.15 dev: false - /@modern-js-reduck/react@1.1.10(@types/react-dom@18.0.6)(@types/react@18.0.21)(react-dom@18.2.0)(react@18.2.0): + /@modern-js-reduck/react@1.1.10(@types/react-dom@18.0.6)(@types/react@18.0.21)(react-dom@18.3.0-canary-8039e6d0b-20231026)(react@18.3.0-canary-8039e6d0b-20231026): resolution: {integrity: sha512-URxdFeeI6zrbAPqha+FGh2zDMadnGJ3Fprgr0M1UXhZYxwsf31m6oukYqi/oMEh6HMFncT1mSQcWQYt0O6xzgg==} peerDependencies: '@types/react': ^18 @@ -13426,8 +13554,8 @@ packages: '@types/react-dom': 18.0.6 hoist-non-react-statics: 3.3.2 invariant: 2.2.4 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) + react: 18.3.0-canary-8039e6d0b-20231026 + react-dom: 18.3.0-canary-8039e6d0b-20231026(react@18.3.0-canary-8039e6d0b-20231026) dev: false /@modern-js-reduck/store@1.1.10: @@ -16552,6 +16680,36 @@ packages: - webpack-cli /@rsdoctor/utils@0.2.4(@rspack/core@0.5.1)(esbuild@0.17.19): + resolution: {integrity: sha512-iztfgAyRMtqNW7juiY77gOdVuVDWi4Jc9tA3BqHPUg+31PIZmUB1dujvr6tfm4VnfGZy5gu4UMJn/8IG32d4/g==} + dependencies: + '@babel/code-frame': 7.24.2 + '@rsdoctor/types': 0.2.4(@rspack/core@0.5.1)(esbuild@0.17.19) + '@types/estree': 1.0.0 + acorn: 8.12.1 + acorn-import-assertions: 1.9.0(acorn@8.12.1) + acorn-walk: 8.3.2 + bytes: 3.1.2 + chalk: 4.1.2 + connect: 3.7.0 + deep-eql: 4.1.0 + envinfo: 7.13.0 + fs-extra: 11.2.0 + get-port: 5.1.1 + json-stream-stringify: 3.0.1 + lines-and-columns: 2.0.4 + lodash: 4.17.21 + rslog: 1.2.1 + strip-ansi: 6.0.1 + transitivePeerDependencies: + - '@rspack/core' + - '@swc/core' + - esbuild + - supports-color + - uglify-js + - webpack-cli + dev: true + + /@rsdoctor/utils@0.2.4(esbuild@0.17.19): resolution: {integrity: sha512-iztfgAyRMtqNW7juiY77gOdVuVDWi4Jc9tA3BqHPUg+31PIZmUB1dujvr6tfm4VnfGZy5gu4UMJn/8IG32d4/g==} dependencies: '@babel/code-frame': 7.24.2 @@ -16579,6 +16737,7 @@ packages: - supports-color - uglify-js - webpack-cli + dev: false /@rspack/binding-darwin-arm64@0.5.1: resolution: {integrity: sha512-Kc0b94ZN1ecUu2Gyj20kGLWzOrdJbeN1JUTMKZx6jlLa3m7uJ+FhRjnsqFmZ5kdK2zx722ejoKr7xkrl7hOkuw==} @@ -18338,6 +18497,20 @@ packages: react: 18.2.0 react-dom: 18.2.0(react@18.2.0) + /@testing-library/react@13.4.0(react-dom@18.3.0-canary-8039e6d0b-20231026)(react@18.3.0-canary-8039e6d0b-20231026): + resolution: {integrity: sha512-sXOGON+WNTh3MLE9rve97ftaZukN3oNf2KjDy7YTx6hcTO2uuLHuCGynMDhFwGw/jYf4OJ2Qk0i4i79qMNNkyw==} + engines: {node: '>=12'} + peerDependencies: + react: ^18.0.0 + react-dom: ^18.0.0 + dependencies: + '@babel/runtime': 7.24.7 + '@testing-library/dom': 8.14.0 + '@types/react-dom': 18.0.6 + react: 18.3.0-canary-8039e6d0b-20231026 + react-dom: 18.3.0-canary-8039e6d0b-20231026(react@18.3.0-canary-8039e6d0b-20231026) + dev: true + /@testing-library/user-event@14.4.3(@testing-library/dom@8.14.0): resolution: {integrity: sha512-kCUc5MEwaEMakkO5x7aoD+DLi02ehmEM2QCGWvNqAS1dV/fAvORWEjnjsEIvml59M7Y5kCkWN6fCCyPOe8OL6Q==} engines: {node: '>=12', npm: '>=6'} @@ -18875,6 +19048,14 @@ packages: resolution: {integrity: sha512-SuT16Q1K51EAVPz1K29DJ/sXjhSQ0zjvsypYJ6tlwVsRV9jwW5Adq2ch8Dq8kDBCkYnELS7N7VNCSB5nC56t/g==} dev: true + /@types/pg@8.10.0: + resolution: {integrity: sha512-LniJdzpYb++pT2FnkfrCX1OA6PiauULKBE+Bp7XvlWcC0NZOXqpBMscdbxEITqpGMvDIk71TaNrx54Qd04r3rA==} + dependencies: + '@types/node': 18.11.17 + pg-protocol: 1.6.1 + pg-types: 4.0.2 + dev: true + /@types/prettier@2.6.3: resolution: {integrity: sha512-ymZk3LEC/fsut+/Q5qejp6R9O1rMxz3XaRHDV6kX8MrGAhOSPqVARbDi+EZvInBpw+BnCX3TD240byVkOfQsHg==} @@ -19404,7 +19585,7 @@ packages: '@vue/shared': 3.3.4 estree-walker: 2.0.2 magic-string: 0.30.5 - postcss: 8.4.40 + postcss: 8.4.41 source-map-js: 1.2.0 dev: false @@ -19708,6 +19889,15 @@ packages: acorn: ^8 dependencies: acorn: 8.11.3 + dev: false + + /acorn-import-assertions@1.9.0(acorn@8.12.1): + resolution: {integrity: sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==} + peerDependencies: + acorn: ^8 + dependencies: + acorn: 8.12.1 + dev: true /acorn-import-attributes@1.9.5(acorn@8.11.3): resolution: {integrity: sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==} @@ -19747,6 +19937,13 @@ packages: acorn: 8.12.1 dev: true + /acorn-loose@8.4.0: + resolution: {integrity: sha512-M0EUka6rb+QC4l9Z3T0nJEzNOO7JcoJlYMrBlyBCiFSXRyxjLKayd4TbQs2FDRWQU1h9FR7QVNHt+PEaoNL5rQ==} + engines: {node: '>=0.4.0'} + dependencies: + acorn: 8.12.1 + dev: false + /acorn-node@1.8.2: resolution: {integrity: sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==} dependencies: @@ -20926,6 +21123,11 @@ packages: /buffer-from@1.1.2: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + /buffer-writer@2.0.0: + resolution: {integrity: sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==} + engines: {node: '>=4'} + dev: false + /buffer-xor@1.0.3: resolution: {integrity: sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==} dev: false @@ -21209,6 +21411,28 @@ packages: resolution: {integrity: sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==} dev: true + /cheerio@0.22.0: + resolution: {integrity: sha512-8/MzidM6G/TgRelkzDG13y3Y9LxBjCb+8yOEZ9+wwq5gVF2w2pV0wmHvjfT0RvuxGyR7UEuK36r+yYMbT4uKgA==} + engines: {node: '>= 0.6'} + dependencies: + css-select: 1.2.0 + dom-serializer: 0.1.1 + entities: 1.1.2 + htmlparser2: 3.10.1 + lodash.assignin: 4.2.0 + lodash.bind: 4.2.1 + lodash.defaults: 4.2.0 + lodash.filter: 4.6.0 + lodash.flatten: 4.4.0 + lodash.foreach: 4.5.0 + lodash.map: 4.6.0 + lodash.merge: 4.6.2 + lodash.pick: 4.4.0 + lodash.reduce: 4.6.0 + lodash.reject: 4.6.0 + lodash.some: 4.6.0 + dev: false + /chokidar@3.5.3: resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==} engines: {node: '>= 8.10.0'} @@ -22068,6 +22292,15 @@ packages: webpack: 5.93.0(esbuild@0.17.19) dev: false + /css-select@1.2.0: + resolution: {integrity: sha512-dUQOBoqdR7QwV90WysXPLXG5LO7nhYBgiWVfxF80DKPF8zx1t/pUd2FYy73emg3zrjtM6dzmYgbHKfV2rxiHQA==} + dependencies: + boolbase: 1.0.0 + css-what: 2.1.3 + domutils: 1.5.1 + nth-check: 1.0.2 + dev: false + /css-select@4.3.0: resolution: {integrity: sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==} dependencies: @@ -22113,6 +22346,10 @@ packages: resolution: {integrity: sha512-IiJwMC8rdZE0+xiEZHeru6YoONC4rfPMqGm2W85jMIbkFvv5nFTwJVFHam2eFrN6txmoUYFAFXiv8ICVeTO0MA==} dev: false + /css-what@2.1.3: + resolution: {integrity: sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg==} + dev: false + /css-what@6.1.0: resolution: {integrity: sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==} engines: {node: '>= 6'} @@ -22730,6 +22967,13 @@ packages: '@babel/runtime': 7.24.7 csstype: 3.1.3 + /dom-serializer@0.1.1: + resolution: {integrity: sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA==} + dependencies: + domelementtype: 1.3.1 + entities: 1.1.2 + dev: false + /dom-serializer@1.4.1: resolution: {integrity: sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==} dependencies: @@ -22754,6 +22998,10 @@ packages: engines: {node: '>=4'} dev: false + /domelementtype@1.3.1: + resolution: {integrity: sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==} + dev: false + /domelementtype@2.3.0: resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} @@ -22764,6 +23012,12 @@ packages: dependencies: webidl-conversions: 7.0.0 + /domhandler@2.4.2: + resolution: {integrity: sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==} + dependencies: + domelementtype: 1.3.1 + dev: false + /domhandler@4.3.1: resolution: {integrity: sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==} engines: {node: '>= 4'} @@ -22776,6 +23030,20 @@ packages: dependencies: domelementtype: 2.3.0 + /domutils@1.5.1: + resolution: {integrity: sha512-gSu5Oi/I+3wDENBsOWBiRK1eoGxcywYSqg3rR960/+EfY0CF4EX1VPkgHOZ3WiS/Jg2DtliF6BhWcHlfpYUcGw==} + dependencies: + dom-serializer: 0.1.1 + domelementtype: 1.3.1 + dev: false + + /domutils@1.7.0: + resolution: {integrity: sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==} + dependencies: + dom-serializer: 0.1.1 + domelementtype: 1.3.1 + dev: false + /domutils@2.8.0: resolution: {integrity: sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==} dependencies: @@ -22970,6 +23238,10 @@ packages: dependencies: ansi-colors: 4.1.3 + /entities@1.1.2: + resolution: {integrity: sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==} + dev: false + /entities@2.2.0: resolution: {integrity: sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==} @@ -23910,6 +24182,12 @@ packages: safe-buffer: 5.2.1 dev: false + /excerpts@0.0.3: + resolution: {integrity: sha512-osE67JikKwTcbZYgEMZrnDFJMto8HDwlYKsjKPyVIkRvOixG6NWqj0hfKkISUwz5R7HOusJEzSqyZmLw565AJQ==} + dependencies: + cheerio: 0.22.0 + dev: false + /execa@5.1.1: resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} engines: {node: '>=10'} @@ -25438,6 +25716,17 @@ packages: resolution: {integrity: sha512-SZwGvLGNtgp8GbgFX7oXEp8OR1aBt5LliX6dG0kdD1kl3KhMonN0QcSa/A3TsTgFewaGCbIryQunjayWDXzxmw==} dev: false + /htmlparser2@3.10.1: + resolution: {integrity: sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==} + dependencies: + domelementtype: 1.3.1 + domhandler: 2.4.2 + domutils: 1.7.0 + entities: 1.1.2 + inherits: 2.0.4 + readable-stream: 3.6.0 + dev: false + /htmlparser2@6.1.0: resolution: {integrity: sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==} dependencies: @@ -25453,7 +25742,6 @@ packages: domhandler: 5.0.3 domutils: 3.1.0 entities: 4.5.0 - dev: true /htmlparser2@9.1.0: resolution: {integrity: sha512-5zfg6mHUoaer/97TxnGpxmbR7zJtPwIYFMZ/H5ucTlPZhKvtum05yiPK3Mgai3a0DyVxv7qYqoweaEd2nrYQzQ==} @@ -27526,6 +27814,14 @@ packages: /lodash-es@4.17.21: resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==} + /lodash.assignin@4.2.0: + resolution: {integrity: sha512-yX/rx6d/UTVh7sSVWVSIMjfnz95evAgDFdb1ZozC35I9mSFCkmzptOzevxjgbQUsc78NR44LVHWjsoMQXy9FDg==} + dev: false + + /lodash.bind@4.2.1: + resolution: {integrity: sha512-lxdsn7xxlCymgLYo1gGvVrfHmkjDiyqVv62FAeF2i5ta72BipE1SLxw8hPEPLhD4/247Ijw07UQH7Hq/chT5LA==} + dev: false + /lodash.camelcase@4.3.0: resolution: {integrity: sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==} @@ -27536,22 +27832,33 @@ packages: /lodash.debounce@4.0.8: resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==} + /lodash.defaults@4.2.0: + resolution: {integrity: sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==} + dev: false + /lodash.escape@4.0.1: resolution: {integrity: sha512-nXEOnb/jK9g0DYMr1/Xvq6l5xMD7GDG55+GSYIYmS0G4tBk/hURD4JR9WCavs04t33WmJx9kCyp9vJ+mr4BOUw==} dev: true + /lodash.filter@4.6.0: + resolution: {integrity: sha512-pXYUy7PR8BCLwX5mgJ/aNtyOvuJTdZAo9EQFUvMIYugqmJxnrYaANvTbgndOzHSCSR0wnlBBfRXJL5SbWxo3FQ==} + dev: false + /lodash.flatmap@4.5.0: resolution: {integrity: sha512-/OcpcAGWlrZyoHGeHh3cAoa6nGdX6QYtmzNP84Jqol6UEQQ2gIaU3H+0eICcjcKGl0/XF8LWOujNn9lffsnaOg==} dev: false /lodash.flatten@4.4.0: resolution: {integrity: sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==} - dev: true /lodash.flow@3.5.0: resolution: {integrity: sha512-ff3BX/tSioo+XojX4MOsOMhJw0nZoUEF011LX8g8d3gvjVbxd89cCio4BCXronjxcTUIJUoqKEUA+n4CqvvRPw==} dev: true + /lodash.foreach@4.5.0: + resolution: {integrity: sha512-aEXTF4d+m05rVOAUG3z4vZZ4xVexLKZGF0lIxuHZ1Hplpk/3B6Z1+/ICICYRLm7c41Z2xiejbkCkJoTlypoXhQ==} + dev: false + /lodash.get@4.4.2: resolution: {integrity: sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==} dev: false @@ -27575,6 +27882,10 @@ packages: /lodash.kebabcase@4.1.1: resolution: {integrity: sha512-N8XRTIMMqqDgSy4VLKPnJ/+hpGZN+PHQiJnSenYqPaVV/NCqEogTnAdZLQiGKhxX+JCs8waWq2t1XHWKOmlY8g==} + /lodash.map@4.6.0: + resolution: {integrity: sha512-worNHGKLDetmcEYDvh2stPCrrQRkP20E4l0iIS7F8EvzMqBBi7ltvFN5m1HvTf1P7Jk1txKhvFcmYsCr8O2F1Q==} + dev: false + /lodash.memoize@4.1.2: resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==} @@ -27585,13 +27896,29 @@ packages: resolution: {integrity: sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==} dev: true + /lodash.pick@4.4.0: + resolution: {integrity: sha512-hXt6Ul/5yWjfklSGvLQl8vM//l3FtyHZeuelpzK6mm99pNvN9yTDruNZPEJZD1oWrqo+izBmB7oUfWgcCX7s4Q==} + dev: false + /lodash.pullall@4.2.0: resolution: {integrity: sha512-VhqxBKH0ZxPpLhiu68YD1KnHmbhQJQctcipvmFnqIBDYzcIHzf3Zpu0tpeOKtR4x76p9yohc506eGdOjTmyIBg==} dev: true + /lodash.reduce@4.6.0: + resolution: {integrity: sha512-6raRe2vxCYBhpBu+B+TtNGUzah+hQjVdu3E17wfusjyrXBka2nBS8OH/gjVZ5PvHOhWmIZTYri09Z6n/QfnNMw==} + dev: false + + /lodash.reject@4.6.0: + resolution: {integrity: sha512-qkTuvgEzYdyhiJBx42YPzPo71R1aEr0z79kAv7Ixg8wPFEjgRgJdUsGMG3Hf3OYSF/kHI79XhNlt+5Ar6OzwxQ==} + dev: false + /lodash.snakecase@4.1.1: resolution: {integrity: sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==} + /lodash.some@4.6.0: + resolution: {integrity: sha512-j7MJE+TuT51q9ggt4fSgVqro163BEFjAt3u97IqU+JA2DkWl80nFTrowzLpZ/BnpN7rrl0JA/593NAdd8p/scQ==} + dev: false + /lodash.startcase@4.4.0: resolution: {integrity: sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==} @@ -27757,6 +28084,12 @@ packages: react: 18.2.0 dev: true + /marked@4.2.12: + resolution: {integrity: sha512-yr8hSKa3Fv4D3jdZmtMMPghgVt6TWbk86WQaWhDloQjRSQhMMYCAro7jP7VDJrjjdV8pxVxMssXS8B8Y5DZ5aw==} + engines: {node: '>= 12'} + hasBin: true + dev: false + /md5.js@1.3.5: resolution: {integrity: sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==} dependencies: @@ -28865,6 +29198,12 @@ packages: resolution: {integrity: sha512-I19aIingLgR1fmhftnbWWO3dXc0hSxqHQHQb3H8m+K3TnEn/iSeTZZOyvKXWqQESMwuUVnatlCnZdLBZZt2VSA==} dev: true + /nth-check@1.0.2: + resolution: {integrity: sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==} + dependencies: + boolbase: 1.0.0 + dev: false + /nth-check@2.1.1: resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} dependencies: @@ -29022,6 +29361,10 @@ packages: resolution: {integrity: sha512-lgHwxlxV1qIg1Eap7LgIeoBWIMFibOjbrYPIPJZcI1mmGAI2m3lNYpK12Y+GBdPQ0U1hRwSord7GIaawz962qQ==} dev: false + /obuf@1.1.2: + resolution: {integrity: sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==} + dev: true + /on-finished@2.3.0: resolution: {integrity: sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==} engines: {node: '>= 0.8'} @@ -29217,6 +29560,10 @@ packages: resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} engines: {node: '>=6'} + /packet-reader@1.0.0: + resolution: {integrity: sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==} + dev: false + /pako@0.2.9: resolution: {integrity: sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==} dev: false @@ -29297,6 +29644,10 @@ packages: engines: {node: '>=0.10.0'} dev: true + /parse-srcset@1.0.2: + resolution: {integrity: sha512-/2qh0lav6CmI15FzA3i/2Bzk2zCgQhGMkvhOhKNcBVQ1ldgpbfiNTVslmooUmWJcADi1f1kIeynbDRVzNlfR6Q==} + dev: false + /parse5@6.0.1: resolution: {integrity: sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==} dev: false @@ -29440,6 +29791,78 @@ packages: q: 1.5.1 dev: false + /pg-connection-string@2.6.4: + resolution: {integrity: sha512-v+Z7W/0EO707aNMaAEfiGnGL9sxxumwLl2fJvCQtMn9Fxsg+lPpPkdcyBSv/KFgpGdYkMfn+EI1Or2EHjpgLCA==} + dev: false + + /pg-int8@1.0.1: + resolution: {integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==} + engines: {node: '>=4.0.0'} + + /pg-numeric@1.0.2: + resolution: {integrity: sha512-BM/Thnrw5jm2kKLE5uJkXqqExRUY/toLHda65XgFTBTFYZyopbKjBe29Ii3RbkvlsMoFwD+tHeGaCjjv0gHlyw==} + engines: {node: '>=4'} + dev: true + + /pg-pool@3.6.2(pg@8.10.0): + resolution: {integrity: sha512-Htjbg8BlwXqSBQ9V8Vjtc+vzf/6fVUuak/3/XXKA9oxZprwW3IMDQTGHP+KDmVL7rtd+R1QjbnCFPuTHm3G4hg==} + peerDependencies: + pg: '>=8.0' + dependencies: + pg: 8.10.0 + dev: false + + /pg-protocol@1.6.1: + resolution: {integrity: sha512-jPIlvgoD63hrEuihvIg+tJhoGjUsLPn6poJY9N5CnlPd91c2T18T/9zBtLxZSb1EhYxBRoZJtzScCaWlYLtktg==} + + /pg-types@2.2.0: + resolution: {integrity: sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==} + engines: {node: '>=4'} + dependencies: + pg-int8: 1.0.1 + postgres-array: 2.0.0 + postgres-bytea: 1.0.0 + postgres-date: 1.0.7 + postgres-interval: 1.2.0 + dev: false + + /pg-types@4.0.2: + resolution: {integrity: sha512-cRL3JpS3lKMGsKaWndugWQoLOCoP+Cic8oseVcbr0qhPzYD5DWXK+RZ9LY9wxRf7RQia4SCwQlXk0q6FCPrVng==} + engines: {node: '>=10'} + dependencies: + pg-int8: 1.0.1 + pg-numeric: 1.0.2 + postgres-array: 3.0.2 + postgres-bytea: 3.0.0 + postgres-date: 2.1.0 + postgres-interval: 3.0.0 + postgres-range: 1.1.4 + dev: true + + /pg@8.10.0: + resolution: {integrity: sha512-ke7o7qSTMb47iwzOSaZMfeR7xToFdkE71ifIipOAAaLIM0DYzfOAXlgFFmYUIE2BcJtvnVlGCID84ZzCegE8CQ==} + engines: {node: '>= 8.0.0'} + peerDependencies: + pg-native: '>=3.0.1' + peerDependenciesMeta: + pg-native: + optional: true + dependencies: + buffer-writer: 2.0.0 + packet-reader: 1.0.0 + pg-connection-string: 2.6.4 + pg-pool: 3.6.2(pg@8.10.0) + pg-protocol: 1.6.1 + pg-types: 2.2.0 + pgpass: 1.0.5 + dev: false + + /pgpass@1.0.5: + resolution: {integrity: sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==} + dependencies: + split2: 4.2.0 + dev: false + /picocolors@1.0.0: resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} @@ -30392,15 +30815,6 @@ packages: picocolors: 1.0.0 source-map-js: 1.0.2 - /postcss@8.4.38: - resolution: {integrity: sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==} - engines: {node: ^10 || ^12 || >=14} - dependencies: - nanoid: 3.3.7 - picocolors: 1.0.1 - source-map-js: 1.2.0 - dev: true - /postcss@8.4.40: resolution: {integrity: sha512-YF2kKIUzAofPMpfH6hOi2cGnv/HrUlfucspc7pDyvv7kGdqXrfj8SCl/t8owkEgKEuu8ZcRjSOxFxVLqwChZ2Q==} engines: {node: ^10 || ^12 || >=14} @@ -30418,6 +30832,54 @@ packages: picocolors: 1.0.1 source-map-js: 1.2.0 + /postgres-array@2.0.0: + resolution: {integrity: sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==} + engines: {node: '>=4'} + dev: false + + /postgres-array@3.0.2: + resolution: {integrity: sha512-6faShkdFugNQCLwucjPcY5ARoW1SlbnrZjmGl0IrrqewpvxvhSLHimCVzqeuULCbG0fQv7Dtk1yDbG3xv7Veog==} + engines: {node: '>=12'} + dev: true + + /postgres-bytea@1.0.0: + resolution: {integrity: sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==} + engines: {node: '>=0.10.0'} + dev: false + + /postgres-bytea@3.0.0: + resolution: {integrity: sha512-CNd4jim9RFPkObHSjVHlVrxoVQXz7quwNFpz7RY1okNNme49+sVyiTvTRobiLV548Hx/hb1BG+iE7h9493WzFw==} + engines: {node: '>= 6'} + dependencies: + obuf: 1.1.2 + dev: true + + /postgres-date@1.0.7: + resolution: {integrity: sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==} + engines: {node: '>=0.10.0'} + dev: false + + /postgres-date@2.1.0: + resolution: {integrity: sha512-K7Juri8gtgXVcDfZttFKVmhglp7epKb1K4pgrkLxehjqkrgPhfG6OO8LHLkfaqkbpjNRnra018XwAr1yQFWGcA==} + engines: {node: '>=12'} + dev: true + + /postgres-interval@1.2.0: + resolution: {integrity: sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==} + engines: {node: '>=0.10.0'} + dependencies: + xtend: 4.0.2 + dev: false + + /postgres-interval@3.0.0: + resolution: {integrity: sha512-BSNDnbyZCXSxgA+1f5UU2GmwhoI0aU5yMxRGO8CdFEcY2BQF9xm/7MqKnYoM1nJDk8nONNWDk9WeSmePFhQdlw==} + engines: {node: '>=12'} + dev: true + + /postgres-range@1.1.4: + resolution: {integrity: sha512-i/hbxIE9803Alj/6ytL7UHQxRvZkI9O4Sy+J3HGc4F4oo/2eQAjTSNJ0bfxyse3bH0nuVesCk+3IRLaMtG3H6w==} + dev: true + /preferred-pm@3.0.3: resolution: {integrity: sha512-+wZgbxNES/KlJs9q40F/1sfOd/j7f1O9JaHcW5Dsn3aUUOZg3L2bjpVUcKV2jvtElYfoTuQiNeMfQJ4kwUAhCQ==} engines: {node: '>=10'} @@ -32452,6 +32914,15 @@ packages: react: 18.2.0 scheduler: 0.23.0 + /react-dom@18.3.0-canary-8039e6d0b-20231026(react@18.3.0-canary-8039e6d0b-20231026): + resolution: {integrity: sha512-H1JoRPsibBazpZeqQ9mWw58ChfxE1EZo5eOiRh+Ztz2rpfLBOMZCa8IjtnLrUOAjWcO+KkBisgibjeCQb6WpvQ==} + peerDependencies: + react: 18.3.0-canary-8039e6d0b-20231026 + dependencies: + loose-envify: 1.4.0 + react: 18.3.0-canary-8039e6d0b-20231026 + scheduler: 0.24.0-canary-8039e6d0b-20231026 + /react-dom@18.3.1(react@18.2.0): resolution: {integrity: sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==} peerDependencies: @@ -32484,6 +32955,16 @@ packages: react-is: 18.1.0 dev: false + /react-error-boundary@3.1.4(react@18.3.0-canary-8039e6d0b-20231026): + resolution: {integrity: sha512-uM9uPzZJTF6wRQORmSrvOIgt4lJ9MC1sNgEOj2XGsDTRE4kmpWxg7ENK9EWNKJRMAOY9z0MuF4yIfl6gp4sotA==} + engines: {node: '>=10', npm: '>=6'} + peerDependencies: + react: '>=16.13.1' + dependencies: + '@babel/runtime': 7.24.7 + react: 18.3.0-canary-8039e6d0b-20231026 + dev: false + /react-error-boundary@4.0.12(react@18.2.0): resolution: {integrity: sha512-kJdxdEYlb7CPC1A0SeUY38cHpjuu6UkvzKiAmqmOFL21VRfMhOcWxTCBgLVCO0VEMh9JhFNcVaXlV4/BTpiwOA==} peerDependencies: @@ -32530,16 +33011,16 @@ packages: shallowequal: 1.1.0 dev: true - /react-helmet@6.1.0(react@18.2.0): + /react-helmet@6.1.0(react@18.3.0-canary-8039e6d0b-20231026): resolution: {integrity: sha512-4uMzEY9nlDlgxr61NL3XbKRy1hEkXmKNXhjbAIOVw5vcFrsdYbH2FEwcNyWvWinl103nXgzYNlns9ca+8kFiWw==} peerDependencies: react: '>=16.3.0' dependencies: object-assign: 4.1.1 prop-types: 15.8.1 - react: 18.2.0 + react: 18.3.0-canary-8039e6d0b-20231026 react-fast-compare: 3.2.0 - react-side-effect: 2.1.2(react@18.2.0) + react-side-effect: 2.1.2(react@18.3.0-canary-8039e6d0b-20231026) dev: false /react-icons@4.11.0(react@18.2.0): @@ -32728,12 +33209,28 @@ packages: react: 18.3.1 dev: true - /react-side-effect@2.1.2(react@18.2.0): + /react-server-dom-webpack@18.3.0-canary-8039e6d0b-20231026(react-dom@18.3.0-canary-8039e6d0b-20231026)(react@18.3.0-canary-8039e6d0b-20231026)(webpack@5.93.0): + resolution: {integrity: sha512-JhmrWiHewwWIUfhVmc38G8QZDO8mFJSOBIbUwIfqKPH/7/u23VqUjejkuXKTGyVUpPKJlC4PIVjmnk7Wqoguzg==} + engines: {node: '>=0.10.0'} + peerDependencies: + react: 18.3.0-canary-8039e6d0b-20231026 + react-dom: 18.3.0-canary-8039e6d0b-20231026 + webpack: ^5.59.0 + dependencies: + acorn-loose: 8.4.0 + loose-envify: 1.4.0 + neo-async: 2.6.2 + react: 18.3.0-canary-8039e6d0b-20231026 + react-dom: 18.3.0-canary-8039e6d0b-20231026(react@18.3.0-canary-8039e6d0b-20231026) + webpack: 5.93.0(esbuild@0.17.19) + dev: false + + /react-side-effect@2.1.2(react@18.3.0-canary-8039e6d0b-20231026): resolution: {integrity: sha512-PVjOcvVOyIILrYoyGEpDN3vmYNLdy1CajSFNt4TDsVQC5KpTijDvWVoR+/7Rz2xT978D8/ZtFceXxzsPwZEDvw==} peerDependencies: react: ^16.3.0 || ^17.0.0 || ^18.0.0 dependencies: - react: 18.2.0 + react: 18.3.0-canary-8039e6d0b-20231026 dev: false /react-style-singleton@2.2.1(@types/react@18.0.21)(react@18.2.0): @@ -32876,6 +33373,12 @@ packages: dependencies: loose-envify: 1.4.0 + /react@18.3.0-canary-8039e6d0b-20231026: + resolution: {integrity: sha512-vlVdzo0PJiwshpfpMSxB4iirygntWJ8AD3nMetQBp6T8YHLv7WMRqMOfna9wn5GMXRJcUw9paQklNiOVGP68ag==} + engines: {node: '>=0.10.0'} + dependencies: + loose-envify: 1.4.0 + /react@18.3.1: resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==} engines: {node: '>=0.10.0'} @@ -33542,6 +34045,17 @@ packages: /safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + /sanitize-html@2.10.0: + resolution: {integrity: sha512-JqdovUd81dG4k87vZt6uA6YhDfWkUGruUu/aPmXLxXi45gZExnt9Bnw/qeQU8oGf82vPyaE0vO4aH0PbobB9JQ==} + dependencies: + deepmerge: 4.3.1 + escape-string-regexp: 4.0.0 + htmlparser2: 8.0.1 + is-plain-object: 5.0.0 + parse-srcset: 1.0.2 + postcss: 8.4.41 + dev: false + /sass-embedded-android-arm64@1.77.8: resolution: {integrity: sha512-EmWHLbEx0Zo/f/lTFzMeH2Du+/I4RmSRlEnERSUKQWVp3aBSO04QDvdxfFezgQ+2Yt/ub9WMqBpma9P/8MPsLg==} engines: {node: '>=14.0.0'} @@ -33755,6 +34269,11 @@ packages: dependencies: loose-envify: 1.4.0 + /scheduler@0.24.0-canary-8039e6d0b-20231026: + resolution: {integrity: sha512-dWUzSzKcmDy+DQz/aNgYmaXMduHlXed7pTfL4UUkZwwHElNUVsJhZfItWIj2S+7t5o+8GrFA12se0CuJkrJVsA==} + dependencies: + loose-envify: 1.4.0 + /schema-utils@3.3.0: resolution: {integrity: sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==} engines: {node: '>= 10.13.0'} @@ -33915,6 +34434,10 @@ packages: transitivePeerDependencies: - supports-color + /server-only@0.0.1: + resolution: {integrity: sha512-qepMx2JxAa5jjfzxG79yPPq+8BuFToHd1hm7kI+Z4zAq1ftQiP7HcxMhDDItrbtwVeLg/cY2JnKnrcFkmiswNA==} + dev: false + /set-blocking@2.0.0: resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} dev: false @@ -34249,6 +34772,11 @@ packages: readable-stream: 3.6.0 dev: true + /split2@4.2.0: + resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} + engines: {node: '>= 10.x'} + dev: false + /sprintf-js@1.0.3: resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} @@ -34556,7 +35084,7 @@ packages: /strip-literal@1.0.1: resolution: {integrity: sha512-QZTsipNpa2Ppr6v1AmJHESqJ3Uz247MUS0OjrnnZjFAvEoWqxuyFuXn2xLgMtRnijJShAa1HL0gtJyUs7u7n3Q==} dependencies: - acorn: 8.11.2 + acorn: 8.12.1 dev: true /strong-log-transformer@2.1.0: @@ -34605,6 +35133,30 @@ packages: shallowequal: 1.1.0 supports-color: 5.5.0 + /styled-components@5.3.5(react-dom@18.3.0-canary-8039e6d0b-20231026)(react-is@18.2.0)(react@18.3.0-canary-8039e6d0b-20231026): + resolution: {integrity: sha512-ndETJ9RKaaL6q41B69WudeqLzOpY1A/ET/glXkNZ2T7dPjPqpPCXXQjDFYZWwNnE5co0wX+gTCqx9mfxTmSIPg==} + engines: {node: '>=10'} + requiresBuild: true + peerDependencies: + react: '>= 16.8.0' + react-dom: '>= 16.8.0' + react-is: '>= 16.8.0' + dependencies: + '@babel/helper-module-imports': 7.22.15 + '@babel/traverse': 7.23.6(supports-color@5.5.0) + '@emotion/is-prop-valid': 1.2.1 + '@emotion/stylis': 0.8.5 + '@emotion/unitless': 0.7.5 + babel-plugin-styled-components: 1.13.3(styled-components@5.3.5) + css-to-react-native: 3.2.0 + hoist-non-react-statics: 3.3.2 + react: 18.3.0-canary-8039e6d0b-20231026 + react-dom: 18.3.0-canary-8039e6d0b-20231026(react@18.3.0-canary-8039e6d0b-20231026) + react-is: 18.2.0 + shallowequal: 1.1.0 + supports-color: 5.5.0 + dev: false + /stylehacks@6.0.0(postcss@8.4.35): resolution: {integrity: sha512-+UT589qhHPwz6mTlCLSt/vMNTJx8dopeJlZAlBMJPWA3ORqu6wmQY7FBXf+qD+FsqoBJODyqNxOUP3jdntFRdw==} engines: {node: ^14 || ^16 || >=18.0} @@ -36294,7 +36846,7 @@ packages: dependencies: '@types/node': 18.11.17 esbuild: 0.17.19 - postcss: 8.4.38 + postcss: 8.4.41 rollup: 3.29.4 optionalDependencies: fsevents: 2.3.3 diff --git a/tests/integration/basic-next-app/.browserslistrc b/tests/integration/basic-next-app/.browserslistrc new file mode 100644 index 000000000000..f5ceef6bb8ec --- /dev/null +++ b/tests/integration/basic-next-app/.browserslistrc @@ -0,0 +1,5 @@ +chrome >= 51 +edge >= 15 +firefox >= 54 +safari >= 10 +ios_saf >= 10 diff --git a/tests/integration/basic-next-app/credentials.js b/tests/integration/basic-next-app/credentials.js new file mode 100644 index 000000000000..edc6d3d66e71 --- /dev/null +++ b/tests/integration/basic-next-app/credentials.js @@ -0,0 +1,7 @@ +module.exports = { + host: process.env.DB_HOST || 'localhost', + database: 'notesapi', + user: 'notesadmin', + password: 'password', + port: '5432', +}; diff --git a/tests/integration/basic-next-app/modern.config.ts b/tests/integration/basic-next-app/modern.config.ts new file mode 100644 index 000000000000..bc7f7c25ec0a --- /dev/null +++ b/tests/integration/basic-next-app/modern.config.ts @@ -0,0 +1,47 @@ +import { applyBaseConfig } from '../../utils/applyBaseConfig'; +import ReactServerWebpackPlugin from 'react-server-dom-webpack/plugin'; +import path from 'path'; + +export default applyBaseConfig({ + runtime: { + state: false, + router: false, + }, + source: { + // 避免 Modern.js 项目代码中用的是其他版本 + alias: { + // react$: require.resolve('react'), + // 'react-dom/client': require.resolve('react-dom/client'), + // 'react-dom': require.resolve('react-dom'), + }, + }, + tools: { + babel(config, { modifyPresetReactOptions }) { + modifyPresetReactOptions({ + runtime: 'automatic', + }); + }, + devServer: { + hot: false, + }, + // webpack(config, ctx) { + // config.resolve.conditionNames = ['require', 'node']; + // }, + bundlerChain(chain) { + chain + .plugin('react-server-dom-webpack-plugin') + .use(ReactServerWebpackPlugin, [ + { + isServer: false, + clientReferences: [ + { + directory: './src', + recursive: true, + include: /\.(js|jsx|ts|tsx)$/, + }, + ], + }, + ]); + }, + }, +}); diff --git a/tests/integration/basic-next-app/package.json b/tests/integration/basic-next-app/package.json new file mode 100644 index 000000000000..3afa065ff691 --- /dev/null +++ b/tests/integration/basic-next-app/package.json @@ -0,0 +1,43 @@ +{ + "private": true, + "name": "tmp", + "version": "2.9.0", + "scripts": { + "dev": "BUNDLER=webpack NODE_OPTIONS='--conditions=react-server' modern dev", + "build": "BUNDLER=webpack modern build", + "inspect": "BUNDLER=webpack NODE_OPTIONS='--conditions=react-server' modern inspect", + "serve": "modern serve", + "new": "modern new", + "lint": "modern lint" + }, + "engines": { + "node": ">=14.17.6" + }, + "eslintIgnore": [ + "node_modules/", + "dist/" + ], + "dependencies": { + "@modern-js/runtime": "workspace:*", + "react": "18.3.0-canary-8039e6d0b-20231026", + "react-dom": "18.3.0-canary-8039e6d0b-20231026", + "marked": "4.2.12", + "sanitize-html": "2.10.0", + "react-error-boundary": "3.1.4", + "pg": "8.10.0", + "server-only": "^0.0.1", + "excerpts": "0.0.3", + "react-server-dom-webpack": "18.3.0-canary-8039e6d0b-20231026" + }, + "devDependencies": { + "@modern-js/app-tools": "workspace:*", + "@modern-js/plugin-swc": "workspace:*", + "@modern-js/server-core": "workspace:*", + "@types/jest": "^29", + "@types/node": "^14", + "@types/react": "^18", + "@types/react-dom": "^18", + "@types/pg": "8.10.0", + "typescript": "^5" + } +} diff --git a/tests/integration/basic-next-app/server/modern.server.ts b/tests/integration/basic-next-app/server/modern.server.ts new file mode 100644 index 000000000000..840504d83ece --- /dev/null +++ b/tests/integration/basic-next-app/server/modern.server.ts @@ -0,0 +1,12 @@ +import reactServerRegister from 'react-server-dom-webpack/node-register'; +import { + defineConfig, + type RenderMiddleware, +} from '@modern-js/app-tools/server'; +import rscServerPlugin from './serverPlugin'; + +reactServerRegister(); + +export default defineConfig({ + plugins: [rscServerPlugin()], +}); diff --git a/tests/integration/basic-next-app/server/server.d.ts b/tests/integration/basic-next-app/server/server.d.ts new file mode 100644 index 000000000000..712c8256e0cd --- /dev/null +++ b/tests/integration/basic-next-app/server/server.d.ts @@ -0,0 +1,57 @@ +declare module 'react-server-dom-webpack/node-register'; +declare module 'react-server-dom-webpack/server'; + +type Reference = {}; + +type TemporaryReferenceSet = Map; + +type ImportManifestEntry = { + id: string; + chunks: string[]; + name: string; +}; + +type ModuleLoading = null | { + prefix: string; + crossOrigin?: 'use-credentials' | ''; +}; + +type SSRModuleMap = null | { + [clientId: string]: { + [clientExportName: string]: ImportManifestEntry; + }; +}; + +type SSRManifest = { + moduleMap: SSRModuleMap; + moduleLoading: ModuleLoading; +}; + +type ServerManifest = { + [id: string]: ImportManifestEntry; +}; + +type ClientManifest = { + [id: string]: ImportManifestEntry; +}; + +declare module 'react-server-dom-webpack/server.edge' { + type Options = { + environmentName?: string; + identifierPrefix?: string; + signal?: AbortSignal; + temporaryReferences?: TemporaryReferenceSet; + onError?: ((error: unknown) => void) | undefined; + onPostpone?: ((reason: string) => void) | undefined; + }; + + export function renderToReadableStream( + model: ReactClientValue, + webpackMap: ClientManifest, + options?: Options, + ): ReadableStream; + export function decodeReply( + body: string | FormData, + webpackMap?: ServerManifest, + ): Promise; +} diff --git a/tests/integration/basic-next-app/server/serverPlugin.ts b/tests/integration/basic-next-app/server/serverPlugin.ts new file mode 100644 index 000000000000..8cc85a36a71c --- /dev/null +++ b/tests/integration/basic-next-app/server/serverPlugin.ts @@ -0,0 +1,93 @@ +import type { Context, ServerPlugin } from '@modern-js/server-core'; +import path from 'path'; +import { readFileSync } from 'fs'; +// import { +// renderToPipeableStream, +// renderToReadableStream, +// } from 'react-server-dom-webpack/server'; +import { renderToReadableStream } from 'react-server-dom-webpack/server.edge'; +import React from 'react'; +import { Pool } from 'pg'; +// import ReactApp from '../src/App'; + +console.log('react1111111111', React.version); +console.log('renderToReadableStream', renderToReadableStream); + +const pool = new Pool(require('../credentials')); + +interface IProps { + selectedId: string; + isEditing: boolean; + searchText: string; +} + +const renderRsc = async (distDir: string, props: IProps) => { + const ReactApp = (await import('../src/App')).default; + const manifest = readFileSync( + path.resolve(distDir, './react-client-manifest.json'), + 'utf8', + ); + + const moduleMap = JSON.parse(manifest); + const readable = renderToReadableStream( + React.createElement(ReactApp, props), + moduleMap, + ); + return readable; +}; + +const handleResponse = async ( + c: Context, + distDir: string, + redirectId?: string, +) => { + const location = JSON.parse(c.req.query('location') as string); + if (redirectId) { + location.selectedId = redirectId; + } + const readable = await renderRsc(distDir, { + selectedId: location.selectedId, + isEditing: location.isEditing, + searchText: location.searchText, + }); + return c.body(readable, 200); +}; + +export default (): ServerPlugin => ({ + name: 'rsc-server-plugin', + setup(api) { + return { + prepare() { + const { middlewares, distDirectory } = api.useAppContext(); + console.log('push middleware'); + middlewares.unshift({ + name: 'rsc', + path: '/react', + handler: async (c, next) => { + // TODO: 临时代码 + return await handleResponse(c, distDirectory); + }, + }); + + // middlewares.unshift({ + // name: 'notes', + // path: '/notes/:id', + // handler: async (c, next) => { + // const { req } = c; + // const now = new Date(); + // const updatedId = Number(req.param('id')); + // await pool.query( + // 'update notes set title = $1, body = $2, updated_at = $3 where id = $4', + // [req.body.title, req.body.body, now, updatedId], + // ); + // await writeFile( + // path.resolve(NOTES_PATH, `${updatedId}.md`), + // req.body.body, + // 'utf8', + // ); + // }, + // }); + }, + }; + }, +}); diff --git a/tests/integration/basic-next-app/src/App.js b/tests/integration/basic-next-app/src/App.js new file mode 100644 index 000000000000..e825616dc186 --- /dev/null +++ b/tests/integration/basic-next-app/src/App.js @@ -0,0 +1,50 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + */ + +import { Suspense } from 'react'; + +import Note from './Note'; +import NoteList from './NoteList'; +import EditButton from './EditButton'; +import SearchField from './SearchField'; +import NoteSkeleton from './NoteSkeleton'; +import NoteListSkeleton from './NoteListSkeleton'; + +export default function App({ selectedId, isEditing, searchText }) { + return ( +
+
+
+ + React Notes +
+
+ + New +
+ +
+
+ }> + + +
+
+ ); +} diff --git a/tests/integration/basic-next-app/src/EditButton.js b/tests/integration/basic-next-app/src/EditButton.js new file mode 100644 index 000000000000..f0265fc45afa --- /dev/null +++ b/tests/integration/basic-next-app/src/EditButton.js @@ -0,0 +1,37 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + */ + +'use client'; + +import {useTransition} from 'react'; +import {useRouter} from './framework/router'; + +export default function EditButton({noteId, children}) { + const [isPending, startTransition] = useTransition(); + const {navigate} = useRouter(); + const isDraft = noteId == null; + return ( + + ); +} diff --git a/tests/integration/basic-next-app/src/Note.js b/tests/integration/basic-next-app/src/Note.js new file mode 100644 index 000000000000..990cf52c0f12 --- /dev/null +++ b/tests/integration/basic-next-app/src/Note.js @@ -0,0 +1,66 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + */ + +import {format} from 'date-fns'; + +// Uncomment if you want to read from a file instead. +// import {readFile} from 'fs/promises'; +// import {resolve} from 'path'; + +import NotePreview from './NotePreview'; +import EditButton from './EditButton'; +import NoteEditor from './NoteEditor'; + +export default async function Note({selectedId, isEditing}) { + if (selectedId === null) { + if (isEditing) { + return ( + + ); + } else { + return ( +
+ + Click a note on the left to view something! 🥺 + +
+ ); + } + } + + const noteResponse = await fetch(`http://localhost:4000/notes/${selectedId}`); + const note = await noteResponse.json(); + + let {id, title, body, updated_at} = note; + const updatedAt = new Date(updated_at); + + // We could also read from a file instead. + // body = await readFile(resolve(`./notes/${note.id}.md`), 'utf8'); + + // Now let's see how the Suspense boundary above lets us not block on this. + // await fetch('http://localhost:4000/sleep/3000'); + + if (isEditing) { + return ; + } else { + return ( +
+
+

{title}

+
+ + Last updated on {format(updatedAt, "d MMM yyyy 'at' h:mm bb")} + + Edit +
+
+ +
+ ); + } +} diff --git a/tests/integration/basic-next-app/src/NoteEditor.js b/tests/integration/basic-next-app/src/NoteEditor.js new file mode 100644 index 000000000000..0b3b7bd8d914 --- /dev/null +++ b/tests/integration/basic-next-app/src/NoteEditor.js @@ -0,0 +1,120 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + */ + +'use client'; + +import {useState, useTransition} from 'react'; +import {useRouter, useMutation} from './framework/router'; + +import NotePreview from './NotePreview'; + +export default function NoteEditor({noteId, initialTitle, initialBody}) { + const [title, setTitle] = useState(initialTitle); + const [body, setBody] = useState(initialBody); + const {location} = useRouter(); + const [isNavigating, startNavigating] = useTransition(); + const [isSaving, saveNote] = useMutation({ + endpoint: noteId !== null ? `/notes/${noteId}` : `/notes`, + method: noteId !== null ? 'PUT' : 'POST', + }); + const [isDeleting, deleteNote] = useMutation({ + endpoint: `/notes/${noteId}`, + method: 'DELETE', + }); + + async function handleSave() { + const payload = {title, body}; + const requestedLocation = { + selectedId: noteId, + isEditing: false, + searchText: location.searchText, + }; + await saveNote(payload, requestedLocation); + } + + async function handleDelete() { + const payload = {}; + const requestedLocation = { + selectedId: null, + isEditing: false, + searchText: location.searchText, + }; + await deleteNote(payload, requestedLocation); + } + + const isDraft = noteId === null; + return ( +
+
e.preventDefault()}> + + { + setTitle(e.target.value); + }} + /> + +