@samitouri / QOS-React-2 / commits / f181ba8aa6

[Flight] Add bundler-less version of RSC using plain ESM (#26889)

This isn't really meant to be actually used, there are many issues with this approach, but it shows the capabilities as a proof-of-concept. It's a new reference implementation package `react-server-dom-esm` as well as a fixture in `fixtures/flight-esm` (fork of `fixtures/flight`). This works pretty much the same as pieces we already have in the Webpack implementation but instead of loading modules using Webpack on the client it uses native browser ESM. To really show it off, I don't use any JSX in the fixture and so it also doesn't use Babel or any compilation of the files. This works because we don't actually bundle the server in the reference implementation in the first place. We instead use [Node.js Loaders](https://nodejs.org/api/esm.html#loaders) to intercept files that contain `"use client"` and `"use server"` and replace them. There's a simple check for those exact bytes, and no parsing, so this is very fast. Since the client isn't actually bundled, there's no module map needed. We can just send the file path to the file we want to load in the RSC payload for client references. Since the existing reference implementation for Node.js already used ESM to load modules on the server, that all works the same, including Server Actions. No bundling. There is one case that isn't implemented here. Importing a `"use server"` file from a Client Component. We don't have that implemented in the Webpack reference implementation neither - only in Next.js atm. In Webpack it would be implemented as a Webpack loader. There are a few ways this can be implemented without a bundler: - We can intercept the request from the browser importing this file in the HTTP server, and do a quick scan for `"use server"` in the file and replace it just like we do with loaders in Node.js. This is effectively how Vite works and likely how anyone using this technique would have to support JSX anyway. - We can use native browser "loaders" once that's eventually available in the same way as in Node.js. - We can generate import maps for each file and replace it with a pointer to a placeholder file. This requires scanning these ahead of time which defeats the purposes. Another case that's not implemented is the inline `"use server"` closure in a Server Component. That would require the existing loader to be a bit smarter but would still only "compile" files that contains those bytes in the fast path check. This would also happen in the loader that already exists so wouldn't do anything substantially different than what we currently have here.

Sebastian Markbåge committed Jun 3, 2023 at 15:58 UTC f181ba8aa6339d62f6e2572109c61242606f16b3
48 files changed +2758
.eslintrc.js
+1
@@ -324,6 +324,7 @@ module.exports = {
324 'packages/react-devtools-shared/**/*.js',
325 'packages/react-noop-renderer/**/*.js',
326 'packages/react-refresh/**/*.js',
327 + 'packages/react-server-dom-esm/**/*.js',
328 'packages/react-server-dom-webpack/**/*.js',
329 'packages/react-test-renderer/**/*.js',
330 'packages/react-debug-tools/**/*.js',
fixtures/flight-esm/.gitignore new
+20
@@ -0,0 +1,20 @@
1 +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 +
3 +# dependencies
4 +/node_modules
5 +/.pnp
6 +.pnp.js
7 +
8 +# testing
9 +/coverage
10 +
11 +# misc
12 +.DS_Store
13 +.env.local
14 +.env.development.local
15 +.env.test.local
16 +.env.production.local
17 +
18 +npm-debug.log*
19 +yarn-debug.log*
20 +yarn-error.log*
fixtures/flight-esm/loader/package.json new
+3
@@ -0,0 +1,3 @@
1 +{
2 + "type": "module"
3 +}
fixtures/flight-esm/loader/region.js new
+52
@@ -0,0 +1,52 @@
1 +import {
2 + resolve,
3 + load as reactLoad,
4 + getSource as getSourceImpl,
5 + transformSource as reactTransformSource,
6 +} from 'react-server-dom-esm/node-loader';
7 +
8 +export {resolve};
9 +
10 +async function textLoad(url, context, defaultLoad) {
11 + const {format} = context;
12 + const result = await defaultLoad(url, context, defaultLoad);
13 + if (result.format === 'module') {
14 + if (typeof result.source === 'string') {
15 + return result;
16 + }
17 + return {
18 + source: Buffer.from(result.source).toString('utf8'),
19 + format: 'module',
20 + };
21 + }
22 + return result;
23 +}
24 +
25 +export async function load(url, context, defaultLoad) {
26 + return await reactLoad(url, context, (u, c) => {
27 + return textLoad(u, c, defaultLoad);
28 + });
29 +}
30 +
31 +async function textTransformSource(source, context, defaultTransformSource) {
32 + const {format} = context;
33 + if (format === 'module') {
34 + if (typeof source === 'string') {
35 + return {source};
36 + }
37 + return {
38 + source: Buffer.from(source).toString('utf8'),
39 + };
40 + }
41 + return defaultTransformSource(source, context, defaultTransformSource);
42 +}
43 +
44 +async function transformSourceImpl(source, context, defaultTransformSource) {
45 + return await reactTransformSource(source, context, (s, c) => {
46 + return textTransformSource(s, c, defaultTransformSource);
47 + });
48 +}
49 +
50 +export const transformSource =
51 + process.version < 'v16' ? transformSourceImpl : undefined;
52 +export const getSource = process.version < 'v16' ? getSourceImpl : undefined;
fixtures/flight-esm/package.json new
+28
@@ -0,0 +1,28 @@
1 +{
2 + "name": "flight-esm",
3 + "type": "module",
4 + "version": "0.1.0",
5 + "private": true,
6 + "dependencies": {
7 + "body-parser": "^1.20.1",
8 + "browserslist": "^4.18.1",
9 + "busboy": "^1.6.0",
10 + "compression": "^1.7.4",
11 + "concurrently": "^7.3.0",
12 + "nodemon": "^2.0.19",
13 + "prompts": "^2.4.2",
14 + "react": "experimental",
15 + "react-dom": "experimental",
16 + "undici": "^5.20.0"
17 + },
18 + "scripts": {
19 + "predev": "cp -r ../../build/oss-experimental/* ./node_modules/",
20 + "prestart": "cp -r ../../build/oss-experimental/* ./node_modules/",
21 + "dev": "concurrently \"npm run dev:region\" \"npm run dev:global\"",
22 + "dev:global": "NODE_ENV=development BUILD_PATH=dist node server/global",
23 + "dev:region": "NODE_ENV=development BUILD_PATH=dist nodemon --watch src --watch dist -- --experimental-loader ./loader/region.js --conditions=react-server server/region",
24 + "start": "concurrently \"npm run start:region\" \"npm run start:global\"",
25 + "start:global": "NODE_ENV=production node server/global",
26 + "start:region": "NODE_ENV=production node --experimental-loader ./loader/region.js --conditions=react-server server/region"
27 + }
28 +}
fixtures/flight-esm/public/favicon.ico
Binary files /dev/null and b/fixtures/flight-esm/public/favicon.ico differ
fixtures/flight-esm/server/global.js new
+137
@@ -0,0 +1,137 @@
1 +'use strict';
2 +
3 +// This is a server to host CDN distributed resources like module source files and SSR
4 +
5 +const path = require('path');
6 +const url = require('url');
7 +
8 +const fs = require('fs').promises;
9 +const compress = require('compression');
10 +const chalk = require('chalk');
11 +const express = require('express');
12 +const http = require('http');
13 +
14 +const {renderToPipeableStream} = require('react-dom/server');
15 +const {createFromNodeStream} = require('react-server-dom-esm/client');
16 +
17 +const moduleBasePath = new URL('../src', url.pathToFileURL(__filename)).href;
18 +
19 +const app = express();
20 +
21 +app.use(compress());
22 +
23 +function request(options, body) {
24 + return new Promise((resolve, reject) => {
25 + const req = http.request(options, res => {
26 + resolve(res);
27 + });
28 + req.on('error', e => {
29 + reject(e);
30 + });
31 + body.pipe(req);
32 + });
33 +}
34 +
35 +app.all('/', async function (req, res, next) {
36 + // Proxy the request to the regional server.
37 + const proxiedHeaders = {
38 + 'X-Forwarded-Host': req.hostname,
39 + 'X-Forwarded-For': req.ips,
40 + 'X-Forwarded-Port': 3000,
41 + 'X-Forwarded-Proto': req.protocol,
42 + };
43 + // Proxy other headers as desired.
44 + if (req.get('rsc-action')) {
45 + proxiedHeaders['Content-type'] = req.get('Content-type');
46 + proxiedHeaders['rsc-action'] = req.get('rsc-action');
47 + } else if (req.get('Content-type')) {
48 + proxiedHeaders['Content-type'] = req.get('Content-type');
49 + }
50 +
51 + const promiseForData = request(
52 + {
53 + host: '127.0.0.1',
54 + port: 3001,
55 + method: req.method,
56 + path: '/',
57 + headers: proxiedHeaders,
58 + },
59 + req
60 + );
61 +
62 + if (req.accepts('text/html')) {
63 + try {
64 + const rscResponse = await promiseForData;
65 +
66 + const moduleBaseURL = '/src';
67 +
68 + // For HTML, we're a "client" emulator that runs the client code,
69 + // so we start by consuming the RSC payload. This needs the local file path
70 + // to load the source files from as well as the URL path for preloads.
71 + const root = await createFromNodeStream(
72 + rscResponse,
73 + moduleBasePath,
74 + moduleBaseURL
75 + );
76 + // Render it into HTML by resolving the client components
77 + res.set('Content-type', 'text/html');
78 + const {pipe} = renderToPipeableStream(root, {
79 + // TODO: bootstrapModules inserts a preload before the importmap which causes
80 + // the import map to be invalid. We need to fix that in Float somehow.
81 + // bootstrapModules: ['/src/index.js'],
82 + });
83 + pipe(res);
84 + } catch (e) {
85 + console.error(`Failed to SSR: ${e.stack}`);
86 + res.statusCode = 500;
87 + res.end();
88 + }
89 + } else {
90 + try {
91 + const rscResponse = await promiseForData;
92 + // For other request, we pass-through the RSC payload.
93 + res.set('Content-type', 'text/x-component');
94 + rscResponse.on('data', data => {
95 + res.write(data);
96 + res.flush();
97 + });
98 + rscResponse.on('end', data => {
99 + res.end();
100 + });
101 + } catch (e) {
102 + console.error(`Failed to proxy request: ${e.stack}`);
103 + res.statusCode = 500;
104 + res.end();
105 + }
106 + }
107 +});
108 +
109 +app.use(express.static('public'));
110 +app.use('/src', express.static('src'));
111 +app.use(
112 + '/node_modules/react-server-dom-esm/esm',
113 + express.static('node_modules/react-server-dom-esm/esm')
114 +);
115 +
116 +app.listen(3000, () => {
117 + console.log('Global Fizz/Webpack Server listening on port 3000...');
118 +});
119 +
120 +app.on('error', function (error) {
121 + if (error.syscall !== 'listen') {
122 + throw error;
123 + }
124 +
125 + switch (error.code) {
126 + case 'EACCES':
127 + console.error('port 3000 requires elevated privileges');
128 + process.exit(1);
129 + break;
130 + case 'EADDRINUSE':
131 + console.error('Port 3000 is already in use');
132 + process.exit(1);
133 + break;
134 + default:
135 + throw error;
136 + }
137 +});
fixtures/flight-esm/server/package.json new
+3
@@ -0,0 +1,3 @@
1 +{
2 + "type": "commonjs"
3 +}
fixtures/flight-esm/server/region.js new
+140
@@ -0,0 +1,140 @@
1 +'use strict';
2 +
3 +// This is a server to host data-local resources like databases and RSC
4 +
5 +const path = require('path');
6 +const url = require('url');
7 +
8 +if (typeof fetch === 'undefined') {
9 + // Patch fetch for earlier Node versions.
10 + global.fetch = require('undici').fetch;
11 +}
12 +
13 +const express = require('express');
14 +const bodyParser = require('body-parser');
15 +const busboy = require('busboy');
16 +const app = express();
17 +const compress = require('compression');
18 +const {Readable} = require('node:stream');
19 +
20 +app.use(compress());
21 +
22 +// Application
23 +
24 +const {readFile} = require('fs').promises;
25 +
26 +const React = require('react');
27 +
28 +const moduleBasePath = new URL('../src', url.pathToFileURL(__filename)).href;
29 +
30 +async function renderApp(res, returnValue) {
31 + const {renderToPipeableStream} = await import('react-server-dom-esm/server');
32 + const m = await import('../src/App.js');
33 +
34 + const App = m.default;
35 + const root = React.createElement(App);
36 + // For client-invoked server actions we refresh the tree and return a return value.
37 + const payload = returnValue ? {returnValue, root} : root;
38 + const {pipe} = renderToPipeableStream(payload, moduleBasePath);
39 + pipe(res);
40 +}
41 +
42 +app.get('/', async function (req, res) {
43 + await renderApp(res, null);
44 +});
45 +
46 +app.post('/', bodyParser.text(), async function (req, res) {
47 + const {
48 + renderToPipeableStream,
49 + decodeReply,
50 + decodeReplyFromBusboy,
51 + decodeAction,
52 + } = await import('react-server-dom-esm/server');
53 + const serverReference = req.get('rsc-action');
54 + if (serverReference) {
55 + // This is the client-side case
56 + const [filepath, name] = serverReference.split('#');
57 + const action = (await import(filepath))[name];
58 + // Validate that this is actually a function we intended to expose and
59 + // not the client trying to invoke arbitrary functions. In a real app,
60 + // you'd have a manifest verifying this before even importing it.
61 + if (action.$$typeof !== Symbol.for('react.server.reference')) {
62 + throw new Error('Invalid action');
63 + }
64 +
65 + let args;
66 + if (req.is('multipart/form-data')) {
67 + // Use busboy to streamingly parse the reply from form-data.
68 + const bb = busboy({headers: req.headers});
69 + const reply = decodeReplyFromBusboy(bb, moduleBasePath);
70 + req.pipe(bb);
71 + args = await reply;
72 + } else {
73 + args = await decodeReply(req.body, moduleBasePath);
74 + }
75 + const result = action.apply(null, args);
76 + try {
77 + // Wait for any mutations
78 + await result;
79 + } catch (x) {
80 + // We handle the error on the client
81 + }
82 + // Refresh the client and return the value
83 + renderApp(res, result);
84 + } else {
85 + // This is the progressive enhancement case
86 + const UndiciRequest = require('undici').Request;
87 + const fakeRequest = new UndiciRequest('http://localhost', {
88 + method: 'POST',
89 + headers: {'Content-Type': req.headers['content-type']},
90 + body: Readable.toWeb(req),
91 + duplex: 'half',
92 + });
93 + const formData = await fakeRequest.formData();
94 + const action = await decodeAction(formData, moduleBasePath);
95 + try {
96 + // Wait for any mutations
97 + await action();
98 + } catch (x) {
99 + const {setServerState} = await import('../src/ServerState.js');
100 + setServerState('Error: ' + x.message);
101 + }
102 + renderApp(res, null);
103 + }
104 +});
105 +
106 +app.get('/todos', function (req, res) {
107 + res.json([
108 + {
109 + id: 1,
110 + text: 'Shave yaks',
111 + },
112 + {
113 + id: 2,
114 + text: 'Eat kale',
115 + },
116 + ]);
117 +});
118 +
119 +app.listen(3001, () => {
120 + console.log('Regional Flight Server listening on port 3001...');
121 +});
122 +
123 +app.on('error', function (error) {
124 + if (error.syscall !== 'listen') {
125 + throw error;
126 + }
127 +
128 + switch (error.code) {
129 + case 'EACCES':
130 + console.error('port 3001 requires elevated privileges');
131 + process.exit(1);
132 + break;
133 + case 'EADDRINUSE':
134 + console.error('Port 3001 is already in use');
135 + process.exit(1);
136 + break;
137 + default:
138 + throw error;
139 + }
140 +});
fixtures/flight-esm/src/App.js new
+92
@@ -0,0 +1,92 @@
1 +import * as React from 'react';
2 +
3 +import Button from './Button.js';
4 +import Form from './Form.js';
5 +
6 +import {like, greet} from './actions.js';
7 +
8 +import {getServerState} from './ServerState.js';
9 +
10 +const h = React.createElement;
11 +
12 +const importMap = {
13 + imports: {
14 + react: 'https://esm.sh/react@experimental?pin=v124&dev',
15 + 'react-dom': 'https://esm.sh/react-dom@experimental?pin=v124&dev',
16 + 'react-dom/': 'https://esm.sh/react-dom@experimental&pin=v124&dev/',
17 + 'react-server-dom-esm/client':
18 + '/node_modules/react-server-dom-esm/esm/react-server-dom-esm-client.browser.development.js',
19 + },
20 +};
21 +
22 +export default async function App() {
23 + const res = await fetch('http://localhost:3001/todos');
24 + const todos = await res.json();
25 + return h(
26 + 'html',
27 + {
28 + lang: 'en',
29 + },
30 + h(
31 + 'head',
32 + null,
33 + h('meta', {
34 + charSet: 'utf-8',
35 + }),
36 + h('meta', {
37 + name: 'viewport',
38 + content: 'width=device-width, initial-scale=1',
39 + }),
40 + h('title', null, 'Flight'),
41 + h('link', {
42 + rel: 'stylesheet',
43 + href: '/src/style.css',
44 + precedence: 'default',
45 + }),
46 + h('script', {
47 + type: 'importmap',
48 + dangerouslySetInnerHTML: {
49 + __html: JSON.stringify(importMap),
50 + },
51 + })
52 + ),
53 + h(
54 + 'body',
55 + null,
56 + h(
57 + 'div',
58 + null,
59 + h('h1', null, getServerState()),
60 + h(
61 + 'ul',
62 + null,
63 + todos.map(todo =>
64 + h(
65 + 'li',
66 + {
67 + key: todo.id,
68 + },
69 + todo.text
70 + )
71 + )
72 + ),
73 + h(Form, {
74 + action: greet,
75 + }),
76 + h(
77 + 'div',
78 + null,
79 + h(
80 + Button,
81 + {
82 + action: like,
83 + },
84 + 'Like'
85 + )
86 + )
87 + ),
88 + // TODO: Move this to bootstrapModules.
89 + h('script', {type: 'module', src: '/src/index.js'})
90 + )
91 + );
92 +}
fixtures/flight-esm/src/Button.js new
+37
@@ -0,0 +1,37 @@
1 +'use client';
2 +
3 +import * as React from 'react';
4 +import {experimental_useFormStatus as useFormStatus} from 'react-dom';
5 +import ErrorBoundary from './ErrorBoundary.js';
6 +
7 +const h = React.createElement;
8 +
9 +function ButtonDisabledWhilePending({action, children}) {
10 + const {pending} = useFormStatus();
11 + return h(
12 + 'button',
13 + {
14 + disabled: pending,
15 + formAction: action,
16 + },
17 + children
18 + );
19 +}
20 +
21 +export default function Button({action, children}) {
22 + return h(
23 + ErrorBoundary,
24 + null,
25 + h(
26 + 'form',
27 + null,
28 + h(
29 + ButtonDisabledWhilePending,
30 + {
31 + action: action,
32 + },
33 + children
34 + )
35 + )
36 + );
37 +}
fixtures/flight-esm/src/ErrorBoundary.js new
+20
@@ -0,0 +1,20 @@
1 +'use client';
2 +
3 +import * as React from 'react';
4 +
5 +export default class ErrorBoundary extends React.Component {
6 + state = {error: null};
7 + static getDerivedStateFromError(error) {
8 + return {error};
9 + }
10 + render() {
11 + if (this.state.error) {
12 + return React.createElement(
13 + 'div',
14 + {},
15 + 'Caught an error: ' + this.state.error.message
16 + );
17 + }
18 + return this.props.children;
19 + }
20 +}
fixtures/flight-esm/src/Form.js new
+45
@@ -0,0 +1,45 @@
1 +'use client';
2 +
3 +import * as React from 'react';
4 +import {experimental_useFormStatus as useFormStatus} from 'react-dom';
5 +import ErrorBoundary from './ErrorBoundary.js';
6 +
7 +const h = React.createElement;
8 +
9 +function Status() {
10 + const {pending} = useFormStatus();
11 + return pending ? 'Saving...' : null;
12 +}
13 +
14 +export default function Form({action, children}) {
15 + const [isPending, setIsPending] = React.useState(false);
16 + return h(
17 + ErrorBoundary,
18 + null,
19 + h(
20 + 'form',
21 + {
22 + action: action,
23 + },
24 + h(
25 + 'label',
26 + {},
27 + 'Name: ',
28 + h('input', {
29 + name: 'name',
30 + })
31 + ),
32 + h(
33 + 'label',
34 + {},
35 + 'File: ',
36 + h('input', {
37 + type: 'file',
38 + name: 'file',
39 + })
40 + ),
41 + h('button', {}, 'Say Hi'),
42 + h(Status, {})
43 + )
44 + );
45 +}
fixtures/flight-esm/src/ServerState.js new
+9
@@ -0,0 +1,9 @@
1 +let serverState = 'Hello World';
2 +
3 +export function setServerState(message) {
4 + serverState = message;
5 +}
6 +
7 +export function getServerState() {
8 + return serverState;
9 +}
fixtures/flight-esm/src/actions.js new
+20
@@ -0,0 +1,20 @@
1 +'use server';
2 +
3 +import {setServerState} from './ServerState.js';
4 +
5 +export async function like() {
6 + setServerState('Liked!');
7 + return new Promise((resolve, reject) => resolve('Liked'));
8 +}
9 +
10 +export async function greet(formData) {
11 + const name = formData.get('name') || 'you';
12 + setServerState('Hi ' + name);
13 + const file = formData.get('file');
14 + if (file) {
15 + return `Ok, ${name}, here is ${file.name}:
16 + ${(await file.text()).toUpperCase()}
17 + `;
18 + }
19 + return 'Hi ' + name + '!';
20 +}
fixtures/flight-esm/src/index.js new
+46
@@ -0,0 +1,46 @@
1 +import * as React from 'react';
2 +import {use, Suspense, useState, startTransition} from 'react';
3 +import ReactDOM from 'react-dom/client';
4 +import {createFromFetch, encodeReply} from 'react-server-dom-esm/client';
5 +
6 +const moduleBaseURL = '/src/';
7 +let updateRoot;
8 +async function callServer(id, args) {
9 + const response = fetch('/', {
10 + method: 'POST',
11 + headers: {
12 + Accept: 'text/x-component',
13 + 'rsc-action': id,
14 + },
15 + body: await encodeReply(args),
16 + });
17 + const {returnValue, root} = await createFromFetch(response, {
18 + callServer,
19 + moduleBaseURL,
20 + });
21 + // Refresh the tree with the new RSC payload.
22 + startTransition(() => {
23 + updateRoot(root);
24 + });
25 + return returnValue;
26 +}
27 +
28 +let data = createFromFetch(
29 + fetch('/', {
30 + headers: {
31 + Accept: 'text/x-component',
32 + },
33 + }),
34 + {
35 + callServer,
36 + moduleBaseURL,
37 + }
38 +);
39 +
40 +function Shell({data}) {
41 + const [root, setRoot] = useState(use(data));
42 + updateRoot = setRoot;
43 + return root;
44 +}
45 +
46 +ReactDOM.hydrateRoot(document, React.createElement(Shell, {data}));
fixtures/flight-esm/src/style.css new
+3
@@ -0,0 +1,3 @@
1 +body {
2 + font-family: Helvetica;
3 +}
\ No newline at end of file
fixtures/flight-esm/yarn.lock new
+788
@@ -0,0 +1,788 @@
1 +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
2 +# yarn lockfile v1
3 +
4 +
5 +"@babel/runtime@^7.21.0":
6 + version "7.22.3"
7 + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.22.3.tgz#0a7fce51d43adbf0f7b517a71f4c3aaca92ebcbb"
8 + integrity sha512-XsDuspWKLUsxwCp6r7EhsExHtYfbe5oAGQ19kqngTdCPUoPQzOPdUbD/pB9PJiwb2ptYKQDjSJT3R6dC+EPqfQ==
9 + dependencies:
10 + regenerator-runtime "^0.13.11"
11 +
12 +abbrev@1:
13 + version "1.1.1"
14 + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8"
15 + integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==
16 +
17 +accepts@~1.3.5:
18 + version "1.3.8"
19 + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e"
20 + integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==
21 + dependencies:
22 + mime-types "~2.1.34"
23 + negotiator "0.6.3"
24 +
25 +ansi-regex@^5.0.1:
26 + version "5.0.1"
27 + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304"
28 + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==
29 +
30 +ansi-styles@^4.0.0, ansi-styles@^4.1.0:
31 + version "4.3.0"
32 + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937"
33 + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==
34 + dependencies:
35 + color-convert "^2.0.1"
36 +
37 +anymatch@~3.1.2:
38 + version "3.1.3"
39 + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e"
40 + integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==
41 + dependencies:
42 + normalize-path "^3.0.0"
43 + picomatch "^2.0.4"
44 +
45 +balanced-match@^1.0.0:
46 + version "1.0.2"
47 + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
48 + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
49 +
50 +binary-extensions@^2.0.0:
51 + version "2.2.0"
52 + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d"
53 + integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==
54 +
55 +body-parser@^1.20.1:
56 + version "1.20.2"
57 + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.2.tgz#6feb0e21c4724d06de7ff38da36dad4f57a747fd"
58 + integrity sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==
59 + dependencies:
60 + bytes "3.1.2"
61 + content-type "~1.0.5"
62 + debug "2.6.9"
63 + depd "2.0.0"
64 + destroy "1.2.0"
65 + http-errors "2.0.0"
66 + iconv-lite "0.4.24"
67 + on-finished "2.4.1"
68 + qs "6.11.0"
69 + raw-body "2.5.2"
70 + type-is "~1.6.18"
71 + unpipe "1.0.0"
72 +
73 +brace-expansion@^1.1.7:
74 + version "1.1.11"
75 + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
76 + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
77 + dependencies:
78 + balanced-match "^1.0.0"
79 + concat-map "0.0.1"
80 +
81 +braces@~3.0.2:
82 + version "3.0.2"
83 + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107"
84 + integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==
85 + dependencies:
86 + fill-range "^7.0.1"
87 +
88 +browserslist@^4.18.1:
89 + version "4.21.7"
90 + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.7.tgz#e2b420947e5fb0a58e8f4668ae6e23488127e551"
91 + integrity sha512-BauCXrQ7I2ftSqd2mvKHGo85XR0u7Ru3C/Hxsy/0TkfCtjrmAbPdzLGasmoiBxplpDXlPvdjX9u7srIMfgasNA==
92 + dependencies:
93 + caniuse-lite "^1.0.30001489"
94 + electron-to-chromium "^1.4.411"
95 + node-releases "^2.0.12"
96 + update-browserslist-db "^1.0.11"
97 +
98 +busboy@^1.6.0:
99 + version "1.6.0"
100 + resolved "https://registry.yarnpkg.com/busboy/-/busboy-1.6.0.tgz#966ea36a9502e43cdb9146962523b92f531f6893"
101 + integrity sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==
102 + dependencies:
103 + streamsearch "^1.1.0"
104 +
105 +bytes@3.0.0:
106 + version "3.0.0"
107 + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048"
108 + integrity sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==
109 +
110 +bytes@3.1.2:
111 + version "3.1.2"
112 + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5"
113 + integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==
114 +
115 +call-bind@^1.0.0:
116 + version "1.0.2"
117 + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c"
118 + integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==
119 + dependencies:
120 + function-bind "^1.1.1"
121 + get-intrinsic "^1.0.2"
122 +
123 +caniuse-lite@^1.0.30001489:
124 + version "1.0.30001492"
125 + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001492.tgz#4a06861788a52b4c81fd3344573b68cc87fe062b"
126 + integrity sha512-2efF8SAZwgAX1FJr87KWhvuJxnGJKOnctQa8xLOskAXNXq8oiuqgl6u1kk3fFpsp3GgvzlRjiK1sl63hNtFADw==
127 +
128 +chalk@^4.1.0:
129 + version "4.1.2"
130 + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01"
131 + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==
132 + dependencies:
133 + ansi-styles "^4.1.0"
134 + supports-color "^7.1.0"
135 +
136 +chokidar@^3.5.2:
137 + version "3.5.3"
138 + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd"
139 + integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==
140 + dependencies:
141 + anymatch "~3.1.2"
142 + braces "~3.0.2"
143 + glob-parent "~5.1.2"
144 + is-binary-path "~2.1.0"
145 + is-glob "~4.0.1"
146 + normalize-path "~3.0.0"
147 + readdirp "~3.6.0"
148 + optionalDependencies:
149 + fsevents "~2.3.2"
150 +
151 +cliui@^8.0.1:
152 + version "8.0.1"
153 + resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa"
154 + integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==
155 + dependencies:
156 + string-width "^4.2.0"
157 + strip-ansi "^6.0.1"
158 + wrap-ansi "^7.0.0"
159 +
160 +color-convert@^2.0.1:
161 + version "2.0.1"
162 + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3"
163 + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==
164 + dependencies:
165 + color-name "~1.1.4"
166 +
167 +color-name@~1.1.4:
168 + version "1.1.4"
169 + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
170 + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
171 +
172 +compressible@~2.0.16:
173 + version "2.0.18"
174 + resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.18.tgz#af53cca6b070d4c3c0750fbd77286a6d7cc46fba"
175 + integrity sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==
176 + dependencies:
177 + mime-db ">= 1.43.0 < 2"
178 +
179 +compression@^1.7.4:
180 + version "1.7.4"
181 + resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.4.tgz#95523eff170ca57c29a0ca41e6fe131f41e5bb8f"
182 + integrity sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==
183 + dependencies:
184 + accepts "~1.3.5"
185 + bytes "3.0.0"
186 + compressible "~2.0.16"
187 + debug "2.6.9"
188 + on-headers "~1.0.2"
189 + safe-buffer "5.1.2"
190 + vary "~1.1.2"
191 +
192 +concat-map@0.0.1:
193 + version "0.0.1"
194 + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
195 + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==
196 +
197 +concurrently@^7.3.0:
198 + version "7.6.0"
199 + resolved "https://registry.yarnpkg.com/concurrently/-/concurrently-7.6.0.tgz#531a6f5f30cf616f355a4afb8f8fcb2bba65a49a"
200 + integrity sha512-BKtRgvcJGeZ4XttiDiNcFiRlxoAeZOseqUvyYRUp/Vtd+9p1ULmeoSqGsDA+2ivdeDFpqrJvGvmI+StKfKl5hw==
201 + dependencies:
202 + chalk "^4.1.0"
203 + date-fns "^2.29.1"
204 + lodash "^4.17.21"
205 + rxjs "^7.0.0"
206 + shell-quote "^1.7.3"
207 + spawn-command "^0.0.2-1"
208 + supports-color "^8.1.0"
209 + tree-kill "^1.2.2"
210 + yargs "^17.3.1"
211 +
212 +content-type@~1.0.5:
213 + version "1.0.5"
214 + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918"
215 + integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==
216 +
217 +date-fns@^2.29.1:
218 + version "2.30.0"
219 + resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.30.0.tgz#f367e644839ff57894ec6ac480de40cae4b0f4d0"
220 + integrity sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==
221 + dependencies:
222 + "@babel/runtime" "^7.21.0"
223 +
224 +debug@2.6.9:
225 + version "2.6.9"
226 + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
227 + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
228 + dependencies:
229 + ms "2.0.0"
230 +
231 +debug@^3.2.7:
232 + version "3.2.7"
233 + resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a"
234 + integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==
235 + dependencies:
236 + ms "^2.1.1"
237 +
238 +depd@2.0.0:
239 + version "2.0.0"
240 + resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df"
241 + integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==
242 +
243 +destroy@1.2.0:
244 + version "1.2.0"
245 + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015"
246 + integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==
247 +
248 +ee-first@1.1.1:
249 + version "1.1.1"
250 + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
251 + integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==
252 +
253 +electron-to-chromium@^1.4.411:
254 + version "1.4.417"
255 + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.417.tgz#a0c7eb992e68287fa50c8da5a5238b01f20b9a82"
256 + integrity sha512-8rY8HdCxuSVY8wku3i/eDac4g1b4cSbruzocenrqBlzqruAZYHjQCHIjC66dLR9DXhEHTojsC4EjhZ8KmzwXqA==
257 +
258 +emoji-regex@^8.0.0:
259 + version "8.0.0"
260 + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37"
261 + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==
262 +
263 +escalade@^3.1.1:
264 + version "3.1.1"
265 + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
266 + integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==
267 +
268 +fill-range@^7.0.1:
269 + version "7.0.1"
270 + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40"
271 + integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==
272 + dependencies:
273 + to-regex-range "^5.0.1"
274 +
275 +fsevents@~2.3.2:
276 + version "2.3.2"
277 + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a"
278 + integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==
279 +
280 +function-bind@^1.1.1:
281 + version "1.1.1"
282 + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
283 + integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
284 +
285 +get-caller-file@^2.0.5:
286 + version "2.0.5"
287 + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e"
288 + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==
289 +
290 +get-intrinsic@^1.0.2:
291 + version "1.2.1"
292 + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.1.tgz#d295644fed4505fc9cde952c37ee12b477a83d82"
293 + integrity sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==
294 + dependencies:
295 + function-bind "^1.1.1"
296 + has "^1.0.3"
297 + has-proto "^1.0.1"
298 + has-symbols "^1.0.3"
299 +
300 +glob-parent@~5.1.2:
301 + version "5.1.2"
302 + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4"
303 + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==
304 + dependencies:
305 + is-glob "^4.0.1"
306 +
307 +has-flag@^3.0.0:
308 + version "3.0.0"
309 + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
310 + integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==
311 +
312 +has-flag@^4.0.0:
313 + version "4.0.0"
314 + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b"
315 + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
316 +
317 +has-proto@^1.0.1:
318 + version "1.0.1"
319 + resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.1.tgz#1885c1305538958aff469fef37937c22795408e0"
320 + integrity sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==
321 +
322 +has-symbols@^1.0.3:
323 + version "1.0.3"
324 + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8"
325 + integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==
326 +
327 +has@^1.0.3:
328 + version "1.0.3"
329 + resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796"
330 + integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==
331 + dependencies:
332 + function-bind "^1.1.1"
333 +
334 +http-errors@2.0.0:
335 + version "2.0.0"
336 + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3"
337 + integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==
338 + dependencies:
339 + depd "2.0.0"
340 + inherits "2.0.4"
341 + setprototypeof "1.2.0"
342 + statuses "2.0.1"
343 + toidentifier "1.0.1"
344 +
345 +iconv-lite@0.4.24:
346 + version "0.4.24"
347 + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
348 + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==
349 + dependencies:
350 + safer-buffer ">= 2.1.2 < 3"
351 +
352 +ignore-by-default@^1.0.1:
353 + version "1.0.1"
354 + resolved "https://registry.yarnpkg.com/ignore-by-default/-/ignore-by-default-1.0.1.tgz#48ca6d72f6c6a3af00a9ad4ae6876be3889e2b09"
355 + integrity sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==
356 +
357 +inherits@2.0.4:
358 + version "2.0.4"
359 + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
360 + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
361 +
362 +is-binary-path@~2.1.0:
363 + version "2.1.0"
364 + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09"
365 + integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==
366 + dependencies:
367 + binary-extensions "^2.0.0"
368 +
369 +is-extglob@^2.1.1:
370 + version "2.1.1"
371 + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
372 + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==
373 +
374 +is-fullwidth-code-point@^3.0.0:
375 + version "3.0.0"
376 + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d"
377 + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==
378 +
379 +is-glob@^4.0.1, is-glob@~4.0.1:
380 + version "4.0.3"
381 + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084"
382 + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==
383 + dependencies:
384 + is-extglob "^2.1.1"
385 +
386 +is-number@^7.0.0:
387 + version "7.0.0"
388 + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
389 + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
390 +
391 +"js-tokens@^3.0.0 || ^4.0.0":
392 + version "4.0.0"
393 + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
394 + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
395 +
396 +kleur@^3.0.3:
397 + version "3.0.3"
398 + resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e"
399 + integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==
400 +
401 +lodash@^4.17.21:
402 + version "4.17.21"
403 + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
404 + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
405 +
406 +loose-envify@^1.1.0:
407 + version "1.4.0"
408 + resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
409 + integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
410 + dependencies:
411 + js-tokens "^3.0.0 || ^4.0.0"
412 +
413 +media-typer@0.3.0:
414 + version "0.3.0"
415 + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
416 + integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==
417 +
418 +mime-db@1.52.0, "mime-db@>= 1.43.0 < 2":
419 + version "1.52.0"
420 + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70"
421 + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==
422 +
423 +mime-types@~2.1.24, mime-types@~2.1.34:
424 + version "2.1.35"
425 + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a"
426 + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==
427 + dependencies:
428 + mime-db "1.52.0"
429 +
430 +minimatch@^3.1.2:
431 + version "3.1.2"
432 + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b"
433 + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
434 + dependencies:
435 + brace-expansion "^1.1.7"
436 +
437 +ms@2.0.0:
438 + version "2.0.0"
439 + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
440 + integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==
441 +
442 +ms@^2.1.1:
443 + version "2.1.3"
444 + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2"
445 + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
446 +
447 +negotiator@0.6.3:
448 + version "0.6.3"
449 + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd"
450 + integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==
451 +
452 +node-releases@^2.0.12:
453 + version "2.0.12"
454 + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.12.tgz#35627cc224a23bfb06fb3380f2b3afaaa7eb1039"
455 + integrity sha512-QzsYKWhXTWx8h1kIvqfnC++o0pEmpRQA/aenALsL2F4pqNVr7YzcdMlDij5WBnwftRbJCNJL/O7zdKaxKPHqgQ==
456 +
457 +nodemon@^2.0.19:
458 + version "2.0.22"
459 + resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-2.0.22.tgz#182c45c3a78da486f673d6c1702e00728daf5258"
460 + integrity sha512-B8YqaKMmyuCO7BowF1Z1/mkPqLk6cs/l63Ojtd6otKjMx47Dq1utxfRxcavH1I7VSaL8n5BUaoutadnsX3AAVQ==
461 + dependencies:
462 + chokidar "^3.5.2"
463 + debug "^3.2.7"
464 + ignore-by-default "^1.0.1"
465 + minimatch "^3.1.2"
466 + pstree.remy "^1.1.8"
467 + semver "^5.7.1"
468 + simple-update-notifier "^1.0.7"
469 + supports-color "^5.5.0"
470 + touch "^3.1.0"
471 + undefsafe "^2.0.5"
472 +
473 +nopt@~1.0.10:
474 + version "1.0.10"
475 + resolved "https://registry.yarnpkg.com/nopt/-/nopt-1.0.10.tgz#6ddd21bd2a31417b92727dd585f8a6f37608ebee"
476 + integrity sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==
477 + dependencies:
478 + abbrev "1"
479 +
480 +normalize-path@^3.0.0, normalize-path@~3.0.0:
481 + version "3.0.0"
482 + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
483 + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
484 +
485 +object-inspect@^1.9.0:
486 + version "1.12.3"
487 + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.3.tgz#ba62dffd67ee256c8c086dfae69e016cd1f198b9"
488 + integrity sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==
489 +
490 +on-finished@2.4.1:
491 + version "2.4.1"
492 + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f"
493 + integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==
494 + dependencies:
495 + ee-first "1.1.1"
496 +
497 +on-headers@~1.0.2:
498 + version "1.0.2"
499 + resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f"
500 + integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==
501 +
502 +picocolors@^1.0.0:
503 + version "1.0.0"
504 + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c"
505 + integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==
506 +
507 +picomatch@^2.0.4, picomatch@^2.2.1:
508 + version "2.3.1"
509 + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42"
510 + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
511 +
512 +prompts@^2.4.2:
513 + version "2.4.2"
514 + resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.2.tgz#7b57e73b3a48029ad10ebd44f74b01722a4cb069"
515 + integrity sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==
516 + dependencies:
517 + kleur "^3.0.3"
518 + sisteransi "^1.0.5"
519 +
520 +pstree.remy@^1.1.8:
521 + version "1.1.8"
522 + resolved "https://registry.yarnpkg.com/pstree.remy/-/pstree.remy-1.1.8.tgz#c242224f4a67c21f686839bbdb4ac282b8373d3a"
523 + integrity sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==
524 +
525 +qs@6.11.0:
526 + version "6.11.0"
527 + resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a"
528 + integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==
529 + dependencies:
530 + side-channel "^1.0.4"
531 +
532 +raw-body@2.5.2:
533 + version "2.5.2"
534 + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.2.tgz#99febd83b90e08975087e8f1f9419a149366b68a"
535 + integrity sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==
536 + dependencies:
537 + bytes "3.1.2"
538 + http-errors "2.0.0"
539 + iconv-lite "0.4.24"
540 + unpipe "1.0.0"
541 +
542 +react-dom@experimental:
543 + version "0.0.0-experimental-018c58c9c-20230601"
544 + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-0.0.0-experimental-018c58c9c-20230601.tgz#2cc0ac824b83bab2ac1c6187f241dbd5dcd5201b"
545 + integrity sha512-hwRsyoG1R3Tub0nUa72YvNcqPvU+pTcr9dadOnUCKKfSiYVbBCy7LxmkqLauCD8OjNJMlwtMgG4UAgtidclYGQ==
546 + dependencies:
547 + loose-envify "^1.1.0"
548 + scheduler "0.0.0-experimental-018c58c9c-20230601"
549 +
550 +react@experimental:
551 + version "0.0.0-experimental-018c58c9c-20230601"
552 + resolved "https://registry.yarnpkg.com/react/-/react-0.0.0-experimental-018c58c9c-20230601.tgz#ab04d1243c8f83b0166ed342056fa6b38ab2cd23"
553 + integrity sha512-nSQIBsZ26Ii899pZ9cRt/6uQLbIUEAcDIivvAQyaHp4pWm289aB+7AK7VCWojAJIf4OStCuWs2berZsk4mzLVg==
554 + dependencies:
555 + loose-envify "^1.1.0"
556 +
557 +readdirp@~3.6.0:
558 + version "3.6.0"
559 + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7"
560 + integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==
561 + dependencies:
562 + picomatch "^2.2.1"
563 +
564 +regenerator-runtime@^0.13.11:
565 + version "0.13.11"
566 + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz#f6dca3e7ceec20590d07ada785636a90cdca17f9"
567 + integrity sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==
568 +
569 +require-directory@^2.1.1:
570 + version "2.1.1"
571 + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42"
572 + integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==
573 +
574 +rxjs@^7.0.0:
575 + version "7.8.1"
576 + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.8.1.tgz#6f6f3d99ea8044291efd92e7c7fcf562c4057543"
577 + integrity sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==
578 + dependencies:
579 + tslib "^2.1.0"
580 +
581 +safe-buffer@5.1.2:
582 + version "5.1.2"
583 + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
584 + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
585 +
586 +"safer-buffer@>= 2.1.2 < 3":
587 + version "2.1.2"
588 + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
589 + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
590 +
591 +scheduler@0.0.0-experimental-018c58c9c-20230601:
592 + version "0.0.0-experimental-018c58c9c-20230601"
593 + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.0.0-experimental-018c58c9c-20230601.tgz#4f083614f8e857bab63dd90b4b37b03783dafe6b"
594 + integrity sha512-otUM7AAAnCoJ5/0jTQwUQ7NhxjgcPEdrfzW7NfkpocrDoTUbql1kIGIhj9L9POMVFDI/wcZzRNK/oIEWsB4DPw==
595 + dependencies:
596 + loose-envify "^1.1.0"
597 +
598 +semver@^5.7.1:
599 + version "5.7.1"
600 + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
601 + integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
602 +
603 +semver@~7.0.0:
604 + version "7.0.0"
605 + resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e"
606 + integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==
607 +
608 +setprototypeof@1.2.0:
609 + version "1.2.0"
610 + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424"
611 + integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==
612 +
613 +shell-quote@^1.7.3:
614 + version "1.8.1"
615 + resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.8.1.tgz#6dbf4db75515ad5bac63b4f1894c3a154c766680"
616 + integrity sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==
617 +
618 +side-channel@^1.0.4:
619 + version "1.0.4"
620 + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf"
621 + integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==
622 + dependencies:
623 + call-bind "^1.0.0"
624 + get-intrinsic "^1.0.2"
625 + object-inspect "^1.9.0"
626 +
627 +simple-update-notifier@^1.0.7:
628 + version "1.1.0"
629 + resolved "https://registry.yarnpkg.com/simple-update-notifier/-/simple-update-notifier-1.1.0.tgz#67694c121de354af592b347cdba798463ed49c82"
630 + integrity sha512-VpsrsJSUcJEseSbMHkrsrAVSdvVS5I96Qo1QAQ4FxQ9wXFcB+pjj7FB7/us9+GcgfW4ziHtYMc1J0PLczb55mg==
631 + dependencies:
632 + semver "~7.0.0"
633 +
634 +sisteransi@^1.0.5:
635 + version "1.0.5"
636 + resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed"
637 + integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==
638 +
639 +spawn-command@^0.0.2-1:
640 + version "0.0.2-1"
641 + resolved "https://registry.yarnpkg.com/spawn-command/-/spawn-command-0.0.2-1.tgz#62f5e9466981c1b796dc5929937e11c9c6921bd0"
642 + integrity sha512-n98l9E2RMSJ9ON1AKisHzz7V42VDiBQGY6PB1BwRglz99wpVsSuGzQ+jOi6lFXBGVTCrRpltvjm+/XA+tpeJrg==
643 +
644 +statuses@2.0.1:
645 + version "2.0.1"
646 + resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63"
647 + integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==
648 +
649 +streamsearch@^1.1.0:
650 + version "1.1.0"
651 + resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-1.1.0.tgz#404dd1e2247ca94af554e841a8ef0eaa238da764"
652 + integrity sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==
653 +
654 +string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
655 + version "4.2.3"
656 + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
657 + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
658 + dependencies:
659 + emoji-regex "^8.0.0"
660 + is-fullwidth-code-point "^3.0.0"
661 + strip-ansi "^6.0.1"
662 +
663 +strip-ansi@^6.0.0, strip-ansi@^6.0.1:
664 + version "6.0.1"
665 + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
666 + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
667 + dependencies:
668 + ansi-regex "^5.0.1"
669 +
670 +supports-color@^5.5.0:
671 + version "5.5.0"
672 + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
673 + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==
674 + dependencies:
675 + has-flag "^3.0.0"
676 +
677 +supports-color@^7.1.0:
678 + version "7.2.0"
679 + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da"
680 + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==
681 + dependencies:
682 + has-flag "^4.0.0"
683 +
684 +supports-color@^8.1.0:
685 + version "8.1.1"
686 + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c"
687 + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==
688 + dependencies:
689 + has-flag "^4.0.0"
690 +
691 +to-regex-range@^5.0.1:
692 + version "5.0.1"
693 + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4"
694 + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==
695 + dependencies:
696 + is-number "^7.0.0"
697 +
698 +toidentifier@1.0.1:
699 + version "1.0.1"
700 + resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35"
701 + integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==
702 +
703 +touch@^3.1.0:
704 + version "3.1.0"
705 + resolved "https://registry.yarnpkg.com/touch/-/touch-3.1.0.tgz#fe365f5f75ec9ed4e56825e0bb76d24ab74af83b"
706 + integrity sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==
707 + dependencies:
708 + nopt "~1.0.10"
709 +
710 +tree-kill@^1.2.2:
711 + version "1.2.2"
712 + resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc"
713 + integrity sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==
714 +
715 +tslib@^2.1.0:
716 + version "2.5.2"
717 + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.5.2.tgz#1b6f07185c881557b0ffa84b111a0106989e8338"
718 + integrity sha512-5svOrSA2w3iGFDs1HibEVBGbDrAY82bFQ3HZ3ixB+88nsbsWQoKqDRb5UBYAUPEzbBn6dAp5gRNXglySbx1MlA==
719 +
720 +type-is@~1.6.18:
721 + version "1.6.18"
722 + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131"
723 + integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==
724 + dependencies:
725 + media-typer "0.3.0"
726 + mime-types "~2.1.24"
727 +
728 +undefsafe@^2.0.5:
729 + version "2.0.5"
730 + resolved "https://registry.yarnpkg.com/undefsafe/-/undefsafe-2.0.5.tgz#38733b9327bdcd226db889fb723a6efd162e6e2c"
731 + integrity sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==
732 +
733 +undici@^5.20.0:
734 + version "5.22.1"
735 + resolved "https://registry.yarnpkg.com/undici/-/undici-5.22.1.tgz#877d512effef2ac8be65e695f3586922e1a57d7b"
736 + integrity sha512-Ji2IJhFXZY0x/0tVBXeQwgPlLWw13GVzpsWPQ3rV50IFMMof2I55PZZxtm4P6iNq+L5znYN9nSTAq0ZyE6lSJw==
737 + dependencies:
738 + busboy "^1.6.0"
739 +
740 +unpipe@1.0.0:
741 + version "1.0.0"
742 + resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"
743 + integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==
744 +
745 +update-browserslist-db@^1.0.11:
746 + version "1.0.11"
747 + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz#9a2a641ad2907ae7b3616506f4b977851db5b940"
748 + integrity sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==
749 + dependencies:
750 + escalade "^3.1.1"
751 + picocolors "^1.0.0"
752 +
753 +vary@~1.1.2:
754 + version "1.1.2"
755 + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
756 + integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==
757 +
758 +wrap-ansi@^7.0.0:
759 + version "7.0.0"
760 + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
761 + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
762 + dependencies:
763 + ansi-styles "^4.0.0"
764 + string-width "^4.1.0"
765 + strip-ansi "^6.0.0"
766 +
767 +y18n@^5.0.5:
768 + version "5.0.8"
769 + resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55"
770 + integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==
771 +
772 +yargs-parser@^21.1.1:
773 + version "21.1.1"
774 + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35"
775 + integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==
776 +
777 +yargs@^17.3.1:
778 + version "17.7.2"
779 + resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269"
780 + integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==
781 + dependencies:
782 + cliui "^8.0.1"
783 + escalade "^3.1.1"
784 + get-caller-file "^2.0.5"
785 + require-directory "^2.1.1"
786 + string-width "^4.2.3"
787 + y18n "^5.0.5"
788 + yargs-parser "^21.1.1"
packages/react-client/src/forks/ReactFlightClientConfig.dom-node-esm.js new
+13
@@ -0,0 +1,13 @@
1 +/**
2 + * Copyright (c) Meta Platforms, Inc. and affiliates.
3 + *
4 + * This source code is licensed under the MIT license found in the
5 + * LICENSE file in the root directory of this source tree.
6 + *
7 + * @flow
8 + */
9 +
10 +// This should really have a Node and a Browser fork but to avoid too many configs we limit this to build the same for both
11 +export * from 'react-client/src/ReactFlightClientConfigBrowser';
12 +export * from 'react-server-dom-esm/src/ReactFlightClientConfigESMBundler';
13 +export * from 'react-dom-bindings/src/shared/ReactFlightClientConfigDOM';
packages/react-reconciler/src/forks/ReactFiberConfig.dom-node-esm.js new
+10
@@ -0,0 +1,10 @@
1 +/**
2 + * Copyright (c) Meta Platforms, Inc. and affiliates.
3 + *
4 + * This source code is licensed under the MIT license found in the
5 + * LICENSE file in the root directory of this source tree.
6 + *
7 + * @flow
8 + */
9 +
10 +export * from 'react-dom-bindings/src/client/ReactFiberConfigDOM';
packages/react-server-dom-esm/README.md new
+5
@@ -0,0 +1,5 @@
1 +# react-server-dom-esm
2 +
3 +Experimental React Flight bindings for DOM using ESM.
4 +
5 +**Use it at your own risk.**
packages/react-server-dom-esm/client.browser.js new
+10
@@ -0,0 +1,10 @@
1 +/**
2 + * Copyright (c) Meta Platforms, Inc. and affiliates.
3 + *
4 + * This source code is licensed under the MIT license found in the
5 + * LICENSE file in the root directory of this source tree.
6 + *
7 + * @flow
8 + */
9 +
10 +export * from './src/ReactFlightDOMClientBrowser';
packages/react-server-dom-esm/client.js new
+10
@@ -0,0 +1,10 @@
1 +/**
2 + * Copyright (c) Meta Platforms, Inc. and affiliates.
3 + *
4 + * This source code is licensed under the MIT license found in the
5 + * LICENSE file in the root directory of this source tree.
6 + *
7 + * @flow
8 + */
9 +
10 +export * from './client.browser';
packages/react-server-dom-esm/client.node.js new
+10
@@ -0,0 +1,10 @@
1 +/**
2 + * Copyright (c) Meta Platforms, Inc. and affiliates.
3 + *
4 + * This source code is licensed under the MIT license found in the
5 + * LICENSE file in the root directory of this source tree.
6 + *
7 + * @flow
8 + */
9 +
10 +export * from './src/ReactFlightDOMClientNode';
packages/react-server-dom-esm/esm/package.json new
+3
@@ -0,0 +1,3 @@
1 +{
2 + "type": "module"
3 +}
packages/react-server-dom-esm/esm/react-server-dom-esm-node-loader.production.min.js new
+10
@@ -0,0 +1,10 @@
1 +/**
2 + * Copyright (c) Meta Platforms, Inc. and affiliates.
3 + *
4 + * This source code is licensed under the MIT license found in the
5 + * LICENSE file in the root directory of this source tree.
6 + *
7 + * @flow
8 + */
9 +
10 +export * from '../src/ReactFlightESMNodeLoader.js';
packages/react-server-dom-esm/index.js new
+10
@@ -0,0 +1,10 @@
1 +/**
2 + * Copyright (c) Meta Platforms, Inc. and affiliates.
3 + *
4 + * This source code is licensed under the MIT license found in the
5 + * LICENSE file in the root directory of this source tree.
6 + *
7 + * @flow
8 + */
9 +
10 +throw new Error('Use react-server-dom-esm/client instead.');
packages/react-server-dom-esm/npm/client.browser.js new
+7
@@ -0,0 +1,7 @@
1 +'use strict';
2 +
3 +if (process.env.NODE_ENV === 'production') {
4 + module.exports = require('./cjs/react-server-dom-esm-client.browser.production.min.js');
5 +} else {
6 + module.exports = require('./cjs/react-server-dom-esm-client.browser.development.js');
7 +}
packages/react-server-dom-esm/npm/client.js new
+3
@@ -0,0 +1,3 @@
1 +'use strict';
2 +
3 +module.exports = require('./client.browser');
packages/react-server-dom-esm/npm/client.node.js new
+7
@@ -0,0 +1,7 @@
1 +'use strict';
2 +
3 +if (process.env.NODE_ENV === 'production') {
4 + module.exports = require('./cjs/react-server-dom-esm-client.node.production.min.js');
5 +} else {
6 + module.exports = require('./cjs/react-server-dom-esm-client.node.development.js');
7 +}
packages/react-server-dom-esm/npm/esm/package.json new
+3
@@ -0,0 +1,3 @@
1 +{
2 + "type": "module"
3 +}
packages/react-server-dom-esm/npm/index.js new
+12
@@ -0,0 +1,12 @@
1 +/**
2 + * Copyright (c) Meta Platforms, Inc. and affiliates.
3 + *
4 + * This source code is licensed under the MIT license found in the
5 + * LICENSE file in the root directory of this source tree.
6 + *
7 + * @flow
8 + */
9 +
10 +'use strict';
11 +
12 +throw new Error('Use react-server-dom-esm/client instead.');
packages/react-server-dom-esm/npm/server.js new
+6
@@ -0,0 +1,6 @@
1 +'use strict';
2 +
3 +throw new Error(
4 + 'The React Server Writer cannot be used outside a react-server environment. ' +
5 + 'You must configure Node.js using the `--conditions react-server` flag.'
6 +);
packages/react-server-dom-esm/npm/server.node.js new
+7
@@ -0,0 +1,7 @@
1 +'use strict';
2 +
3 +if (process.env.NODE_ENV === 'production') {
4 + module.exports = require('./cjs/react-server-dom-esm-server.node.production.min.js');
5 +} else {
6 + module.exports = require('./cjs/react-server-dom-esm-server.node.development.js');
7 +}
packages/react-server-dom-esm/package.json new
+56
@@ -0,0 +1,56 @@
1 +{
2 + "name": "react-server-dom-esm",
3 + "description": "React Server Components bindings for DOM using ESM. This is intended to be integrated into meta-frameworks. It is not intended to be imported directly.",
4 + "version": "18.2.0",
5 + "keywords": [
6 + "react"
7 + ],
8 + "homepage": "https://reactjs.org/",
9 + "bugs": "https://github.com/facebook/react/issues",
10 + "license": "MIT",
11 + "files": [
12 + "LICENSE",
13 + "README.md",
14 + "index.js",
15 + "client.js",
16 + "client.browser.js",
17 + "client.node.js",
18 + "server.js",
19 + "server.node.js",
20 + "cjs/",
21 + "esm/"
22 + ],
23 + "exports": {
24 + ".": "./index.js",
25 + "./client": {
26 + "node": "./client.node.js",
27 + "default": "./client.browser.js"
28 + },
29 + "./client.browser": "./client.browser.js",
30 + "./client.node": "./client.node.js",
31 + "./server": {
32 + "react-server": "./server.node.js",
33 + "default": "./server.js"
34 + },
35 + "./server.node": "./server.node.js",
36 + "./node-loader": "./esm/react-server-dom-esm-node-loader.production.min.js",
37 + "./src/*": "./src/*.js",
38 + "./package.json": "./package.json"
39 + },
40 + "main": "index.js",
41 + "repository": {
42 + "type" : "git",
43 + "url" : "https://github.com/facebook/react.git",
44 + "directory": "packages/react-server-dom-esm"
45 + },
46 + "engines": {
47 + "node": ">=0.10.0"
48 + },
49 + "peerDependencies": {
50 + "react": "^18.2.0",
51 + "react-dom": "^18.2.0"
52 + },
53 + "dependencies": {
54 + "acorn-loose": "^8.3.0"
55 + }
56 +}
packages/react-server-dom-esm/server.js new
+13
@@ -0,0 +1,13 @@
1 +/**
2 + * Copyright (c) Meta Platforms, Inc. and affiliates.
3 + *
4 + * This source code is licensed under the MIT license found in the
5 + * LICENSE file in the root directory of this source tree.
6 + *
7 + * @flow
8 + */
9 +
10 +throw new Error(
11 + 'The React Server cannot be used outside a react-server environment. ' +
12 + 'You must configure Node.js using the `--conditions react-server` flag.',
13 +);
packages/react-server-dom-esm/server.node.js new
+10
@@ -0,0 +1,10 @@
1 +/**
2 + * Copyright (c) Meta Platforms, Inc. and affiliates.
3 + *
4 + * This source code is licensed under the MIT license found in the
5 + * LICENSE file in the root directory of this source tree.
6 + *
7 + * @flow
8 + */
9 +
10 +export * from './src/ReactFlightDOMServerNode';
packages/react-server-dom-esm/src/ReactFlightClientConfigESMBundler.js new
+103
@@ -0,0 +1,103 @@
1 +/**
2 + * Copyright (c) Meta Platforms, Inc. and affiliates.
3 + *
4 + * This source code is licensed under the MIT license found in the
5 + * LICENSE file in the root directory of this source tree.
6 + *
7 + * @flow
8 + */
9 +
10 +import type {
11 + Thenable,
12 + FulfilledThenable,
13 + RejectedThenable,
14 +} from 'shared/ReactTypes';
15 +
16 +export type SSRManifest = string; // Module root path
17 +
18 +export type ServerManifest = string; // Module root path
19 +
20 +export type ServerReferenceId = string;
21 +
22 +export opaque type ClientReferenceMetadata = [
23 + string, // module path
24 + string, // export name
25 +];
26 +
27 +// eslint-disable-next-line no-unused-vars
28 +export opaque type ClientReference<T> = {
29 + specifier: string,
30 + name: string,
31 +};
32 +
33 +export function resolveClientReference<T>(
34 + bundlerConfig: SSRManifest,
35 + metadata: ClientReferenceMetadata,
36 +): ClientReference<T> {
37 + const baseURL = bundlerConfig;
38 + return {
39 + specifier: baseURL + metadata[0],
40 + name: metadata[1],
41 + };
42 +}
43 +
44 +export function resolveServerReference<T>(
45 + config: ServerManifest,
46 + id: ServerReferenceId,
47 +): ClientReference<T> {
48 + const baseURL: string = config;
49 + const idx = id.lastIndexOf('#');
50 + const exportName = id.slice(idx + 1);
51 + const fullURL = id.slice(0, idx);
52 + if (!fullURL.startsWith(baseURL)) {
53 + throw new Error(
54 + 'Attempted to load a Server Reference outside the hosted root.',
55 + );
56 + }
57 + return {specifier: fullURL, name: exportName};
58 +}
59 +
60 +const asyncModuleCache: Map<string, Thenable<any>> = new Map();
61 +
62 +export function preloadModule<T>(
63 + metadata: ClientReference<T>,
64 +): null | Thenable<any> {
65 + const existingPromise = asyncModuleCache.get(metadata.specifier);
66 + if (existingPromise) {
67 + if (existingPromise.status === 'fulfilled') {
68 + return null;
69 + }
70 + return existingPromise;
71 + } else {
72 + // $FlowFixMe[unsupported-syntax]
73 + const modulePromise: Thenable<T> = import(metadata.specifier);
74 + modulePromise.then(
75 + value => {
76 + const fulfilledThenable: FulfilledThenable<mixed> =
77 + (modulePromise: any);
78 + fulfilledThenable.status = 'fulfilled';
79 + fulfilledThenable.value = value;
80 + },
81 + reason => {
82 + const rejectedThenable: RejectedThenable<mixed> = (modulePromise: any);
83 + rejectedThenable.status = 'rejected';
84 + rejectedThenable.reason = reason;
85 + },
86 + );
87 + asyncModuleCache.set(metadata.specifier, modulePromise);
88 + return modulePromise;
89 + }
90 +}
91 +
92 +export function requireModule<T>(metadata: ClientReference<T>): T {
93 + let moduleExports;
94 + // We assume that preloadModule has been called before, which
95 + // should have added something to the module cache.
96 + const promise: any = asyncModuleCache.get(metadata.specifier);
97 + if (promise.status === 'fulfilled') {
98 + moduleExports = promise.value;
99 + } else {
100 + throw promise.reason;
101 + }
102 + return moduleExports[metadata.name];
103 +}
packages/react-server-dom-esm/src/ReactFlightDOMClientBrowser.js new
+110
@@ -0,0 +1,110 @@
1 +/**
2 + * Copyright (c) Meta Platforms, Inc. and affiliates.
3 + *
4 + * This source code is licensed under the MIT license found in the
5 + * LICENSE file in the root directory of this source tree.
6 + *
7 + * @flow
8 + */
9 +
10 +import type {Thenable} from 'shared/ReactTypes.js';
11 +
12 +import type {Response as FlightResponse} from 'react-client/src/ReactFlightClient';
13 +
14 +import type {ReactServerValue} from 'react-client/src/ReactFlightReplyClient';
15 +
16 +import {
17 + createResponse,
18 + getRoot,
19 + reportGlobalError,
20 + processBinaryChunk,
21 + close,
22 +} from 'react-client/src/ReactFlightClient';
23 +
24 +import {
25 + processReply,
26 + createServerReference,
27 +} from 'react-client/src/ReactFlightReplyClient';
28 +
29 +type CallServerCallback = <A, T>(string, args: A) => Promise<T>;
30 +
31 +export type Options = {
32 + moduleBaseURL?: string,
33 + callServer?: CallServerCallback,
34 +};
35 +
36 +function createResponseFromOptions(options: void | Options) {
37 + return createResponse(
38 + options && options.moduleBaseURL ? options.moduleBaseURL : '',
39 + options && options.callServer ? options.callServer : undefined,
40 + );
41 +}
42 +
43 +function startReadingFromStream(
44 + response: FlightResponse,
45 + stream: ReadableStream,
46 +): void {
47 + const reader = stream.getReader();
48 + function progress({
49 + done,
50 + value,
51 + }: {
52 + done: boolean,
53 + value: ?any,
54 + ...
55 + }): void | Promise<void> {
56 + if (done) {
57 + close(response);
58 + return;
59 + }
60 + const buffer: Uint8Array = (value: any);
61 + processBinaryChunk(response, buffer);
62 + return reader.read().then(progress).catch(error);
63 + }
64 + function error(e: any) {
65 + reportGlobalError(response, e);
66 + }
67 + reader.read().then(progress).catch(error);
68 +}
69 +
70 +function createFromReadableStream<T>(
71 + stream: ReadableStream,
72 + options?: Options,
73 +): Thenable<T> {
74 + const response: FlightResponse = createResponseFromOptions(options);
75 + startReadingFromStream(response, stream);
76 + return getRoot(response);
77 +}
78 +
79 +function createFromFetch<T>(
80 + promiseForResponse: Promise<Response>,
81 + options?: Options,
82 +): Thenable<T> {
83 + const response: FlightResponse = createResponseFromOptions(options);
84 + promiseForResponse.then(
85 + function (r) {
86 + startReadingFromStream(response, (r.body: any));
87 + },
88 + function (e) {
89 + reportGlobalError(response, e);
90 + },
91 + );
92 + return getRoot(response);
93 +}
94 +
95 +function encodeReply(
96 + value: ReactServerValue,
97 +): Promise<
98 + string | URLSearchParams | FormData,
99 +> /* We don't use URLSearchParams yet but maybe */ {
100 + return new Promise((resolve, reject) => {
101 + processReply(value, '', resolve, reject);
102 + });
103 +}
104 +
105 +export {
106 + createFromFetch,
107 + createFromReadableStream,
108 + encodeReply,
109 + createServerReference,
110 +};
packages/react-server-dom-esm/src/ReactFlightDOMClientNode.js new
+60
@@ -0,0 +1,60 @@
1 +/**
2 + * Copyright (c) Meta Platforms, Inc. and affiliates.
3 + *
4 + * This source code is licensed under the MIT license found in the
5 + * LICENSE file in the root directory of this source tree.
6 + *
7 + * @flow
8 + */
9 +
10 +import type {Thenable} from 'shared/ReactTypes.js';
11 +
12 +import type {Response} from 'react-client/src/ReactFlightClient';
13 +
14 +import type {Readable} from 'stream';
15 +
16 +import {
17 + createResponse,
18 + getRoot,
19 + reportGlobalError,
20 + processBinaryChunk,
21 + close,
22 +} from 'react-client/src/ReactFlightClient';
23 +import {processStringChunk} from '../../react-client/src/ReactFlightClient';
24 +
25 +function noServerCall() {
26 + throw new Error(
27 + 'Server Functions cannot be called during initial render. ' +
28 + 'This would create a fetch waterfall. Try to use a Server Component ' +
29 + 'to pass data to Client Components instead.',
30 + );
31 +}
32 +
33 +export function createServerReference<A: Iterable<any>, T>(
34 + id: any,
35 + callServer: any,
36 +): (...A) => Promise<T> {
37 + return noServerCall;
38 +}
39 +
40 +function createFromNodeStream<T>(
41 + stream: Readable,
42 + moduleRootPath: string,
43 + moduleBaseURL: string, // TODO: Used for preloading hints
44 +): Thenable<T> {
45 + const response: Response = createResponse(moduleRootPath, noServerCall);
46 + stream.on('data', chunk => {
47 + if (typeof chunk === 'string') {
48 + processStringChunk(response, chunk, 0);
49 + } else {
50 + processBinaryChunk(response, chunk);
51 + }
52 + });
53 + stream.on('error', error => {
54 + reportGlobalError(response, error);
55 + });
56 + stream.on('end', () => close(response));
57 + return getRoot(response);
58 +}
59 +
60 +export {createFromNodeStream};
packages/react-server-dom-esm/src/ReactFlightDOMServerNode.js new
+158
@@ -0,0 +1,158 @@
1 +/**
2 + * Copyright (c) Meta Platforms, Inc. and affiliates.
3 + *
4 + * This source code is licensed under the MIT license found in the
5 + * LICENSE file in the root directory of this source tree.
6 + *
7 + * @flow
8 + */
9 +
10 +import type {
11 + Request,
12 + ReactClientValue,
13 +} from 'react-server/src/ReactFlightServer';
14 +import type {Destination} from 'react-server/src/ReactServerStreamConfigNode';
15 +import type {ClientManifest} from './ReactFlightServerConfigESMBundler';
16 +import type {ServerManifest} from 'react-client/src/ReactFlightClientConfig';
17 +import type {Busboy} from 'busboy';
18 +import type {Writable} from 'stream';
19 +import type {ServerContextJSONValue, Thenable} from 'shared/ReactTypes';
20 +
21 +import {
22 + createRequest,
23 + startWork,
24 + startFlowing,
25 + abort,
26 +} from 'react-server/src/ReactFlightServer';
27 +
28 +import {
29 + createResponse,
30 + reportGlobalError,
31 + close,
32 + resolveField,
33 + resolveFileInfo,
34 + resolveFileChunk,
35 + resolveFileComplete,
36 + getRoot,
37 +} from 'react-server/src/ReactFlightReplyServer';
38 +
39 +import {decodeAction} from 'react-server/src/ReactFlightActionServer';
40 +
41 +function createDrainHandler(destination: Destination, request: Request) {
42 + return () => startFlowing(request, destination);
43 +}
44 +
45 +type Options = {
46 + onError?: (error: mixed) => void,
47 + context?: Array<[string, ServerContextJSONValue]>,
48 + identifierPrefix?: string,
49 +};
50 +
51 +type PipeableStream = {
52 + abort(reason: mixed): void,
53 + pipe<T: Writable>(destination: T): T,
54 +};
55 +
56 +function renderToPipeableStream(
57 + model: ReactClientValue,
58 + moduleBasePath: ClientManifest,
59 + options?: Options,
60 +): PipeableStream {
61 + const request = createRequest(
62 + model,
63 + moduleBasePath,
64 + options ? options.onError : undefined,
65 + options ? options.context : undefined,
66 + options ? options.identifierPrefix : undefined,
67 + );
68 + let hasStartedFlowing = false;
69 + startWork(request);
70 + return {
71 + pipe<T: Writable>(destination: T): T {
72 + if (hasStartedFlowing) {
73 + throw new Error(
74 + 'React currently only supports piping to one writable stream.',
75 + );
76 + }
77 + hasStartedFlowing = true;
78 + startFlowing(request, destination);
79 + destination.on('drain', createDrainHandler(destination, request));
80 + return destination;
81 + },
82 + abort(reason: mixed) {
83 + abort(request, reason);
84 + },
85 + };
86 +}
87 +
88 +function decodeReplyFromBusboy<T>(
89 + busboyStream: Busboy,
90 + moduleBasePath: ServerManifest,
91 +): Thenable<T> {
92 + const response = createResponse(moduleBasePath, '');
93 + let pendingFiles = 0;
94 + const queuedFields: Array<string> = [];
95 + busboyStream.on('field', (name, value) => {
96 + if (pendingFiles > 0) {
97 + // Because the 'end' event fires two microtasks after the next 'field'
98 + // we would resolve files and fields out of order. To handle this properly
99 + // we queue any fields we receive until the previous file is done.
100 + queuedFields.push(name, value);
101 + } else {
102 + resolveField(response, name, value);
103 + }
104 + });
105 + busboyStream.on('file', (name, value, {filename, encoding, mimeType}) => {
106 + if (encoding.toLowerCase() === 'base64') {
107 + throw new Error(
108 + "React doesn't accept base64 encoded file uploads because we don't expect " +
109 + "form data passed from a browser to ever encode data that way. If that's " +
110 + 'the wrong assumption, we can easily fix it.',
111 + );
112 + }
113 + pendingFiles++;
114 + const file = resolveFileInfo(response, name, filename, mimeType);
115 + value.on('data', chunk => {
116 + resolveFileChunk(response, file, chunk);
117 + });
118 + value.on('end', () => {
119 + resolveFileComplete(response, name, file);
120 + pendingFiles--;
121 + if (pendingFiles === 0) {
122 + // Release any queued fields
123 + for (let i = 0; i < queuedFields.length; i += 2) {
124 + resolveField(response, queuedFields[i], queuedFields[i + 1]);
125 + }
126 + queuedFields.length = 0;
127 + }
128 + });
129 + });
130 + busboyStream.on('finish', () => {
131 + close(response);
132 + });
133 + busboyStream.on('error', err => {
134 + reportGlobalError(response, err);
135 + });
136 + return getRoot(response);
137 +}
138 +
139 +function decodeReply<T>(
140 + body: string | FormData,
141 + moduleBasePath: ServerManifest,
142 +): Thenable<T> {
143 + if (typeof body === 'string') {
144 + const form = new FormData();
145 + form.append('0', body);
146 + body = form;
147 + }
148 + const response = createResponse(moduleBasePath, '', body);
149 + close(response);
150 + return getRoot(response);
151 +}
152 +
153 +export {
154 + renderToPipeableStream,
155 + decodeReplyFromBusboy,
156 + decodeReply,
157 + decodeAction,
158 +};
packages/react-server-dom-esm/src/ReactFlightESMNodeLoader.js new
+478
@@ -0,0 +1,478 @@
1 +/**
2 + * Copyright (c) Meta Platforms, Inc. and affiliates.
3 + *
4 + * This source code is licensed under the MIT license found in the
5 + * LICENSE file in the root directory of this source tree.
6 + *
7 + * @flow
8 + */
9 +
10 +import * as acorn from 'acorn-loose';
11 +
12 +type ResolveContext = {
13 + conditions: Array<string>,
14 + parentURL: string | void,
15 +};
16 +
17 +type ResolveFunction = (
18 + string,
19 + ResolveContext,
20 + ResolveFunction,
21 +) => {url: string} | Promise<{url: string}>;
22 +
23 +type GetSourceContext = {
24 + format: string,
25 +};
26 +
27 +type GetSourceFunction = (
28 + string,
29 + GetSourceContext,
30 + GetSourceFunction,
31 +) => Promise<{source: Source}>;
32 +
33 +type TransformSourceContext = {
34 + format: string,
35 + url: string,
36 +};
37 +
38 +type TransformSourceFunction = (
39 + Source,
40 + TransformSourceContext,
41 + TransformSourceFunction,
42 +) => Promise<{source: Source}>;
43 +
44 +type LoadContext = {
45 + conditions: Array<string>,
46 + format: string | null | void,
47 + importAssertions: Object,
48 +};
49 +
50 +type LoadFunction = (
51 + string,
52 + LoadContext,
53 + LoadFunction,
54 +) => Promise<{format: string, shortCircuit?: boolean, source: Source}>;
55 +
56 +type Source = string | ArrayBuffer | Uint8Array;
57 +
58 +let warnedAboutConditionsFlag = false;
59 +
60 +let stashedGetSource: null | GetSourceFunction = null;
61 +let stashedResolve: null | ResolveFunction = null;
62 +
63 +export async function resolve(
64 + specifier: string,
65 + context: ResolveContext,
66 + defaultResolve: ResolveFunction,
67 +): Promise<{url: string}> {
68 + // We stash this in case we end up needing to resolve export * statements later.
69 + stashedResolve = defaultResolve;
70 +
71 + if (!context.conditions.includes('react-server')) {
72 + context = {
73 + ...context,
74 + conditions: [...context.conditions, 'react-server'],
75 + };
76 + if (!warnedAboutConditionsFlag) {
77 + warnedAboutConditionsFlag = true;
78 + // eslint-disable-next-line react-internal/no-production-logging
79 + console.warn(
80 + 'You did not run Node.js with the `--conditions react-server` flag. ' +
81 + 'Any "react-server" override will only work with ESM imports.',
82 + );
83 + }
84 + }
85 + return await defaultResolve(specifier, context, defaultResolve);
86 +}
87 +
88 +export async function getSource(
89 + url: string,
90 + context: GetSourceContext,
91 + defaultGetSource: GetSourceFunction,
92 +): Promise<{source: Source}> {
93 + // We stash this in case we end up needing to resolve export * statements later.
94 + stashedGetSource = defaultGetSource;
95 + return defaultGetSource(url, context, defaultGetSource);
96 +}
97 +
98 +function addLocalExportedNames(names: Map<string, string>, node: any) {
99 + switch (node.type) {
100 + case 'Identifier':
101 + names.set(node.name, node.name);
102 + return;
103 + case 'ObjectPattern':
104 + for (let i = 0; i < node.properties.length; i++)
105 + addLocalExportedNames(names, node.properties[i]);
106 + return;
107 + case 'ArrayPattern':
108 + for (let i = 0; i < node.elements.length; i++) {
109 + const element = node.elements[i];
110 + if (element) addLocalExportedNames(names, element);
111 + }
112 + return;
113 + case 'Property':
114 + addLocalExportedNames(names, node.value);
115 + return;
116 + case 'AssignmentPattern':
117 + addLocalExportedNames(names, node.left);
118 + return;
119 + case 'RestElement':
120 + addLocalExportedNames(names, node.argument);
121 + return;
122 + case 'ParenthesizedExpression':
123 + addLocalExportedNames(names, node.expression);
124 + return;
125 + }
126 +}
127 +
128 +function transformServerModule(
129 + source: string,
130 + body: any,
131 + url: string,
132 + loader: LoadFunction,
133 +): string {
134 + // If the same local name is exported more than once, we only need one of the names.
135 + const localNames: Map<string, string> = new Map();
136 + const localTypes: Map<string, string> = new Map();
137 +
138 + for (let i = 0; i < body.length; i++) {
139 + const node = body[i];
140 + switch (node.type) {
141 + case 'ExportAllDeclaration':
142 + // If export * is used, the other file needs to explicitly opt into "use server" too.
143 + break;
144 + case 'ExportDefaultDeclaration':
145 + if (node.declaration.type === 'Identifier') {
146 + localNames.set(node.declaration.name, 'default');
147 + } else if (node.declaration.type === 'FunctionDeclaration') {
148 + if (node.declaration.id) {
149 + localNames.set(node.declaration.id.name, 'default');
150 + localTypes.set(node.declaration.id.name, 'function');
151 + } else {
152 + // TODO: This needs to be rewritten inline because it doesn't have a local name.
153 + }
154 + }
155 + continue;
156 + case 'ExportNamedDeclaration':
157 + if (node.declaration) {
158 + if (node.declaration.type === 'VariableDeclaration') {
159 + const declarations = node.declaration.declarations;
160 + for (let j = 0; j < declarations.length; j++) {
161 + addLocalExportedNames(localNames, declarations[j].id);
162 + }
163 + } else {
164 + const name = node.declaration.id.name;
165 + localNames.set(name, name);
166 + if (node.declaration.type === 'FunctionDeclaration') {
167 + localTypes.set(name, 'function');
168 + }
169 + }
170 + }
171 + if (node.specifiers) {
172 + const specifiers = node.specifiers;
173 + for (let j = 0; j < specifiers.length; j++) {
174 + const specifier = specifiers[j];
175 + localNames.set(specifier.local.name, specifier.exported.name);
176 + }
177 + }
178 + continue;
179 + }
180 + }
181 +
182 + let newSrc = source + '\n\n;';
183 + localNames.forEach(function (exported, local) {
184 + if (localTypes.get(local) !== 'function') {
185 + // We first check if the export is a function and if so annotate it.
186 + newSrc += 'if (typeof ' + local + ' === "function") ';
187 + }
188 + newSrc += 'Object.defineProperties(' + local + ',{';
189 + newSrc += '$$typeof: {value: Symbol.for("react.server.reference")},';
190 + newSrc += '$$id: {value: ' + JSON.stringify(url + '#' + exported) + '},';
191 + newSrc += '$$bound: { value: null }';
192 + newSrc += '});\n';
193 + });
194 + return newSrc;
195 +}
196 +
197 +function addExportNames(names: Array<string>, node: any) {
198 + switch (node.type) {
199 + case 'Identifier':
200 + names.push(node.name);
201 + return;
202 + case 'ObjectPattern':
203 + for (let i = 0; i < node.properties.length; i++)
204 + addExportNames(names, node.properties[i]);
205 + return;
206 + case 'ArrayPattern':
207 + for (let i = 0; i < node.elements.length; i++) {
208 + const element = node.elements[i];
209 + if (element) addExportNames(names, element);
210 + }
211 + return;
212 + case 'Property':
213 + addExportNames(names, node.value);
214 + return;
215 + case 'AssignmentPattern':
216 + addExportNames(names, node.left);
217 + return;
218 + case 'RestElement':
219 + addExportNames(names, node.argument);
220 + return;
221 + case 'ParenthesizedExpression':
222 + addExportNames(names, node.expression);
223 + return;
224 + }
225 +}
226 +
227 +function resolveClientImport(
228 + specifier: string,
229 + parentURL: string,
230 +): {url: string} | Promise<{url: string}> {
231 + // Resolve an import specifier as if it was loaded by the client. This doesn't use
232 + // the overrides that this loader does but instead reverts to the default.
233 + // This resolution algorithm will not necessarily have the same configuration
234 + // as the actual client loader. It should mostly work and if it doesn't you can
235 + // always convert to explicit exported names instead.
236 + const conditions = ['node', 'import'];
237 + if (stashedResolve === null) {
238 + throw new Error(
239 + 'Expected resolve to have been called before transformSource',
240 + );
241 + }
242 + return stashedResolve(specifier, {conditions, parentURL}, stashedResolve);
243 +}
244 +
245 +async function parseExportNamesInto(
246 + body: any,
247 + names: Array<string>,
248 + parentURL: string,
249 + loader: LoadFunction,
250 +): Promise<void> {
251 + for (let i = 0; i < body.length; i++) {
252 + const node = body[i];
253 + switch (node.type) {
254 + case 'ExportAllDeclaration':
255 + if (node.exported) {
256 + addExportNames(names, node.exported);
257 + continue;
258 + } else {
259 + const {url} = await resolveClientImport(node.source.value, parentURL);
260 + const {source} = await loader(
261 + url,
262 + {format: 'module', conditions: [], importAssertions: {}},
263 + loader,
264 + );
265 + if (typeof source !== 'string') {
266 + throw new Error('Expected the transformed source to be a string.');
267 + }
268 + let childBody;
269 + try {
270 + childBody = acorn.parse(source, {
271 + ecmaVersion: '2024',
272 + sourceType: 'module',
273 + }).body;
274 + } catch (x) {
275 + // eslint-disable-next-line react-internal/no-production-logging
276 + console.error('Error parsing %s %s', url, x.message);
277 + continue;
278 + }
279 + await parseExportNamesInto(childBody, names, url, loader);
280 + continue;
281 + }
282 + case 'ExportDefaultDeclaration':
283 + names.push('default');
284 + continue;
285 + case 'ExportNamedDeclaration':
286 + if (node.declaration) {
287 + if (node.declaration.type === 'VariableDeclaration') {
288 + const declarations = node.declaration.declarations;
289 + for (let j = 0; j < declarations.length; j++) {
290 + addExportNames(names, declarations[j].id);
291 + }
292 + } else {
293 + addExportNames(names, node.declaration.id);
294 + }
295 + }
296 + if (node.specifiers) {
297 + const specifiers = node.specifiers;
298 + for (let j = 0; j < specifiers.length; j++) {
299 + addExportNames(names, specifiers[j].exported);
300 + }
301 + }
302 + continue;
303 + }
304 + }
305 +}
306 +
307 +async function transformClientModule(
308 + body: any,
309 + url: string,
310 + loader: LoadFunction,
311 +): Promise<string> {
312 + const names: Array<string> = [];
313 +
314 + await parseExportNamesInto(body, names, url, loader);
315 +
316 + let newSrc =
317 + "const CLIENT_REFERENCE = Symbol.for('react.client.reference');\n";
318 + for (let i = 0; i < names.length; i++) {
319 + const name = names[i];
320 + if (name === 'default') {
321 + newSrc += 'export default ';
322 + newSrc += 'Object.defineProperties(function() {';
323 + newSrc +=
324 + 'throw new Error(' +
325 + JSON.stringify(
326 + `Attempted to call the default export of ${url} from the server` +
327 + `but it's on the client. It's not possible to invoke a client function from ` +
328 + `the server, it can only be rendered as a Component or passed to props of a` +
329 + `Client Component.`,
330 + ) +
331 + ');';
332 + } else {
333 + newSrc += 'export const ' + name + ' = ';
334 + newSrc += 'Object.defineProperties(function() {';
335 + newSrc +=
336 + 'throw new Error(' +
337 + JSON.stringify(
338 + `Attempted to call ${name}() from the server but ${name} is on the client. ` +
339 + `It's not possible to invoke a client function from the server, it can ` +
340 + `only be rendered as a Component or passed to props of a Client Component.`,
341 + ) +
342 + ');';
343 + }
344 + newSrc += '},{';
345 + newSrc += '$$typeof: {value: CLIENT_REFERENCE},';
346 + newSrc += '$$id: {value: ' + JSON.stringify(url + '#' + name) + '}';
347 + newSrc += '});\n';
348 + }
349 + return newSrc;
350 +}
351 +
352 +async function loadClientImport(
353 + url: string,
354 + defaultTransformSource: TransformSourceFunction,
355 +): Promise<{format: string, shortCircuit?: boolean, source: Source}> {
356 + if (stashedGetSource === null) {
357 + throw new Error(
358 + 'Expected getSource to have been called before transformSource',
359 + );
360 + }
361 + // TODO: Validate that this is another module by calling getFormat.
362 + const {source} = await stashedGetSource(
363 + url,
364 + {format: 'module'},
365 + stashedGetSource,
366 + );
367 + const result = await defaultTransformSource(
368 + source,
369 + {format: 'module', url},
370 + defaultTransformSource,
371 + );
372 + return {format: 'module', source: result.source};
373 +}
374 +
375 +async function transformModuleIfNeeded(
376 + source: string,
377 + url: string,
378 + loader: LoadFunction,
379 +): Promise<string> {
380 + // Do a quick check for the exact string. If it doesn't exist, don't
381 + // bother parsing.
382 + if (
383 + source.indexOf('use client') === -1 &&
384 + source.indexOf('use server') === -1
385 + ) {
386 + return source;
387 + }
388 +
389 + let body;
390 + try {
391 + body = acorn.parse(source, {
392 + ecmaVersion: '2024',
393 + sourceType: 'module',
394 + }).body;
395 + } catch (x) {
396 + // eslint-disable-next-line react-internal/no-production-logging
397 + console.error('Error parsing %s %s', url, x.message);
398 + return source;
399 + }
400 +
401 + let useClient = false;
402 + let useServer = false;
403 + for (let i = 0; i < body.length; i++) {
404 + const node = body[i];
405 + if (node.type !== 'ExpressionStatement' || !node.directive) {
406 + break;
407 + }
408 + if (node.directive === 'use client') {
409 + useClient = true;
410 + }
411 + if (node.directive === 'use server') {
412 + useServer = true;
413 + }
414 + }
415 +
416 + if (!useClient && !useServer) {
417 + return source;
418 + }
419 +
420 + if (useClient && useServer) {
421 + throw new Error(
422 + 'Cannot have both "use client" and "use server" directives in the same file.',
423 + );
424 + }
425 +
426 + if (useClient) {
427 + return transformClientModule(body, url, loader);
428 + }
429 +
430 + return transformServerModule(source, body, url, loader);
431 +}
432 +
433 +export async function transformSource(
434 + source: Source,
435 + context: TransformSourceContext,
436 + defaultTransformSource: TransformSourceFunction,
437 +): Promise<{source: Source}> {
438 + const transformed = await defaultTransformSource(
439 + source,
440 + context,
441 + defaultTransformSource,
442 + );
443 + if (context.format === 'module') {
444 + const transformedSource = transformed.source;
445 + if (typeof transformedSource !== 'string') {
446 + throw new Error('Expected source to have been transformed to a string.');
447 + }
448 + const newSrc = await transformModuleIfNeeded(
449 + transformedSource,
450 + context.url,
451 + (url: string, ctx: LoadContext, defaultLoad: LoadFunction) => {
452 + return loadClientImport(url, defaultTransformSource);
453 + },
454 + );
455 + return {source: newSrc};
456 + }
457 + return transformed;
458 +}
459 +
460 +export async function load(
461 + url: string,
462 + context: LoadContext,
463 + defaultLoad: LoadFunction,
464 +): Promise<{format: string, shortCircuit?: boolean, source: Source}> {
465 + const result = await defaultLoad(url, context, defaultLoad);
466 + if (result.format === 'module') {
467 + if (typeof result.source !== 'string') {
468 + throw new Error('Expected source to have been loaded into a string.');
469 + }
470 + const newSrc = await transformModuleIfNeeded(
471 + result.source,
472 + url,
473 + defaultLoad,
474 + );
475 + return {format: 'module', source: newSrc};
476 + }
477 + return result;
478 +}
packages/react-server-dom-esm/src/ReactFlightServerConfigESMBundler.js new
+83
@@ -0,0 +1,83 @@
1 +/**
2 + * Copyright (c) Meta Platforms, Inc. and affiliates.
3 + *
4 + * This source code is licensed under the MIT license found in the
5 + * LICENSE file in the root directory of this source tree.
6 + *
7 + * @flow
8 + */
9 +
10 +import type {ReactClientValue} from 'react-server/src/ReactFlightServer';
11 +
12 +export type ClientManifest = string; // base URL on the file system
13 +
14 +export type ServerReference<T: Function> = T & {
15 + $$typeof: symbol,
16 + $$id: string,
17 + $$bound: null | Array<ReactClientValue>,
18 +};
19 +
20 +export type ServerReferenceId = string;
21 +
22 +// eslint-disable-next-line no-unused-vars
23 +export type ClientReference<T> = {
24 + $$typeof: symbol,
25 + $$id: string,
26 +};
27 +
28 +export type ClientReferenceMetadata = [
29 + string, // module path
30 + string, // export name
31 +];
32 +
33 +export type ClientReferenceKey = string;
34 +
35 +const CLIENT_REFERENCE_TAG = Symbol.for('react.client.reference');
36 +const SERVER_REFERENCE_TAG = Symbol.for('react.server.reference');
37 +
38 +export function getClientReferenceKey(
39 + reference: ClientReference<any>,
40 +): ClientReferenceKey {
41 + return reference.$$id;
42 +}
43 +
44 +export function isClientReference(reference: Object): boolean {
45 + return reference.$$typeof === CLIENT_REFERENCE_TAG;
46 +}
47 +
48 +export function isServerReference(reference: Object): boolean {
49 + return reference.$$typeof === SERVER_REFERENCE_TAG;
50 +}
51 +
52 +export function resolveClientReferenceMetadata<T>(
53 + config: ClientManifest,
54 + clientReference: ClientReference<T>,
55 +): ClientReferenceMetadata {
56 + const baseURL: string = config;
57 + const id = clientReference.$$id;
58 + const idx = id.lastIndexOf('#');
59 + const exportName = id.slice(idx + 1);
60 + const fullURL = id.slice(0, idx);
61 + if (!fullURL.startsWith(baseURL)) {
62 + throw new Error(
63 + 'Attempted to load a Client Module outside the hosted root.',
64 + );
65 + }
66 + // Relative URL
67 + const modulePath = fullURL.slice(baseURL.length);
68 + return [modulePath, exportName];
69 +}
70 +
71 +export function getServerReferenceId<T>(
72 + config: ClientManifest,
73 + serverReference: ServerReference<T>,
74 +): ServerReferenceId {
75 + return serverReference.$$id;
76 +}
77 +
78 +export function getServerReferenceBoundArguments<T>(
79 + config: ClientManifest,
80 + serverReference: ServerReference<T>,
81 +): null | Array<ReactClientValue> {
82 + return serverReference.$$bound;
83 +}
packages/react-server/src/forks/ReactFizzConfig.dom-node-esm.js new
+17
@@ -0,0 +1,17 @@
1 +/**
2 + * Copyright (c) Meta Platforms, Inc. and affiliates.
3 + *
4 + * This source code is licensed under the MIT license found in the
5 + * LICENSE file in the root directory of this source tree.
6 + *
7 + * @flow
8 + */
9 +import {AsyncLocalStorage} from 'async_hooks';
10 +
11 +import type {Request} from 'react-server/src/ReactFizzServer';
12 +
13 +export * from 'react-dom-bindings/src/server/ReactFizzConfigDOM';
14 +
15 +export const supportsRequestStorage = true;
16 +export const requestStorage: AsyncLocalStorage<Request> =
17 + new AsyncLocalStorage();
packages/react-server/src/forks/ReactFlightServerConfig.dom-node-esm.js new
+18
@@ -0,0 +1,18 @@
1 +/**
2 + * Copyright (c) Meta Platforms, Inc. and affiliates.
3 + *
4 + * This source code is licensed under the MIT license found in the
5 + * LICENSE file in the root directory of this source tree.
6 + *
7 + * @flow
8 + */
9 +import {AsyncLocalStorage} from 'async_hooks';
10 +
11 +import type {Request} from 'react-server/src/ReactFlightServer';
12 +
13 +export * from 'react-server-dom-esm/src/ReactFlightServerConfigESMBundler';
14 +export * from 'react-dom-bindings/src/server/ReactFlightServerConfigDOM';
15 +
16 +export const supportsRequestStorage = true;
17 +export const requestStorage: AsyncLocalStorage<Request> =
18 + new AsyncLocalStorage();
packages/react-server/src/forks/ReactServerStreamConfig.dom-node-esm.js new
+10
@@ -0,0 +1,10 @@
1 +/**
2 + * Copyright (c) Meta Platforms, Inc. and affiliates.
3 + *
4 + * This source code is licensed under the MIT license found in the
5 + * LICENSE file in the root directory of this source tree.
6 + *
7 + * @flow
8 + */
9 +
10 +export * from '../ReactServerStreamConfigNode';
scripts/rollup/bundles.js
+39
@@ -450,6 +450,45 @@ const bundles = [
450 externals: ['url', 'module'],
451 },
452
453 + /******* React Server DOM ESM Server *******/
454 + {
455 + bundleTypes: [NODE_DEV, NODE_PROD],
456 + moduleType: RENDERER,
457 + entry: 'react-server-dom-esm/server.node',
458 + minifyWithProdErrorCodes: false,
459 + wrapWithModuleBoundaries: false,
460 + externals: ['react', 'util', 'async_hooks', 'react-dom'],
461 + },
462 +
463 + /******* React Server DOM ESM Client *******/
464 + {
465 + bundleTypes: [NODE_DEV, NODE_PROD, ESM_DEV, ESM_PROD],
466 + moduleType: RENDERER,
467 + entry: 'react-server-dom-esm/client.browser',
468 + minifyWithProdErrorCodes: false,
469 + wrapWithModuleBoundaries: false,
470 + externals: ['react', 'react-dom'],
471 + },
472 + {
473 + bundleTypes: [NODE_DEV, NODE_PROD],
474 + moduleType: RENDERER,
475 + entry: 'react-server-dom-esm/client.node',
476 + minifyWithProdErrorCodes: false,
477 + wrapWithModuleBoundaries: false,
478 + externals: ['react', 'react-dom', 'util'],
479 + },
480 +
481 + /******* React Server DOM ESM Node.js Loader *******/
482 + {
483 + bundleTypes: [ESM_PROD],
484 + moduleType: RENDERER_UTILS,
485 + entry: 'react-server-dom-esm/node-loader',
486 + global: 'ReactServerESMNodeLoader',
487 + minifyWithProdErrorCodes: false,
488 + wrapWithModuleBoundaries: false,
489 + externals: ['acorn'],
490 + },
491 +
492 /******* React Suspense Test Utils *******/
493 {
494 bundleTypes: [NODE_ES2015],
scripts/shared/inlinedHostConfigs.js
+33
@@ -155,6 +155,39 @@ module.exports = [
155 isFlowTyped: true,
156 isServerSupported: true,
157 },
158 + {
159 + shortName: 'dom-node-esm',
160 + entryPoints: [
161 + 'react-server-dom-esm/client.browser',
162 + 'react-server-dom-esm/server.node',
163 + 'react-server-dom-esm/client.node',
164 + ],
165 + paths: [
166 + 'react-dom',
167 + 'react-dom-bindings',
168 + 'react-dom/client',
169 + 'react-dom/server',
170 + 'react-dom/server.node',
171 + 'react-dom/static',
172 + 'react-dom/static.node',
173 + 'react-dom/src/server/ReactDOMFizzServerNode.js', // react-dom/server.node
174 + 'react-dom/src/server/ReactDOMFizzStaticNode.js',
175 + 'react-server-dom-esm',
176 + 'react-server-dom-esm/client.browser',
177 + 'react-server-dom-esm/client.node',
178 + 'react-server-dom-esm/server',
179 + 'react-server-dom-esm/server.node',
180 + 'react-server-dom-esm/src/ReactFlightDOMServerNode.js', // react-server-dom-webpack/server.node
181 + 'react-devtools',
182 + 'react-devtools-core',
183 + 'react-devtools-shell',
184 + 'react-devtools-shared',
185 + 'react-interactions',
186 + 'shared/ReactDOMSharedInternals',
187 + ],
188 + isFlowTyped: true,
189 + isServerSupported: true,
190 + },
191 {
192 shortName: 'dom-legacy',
193 entryPoints: [