diff --git a/.changesets/10064.md b/.changesets/10064.md index 785c49a2ec24..286624f3e066 100644 --- a/.changesets/10064.md +++ b/.changesets/10064.md @@ -1,7 +1,8 @@ - Add Storybook (Vite) framework package (#10064) by @arimendelow Adds: + - Storybook framework package for using Storybook with Vite. - CLI package (command: `yarn rw sbv`) for running Storybook using Vite. CLI package additionally creates Mock Service Worker, and, on first run, the project-side Storybook config files. -Current Storybook (Webpack) users will need to manually migrate any additional Storybook config (mocks, etc.). The primary user-facing difference between the old and new Storybook integrations is that the config used by the old one lives in the `@redwoodjs/testing` package, and the config used by this new one lives in the user's `web/.storybook` directory. \ No newline at end of file +Current Storybook (Webpack) users will need to manually migrate any additional Storybook config (mocks, etc.). The primary user-facing difference between the old and new Storybook integrations is that the config used by the old one lives in the `@redwoodjs/testing` package, and the config used by this new one lives in the user's `web/.storybook` directory. diff --git a/.changesets/10179.md b/.changesets/10179.md index 6cae15af6c5f..ffd8f9b7aaa7 100644 --- a/.changesets/10179.md +++ b/.changesets/10179.md @@ -5,7 +5,7 @@ This PR upgrades Redwood internally to Prettier v3. We believe this won't have a If you have Tailwind CSS configured, can upgrade `prettier-plugin-tailwindcss` to a version later than `0.4.1` if you make a few changes: - Change `prettier.config.js` to `prettier.config.mjs` (js -> mjs) -- `export default` instead of `module.exports` +- `export default` instead of `module.exports` - `await import('...')` any plugins instead of `require('...')` Here's an example of an updated `prettier.config.mjs` to work with `prettier-plugin-tailwindcss@^0.5.12`: diff --git a/.changesets/10266.md b/.changesets/10266.md index 1201549dc6bd..5556caf2e2f6 100644 --- a/.changesets/10266.md +++ b/.changesets/10266.md @@ -1,6 +1,5 @@ - chore(linting): Update versions and avoid `{}` (#10266) by @Josh-Walker-GM -This PR updates the versions of the `eslint` and the `@typescript-eslint` packages from v5 to v7. +This PR updates the versions of the `eslint` and the `@typescript-eslint` packages from v5 to v7. This is a major upgrade of the `@typescript-eslint` package and although we think it is unlikely to introduce a breaking change for you we would recommend that you read the associated documentation. The v6 upgrade can be found [here](https://typescript-eslint.io/blog/announcing-typescript-eslint-v6/) and the v7 one [here](https://typescript-eslint.io/blog/announcing-typescript-eslint-v7/). - diff --git a/.changesets/10342.md b/.changesets/10342.md index 9a2dffd923f2..5179cd5e797e 100644 --- a/.changesets/10342.md +++ b/.changesets/10342.md @@ -23,7 +23,6 @@ The `` above would get the following classes if it was the active link That same `` now only gets the `activeClassName` classes `active inline-block rounded-t-lg border-b-2 border-blue-600 p-4 text-blue-600 dark:border-blue-500 dark:text-blue-500` - ## Breaking If you were relying on the merging behavior you will now have to copy all classes from `className` and also include them in `activeClassName`. diff --git a/.changesets/10344.md b/.changesets/10344.md index bd41152c0142..277035ccfdb0 100644 --- a/.changesets/10344.md +++ b/.changesets/10344.md @@ -5,6 +5,7 @@ Add intellisense and color support for not only `className` (which is enabled by ## Manual Instructions If you already have TW set up and want to enable this, open `.vscode/settings.json` and add this: + ```json "tailwindCSS": { "classAttributes": ["class", "className", "activeClassName", "errorClassName"] diff --git a/.changesets/10395.md b/.changesets/10395.md index 4b0bbaf2ffd7..fbb0c98be5a3 100644 --- a/.changesets/10395.md +++ b/.changesets/10395.md @@ -1,22 +1,24 @@ - Middleware Routing & `registerMiddleware` (#10395) by @dac09 -Implements the new syntax of using Middleware after discussion. This sets us up for doing Auth better, but also for implementations like OG Image generation. +Implements the new syntax of using Middleware after discussion. This sets us up for doing Auth better, but also for implementations like OG Image generation. ```js export const registerMiddleware = async () => { - return [ - dbAuthMiddleware(), - [new OgMiddleware({ rootFilename: 'index' }), [ '/:route.:extension']] - ] + return [ + dbAuthMiddleware(), + [new OgMiddleware({ rootFilename: 'index' }), ['/:route.:extension']], + ] } ``` **Features** + - [x] Registering middleware with above syntax - [x] Chaining multiple middleware by passing array of middleware, or tuples - [x] Defining the route patterns to match in the find-my-way syntax ---- +--- + **What syntax are you using for the route patterns?** After discussion that Regexes are slow and unwieldy, I did some research and comparisons here: https://www.notion.so/redwoodjs/Middleware-Route-patterns-0f1c5587b4134073adfae896a782b5ea?pvs= @@ -24,11 +26,13 @@ This implementation uses https://github.com/delvedor/find-my-way - which is the **Important for understanding** Quoting from find-my-way docs: + > The nodes are matched in the following order: + static parametric node with static ending parametric(regex)/multi-parametric parametric wildcard -Which means, if you have a more specific one - example you have `[mw1, `*`]` and `[mw2, '/refresh_auth']` - then a request to /refresh_auth will ONLY trigger mw2. This is sort of counter intuitive, but them are the rules with fmw. +Which means, if you have a more specific one - example you have `[mw1, `\*`]` and `[mw2, '/refresh_auth']` - then a request to /refresh_auth will ONLY trigger mw2. This is sort of counter intuitive, but them are the rules with fmw. diff --git a/.changesets/10420.md b/.changesets/10420.md index 58c60cddc8c1..75481c745124 100644 --- a/.changesets/10420.md +++ b/.changesets/10420.md @@ -1,4 +1,4 @@ -- feat: [Auth] Common AuthProvider & use* changes for middleware auth #10420 by @dac09 and @dthyresson +- feat: [Auth] Common AuthProvider & use\* changes for middleware auth #10420 by @dac09 and @dthyresson * First step of supporting Auth using middleware * Ensure backwards compatibility with non-SSR auth @@ -6,7 +6,3 @@ ### Breaking Change Removes `skipFetchCurrentUser` which was used by the no longer existing nHost auth provider, but could potentially have been used by custom auth. - - - - diff --git a/.changesets/10441.md b/.changesets/10441.md index de04d1ae4272..66869280a58c 100644 --- a/.changesets/10441.md +++ b/.changesets/10441.md @@ -1,10 +1,10 @@ - feat(og-gen): Update implementation of useLocation | Update App template (#10441) by @dac09 -**Updated App.tsx template** -We modified the `App.tsx` template to accept possible children, and render them if present. This lets the og:image handler inject your component into the Document tree, without including the entire Router, but still style your og:image component using whatever you used to style the rest of your app (Tailwind, perhaps?) + **Updated App.tsx template** + We modified the `App.tsx` template to accept possible children, and render them if present. This lets the og:image handler inject your component into the Document tree, without including the entire Router, but still style your og:image component using whatever you used to style the rest of your app (Tailwind, perhaps?) **Updated useLocation implementation** We also modified the `useLocation()` hook to now return everything that the [URL API](https://developer.mozilla.org/en-US/docs/Web/API/URL) returns. Previously it only returned three attributes of the url (pathname, search, hash), now it returns everything available to a call to `new URL()` (origin, href, searchParams, etc.). The reason for this is now that we have SSR, we can get access to more details in the hook - in this case we needed origin -Both changes should be non-breaking! +Both changes should be non-breaking! diff --git a/.changesets/10444.md b/.changesets/10444.md index eb3f6aee2016..0e13368a17c0 100644 --- a/.changesets/10444.md +++ b/.changesets/10444.md @@ -1,4 +1,5 @@ - feat(server-auth): Part 1/3: dbAuth middleware support (web side changes) (#10444) by @dac09 -Adds ability to `createMiddlewareAuth` in dbAuth client which: + Adds ability to `createMiddlewareAuth` in dbAuth client which: + 1. Updates the dbAuth web client to speak to middleware instead of graphql 2. Implements fetching current user from middleware diff --git a/.changesets/10453.md b/.changesets/10453.md index 42f3da15e1cb..54ff985037dc 100644 --- a/.changesets/10453.md +++ b/.changesets/10453.md @@ -1,5 +1,5 @@ - feat: Remove `--performance` option from `yarn rw build` (#10453) by @Josh-Walker-GM -This change removes the `--performance` flag from the `yarn rw build` command. It will no longer be available to use and the CLI will no longer accept this flag being passed in. +This change removes the `--performance` flag from the `yarn rw build` command. It will no longer be available to use and the CLI will no longer accept this flag being passed in. -Additionally, the associated webpack config (`@redwoodjs/core/config/webpack.perf.js`) has been removed so it can no longer be imported if you were doing so. +Additionally, the associated webpack config (`@redwoodjs/core/config/webpack.perf.js`) has been removed so it can no longer be imported if you were doing so. diff --git a/.changesets/10457.md b/.changesets/10457.md index daa8f21d0e87..4cbf40a10c3a 100644 --- a/.changesets/10457.md +++ b/.changesets/10457.md @@ -1,28 +1,30 @@ -- feat(server-auth): dbAuth 3/3 - handle login, logout, signup, etc. requests if forwarded from middleware (#10457) by @dac09 +- feat(server-auth): dbAuth 3/3 - handle login, logout, signup, etc. requests if forwarded from middleware (#10457) by @dac09 -This PR updates the DbAuthHandler class to handle requests forwarded from middleware, so it can generate responses for login, logout, signup, etc. These are POST requests - it used to be to the `/auth` function, but now they will be captured by dbAuth middleware and forwarded onto DbAuthHandler. +This PR updates the DbAuthHandler class to handle requests forwarded from middleware, so it can generate responses for login, logout, signup, etc. These are POST requests - it used to be to the `/auth` function, but now they will be captured by dbAuth middleware and forwarded onto DbAuthHandler. **High level changes:** + - use the `Headers` class in each of the "method" responses. This allows us to set multi-value headers like Set-Cookie. A simple object would not. See type `AuthMethodOutput` -- extracts `buildResponse` into a testable function and adds test. For `Set-Cookie` headers we return an array of strings. +- extracts `buildResponse` into a testable function and adds test. For `Set-Cookie` headers we return an array of strings. In the middleware here's the code I had for the final conversion: -```ts - if (AUTHHANDLER_REQUEST) { - const output = await dbAuthHandler(req) - const finalHeaders = new Headers() - Object.entries(output.headers).forEach(([key, value]) => { - if (Array.isArray(value)) { - value.forEach((v) => finalHeaders.append(key, v)) - } else { - finalHeaders.append(key, value) - } - }) +```ts +if (AUTHHANDLER_REQUEST) { + const output = await dbAuthHandler(req) - return new MiddlewareResponse(output.body, { - headers: finalHeaders, - status: output.statusCode, - }) + const finalHeaders = new Headers() + Object.entries(output.headers).forEach(([key, value]) => { + if (Array.isArray(value)) { + value.forEach((v) => finalHeaders.append(key, v)) + } else { + finalHeaders.append(key, value) } + }) + + return new MiddlewareResponse(output.body, { + headers: finalHeaders, + status: output.statusCode, + }) +} ``` diff --git a/.changesets/10460.md b/.changesets/10460.md index 19bb349dd502..de8debaa45e3 100644 --- a/.changesets/10460.md +++ b/.changesets/10460.md @@ -1,8 +1,8 @@ - chore(dbauth-mw): Refactor web side dbAuth creation (#10460) by @dac09 -This PR changes how the webside auth is initialised, by removing the `createMiddlewareAuth` function, instead it just detects it internally. +This PR changes how the webside auth is initialised, by removing the `createMiddlewareAuth` function, instead it just detects it internally. -For dbAuth this is what it will looks like: +For dbAuth this is what it will looks like: ```js:web/src/auth.ts import { @@ -23,13 +23,16 @@ export const { AuthProvider, useAuth } = createAuth(dbAuthClient) For other auth providers we are going to export a similar looking function: ```js -import { createAuth, createSupabaseAuthClient } from '@redwoodjs/auth-supabase-web' +import { + createAuth, + createSupabaseAuthClient, +} from '@redwoodjs/auth-supabase-web' // This function is new, and just wraps creating supabase👇 const supabaseClient = createSupabaseAuthClient({ supabaseUrl: process.env.SUPABASE_URL || '', supabaseKey: process.env.SUPABASE_KEY || '', - middleware: true + middleware: true, }) export const { AuthProvider, useAuth } = createAuth(supabaseClient) diff --git a/.changesets/10464.md b/.changesets/10464.md index 5741c801f356..5e4985ea77a8 100644 --- a/.changesets/10464.md +++ b/.changesets/10464.md @@ -4,7 +4,7 @@ We were using both `index.ts` and `router.tsx` as barrel export files. We should This is a breaking change for anyone who does `import ... from '@redwoodjs/router/dist/router'` in their project. Which hopefully isn't very many. - - The quick fix is to find the original export and pull from there instead - - The real fix is to talk to us on the core team and see if we can provide an - official way of solving it instead of relying on internal implementation - details 🙂 +- The quick fix is to find the original export and pull from there instead +- The real fix is to talk to us on the core team and see if we can provide an + official way of solving it instead of relying on internal implementation + details 🙂 diff --git a/.changesets/10465.md b/.changesets/10465.md index 0c667c4d47dd..c5a10d3b5ba2 100644 --- a/.changesets/10465.md +++ b/.changesets/10465.md @@ -2,12 +2,12 @@ **1. Updates `getAuthenticationContext` to parse the cookie header and pass it to authDecoder.** -Note that the authentication context itself does not pull out the token from cookies, because with some providers (e.g. supabase) - we don't know the name of the cookie. This is left to the authDecoder implementation. +Note that the authentication context itself does not pull out the token from cookies, because with some providers (e.g. supabase) - we don't know the name of the cookie. This is left to the authDecoder implementation. -The return type from this function is actually just a deserialized cookie header i.e. +The return type from this function is actually just a deserialized cookie header i.e. `cookie: auth-provider=one; session=xx/yy/zz; somethingElse=bsbs` => `{ 'auth-provider': 'one', session: 'xx/yy/zz', somethingElse: 'bsbs'` -**2. Retains support for header/token based auth** +**2. Retains support for header/token based auth** See test on line 259 of `packages/api/src/auth/__tests__/getAuthenticationContext.test.ts`. If a the `authorization` and `auth-provider` headers are passed in the request (as we do for SPA based auth) - then cookies will take precedence. -The end result is that graphql requests will now work with middleware-based auth providers! +The end result is that graphql requests will now work with middleware-based auth providers! diff --git a/.changesets/10469.md b/.changesets/10469.md index 7b2c8a51ca2b..8bbb2e124e5d 100644 --- a/.changesets/10469.md +++ b/.changesets/10469.md @@ -1,45 +1,49 @@ -- feat(og-gen): Implement middleware and hooks (#10469) by @dac09 +- feat(og-gen): Implement middleware and hooks (#10469) by @dac09 -The OG Gen saga continues with @cannikin and @dac09 ⚔️ +The OG Gen saga continues with @cannikin and @dac09 ⚔️ This PR: + - adds OgImageMiddleware and Hooks to `@redwoodjs/og-gen`, complete with tests ⚠️ Template changes: + - updates entry.client template to pass in Routes to App - updates App to take children (i.e. Routes) This is so that we can pass the OG component to be rendered _with_ your App's CSS setup. - **How to use this?** 1. **Registering the middleware:** - ```ts - import OgImageMiddleware from '@redwoodjs/ogimage-gen/middleware' - export const registerMiddleware = () => { - const ogMw = new OgImageMiddleware({ - App, - Document, - }) + ```ts + import OgImageMiddleware from '@redwoodjs/ogimage-gen/middleware' - return [ogMw] - } - ``` + export const registerMiddleware = () => { + const ogMw = new OgImageMiddleware({ + App, + Document, + }) + + return [ogMw] + } + ``` 2. Configure your `vite.config.ts` - ```ts - import vitePluginOgImageGen from '@redwoodjs/ogimage-gen/plugin' - const viteConfig: UserConfig = { - // 👇 so it builds your OG components - plugins: [redwood(), vitePluginOgImageGen()], - } + ```ts + import vitePluginOgImageGen from '@redwoodjs/ogimage-gen/plugin' + + const viteConfig: UserConfig = { + // 👇 so it builds your OG components + plugins: [redwood(), vitePluginOgImageGen()], + } + + export default defineConfig(viteConfig) + ``` - export default defineConfig(viteConfig) - ``` 3. Add your OG Image component next to the page it's for -e.g. web/src/pages/AboutPage/AboutPage.png.tsx + e.g. web/src/pages/AboutPage/AboutPage.png.tsx 4. Use hooks on AboutPage to generate the ogURL diff --git a/.changesets/10493.md b/.changesets/10493.md index 461695b4b362..15861211dbae 100644 --- a/.changesets/10493.md +++ b/.changesets/10493.md @@ -10,10 +10,9 @@ const myCookie = mwRequest.cookies.get('myCookie') const actualValue = myCookie.value ``` -This is unwieldy, and feels unergonomic for the 98% of cases where `get` will be used to just see the value. +This is unwieldy, and feels unergonomic for the 98% of cases where `get` will be used to just see the value. **How do I still see the options of the cookie?** You can still access all the details of the cookie by doing `cookie.entries`. I don't really have a case for this yet, so let's not optimise for this case, but we know it's possible! - This is me just stabilizing the API for Middleware stuff, before we ship it out of experimental diff --git a/.changesets/10498.md b/.changesets/10498.md index 611d82c6371c..6543f393acda 100644 --- a/.changesets/10498.md +++ b/.changesets/10498.md @@ -6,5 +6,3 @@ This is because the dbauth-provider-web packages are still CJS only. When import **2. Updates the default auth provider state for middleware auth** Middleware auth default state is _almost_ the same as SPA default auth state. Except that loading is always false! Otherwise you can get stuck in a loading state forever. - - \ No newline at end of file diff --git a/.changesets/10499.md b/.changesets/10499.md index de951de649f5..f80f8fef394c 100644 --- a/.changesets/10499.md +++ b/.changesets/10499.md @@ -2,11 +2,9 @@ Implement Supabase Auth Middleware to authenticate server-side requests. -* Adds middleware to the Supabase auth-providers package. -* createSupabaseAuthMiddleware is responsible for authenticating Supabase requests -* It does so by checking if the request has a supabase auth-provider header, and then uses the authDecoder to verify the session cookie using the Supabase ServerAuthClient and returning a decoded access token -- or throwing an exception if the session cookie is invalid -* Once the middleware has the decoded JWT, it hands that to the provided getCurrentUser from he user's project to return the information about authenticated user -* Lastly, it sets serverAuthState with user and metadata info to know the request isAuthenticated -* If the session is invalid or the cookie tampered with such that the access token cannot be verified, serverAuthState is cleared as are the auth provider and Supabase cookies - - +- Adds middleware to the Supabase auth-providers package. +- createSupabaseAuthMiddleware is responsible for authenticating Supabase requests +- It does so by checking if the request has a supabase auth-provider header, and then uses the authDecoder to verify the session cookie using the Supabase ServerAuthClient and returning a decoded access token -- or throwing an exception if the session cookie is invalid +- Once the middleware has the decoded JWT, it hands that to the provided getCurrentUser from he user's project to return the information about authenticated user +- Lastly, it sets serverAuthState with user and metadata info to know the request isAuthenticated +- If the session is invalid or the cookie tampered with such that the access token cannot be verified, serverAuthState is cleared as are the auth provider and Supabase cookies diff --git a/.changesets/10502.md b/.changesets/10502.md index 51a50674f2b1..5d2452434ca6 100644 --- a/.changesets/10502.md +++ b/.changesets/10502.md @@ -1,2 +1,2 @@ - fix(dbauth-mw): Unset cookie instead of clearing (#10502) by @dac09 -Updates dbAuth middleware implementation to _unset_ the cookies, instead of clearing them. + Updates dbAuth middleware implementation to _unset_ the cookies, instead of clearing them. diff --git a/.changesets/10520.md b/.changesets/10520.md index f18c4c48d7c0..d926d379c501 100644 --- a/.changesets/10520.md +++ b/.changesets/10520.md @@ -1,3 +1,3 @@ - feat(eslint): Disable restricted $api imports for entryserver (#10520) by @dac09 -With the introduction of middleware, it's pretty common to import things from the $api side. This is a non-issue as entry.server.{jsx,tsx} is not part of the client bundle we generate. +With the introduction of middleware, it's pretty common to import things from the $api side. This is a non-issue as entry.server.{jsx,tsx} is not part of the client bundle we generate. diff --git a/.changesets/10522.md b/.changesets/10522.md index 915280d80667..84953f30fb31 100644 --- a/.changesets/10522.md +++ b/.changesets/10522.md @@ -5,7 +5,7 @@ In `web/src/auth.ts`: ``` -// 👇 notice where this is imported from! +// 👇 notice where this is imported from! import { createBrowserClient } from '@supabase/ssr' import { createAuth } from '@redwoodjs/auth-supabase-web' diff --git a/.changesets/10538.md b/.changesets/10538.md index 02f8016306de..1991248970db 100644 --- a/.changesets/10538.md +++ b/.changesets/10538.md @@ -1,6 +1,7 @@ - fix(serverauth): Export dbAuthMiddleware as default export to match supabase (#10538) by @dac09 An example: + ```js //before import { createDbAuthMiddleware } from '@redwoodjs/auth-dbauth-middleware' diff --git a/.changesets/10542.md b/.changesets/10542.md index 0d665cc2bc8b..229f41e551e3 100644 --- a/.changesets/10542.md +++ b/.changesets/10542.md @@ -1,4 +1,4 @@ -- Rename og component assets from *.png.jsx to just*.og.jsx (#10542) by @cannikin +- Rename og component assets from _.png.jsx to just_.og.jsx (#10542) by @cannikin We ran into a conflict where you could name your component file something like `AboutPage.png.jsx` (where the returned content-type would be image/png). But, when you invoke `useOgImage()` to actually create the URL for a `` tag, you could instead use a different extension, like `.jpg`. Which one should win? diff --git a/.changesets/10570.md b/.changesets/10570.md index 679568957b17..4226df248500 100644 --- a/.changesets/10570.md +++ b/.changesets/10570.md @@ -2,4 +2,4 @@ With an empty/null payload (which it is by default) the body should be empty, not the string `'null'` -This is a breaking change for anyone who was depending on the current "null" behavior in their api function tests. More specifically, if you're **NOT** passing `body` or `payload` to `mockHttpEvent({ ... })` or if you're trying to explicitly set `payload` to `null` you might have to update your tests. +This is a breaking change for anyone who was depending on the current "null" behavior in their api function tests. More specifically, if you're **NOT** passing `body` or `payload` to `mockHttpEvent({ ... })` or if you're trying to explicitly set `payload` to `null` you might have to update your tests. diff --git a/.changesets/10585.md b/.changesets/10585.md index 0bd8ded820ca..22640b7ba67e 100644 --- a/.changesets/10585.md +++ b/.changesets/10585.md @@ -4,12 +4,12 @@ First pass at implementing a per-request store that allows: - access to headers and cookies from requests in server components - access to serverAuthState from server components -- maps serverAuthState updated from middleware to the the per request store +- maps serverAuthState updated from middleware to the the per request store This PR also implements execution of middleware in the RSC handler. Note that this is done in a "good enough" way currently, because the RSC handler doesn't use Fetch requests (but everything else does) - + Important things to note: + - the store is initialised _again_ in the RSC worker, with the same values on each invocation of renderRsc - we have _not_ tested or tried in Dev because `rw dev` does not work in RSC yet -- we have _not_ tested behaviour on initial SSR - because this is not implemented yet in RSC - +- we have _not_ tested behaviour on initial SSR - because this is not implemented yet in RSC diff --git a/.changesets/10586.md b/.changesets/10586.md index 864ae5c1420e..c2317e8fd1f5 100644 --- a/.changesets/10586.md +++ b/.changesets/10586.md @@ -1,6 +1,6 @@ - feat(middleware): Add .shortCircuit to MiddlewareResponse (#10586) by @dac09 -Adds a helper to generate a intercept/short-circuit response, that will interrupt execution of _all_ middleware and react rendering, and immediately return the response. +Adds a helper to generate a intercept/short-circuit response, that will interrupt execution of _all_ middleware and react rendering, and immediately return the response. There's a few different ways you can use this, see examples below: @@ -24,7 +24,5 @@ const shortCircuitMw: Middleware = (req, res) => { headers: { shortCircuitDirect: 'yes' }, }) } - } ``` - diff --git a/.changesets/10656.md b/.changesets/10656.md index 8307e1eda502..89780e1a68cf 100644 --- a/.changesets/10656.md +++ b/.changesets/10656.md @@ -6,6 +6,7 @@ - Introduces new `clear()` function to remove auth state - just syntax sugar ## Example usage + ```tsx // In entry.server.tsx export const registerMiddleware = () => { @@ -15,9 +16,9 @@ export const registerMiddleware = () => { getCurrentUser, getRoles: (decoded) => { return decoded.currentUser.roles || [] - } + }, }) - + return [authMw] } ``` diff --git a/.changesets/10668.md b/.changesets/10668.md index 2c2b6830fb66..187acaad387f 100644 --- a/.changesets/10668.md +++ b/.changesets/10668.md @@ -1,10 +1,12 @@ - fix(dbAuthMw): Update and fix logic related to dbAuth "verbs" and decryptionErrors (#10668) by @dac09 This PR does the following: + - updates the dbauth mw to correctly handle the cookieName option (it should always have been optional) - throws an error when the `dbAuthSession` returns an empty decoded token so that it clears the authState -- we had a check for only "POST" requests to be passed to the dbAuthHandler. This was incorrect because some of the dbAuth "verbs" or actions - like `webAuthnRegOptions` - uses a GET request. +- we had a check for only "POST" requests to be passed to the dbAuthHandler. This was incorrect because some of the dbAuth "verbs" or actions - like `webAuthnRegOptions` - uses a GET request. As a result, the tests started showing failures, so I: + - added a mock for `dbAuthSession`, so we can check both happy path and unhappy paths for session decryption - updated the tests where relevant diff --git a/.changesets/10677.md b/.changesets/10677.md index 4113d125217d..a62f180d5450 100644 --- a/.changesets/10677.md +++ b/.changesets/10677.md @@ -1,6 +1,7 @@ - Adds `searchParams` option to `useOgImage()` hook for adding arbitrary query string vars to generated URL (#10677) by @cannikin This can be used like so: + ``` const { url } = useOgImage({ searchParams: { foo: 'bar' }) console.log(url) // => http://localhost:8910/photo.png?foo=bar diff --git a/.changesets/10680.md b/.changesets/10680.md index e1a54c0ea56f..34aad4ebc011 100644 --- a/.changesets/10680.md +++ b/.changesets/10680.md @@ -3,10 +3,10 @@ This PR adds the `page_identifier_str` of `pageIdentifier` to the Route Manifest. Known what page belongs to the route can be useful to : - -* ensure if rendering a page/component that it belongs to the route and its auth permissions -* for visualizing routes -* general completeness in the manifest with the Routes jsx in manifest form + +- ensure if rendering a page/component that it belongs to the route and its auth permissions +- for visualizing routes +- general completeness in the manifest with the Routes jsx in manifest form ## Example diff --git a/.changesets/10697.md b/.changesets/10697.md index 475e74ed509f..559b35e5c3c3 100644 --- a/.changesets/10697.md +++ b/.changesets/10697.md @@ -2,8 +2,8 @@ 1. Adds fullUrl property to serverStore 2. Adds two utility functions: -a) `getFullUrl` - to construct the absolute url from an express request -b) `getFullUrlFromFlightRequest` - this is used when we get a request to render RSCs in the rscRequestHandler. This one is different because the location we want is for the actual page, not of the request (which goes to to the RSC endpoint). + a) `getFullUrl` - to construct the absolute url from an express request + b) `getFullUrlFromFlightRequest` - this is used when we get a request to render RSCs in the rscRequestHandler. This one is different because the location we want is for the actual page, not of the request (which goes to to the RSC endpoint). 3. Adds `getLocation` function to retrieve the Location (URL object) from server store Short video demonstrating location coming through in two cases: @@ -13,6 +13,7 @@ b) Hard render https://s.tape.sh/4g7LFsYP **Usage example:** + ```tsx import { getLocation } from '@redwoodjs/vite/serverStore' @@ -21,4 +22,4 @@ const NavigationLayout = ({ children, rnd }: NavigationLayoutProps) => { console.log(`👉 \n ~ location:`, location) ``` -Longer term, we may want to change how the endpoint for flight requests so that the location doesn't have to be constructed specially. +Longer term, we may want to change how the endpoint for flight requests so that the location doesn't have to be constructed specially. diff --git a/.changesets/10702.md b/.changesets/10702.md index 908ec2de515c..e543463368b8 100644 --- a/.changesets/10702.md +++ b/.changesets/10702.md @@ -12,4 +12,4 @@ In production Docker, the server file was never run and therefore the plugin to Here api server, simply ran the GraphQL function as expected, but the plugin was never invoked so Realtime was never configured or added to the schema. -This happened because by default, production Docker launch the plain vanilla api server -- it didn't launch server file that uses `createServer` to setup a separate GraphQL server and also add in the realtime plugin. +This happened because by default, production Docker launch the plain vanilla api server -- it didn't launch server file that uses `createServer` to setup a separate GraphQL server and also add in the realtime plugin. diff --git a/.changesets/10768.md b/.changesets/10768.md index 30fe7ebd1b03..294985a45d0b 100644 --- a/.changesets/10768.md +++ b/.changesets/10768.md @@ -1,4 +1,5 @@ - Add Storybook Vite smoke tests (#10768) by @arimendelow Adds: + - Unit tests for storybook-vite CLI (based on those from the dataMigrate CLI) diff --git a/.changesets/10817.md b/.changesets/10817.md index 17d6b873a3c3..8617c77192c7 100644 --- a/.changesets/10817.md +++ b/.changesets/10817.md @@ -10,8 +10,8 @@ The plgin for persisted operations lets one define what can bypass trusted docs So, we can use that in the useTrustedDocuments plugin to just allow that specific request. -const REDWOOD__AUTH_GET_CURRENT_USER_QUERY = - '{"query":"query __REDWOOD__AUTH_GET_CURRENT_USER { redwood { currentUser } }"}' +const REDWOOD**AUTH_GET_CURRENT_USER_QUERY = +'{"query":"query **REDWOOD\_\_AUTH_GET_CURRENT_USER { redwood { currentUser } }"}' When using Redwood Auth, we want to allow the known, trusted redwood.currentUser query to be executed without a persisted operation. This is because the currentUser query is a special case that is used to get the current user from the auth provider. diff --git a/.changesets/10825.md b/.changesets/10825.md index 1b40b11bf61a..c5f527bf4c13 100644 --- a/.changesets/10825.md +++ b/.changesets/10825.md @@ -4,8 +4,7 @@ Fixes https://github.com/redwoodjs/redwood/issues/10807 If one used GraphQL fragments, when mocking the GraphQL query for use in Storybook, the `typename` for the data object must be included otherwise Apollo client cannot properly map the data. -This PR - -* adds the typename to the cell generator templates -* updates the testing and graphql mock and fragments documentation to show how properly defines mock data +This PR +- adds the typename to the cell generator templates +- updates the testing and graphql mock and fragments documentation to show how properly defines mock data diff --git a/.changesets/10830.md b/.changesets/10830.md index d667110d4ddf..906feae23a7b 100644 --- a/.changesets/10830.md +++ b/.changesets/10830.md @@ -1,3 +1,3 @@ - fix(cli): Add check for excessively long route (#10830) by @Josh-Walker-GM -This change adds an additional internal check to protect against route definitions which are preposterously long. +This change adds an additional internal check to protect against route definitions which are preposterously long. diff --git a/.changesets/10833.md b/.changesets/10833.md index 68a7d6449afe..08c80b8b931a 100644 --- a/.changesets/10833.md +++ b/.changesets/10833.md @@ -2,4 +2,4 @@ This change updates our firebase auth provider to use the v12 major version of the `firebase-admin` package. This will require you to update your own version of `firebase-admin` that is listed in your api side package json file. -We have noticed no breaking api changes in our limited testing. Please consult the `firebase-admin` upgrade guide if you experience problems after upgrading - especially if you have more extensive or complex use of the firebase suite of products. +We have noticed no breaking api changes in our limited testing. Please consult the `firebase-admin` upgrade guide if you experience problems after upgrading - especially if you have more extensive or complex use of the firebase suite of products. diff --git a/.changesets/10865.md b/.changesets/10865.md index 7f2848b9fd06..0dc3fba1dcaa 100644 --- a/.changesets/10865.md +++ b/.changesets/10865.md @@ -1,3 +1,3 @@ - feat(dbAuth): Prompt to generate dbAuth pages (#10865) by @Tobbe -When setting up dbAuth we'll now prompt if the user also wants to generate pages for login, signup, password reset etc. We only prompt if no existing pages exist. \ No newline at end of file +When setting up dbAuth we'll now prompt if the user also wants to generate pages for login, signup, password reset etc. We only prompt if no existing pages exist. diff --git a/.changesets/10867.md b/.changesets/10867.md index 09f6f86a07ad..6dcd0b7065fb 100644 --- a/.changesets/10867.md +++ b/.changesets/10867.md @@ -1,6 +1,7 @@ - breaking: remove webpack (#10867) by @Josh-Walker-GM This PR removes support for webpack. There are a number of breaking changes associated with removing a core component of previous versions. A list of such changes is: + 1. `prebuildWebFile` is function no longer exported from `@redwoodjs/babel-config` package 2. `@redwoodjs/cli-storybook` has been removed 3. `yarn rw build` no longer accepts the `--stats` flag diff --git a/.changesets/10869.md b/.changesets/10869.md index e87bb1dbb3f5..beac04684f9b 100644 --- a/.changesets/10869.md +++ b/.changesets/10869.md @@ -1,25 +1,25 @@ feat(prisma): Support multi file Prisma schemas (#10869) by @dthyresson -Prisma's `prismaSchemaFolder` [feature](https://www.prisma.io/docs/orm/prisma-schema/overview/location#multi-file-prisma-schema) allows you to define multiple files in a schema subdirectory of your prisma directory. +Prisma's `prismaSchemaFolder` [feature](https://www.prisma.io/docs/orm/prisma-schema/overview/location#multi-file-prisma-schema) allows you to define multiple files in a schema subdirectory of your prisma directory. This PR updates: -* Prisma utilities -* generators -* dbAuth setup -* documentation +- Prisma utilities +- generators +- dbAuth setup +- documentation to support single and multi file Prisma schemas. If you have enabled Prisma multi file schemas, you configure your project toml api `schemaPath` setting the directory where your schema.prisma can be found, for example: './api/db/schema' -When [organizing your Prisma Schema into multiple files](https://www.prisma.io/blog/organize-your-prisma-schema-with-multi-file-support), you will need [enable](https://www.prisma.io/docs/orm/prisma-schema/overview/location#multi-file-prisma-schema) that feature in Prisma, move your `schema.prisma` file into a new directory such as `./api/db/schema` and then set `schemaPath` in the api toml config. +When [organizing your Prisma Schema into multiple files](https://www.prisma.io/blog/organize-your-prisma-schema-with-multi-file-support), you will need [enable](https://www.prisma.io/docs/orm/prisma-schema/overview/location#multi-file-prisma-schema) that feature in Prisma, move your `schema.prisma` file into a new directory such as `./api/db/schema` and then set `schemaPath` in the api toml config. ::: For example: ```toml title="redwood.toml" [api] - port = 8911 + port = 8911 schemaPath = "./api/db/schema" ``` diff --git a/.changesets/10888.md b/.changesets/10888.md index 3369c04737f0..4a38e50a9410 100644 --- a/.changesets/10888.md +++ b/.changesets/10888.md @@ -1,3 +1,3 @@ - fix(prerender): Fold output to prevent crashing on large prerender counts (#10888) by @Josh-Walker-GM -This change alters the CLI output during prerendering to prevent crashes when prerendering a large number (>100,000) of routes. +This change alters the CLI output during prerendering to prevent crashes when prerendering a large number (>100,000) of routes. diff --git a/.changesets/10893.md b/.changesets/10893.md index ca4f270a6e2b..c83381b21236 100644 --- a/.changesets/10893.md +++ b/.changesets/10893.md @@ -2,7 +2,7 @@ fix(realtime/trusted-docs): Supports GraphQL subscriptions and trusted documents Fixes: https://github.com/redwoodjs/redwood/issues/10892 -This PR updates the SSELink to check if there is a trusted document hash in the request. If there is, then don't also include the query. +This PR updates the SSELink to check if there is a trusted document hash in the request. If there is, then don't also include the query. The persisted operations plugin checks if the params has a query. If it does then raises an error that only persisted operations are allowed. diff --git a/.changesets/10900.md b/.changesets/10900.md index 75831396d6ca..d2c810b34926 100644 --- a/.changesets/10900.md +++ b/.changesets/10900.md @@ -1,3 +1,3 @@ - feat(Storybook Vite): Add JS project support (#10900) by @arimendelow -This adds support to the SBV CLI for JS projects. \ No newline at end of file +This adds support to the SBV CLI for JS projects. diff --git a/.changesets/10911.md b/.changesets/10911.md index b1e68bee2c1c..b82c358dd9be 100644 --- a/.changesets/10911.md +++ b/.changesets/10911.md @@ -5,32 +5,32 @@ This change updates Redwood linting config and introduces some changes to the li Specifically: 1. `jsx-a11y/no-noninteractive-element-to-interactive-role` has it's default config updated. -3. `@typescript-eslint/explicit-function-return-type` used to be turned off, now it's no longer applied. -4. `@typescript-eslint/no-empty-interface` - used to be turned off, now it's no longer applied. -5. `@typescript-eslint/explicit-module-boundary-types` - used be turned off, now it's no longer applied. -6. `@typescript-eslint/ban-types` - used to be 'warn', now it's no longer applied. This has been replaces with a set of smaller more specific rules. -7. `no-empty-function` - used be turned off, now it's no longer applied. The ts-eslint flavour is still there and turned off still. -8. `camelcase` - used to be turned off, now it's 'warn'. -9. `@typescript-eslint/camelcase` - used to be turned off, now it's no longer applied. -10. `no-use-before-define` - used to be turned off, now it's no longer applied. -11. `@typescript-eslint/no-use-before-define` - used to be turned off, now it's no longer applied. -12. `@typescript-eslint/prefer-namespace-keyword` - used to be turned off, now it's 'error' -13. `unicode-bom` - used to be turned off, now it's no longer applied. -14. `@typescript-eslint/adjacent-overload-signatures` - used to be 'error', now it's no longer applied. -15. `@typescript-eslint/no-explicit-any` - used be 'warn', now 'error' -16. `@typescript-eslint/no-inferrable-types` - used to be 'error', now it's no longer applied. -17. `no-loss-of-precision` - used be 'off', now 'error' -18. `@typescript-eslint/no-loss-of-precision` - used be 'error', now it's no longer applied. -19. `@typescript-eslint/no-non-null-assertion` - used be 'warn', now it's no longer applied. -20. `valid-typeof` - used be either 'error' or 'off', now always 'error' -21. `no-unused-expressions` - used be always 'error', now either 'error' or 'off' -22. `@typescript-eslint/prefer-function-type` - newly added as 'off' -23. `@typescript-eslint/no-require-imports` - newly added as 'off' -24. `@typescript-eslint/no-empty-object-type` - newly added as 'off' -25. `unicorn/template-indent` - newly added as 'off' -26. `@typescript-eslint/no-duplicate-enum-values` - newly added as 'error' -27. `@typescript-eslint/no-unsafe-declaration-merging` - newly added as 'error' -28. `@typescript-eslint/no-unsafe-function-type` - newly added as 'error' -29. `@typescript-eslint/no-unused-expressions` - newly added as 'error' -30. `@typescript-eslint/no-wrapper-object-types` - newly added as 'error' -31. `no-new-native-nonconstructor` - newly added as 'off' +2. `@typescript-eslint/explicit-function-return-type` used to be turned off, now it's no longer applied. +3. `@typescript-eslint/no-empty-interface` - used to be turned off, now it's no longer applied. +4. `@typescript-eslint/explicit-module-boundary-types` - used be turned off, now it's no longer applied. +5. `@typescript-eslint/ban-types` - used to be 'warn', now it's no longer applied. This has been replaces with a set of smaller more specific rules. +6. `no-empty-function` - used be turned off, now it's no longer applied. The ts-eslint flavour is still there and turned off still. +7. `camelcase` - used to be turned off, now it's 'warn'. +8. `@typescript-eslint/camelcase` - used to be turned off, now it's no longer applied. +9. `no-use-before-define` - used to be turned off, now it's no longer applied. +10. `@typescript-eslint/no-use-before-define` - used to be turned off, now it's no longer applied. +11. `@typescript-eslint/prefer-namespace-keyword` - used to be turned off, now it's 'error' +12. `unicode-bom` - used to be turned off, now it's no longer applied. +13. `@typescript-eslint/adjacent-overload-signatures` - used to be 'error', now it's no longer applied. +14. `@typescript-eslint/no-explicit-any` - used be 'warn', now 'error' +15. `@typescript-eslint/no-inferrable-types` - used to be 'error', now it's no longer applied. +16. `no-loss-of-precision` - used be 'off', now 'error' +17. `@typescript-eslint/no-loss-of-precision` - used be 'error', now it's no longer applied. +18. `@typescript-eslint/no-non-null-assertion` - used be 'warn', now it's no longer applied. +19. `valid-typeof` - used be either 'error' or 'off', now always 'error' +20. `no-unused-expressions` - used be always 'error', now either 'error' or 'off' +21. `@typescript-eslint/prefer-function-type` - newly added as 'off' +22. `@typescript-eslint/no-require-imports` - newly added as 'off' +23. `@typescript-eslint/no-empty-object-type` - newly added as 'off' +24. `unicorn/template-indent` - newly added as 'off' +25. `@typescript-eslint/no-duplicate-enum-values` - newly added as 'error' +26. `@typescript-eslint/no-unsafe-declaration-merging` - newly added as 'error' +27. `@typescript-eslint/no-unsafe-function-type` - newly added as 'error' +28. `@typescript-eslint/no-unused-expressions` - newly added as 'error' +29. `@typescript-eslint/no-wrapper-object-types` - newly added as 'error' +30. `no-new-native-nonconstructor` - newly added as 'off' diff --git a/.changesets/10961.md b/.changesets/10961.md index 8cd365b8663c..ee75c7843a56 100644 --- a/.changesets/10961.md +++ b/.changesets/10961.md @@ -1,3 +1,3 @@ - fix(storybook): Fix import issues with storybook vite (#10961) by @Josh-Walker-GM -Fixes an issue with the `yarn rw storybook-vite` command where it would not start due to an import issue. +Fixes an issue with the `yarn rw storybook-vite` command where it would not start due to an import issue. diff --git a/.changesets/11062.md b/.changesets/11062.md index f8f9c2f818e3..a2e51acf7bf6 100644 --- a/.changesets/11062.md +++ b/.changesets/11062.md @@ -1,3 +1,3 @@ -- fix(router): Add check for excessively long path (#11062) by @Josh-Walker-GM +- fix(router): Add check for excessively long path (#11062) by @Josh-Walker-GM This change adds an additional internal check to protect against route paths which are excessively long. diff --git a/.changesets/11072.md b/.changesets/11072.md index e4b3635cf9e6..5c3a91845806 100644 --- a/.changesets/11072.md +++ b/.changesets/11072.md @@ -1,3 +1,3 @@ - feat(cli): Move docker setup out of experimental (#11072) by @Josh-Walker-GM -This change introduces `yarn rw setup docker`. This is a result of moving our docker setup command out of it's experimental phase. +This change introduces `yarn rw setup docker`. This is a result of moving our docker setup command out of it's experimental phase. diff --git a/.changesets/11108.md b/.changesets/11108.md index f98f93c7a310..8fe7cd0208af 100644 --- a/.changesets/11108.md +++ b/.changesets/11108.md @@ -1,16 +1,15 @@ -- feat(testing): Configure jest to ignore sidecar files in __tests__ folder (#11108) by @V1shvesh +- feat(testing): Configure jest to ignore sidecar files in **tests** folder (#11108) by @V1shvesh Solves for #10870 ### Description: + `./api` directory structure: image `./web` directory structure: image - - -Before: +Before: `yarn rw test api`: image @@ -18,12 +17,9 @@ Before: `yarn rw test web`: image - - After: `yarn rw test api`: image `yarn rw test web`: image - diff --git a/.changesets/11109.md b/.changesets/11109.md index 0a79d4a4c51b..860cf6226eb8 100644 --- a/.changesets/11109.md +++ b/.changesets/11109.md @@ -5,9 +5,10 @@ The more detail the better. E.g., is it a new feature? How do they use it? Code - fix: concurrent api builds (#11109) by @callingmedic911 A few users [reported](https://community.redwoodjs.com/t/redwood-v7-0-0-upgrade-guide/5713/90?u=callingmedic911) that the API server crashes with the error `EADDRINUSE` when switching between branches. This issue happens on the API side when: + 1. New files are added or existing files are removed. 2. Immediately after, an existing file is changed. This scenario is common when doing git operations like switching branches or using git stash, where these changes occur simultaneously. When this happens, step 1 triggers a full build (without esbuild's rebuild), and step 2, without canceling the build from step 1, triggers a separate `rebuild`. This results in concurrent builds and two instances of the API server trying to start. -This PR provides a quick fix for the issue. A follow-up PR will be created to refactor the process, aiming to avoid separate build processes altogether, ensure a cleaner separation between the build and the server, and improve overall readability. \ No newline at end of file +This PR provides a quick fix for the issue. A follow-up PR will be created to refactor the process, aiming to avoid separate build processes altogether, ensure a cleaner separation between the build and the server, and improve overall readability. diff --git a/.changesets/11135.md b/.changesets/11135.md index 932c7fa1fd0e..afb073672f46 100644 --- a/.changesets/11135.md +++ b/.changesets/11135.md @@ -1,6 +1,6 @@ - fix(cli-cache): Remove RW CLI cache on upgrade (#11135) by @dac09 -This change removes the redwood cli plugin cache in `.redwood/commandCache.json` on running `rw upgrade`. +This change removes the redwood cli plugin cache in `.redwood/commandCache.json` on running `rw upgrade`. This prevents the redwood CLI from using outdated versions of CLI plugins, and is particularly important when they same alias. diff --git a/.changesets/11170.md b/.changesets/11170.md index 4f4390a76c6e..3fd0e84e161e 100644 --- a/.changesets/11170.md +++ b/.changesets/11170.md @@ -1,9 +1,10 @@ - fix: Update default tsconfig options (target, module and moduleResolution) (#11170) by @Josh-Walker-GM This changes the default values of: - - target - - module - - moduleResolution + +- target +- module +- moduleResolution in the tsconfig files for both the API and web side. The benefit of this change is increased correctness for build time checking of the imports from packages which specify `exports` in their `package.json` files. diff --git a/.changesets/11189.md b/.changesets/11189.md index 8f823c814668..f5ee9ad36933 100644 --- a/.changesets/11189.md +++ b/.changesets/11189.md @@ -1,6 +1,7 @@ - fix(babel-plugins): Handle additional syntax when extracting graphql options (#11189) by @Josh-Walker-GM This fixes an issue with the automatic extraction of options from the `createGraphQLHandler` function when you were wrapping that function within a custom handler function. For example the following would have failed before this fix: + ```ts const graphQLHandler = createGraphQLHandler({ // ...options diff --git a/.changesets/11250.md b/.changesets/11250.md new file mode 100644 index 000000000000..ae78b6e9abad --- /dev/null +++ b/.changesets/11250.md @@ -0,0 +1,7 @@ +- fix(cli): Service generator supports relations (#11250) by @dthyresson + +This PR address an issue when using `yarn rw g service` independently vs having ti be called by `yarn rw g sdl` or `yarn rw g scaffold`. + +When using `yarn rw g service`, the model's relations were not correctly determined. For the sdl generator, relations are determined and then passed as an argument to the service generator; however, if you run just the service generator, the relations were always `[]`. + +This PR fixes that by adding a check to see if the relations are already passed in as an argument. If they are, it uses that; otherwise, it falls back to determining the relations itself. diff --git a/.changesets/11262.md b/.changesets/11262.md new file mode 100644 index 000000000000..70d00a9d4c0c --- /dev/null +++ b/.changesets/11262.md @@ -0,0 +1,4 @@ +- fix(exec): Include nested scripts in --list (#11262) by @Tobbe + +Now also nested scripts, like `scripts/nested/script.ts`, are included in the +output of `yarn rw exec --list` diff --git a/.changesets/11278.md b/.changesets/11278.md new file mode 100644 index 000000000000..891d5b90c13d --- /dev/null +++ b/.changesets/11278.md @@ -0,0 +1,8 @@ +- feat(exec): Add --silent to silence all RW output (#11278) by @Tobbe + +Run with `--silent` (or `-s`) to not have the framework itself print anything to +your console. Only console logs you have yourself in the script, or any files +the script includes, will come through. + +If you're using Prisma you might want to tweak Prisma's logging (in +`api/lib/db.ts`) and turn off "info" logging, depending on your goals. diff --git a/.changesets/11307.md b/.changesets/11307.md new file mode 100644 index 000000000000..c45f540bd004 --- /dev/null +++ b/.changesets/11307.md @@ -0,0 +1,3 @@ +- refactor(api): Add conditional exports to package.json (#11307) by @Josh-Walker-GM + +This change restricts the available imports from this package. You can no longer freely import from within the dist like `@redwoodjs/api/dist/...`. If you were doing so please consult the `@redwoodjs/api` `package.json` file to see what exports are now available. diff --git a/.changesets/9848.md b/.changesets/9848.md new file mode 100644 index 000000000000..03ce8329ef77 --- /dev/null +++ b/.changesets/9848.md @@ -0,0 +1,3 @@ +- Detect/resolve ambiguous script names (#9848) by @codersmith + +Detects and resolves ambiguous script name combinations like `[foo.js, foo.ts]` or `[foo.ts, foo.json]` when running `yarn rw exec foo`. diff --git a/.changesets/young-spiders-ring.md b/.changesets/young-spiders-ring.md index 83912e0a90bb..4b9212d8ccee 100644 --- a/.changesets/young-spiders-ring.md +++ b/.changesets/young-spiders-ring.md @@ -2,4 +2,4 @@ fix: Fixes Unknown Fragment issues due to GraphQL Tag type mismatch in web (#10357) by @dthyresson - Users reported in #10322 an incompatibility with fragments and when using gql from global web. The TS errors were caused by the global web gql type not being compatible with the standard graphql-tag type. +Users reported in #10322 an incompatibility with fragments and when using gql from global web. The TS errors were caused by the global web gql type not being compatible with the standard graphql-tag type. diff --git a/.eslintrc.js b/.eslintrc.js index 423923ee35b2..a7094e6c548f 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -198,20 +198,14 @@ module.exports = { camelcase: 'off', // TODO(jgmw): Work through these and either keep disabled or fix and re-enable - '@typescript-eslint/prefer-string-starts-ends-with': 'off', - '@typescript-eslint/await-thenable': 'off', '@typescript-eslint/no-unsafe-call': 'off', '@typescript-eslint/no-unsafe-assignment': 'off', '@typescript-eslint/require-await': 'off', '@typescript-eslint/prefer-nullish-coalescing': 'off', '@typescript-eslint/no-unsafe-member-access': 'off', - '@typescript-eslint/no-unnecessary-type-assertion': 'off', - '@typescript-eslint/no-unsafe-enum-comparison': 'off', '@typescript-eslint/dot-notation': 'off', - '@typescript-eslint/only-throw-error': 'off', '@typescript-eslint/no-unsafe-argument': 'off', '@typescript-eslint/no-unsafe-return': 'off', - '@typescript-eslint/prefer-optional-chain': 'off', '@typescript-eslint/prefer-promise-reject-errors': 'off', '@typescript-eslint/no-redundant-type-constituents': 'off', '@typescript-eslint/restrict-plus-operands': 'off', @@ -220,12 +214,8 @@ module.exports = { '@typescript-eslint/prefer-regexp-exec': 'off', '@typescript-eslint/restrict-template-expressions': 'off', '@typescript-eslint/non-nullable-type-assertion-style': 'off', - '@typescript-eslint/no-implied-eval': 'off', - '@typescript-eslint/prefer-includes': 'off', '@typescript-eslint/no-base-to-string': 'off', - '@typescript-eslint/no-duplicate-type-constituents': 'off', '@typescript-eslint/unbound-method': 'off', - '@typescript-eslint/prefer-find': 'off', }, }, { diff --git a/.github/ISSUE_TEMPLATE/bug-report.yml b/.github/ISSUE_TEMPLATE/bug-report.yml index 0e6a6d9f9260..85949ff4a22b 100644 --- a/.github/ISSUE_TEMPLATE/bug-report.yml +++ b/.github/ISSUE_TEMPLATE/bug-report.yml @@ -1,7 +1,7 @@ -name: "🐛 Bug report" -description: "Something not working the way it should be?" +name: '🐛 Bug report' +description: 'Something not working the way it should be?' -title: "[Bug?]: " +title: '[Bug?]: ' labels: bug/needs-info body: @@ -29,7 +29,7 @@ body: you're much more likely to get a timely response and fix from us if you fill it out. Issues without reproductions are much harder for us to debug. validations: - required: false + required: false - type: textarea attributes: @@ -52,7 +52,7 @@ body: npmPackages: @redwoodjs/core: 1.5.2 => 1.5.2 validations: - required: false + required: false - type: checkboxes attributes: diff --git a/.github/ISSUE_TEMPLATE/documentation.yml b/.github/ISSUE_TEMPLATE/documentation.yml index 0f299a954c91..3d86c31deb4a 100644 --- a/.github/ISSUE_TEMPLATE/documentation.yml +++ b/.github/ISSUE_TEMPLATE/documentation.yml @@ -1,7 +1,7 @@ -name: "📖 Documentation" -description: "A catch-all template for issues about documentation" +name: '📖 Documentation' +description: 'A catch-all template for issues about documentation' -title: "[Docs]: " +title: '[Docs]: ' labels: topic/docs body: diff --git a/.github/ISSUE_TEMPLATE/rfc.yml b/.github/ISSUE_TEMPLATE/rfc.yml index 2a081eb62884..69aa95c7e632 100644 --- a/.github/ISSUE_TEMPLATE/rfc.yml +++ b/.github/ISSUE_TEMPLATE/rfc.yml @@ -1,7 +1,7 @@ -name: "💬 RFC" -description: "For detailed proposals about new features or changes to existing ones" +name: '💬 RFC' +description: 'For detailed proposals about new features or changes to existing ones' -title: "[RFC]: " +title: '[RFC]: ' body: - type: markdown diff --git a/.github/actions/actionsLib.mjs b/.github/actions/actionsLib.mjs index 8f82656af54d..deacbe1ef610 100644 --- a/.github/actions/actionsLib.mjs +++ b/.github/actions/actionsLib.mjs @@ -12,24 +12,22 @@ import { hashFiles } from '@actions/glob' * @typedef {import('@actions/exec').ExecOptions} ExecOptions */ -export const REDWOOD_FRAMEWORK_PATH = fileURLToPath(new URL('../../', import.meta.url)) +export const REDWOOD_FRAMEWORK_PATH = fileURLToPath( + new URL('../../', import.meta.url), +) /** * @param {string} command * @param {ExecOptions} options */ function execWithEnv(command, { env = {}, ...rest } = {}) { - return getExecOutput( - command, - undefined, - { - env: { - ...process.env, - ...env - }, - ...rest - } - ) + return getExecOutput(command, undefined, { + env: { + ...process.env, + ...env, + }, + ...rest, + }) } /** @@ -51,52 +49,64 @@ export const execInFramework = createExecWithEnvInCwd(REDWOOD_FRAMEWORK_PATH) * @param {string} redwoodProjectCwd */ export function projectDeps(redwoodProjectCwd) { - return execInFramework('yarn project:deps', { env: { RWJS_CWD: redwoodProjectCwd } }) + return execInFramework('yarn project:deps', { + env: { RWJS_CWD: redwoodProjectCwd }, + }) } /** * @param {string} redwoodProjectCwd */ export function projectCopy(redwoodProjectCwd) { - return execInFramework('yarn project:copy', { env: { RWJS_CWD: redwoodProjectCwd } }) + return execInFramework('yarn project:copy', { + env: { RWJS_CWD: redwoodProjectCwd }, + }) } /** * @param {{ baseKeyPrefix: string, distKeyPrefix: string, canary: boolean }} options */ -export async function createCacheKeys({ baseKeyPrefix, distKeyPrefix, canary }) { +export async function createCacheKeys({ + baseKeyPrefix, + distKeyPrefix, + canary, +}) { const baseKey = [ baseKeyPrefix, process.env.RUNNER_OS, process.env.GITHUB_REF.replaceAll('/', '-'), - await hashFiles(path.join('__fixtures__', 'test-project')) + await hashFiles(path.join('__fixtures__', 'test-project')), ].join('-') - const dependenciesKey = [ - baseKey, - 'dependencies', - await hashFiles(['yarn.lock', '.yarnrc.yml'].join('\n')), - ].join('-') + (canary ? '-canary' : '') - - const distKey = [ - dependenciesKey, - distKeyPrefix, - 'dist', - await hashFiles([ - 'package.json', - 'babel.config.js', - 'tsconfig.json', - 'tsconfig.compilerOption.json', - 'nx.json', - 'lerna.json', - 'packages', - ].join('\n')) - ].join('-') + (canary ? '-canary' : '') + const dependenciesKey = + [ + baseKey, + 'dependencies', + await hashFiles(['yarn.lock', '.yarnrc.yml'].join('\n')), + ].join('-') + (canary ? '-canary' : '') + + const distKey = + [ + dependenciesKey, + distKeyPrefix, + 'dist', + await hashFiles( + [ + 'package.json', + 'babel.config.js', + 'tsconfig.json', + 'tsconfig.compilerOption.json', + 'nx.json', + 'lerna.json', + 'packages', + ].join('\n'), + ), + ].join('-') + (canary ? '-canary' : '') return { baseKey, dependenciesKey, - distKey + distKey, } } @@ -119,7 +129,7 @@ export async function setUpRscTestProject( testProjectPath, fixtureName, core, - execInProject + execInProject, ) { core.setOutput('test-project-path', testProjectPath) @@ -129,15 +139,15 @@ export async function setUpRscTestProject( const fixturePath = path.join( REDWOOD_FRAMEWORK_PATH, '__fixtures__', - fixtureName + fixtureName, ) const rwBinPath = path.join( REDWOOD_FRAMEWORK_PATH, - 'packages/cli/dist/index.js' + 'packages/cli/dist/index.js', ) const rwfwBinPath = path.join( REDWOOD_FRAMEWORK_PATH, - 'packages/cli/dist/rwfw.js' + 'packages/cli/dist/rwfw.js', ) console.log(`Creating project at ${testProjectPath}`) diff --git a/.github/actions/check_changesets/check_changesets.mjs b/.github/actions/check_changesets/check_changesets.mjs index 334b23bf9455..07c7418e1466 100644 --- a/.github/actions/check_changesets/check_changesets.mjs +++ b/.github/actions/check_changesets/check_changesets.mjs @@ -5,7 +5,9 @@ import github from '@actions/github' async function main() { // If the PR has the "changesets-ok" label, just pass. const { labels } = JSON.parse(getInput('labels')) - const hasChangesetsOkLabel = labels.some((label) => label.name === 'changesets-ok') + const hasChangesetsOkLabel = labels.some( + (label) => label.name === 'changesets-ok', + ) if (hasChangesetsOkLabel) { console.log('Skipping check because of the "changesets-ok" label') return @@ -21,17 +23,18 @@ async function main() { // Check if the PR adds a changeset. await exec('git fetch origin main', [], { silent: true }) - const { stdout } = await getExecOutput('git diff origin/main --name-only', [], { silent: true }) + const { stdout } = await getExecOutput( + 'git diff origin/main --name-only', + [], + { silent: true }, + ) const changedFiles = stdout.toString().trim().split('\n').filter(Boolean) - const addedChangeset = changedFiles.some((file) => file.startsWith('.changesets/')) + const addedChangeset = changedFiles.some((file) => + file.startsWith('.changesets/'), + ) if (addedChangeset) { // Empty space here (and in subsequent `console.log`s) for formatting in the action. - console.log( - [ - '', - "Added a changeset", - ].join('\n') - ) + console.log(['', 'Added a changeset'].join('\n')) return } @@ -46,7 +49,7 @@ async function main() { 'If this is a user-facing PR (a feature or a fix), it should probably have a changeset.', `Run \`yarn changesets ${pr.number}\` to create a changeset for this PR.`, "If it doesn't need one (it's a chore), you can add the 'changesets-ok' label.", - ].join('\n') + ].join('\n'), ) process.exitCode = 1 diff --git a/.github/actions/check_create_redwood_app/check_create_redwood_app.mjs b/.github/actions/check_create_redwood_app/check_create_redwood_app.mjs index 130121c41a2a..0fd39fff6d54 100644 --- a/.github/actions/check_create_redwood_app/check_create_redwood_app.mjs +++ b/.github/actions/check_create_redwood_app/check_create_redwood_app.mjs @@ -14,7 +14,7 @@ if (hasCRWA_OkLabel) { const { stdout } = await getExecOutput('git diff origin/main --name-only') const changedFiles = stdout.toString().trim().split('\n').filter(Boolean) const didRebuildJS_Template = changedFiles.some((file) => - file.startsWith('packages/create-redwood-app/templates/js') + file.startsWith('packages/create-redwood-app/templates/js'), ) if (didRebuildJS_Template) { @@ -24,17 +24,21 @@ if (hasCRWA_OkLabel) { // because git fetch origin main prints to stdout. '', "The create redwood app JS template's been rebuilt", - ].join('\n') + ].join('\n'), ) } else { // If it doesn't, does it need to be rebuilt? If not, no problem. Otherwise, throw. - const shouldRebuildJS_Template = changedFiles.some( - (file) => - file.startsWith('packages/create-redwood-app/templates/ts') + const shouldRebuildJS_Template = changedFiles.some((file) => + file.startsWith('packages/create-redwood-app/templates/ts'), ) if (!shouldRebuildJS_Template) { - console.log(['', "The create redwood app JS template doesn't need to be rebuilt"].join('\n')) + console.log( + [ + '', + "The create redwood app JS template doesn't need to be rebuilt", + ].join('\n'), + ) } else { console.log( [ @@ -46,7 +50,7 @@ if (hasCRWA_OkLabel) { ' cd packages/create-redwood-app', ' yarn ts-to-js', '', - ].join('\n') + ].join('\n'), ) process.exitCode = 1 diff --git a/.github/actions/detect-changes/README.md b/.github/actions/detect-changes/README.md index 234c211c6d76..3ec4d8aea297 100644 --- a/.github/actions/detect-changes/README.md +++ b/.github/actions/detect-changes/README.md @@ -1,6 +1,7 @@ You can run this script locally to debug/verify Make sure you have a GITHUB_TOKEN or REDWOOD_GITHUB_TOKEN env var set, and then run this command: + ``` GITHUB_REF=refs/pull/6919/merge GITHUB_BASE_REF=main node .github/actions/detect-changes/detectChanges.mjs ``` diff --git a/.github/actions/detect-changes/cases/rsc.mjs b/.github/actions/detect-changes/cases/rsc.mjs index 796f3e7f6eb8..15bf5c117877 100644 --- a/.github/actions/detect-changes/cases/rsc.mjs +++ b/.github/actions/detect-changes/cases/rsc.mjs @@ -4,7 +4,7 @@ * @param {string[]} changedFiles The list of files which git has listed as changed * @returns {boolean} True if there are changes, false if not */ -export function rscChanged(changedFiles){ +export function rscChanged(changedFiles) { for (const changedFile of changedFiles) { // As the RSC implementation changes, this list will need to be updated. // Also, I could be much more specific here, but then I'd also have to @@ -15,7 +15,9 @@ export function rscChanged(changedFiles){ changedFile.startsWith('tasks/smoke-tests/rsa/') || changedFile.startsWith('tasks/smoke-tests/basePlaywright.config.ts') || changedFile.startsWith('.github/actions/set-up-rsa-project/') || - changedFile.startsWith('.github/actions/set-up-rsc-kitchen-sink-project/') || + changedFile.startsWith( + '.github/actions/set-up-rsc-kitchen-sink-project/', + ) || changedFile.startsWith('.github/actions/set-up-rsc-project/') || changedFile.startsWith('packages/internal/') || changedFile.startsWith('packages/project-config/') || diff --git a/.github/actions/detect-changes/cases/ssr.mjs b/.github/actions/detect-changes/cases/ssr.mjs index c3d05e7296cb..8bc6506f4465 100644 --- a/.github/actions/detect-changes/cases/ssr.mjs +++ b/.github/actions/detect-changes/cases/ssr.mjs @@ -4,7 +4,7 @@ * @param {string[]} changedFiles The list of files which git has listed as changed * @returns {boolean} True if there are changes, false if not */ -export function ssrChanged(changedFiles){ +export function ssrChanged(changedFiles) { for (const changedFile of changedFiles) { if ( changedFile.startsWith('tasks/smoke-tests/streaming-ssr') || diff --git a/.github/actions/require-milestone/requireMilestone.mjs b/.github/actions/require-milestone/requireMilestone.mjs index 3c6b76b3dfe9..f1bcb6e4da60 100644 --- a/.github/actions/require-milestone/requireMilestone.mjs +++ b/.github/actions/require-milestone/requireMilestone.mjs @@ -9,9 +9,7 @@ function main() { const event = fs.readFileSync(process.env.GITHUB_EVENT_PATH, 'utf-8') const { - pull_request: { - milestone - } + pull_request: { milestone }, } = JSON.parse(event) if (milestone) { @@ -20,16 +18,18 @@ function main() { process.exitCode = 1 - console.error([ - "A pull request must have a milestone that indicates where it's supposed to be released:", - '', - "- next-release -- the PR should be released in the next minor (it's a feature)", - "- next-release-patch -- the PR should be released in the next patch (it's a bug fix or project-side chore)", - "- v7.0.0 -- the PR should be released in v7.0.0 (it's breaking or builds off a breaking PR)", - "- chore -- the PR is a framework-side chore (changes CI, tasks, etc.) and it isn't released, per se", - '', - `(If you're still not sure, go with "next-release".)` - ].join('\n')) + console.error( + [ + "A pull request must have a milestone that indicates where it's supposed to be released:", + '', + "- next-release -- the PR should be released in the next minor (it's a feature)", + "- next-release-patch -- the PR should be released in the next patch (it's a bug fix or project-side chore)", + "- v7.0.0 -- the PR should be released in v7.0.0 (it's breaking or builds off a breaking PR)", + "- chore -- the PR is a framework-side chore (changes CI, tasks, etc.) and it isn't released, per se", + '', + `(If you're still not sure, go with "next-release".)`, + ].join('\n'), + ) } main() diff --git a/.github/actions/set-up-rsa-project/jsconfig.json b/.github/actions/set-up-rsa-project/jsconfig.json index 8effcfaa09ef..dc34d6dedca3 100644 --- a/.github/actions/set-up-rsa-project/jsconfig.json +++ b/.github/actions/set-up-rsa-project/jsconfig.json @@ -7,5 +7,5 @@ "moduleResolution": "node", "skipLibCheck": false, "jsx": "react-jsx" - }, + } } diff --git a/.github/actions/set-up-rsa-project/setUpRsaProjectGitHub.mjs b/.github/actions/set-up-rsa-project/setUpRsaProjectGitHub.mjs index 497d82e4c9bf..7657af8f9b8d 100644 --- a/.github/actions/set-up-rsa-project/setUpRsaProjectGitHub.mjs +++ b/.github/actions/set-up-rsa-project/setUpRsaProjectGitHub.mjs @@ -10,7 +10,7 @@ import { createExecWithEnvInCwd, setUpRscTestProject } from '../actionsLib.mjs' const testProjectAndFixtureName = 'test-project-rsa' const testProjectPath = path.join( path.dirname(process.cwd()), - testProjectAndFixtureName + testProjectAndFixtureName, ) const execInProject = createExecWithEnvInCwd(testProjectPath) @@ -18,5 +18,5 @@ setUpRscTestProject( testProjectPath, testProjectAndFixtureName, core, - execInProject + execInProject, ) diff --git a/.github/actions/set-up-rsa-project/setUpRsaProjectLocally.mjs b/.github/actions/set-up-rsa-project/setUpRsaProjectLocally.mjs index 8e9baa044594..8a738887fb56 100644 --- a/.github/actions/set-up-rsa-project/setUpRsaProjectLocally.mjs +++ b/.github/actions/set-up-rsa-project/setUpRsaProjectLocally.mjs @@ -78,7 +78,7 @@ const testProjectPath = path.join( 'redwood', testProjectAndFixtureName, // ":" is problematic with paths - new Date().toISOString().split(':').join('-') + new Date().toISOString().split(':').join('-'), ) // Mock for @actions/core @@ -99,7 +99,7 @@ function execInProject(commandLine, options) { return exec( commandLine, undefined, - getExecaOptions(testProjectPath, options?.env) + getExecaOptions(testProjectPath, options?.env), ) } @@ -107,5 +107,5 @@ setUpRscTestProject( testProjectPath, testProjectAndFixtureName, core, - execInProject + execInProject, ) diff --git a/.github/actions/set-up-rsc-kitchen-sink-project/jsconfig.json b/.github/actions/set-up-rsc-kitchen-sink-project/jsconfig.json index 8effcfaa09ef..dc34d6dedca3 100644 --- a/.github/actions/set-up-rsc-kitchen-sink-project/jsconfig.json +++ b/.github/actions/set-up-rsc-kitchen-sink-project/jsconfig.json @@ -7,5 +7,5 @@ "moduleResolution": "node", "skipLibCheck": false, "jsx": "react-jsx" - }, + } } diff --git a/.github/actions/set-up-rsc-kitchen-sink-project/setUpRscKitchenSinkProjectGitHub.mjs b/.github/actions/set-up-rsc-kitchen-sink-project/setUpRscKitchenSinkProjectGitHub.mjs index 27490e9f6cf3..094e85023c98 100644 --- a/.github/actions/set-up-rsc-kitchen-sink-project/setUpRscKitchenSinkProjectGitHub.mjs +++ b/.github/actions/set-up-rsc-kitchen-sink-project/setUpRscKitchenSinkProjectGitHub.mjs @@ -10,7 +10,7 @@ import { createExecWithEnvInCwd, setUpRscTestProject } from '../actionsLib.mjs' const testProjectAndFixtureName = 'test-project-rsc-kitchen-sink' const testProjectPath = path.join( path.dirname(process.cwd()), - testProjectAndFixtureName + testProjectAndFixtureName, ) const execInProject = createExecWithEnvInCwd(testProjectPath) @@ -18,5 +18,5 @@ setUpRscTestProject( testProjectPath, testProjectAndFixtureName, core, - execInProject + execInProject, ) diff --git a/.github/actions/set-up-rsc-kitchen-sink-project/setUpRscKitchenSinkProjectLocally.mjs b/.github/actions/set-up-rsc-kitchen-sink-project/setUpRscKitchenSinkProjectLocally.mjs index 41a966452833..38128b8badfd 100644 --- a/.github/actions/set-up-rsc-kitchen-sink-project/setUpRscKitchenSinkProjectLocally.mjs +++ b/.github/actions/set-up-rsc-kitchen-sink-project/setUpRscKitchenSinkProjectLocally.mjs @@ -78,7 +78,7 @@ const testProjectPath = path.join( 'redwood', testProjectAndFixtureName, // ":" is problematic with paths - new Date().toISOString().split(':').join('-') + new Date().toISOString().split(':').join('-'), ) // Mock for @actions/core @@ -99,7 +99,7 @@ function execInProject(commandLine, options) { return exec( commandLine, undefined, - getExecaOptions(testProjectPath, options?.env) + getExecaOptions(testProjectPath, options?.env), ) } @@ -107,5 +107,5 @@ setUpRscTestProject( testProjectPath, testProjectAndFixtureName, core, - execInProject + execInProject, ) diff --git a/.github/actions/set-up-rsc-project/jsconfig.json b/.github/actions/set-up-rsc-project/jsconfig.json index 8effcfaa09ef..dc34d6dedca3 100644 --- a/.github/actions/set-up-rsc-project/jsconfig.json +++ b/.github/actions/set-up-rsc-project/jsconfig.json @@ -7,5 +7,5 @@ "moduleResolution": "node", "skipLibCheck": false, "jsx": "react-jsx" - }, + } } diff --git a/.github/actions/set-up-rsc-project/setUpRscProject.mjs b/.github/actions/set-up-rsc-project/setUpRscProject.mjs index 6c2ec2f7cc17..76c247a8b5d1 100644 --- a/.github/actions/set-up-rsc-project/setUpRscProject.mjs +++ b/.github/actions/set-up-rsc-project/setUpRscProject.mjs @@ -36,22 +36,13 @@ import { REDWOOD_FRAMEWORK_PATH } from '../actionsLib.mjs' * @param {ExecInProject} execInProject * @returns {Promise} */ -export async function main( - rscProjectPath, - core, - exec, - execInProject -) { +export async function main(rscProjectPath, core, exec, execInProject) { core.setOutput('rsc-project-path', rscProjectPath) console.log('rwPath', REDWOOD_FRAMEWORK_PATH) console.log('rscProjectPath', rscProjectPath) - await setUpRscProject( - rscProjectPath, - exec, - execInProject, - ) + await setUpRscProject(rscProjectPath, exec, execInProject) } /** @@ -60,14 +51,10 @@ export async function main( * @param {ExecInProject} execInProject * @returns {Promise} */ -async function setUpRscProject( - rscProjectPath, - exec, - execInProject, -) { +async function setUpRscProject(rscProjectPath, exec, execInProject) { const rwBinPath = path.join( REDWOOD_FRAMEWORK_PATH, - 'packages/cli/dist/index.js' + 'packages/cli/dist/index.js', ) console.log(`Creating project at ${rscProjectPath}`) diff --git a/.github/actions/set-up-rsc-project/setUpRscProjectLocally.mjs b/.github/actions/set-up-rsc-project/setUpRscProjectLocally.mjs index c5c57ab2b31f..0ad4881ca2ce 100644 --- a/.github/actions/set-up-rsc-project/setUpRscProjectLocally.mjs +++ b/.github/actions/set-up-rsc-project/setUpRscProjectLocally.mjs @@ -75,7 +75,7 @@ const rscProjectPath = path.join( os.tmpdir(), 'redwood-rsc-project', // ":" is problematic with paths - new Date().toISOString().split(':').join('-') + new Date().toISOString().split(':').join('-'), ) // Mock for @actions/core @@ -96,7 +96,7 @@ function execInProject(commandLine, options) { return exec( commandLine, undefined, - getExecaOptions(rscProjectPath, options?.env) + getExecaOptions(rscProjectPath, options?.env), ) } diff --git a/.github/actions/set-up-test-project/action.yaml b/.github/actions/set-up-test-project/action.yaml index 78afea244e22..7c3528987a56 100644 --- a/.github/actions/set-up-test-project/action.yaml +++ b/.github/actions/set-up-test-project/action.yaml @@ -8,7 +8,7 @@ runs: inputs: canary: description: Upgrade the project to canary? - default: "false" + default: 'false' outputs: test-project-path: diff --git a/.github/actions/set-up-test-project/setUpTestProject.mjs b/.github/actions/set-up-test-project/setUpTestProject.mjs index eb6cbb55e3a1..5075ed383d64 100644 --- a/.github/actions/set-up-test-project/setUpTestProject.mjs +++ b/.github/actions/set-up-test-project/setUpTestProject.mjs @@ -13,16 +13,13 @@ import { REDWOOD_FRAMEWORK_PATH, } from '../actionsLib.mjs' -const TEST_PROJECT_PATH = path.join( - path.dirname(process.cwd()), - 'test-project' -) +const TEST_PROJECT_PATH = path.join(path.dirname(process.cwd()), 'test-project') core.setOutput('test-project-path', TEST_PROJECT_PATH) const canary = core.getInput('canary') === 'true' console.log({ - canary + canary, }) console.log() @@ -32,7 +29,7 @@ console.log() */ async function main() { await setUpTestProject({ - canary: true + canary: true, }) } @@ -44,14 +41,16 @@ async function setUpTestProject({ canary }) { const TEST_PROJECT_FIXTURE_PATH = path.join( REDWOOD_FRAMEWORK_PATH, '__fixtures__', - 'test-project' + 'test-project', ) console.log(`Creating project at ${TEST_PROJECT_PATH}`) console.log() await fs.copy(TEST_PROJECT_FIXTURE_PATH, TEST_PROJECT_PATH) - await execInFramework('yarn project:tarsync --verbose', { env: { RWJS_CWD: TEST_PROJECT_PATH } }) + await execInFramework('yarn project:tarsync --verbose', { + env: { RWJS_CWD: TEST_PROJECT_PATH }, + }) if (canary) { console.log(`Upgrading project to canary`) @@ -69,20 +68,17 @@ const execInProject = createExecWithEnvInCwd(TEST_PROJECT_PATH) */ async function sharedTasks() { console.log('Generating dbAuth secret') - const { stdout } = await execInProject( - 'yarn rw g secret --raw', - { silent: true } - ) + const { stdout } = await execInProject('yarn rw g secret --raw', { + silent: true, + }) fs.appendFileSync( path.join(TEST_PROJECT_PATH, '.env'), - `SESSION_SECRET='${stdout}'` + `SESSION_SECRET='${stdout}'`, ) console.log() console.log('Running prisma migrate reset') - await execInProject( - 'yarn rw prisma migrate reset --force', - ) + await execInProject('yarn rw prisma migrate reset --force') } main() diff --git a/.github/actions/telemetry_check/check.mjs b/.github/actions/telemetry_check/check.mjs index 54e34c79b54a..4191dad81b49 100644 --- a/.github/actions/telemetry_check/check.mjs +++ b/.github/actions/telemetry_check/check.mjs @@ -6,7 +6,7 @@ import path from 'path' import { exec } from '@actions/exec' console.log( - `Telemetry is being redirected to ${process.env.REDWOOD_REDIRECT_TELEMETRY}` + `Telemetry is being redirected to ${process.env.REDWOOD_REDIRECT_TELEMETRY}`, ) // Setup fake telemetry server @@ -37,23 +37,21 @@ try { switch (mode) { case 'crwa': exitCode = await exec( - `yarn node ./packages/create-redwood-app/dist/create-redwood-app.js ../project-for-telemetry --typescript true --git false --no-yarn-install` + `yarn node ./packages/create-redwood-app/dist/create-redwood-app.js ../project-for-telemetry --typescript true --git false --no-yarn-install`, ) if (exitCode) { process.exit(1) } break case 'cli': - exitCode = await exec( - `yarn install`, null, { - cwd: path.join(process.cwd(), '../project-for-telemetry') - } - ) + exitCode = await exec(`yarn install`, null, { + cwd: path.join(process.cwd(), '../project-for-telemetry'), + }) if (exitCode) { process.exit(1) } exitCode = await exec( - `yarn --cwd ../project-for-telemetry node ../redwood/packages/cli/dist/index.js info` + `yarn --cwd ../project-for-telemetry node ../redwood/packages/cli/dist/index.js info`, ) if (exitCode) { process.exit(1) diff --git a/.github/scripts/publish_canary.sh b/.github/scripts/publish_canary.sh index 3ed23efcc4fd..321113d1d8fe 100755 --- a/.github/scripts/publish_canary.sh +++ b/.github/scripts/publish_canary.sh @@ -33,14 +33,14 @@ args+=( # final number that lerna will use when publishing the canary packages. echo 'n' \ | yarn lerna publish "${args[@]}" 2>&1 \ - > publish_output + > publish_output cat publish_output \ | grep '\-canary\.' \ | tail -n 1 \ | sed 's/.*=> //' \ | sed 's/\+.*//' \ | awk -F. '{ $NF = $NF + 1 } 1' OFS=. \ - > canary_version + > canary_version if [ ! -s canary_version ]; then echo "The canary_version file is empty or does not exist." @@ -82,8 +82,8 @@ ws="$(yarn workspaces list --json)" IFS=$'\n' for line in $ws; do location=$( - echo "$line" | - jq -r '.location' + echo "$line" \ + | jq -r '.location' ) relative_pkg_json_path="$location/package.json" @@ -101,7 +101,7 @@ for line in $ws; do printf "Processing:\t%s\n" "$relative_pkg_json_path" sed "s/workspace:\*/$(cat canary_version)/g" "$pkg_json_path" > tmpfile \ - && mv tmpfile "$pkg_json_path" + && mv tmpfile "$pkg_json_path" done # Commit the changes diff --git a/.github/workflows/check-changelog.yml b/.github/workflows/check-changelog.yml index d854c06298c5..af5be4a6b56d 100644 --- a/.github/workflows/check-changelog.yml +++ b/.github/workflows/check-changelog.yml @@ -2,7 +2,16 @@ name: 📝 Check changesets on: pull_request: - types: [opened, synchronize, reopened, labeled, unlabeled, milestoned, demilestoned] + types: + [ + opened, + synchronize, + reopened, + labeled, + unlabeled, + milestoned, + demilestoned, + ] # Cancel in-progress runs of this workflow. # See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#example-only-cancel-in-progress-jobs-or-runs-for-the-current-workflow. diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 579637f5f3cd..266936d63bae 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -52,11 +52,11 @@ jobs: uses: ./.github/actions/set-up-job with: set-up-yarn-cache: false - yarn-install-directory: ./tasks/check + yarn-install-directory: . build: false - name: ✅ Check constraints, dependencies, and package.json's - uses: ./tasks/check + run: yarn check check-skip: needs: detect-changes @@ -166,7 +166,7 @@ jobs: wait-on: 'http://[::1]:8910' working-directory: ./tasks/e2e spec: | - cypress/e2e/01-tutorial/*.cy.js + cypress/e2e/01-tutorial/*.cy.js - uses: actions/upload-artifact@v4 if: always() @@ -505,7 +505,7 @@ jobs: runs-on: ${{ matrix.os }} env: - REDWOOD_REDIRECT_TELEMETRY: "http://127.0.0.1:48619" # Random port + REDWOOD_REDIRECT_TELEMETRY: 'http://127.0.0.1:48619' # Random port steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 2af57bf1c982..6f575dc9468e 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -13,10 +13,10 @@ name: 🔒 CodeQL on: push: - branches: [ main ] + branches: [main] pull_request: # The branches below must be a subset of the branches above - branches: [ main ] + branches: [main] schedule: - cron: '42 5 * * 3' @@ -34,41 +34,41 @@ jobs: strategy: fail-fast: false matrix: - language: [ 'javascript' ] + language: ['javascript'] # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] # Learn more: # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed steps: - - name: Checkout repository - uses: actions/checkout@v4 + - name: Checkout repository + uses: actions/checkout@v4 - # Initializes the CodeQL tools for scanning. - - name: Initialize CodeQL - uses: github/codeql-action/init@v3 - with: - languages: ${{ matrix.language }} - config-file: ./.github/codeql/codeql-config.yml - # If you wish to specify custom queries, you can do so here or in a config file. - # By default, queries listed here will override any specified in a config file. - # Prefix the list here with "+" to use these queries and those in the config file. - # queries: ./path/to/local/query, your-org/your-repo/queries@main + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v3 + with: + languages: ${{ matrix.language }} + config-file: ./.github/codeql/codeql-config.yml + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + # queries: ./path/to/local/query, your-org/your-repo/queries@main - # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). - # If this step fails, then you should remove it and run the build manually (see below) - - name: Autobuild - uses: github/codeql-action/autobuild@v3 + # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). + # If this step fails, then you should remove it and run the build manually (see below) + - name: Autobuild + uses: github/codeql-action/autobuild@v3 - # ℹ️ Command-line programs to run using the OS shell. - # 📚 https://git.io/JvXDl + # ℹ️ Command-line programs to run using the OS shell. + # 📚 https://git.io/JvXDl - # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines - # and modify them (or add more) to build your code if your project - # uses a compiled language + # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines + # and modify them (or add more) to build your code if your project + # uses a compiled language - #- run: | - # make bootstrap - # make release + #- run: | + # make bootstrap + # make release - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v3 + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v3 diff --git a/.github/workflows/publish-canary.yml b/.github/workflows/publish-canary.yml index e4d5d968e260..d0775673329a 100644 --- a/.github/workflows/publish-canary.yml +++ b/.github/workflows/publish-canary.yml @@ -62,7 +62,7 @@ jobs: - name: 💬 Message Slack uses: ./.github/actions/message_slack_publishing with: - title: "🦜 Canary Packages" + title: '🦜 Canary Packages' status: ${{ needs.publish-canary.result }} version: ${{ needs.publish-canary.outputs.version }} slack-webhook-url: ${{ secrets.SLACK_WEBHOOK_URL_PACKAGE_PUBLISHING }} diff --git a/.github/workflows/publish-release-candidate.yml b/.github/workflows/publish-release-candidate.yml index 1b34beff9346..85d785fab0f8 100644 --- a/.github/workflows/publish-release-candidate.yml +++ b/.github/workflows/publish-release-candidate.yml @@ -107,7 +107,7 @@ jobs: - name: 💬 Message Slack uses: ./.github/actions/message_slack_publishing with: - title: "🏎 RC Packages" + title: '🏎 RC Packages' status: ${{ needs.publish-release-candidate.result }} version: ${{ needs.publish-release-candidate.outputs.version }} slack-webhook-url: ${{ secrets.SLACK_WEBHOOK_URL_PACKAGE_PUBLISHING }} diff --git a/.github/workflows/require-release-label.yml b/.github/workflows/require-release-label.yml index 6986f5239ba4..73b1624e8b03 100644 --- a/.github/workflows/require-release-label.yml +++ b/.github/workflows/require-release-label.yml @@ -19,4 +19,4 @@ jobs: with: mode: exactly count: 1 - labels: "release:docs, release:chore, release:experimental-breaking, release:fix, release:feature, release:breaking, release:dependency" + labels: 'release:docs, release:chore, release:experimental-breaking, release:fix, release:feature, release:breaking, release:dependency' diff --git a/.prettierignore b/.prettierignore index 27e9f9c57db3..e915df037993 100644 --- a/.prettierignore +++ b/.prettierignore @@ -2,27 +2,26 @@ **/dist # Ignore fixture projects -__fixtures__ +/__fixtures__ -# Ignore the docs (docusaurus) project -docs/ +# Ignore the certain files in /docs +/docs/.docusaurus +/docs/build +/docs/versioned_docs +/docs/versioned_sidebars # Ignore the .nx directory /.nx # Ignore create-redwood-app (we don't want to mismatch between framework and project) -packages/create-redwood-app +/packages/create-redwood-app/templates +/packages/create-redwood-app/tests/**/*.sh # Ignore create-redwood-rsc-app (it has it's own config) -packages/create-redwood-rsc-app +/packages/create-redwood-rsc-app # TODO(jgmw): Is this too broad? # Ignore test fixtures **/__testfixtures__ **/__tests__/fixtures - -# TODO(jgmw): Re-enable these in managable chunks -tasks -.github -.changesets -packages/create-redwood-app/tests/e2e_prompts* +**/__tests__/__fixtures__ diff --git a/.prettierrc.json b/.prettierrc.json deleted file mode 100644 index ef04338a6774..000000000000 --- a/.prettierrc.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "$schema": "http://json.schemastore.org/prettierrc", - "bracketSpacing": true, - "tabWidth": 2, - "semi": false, - "singleQuote": true, - "plugins": [ - "prettier-plugin-curly", - "prettier-plugin-sh", - "prettier-plugin-packagejson" - ] -} diff --git a/README.md b/README.md index 295271c7656d..9071e2d02fd6 100644 --- a/README.md +++ b/README.md @@ -169,13 +169,10 @@ _A gigantic "Thank YOU!" to everyone below who has contributed to one or more Re - - + - - - +

David Thyresson

maintainer

Daniel Choudhury

maintainer

Kris Coulson

maintainer

Daniel Choudhury

maintainer

Keith T Elliot

community

Barrett Burnworth

community

Josh Walker

maintainer

Josh GM Walker

maintainer
@@ -214,6 +211,9 @@ _A gigantic "Thank YOU!" to everyone below who has contributed to one or more Re
Kim-Adeline Miguel


Dominic Saadi

+ +
Kris Coulson

+ diff --git a/__fixtures__/test-project/scripts/one/two/myNestedScript.ts b/__fixtures__/test-project/scripts/one/two/myNestedScript.ts new file mode 100644 index 000000000000..d8e6c4138eed --- /dev/null +++ b/__fixtures__/test-project/scripts/one/two/myNestedScript.ts @@ -0,0 +1,3 @@ +export default async () => { + console.log('Hello from myNestedScript.ts') +} diff --git a/__fixtures__/test-project/web/src/Redwood.stories.mdx b/__fixtures__/test-project/web/src/Redwood.stories.mdx index 4481bff2fdc9..d0ef9e47cfcb 100644 --- a/__fixtures__/test-project/web/src/Redwood.stories.mdx +++ b/__fixtures__/test-project/web/src/Redwood.stories.mdx @@ -3,7 +3,10 @@ import { Meta } from '@storybook/addon-docs'

- +

Redwood

diff --git a/constraints.pro b/constraints.pro deleted file mode 100644 index 463749739678..000000000000 --- a/constraints.pro +++ /dev/null @@ -1,27 +0,0 @@ -% Yarn Constraints https://yarnpkg.com/features/constraints -% check with "yarn constraints" (fix w/ "yarn constraints --fix") -% reference for other constraints: https://github.com/babel/babel/blob/main/constraints.pro - -% Enforces that a dependency doesn't appear in both `dependencies` and `devDependencies` -gen_enforced_dependency(WorkspaceCwd, DependencyIdent, null, 'devDependencies') :- - workspace_has_dependency(WorkspaceCwd, DependencyIdent, _, 'devDependencies'), - workspace_has_dependency(WorkspaceCwd, DependencyIdent, _, 'dependencies'). - -% Prevent two workspaces from depending on conflicting versions of a same dependency -gen_enforced_dependency(WorkspaceCwd, DependencyIdent, DependencyRange2, DependencyType) :- - workspace_has_dependency(WorkspaceCwd, DependencyIdent, DependencyRange, DependencyType), - workspace_has_dependency(OtherWorkspaceCwd, DependencyIdent, DependencyRange2, DependencyType2), - DependencyRange \= DependencyRange2. - -% Enforce that all workspaces building with Babel depend on '@babel/runtime-corejs3' and 'core-js'. -gen_enforced_dependency(WorkspaceCwd, DependencyIdent, DependencyRange, 'dependencies') :- - member(DependencyIdent, [ - '@babel/runtime-corejs3', - 'core-js' - ]), - % Exclude the root workspace - WorkspaceCwd \= '.', - % Only target workspaces with a build:js script - workspace_field(WorkspaceCwd, 'scripts.build:js', _), - % Get the range from the root workspace - workspace_has_dependency('.', DependencyIdent, DependencyRange, _). diff --git a/crowdin.yml b/crowdin.yml deleted file mode 100644 index 6cbb752d4ee3..000000000000 --- a/crowdin.yml +++ /dev/null @@ -1,5 +0,0 @@ -files: - - source: /learn.redwoodjs.com/docs/tutorial - translation: /learn.redwoodjs.com/i18n/%two_letters_code%/tutorial/%original_file_name% - - source: /learn.redwoodjs.com/docs/tutorial2 - translation: /learn.redwoodjs.com/i18n/%two_letters_code%/tutorial2/%original_file_name% diff --git a/docs/README.md b/docs/README.md index 7f694bc3c9f8..8c47a8c4e6bc 100644 --- a/docs/README.md +++ b/docs/README.md @@ -20,7 +20,7 @@ After running `yarn start`, you should be able to see your changes in the local #### Internal linking -For links to other docs inside the `tutorials` directory you need to use *relative* links. +For links to other docs inside the `tutorials` directory you need to use _relative_ links. ``` In [previous section](./first-page) we.... @@ -35,6 +35,7 @@ Fork the repo, make your changes and open a PR on GitHub. That will build and la Double check that your changes look good! ### Updating Doc Images + To update any images in the doc, first upload your screenshot into a comment textbox in your PR. Once it's uploaded, you can open the image in a new tab and use the github url as a image link in your docs. ## Contributors diff --git a/docs/docs/app-configuration-redwood-toml.md b/docs/docs/app-configuration-redwood-toml.md index 214a17d0c481..afb3abbdd613 100644 --- a/docs/docs/app-configuration-redwood-toml.md +++ b/docs/docs/app-configuration-redwood-toml.md @@ -28,17 +28,17 @@ For certain options, instead of having to configure build tools directly, there' ## [web] -| Key | Description | Default | -| :---------------------------- | :--------------------------------------------------------- | :---------------------- | -| `title` | Title of your Redwood app | `'Redwood App'` | -| `port` | Port for the web server to listen at | `8910` | -| `apiUrl` | URL to your api server. This can be a relative URL in which case it acts like a proxy, or a fully-qualified URL | `'/.redwood/functions'` | -| `includeEnvironmentVariables` | Environment variables made available to the web side during dev and build | `[]` | -| `host` | Hostname for the web server to listen at | Defaults to `'0.0.0.0'` in production and `'::'` in development | -| `apiGraphQLUrl` | URL to your GraphQL function | `'${apiUrl}/graphql'` | -| `apiDbAuthUrl` | URL to your dbAuth function | `'${apiUrl}/auth'` | -| `sourceMap` | Enable source maps for production builds | `false` | -| `a11y` | Enable storybook `addon-a11y` and `eslint-plugin-jsx-a11y` | `true` | +| Key | Description | Default | +| :---------------------------- | :-------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------- | +| `title` | Title of your Redwood app | `'Redwood App'` | +| `port` | Port for the web server to listen at | `8910` | +| `apiUrl` | URL to your api server. This can be a relative URL in which case it acts like a proxy, or a fully-qualified URL | `'/.redwood/functions'` | +| `includeEnvironmentVariables` | Environment variables made available to the web side during dev and build | `[]` | +| `host` | Hostname for the web server to listen at | Defaults to `'0.0.0.0'` in production and `'::'` in development | +| `apiGraphQLUrl` | URL to your GraphQL function | `'${apiUrl}/graphql'` | +| `apiDbAuthUrl` | URL to your dbAuth function | `'${apiUrl}/auth'` | +| `sourceMap` | Enable source maps for production builds | `false` | +| `a11y` | Enable storybook `addon-a11y` and `eslint-plugin-jsx-a11y` | `true` | ### Customizing the GraphQL Endpoint @@ -105,22 +105,20 @@ Don't make secrets available to your web side. Everything in `includeEnvironment ## [api] -| Key | Description | Default | -| :------------- | :---------------------------------- | :------------------------- | -| `port` | Port for the api server to listen at | `8911` | -| `host` | Hostname for the api server to listen at | Defaults to `'0.0.0.0'` in production and `'::'` in development | -| `schemaPath` | The location of your Prisma schema. If you have [enabled Prisma multi file schemas](https://www.prisma.io/docs/orm/prisma-schema/overview/location#multi-file-prisma-schema), then its value is the directory where your `schema.prisma` can be found, for example: `'./api/db/schema'` | Defaults to `'./api/db/schema.prisma'` | -| `debugPort` | Port for the debugger to listen at | `18911` | - +| Key | Description | Default | +| :----------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------- | +| `port` | Port for the api server to listen at | `8911` | +| `host` | Hostname for the api server to listen at | Defaults to `'0.0.0.0'` in production and `'::'` in development | +| `schemaPath` | The location of your Prisma schema. If you have [enabled Prisma multi file schemas](https://www.prisma.io/docs/orm/prisma-schema/overview/location#multi-file-prisma-schema), then its value is the directory where your `schema.prisma` can be found, for example: `'./api/db/schema'` | Defaults to `'./api/db/schema.prisma'` | +| `debugPort` | Port for the debugger to listen at | `18911` | Additional server configuration can be done using [Server File](docker.md#using-the-server-file) - ### Multi File Schema -Prisma's `prismaSchemaFolder` [feature](https://www.prisma.io/docs/orm/prisma-schema/overview/location#multi-file-prisma-schema) allows you to define multiple files in a schema subdirectory of your prisma directory. +Prisma's `prismaSchemaFolder` [feature](https://www.prisma.io/docs/orm/prisma-schema/overview/location#multi-file-prisma-schema) allows you to define multiple files in a schema subdirectory of your prisma directory. -:::note Important +:::note Important If you wish to [organize your Prisma Schema into multiple files](https://www.prisma.io/blog/organize-your-prisma-schema-with-multi-file-support), you will need [enable](https://www.prisma.io/docs/orm/prisma-schema/overview/location#multi-file-prisma-schema) that feature in Prisma, move your `schema.prisma` file into a new directory such as `./api/db/schema` and then set `schemaPath` in the api toml config. ::: @@ -128,7 +126,7 @@ For example: ```toml title="redwood.toml" [api] - port = 8911 + port = 8911 schemaPath = "./api/db/schema" ``` diff --git a/docs/docs/assets-and-files.md b/docs/docs/assets-and-files.md index 785f92861ef5..2cdcf544242c 100644 --- a/docs/docs/assets-and-files.md +++ b/docs/docs/assets-and-files.md @@ -144,8 +144,8 @@ export const CarIcon = (props: SVGProps) => { If you needed to convert a whole library of SVGs into stylable (or animatable!) components, one easy way would be to use the [SVGR cli](https://react-svgr.com/docs/cli/) - ## Custom fonts + There are many different ways to peel this potato – it's all a search away – but if you're using the CSS `@font-face` rule, we have a quick tip for you: 1. Place your fonts in the public folder, so it gets carried across @@ -154,15 +154,15 @@ There are many different ways to peel this potato – it's all a search away – ```shell web/ ├── src - ├── App.tsx - ├── entry.client.tsx - ├── index.css - ├── ... +├── App.tsx +├── entry.client.tsx +├── index.css +├── ... ├── public -│ ├── favicon.png -│ ├── fonts +│ ├── favicon.png +│ ├── fonts // highlight-next-line -│ │ └── RedwoodNeue.woff2 +│ │ └── RedwoodNeue.woff2 ``` ```css diff --git a/docs/docs/auth/azure.md b/docs/docs/auth/azure.md index cf46c4d44f88..61477529fcb6 100644 --- a/docs/docs/auth/azure.md +++ b/docs/docs/auth/azure.md @@ -94,9 +94,7 @@ const HomePage = () => { {/* MetaTags, h1, paragraphs, etc. */}

{JSON.stringify({ isAuthenticated })}

- + ) } @@ -155,7 +153,7 @@ AZURE_ACTIVE_DIRECTORY_KNOWN_AUTHORITY=https://rwauthtestb2c.b2clogin.com ``` And don't forget to add `AZURE_ACTIVE_DIRECTORY_KNOWN_AUTHORITY` to the `includeEnvironmentVariables` array in `redwood.toml`. -(`AZURE_ACTIVE_DIRECTORY_JWT_ISSUER` is only used on the API side. But more importantly, it's sensitive—do *not* include it in the web side.) +(`AZURE_ACTIVE_DIRECTORY_JWT_ISSUER` is only used on the API side. But more importantly, it's sensitive—do _not_ include it in the web side.) #### Update `activeDirectoryClient` instance @@ -170,7 +168,7 @@ const azureActiveDirectoryClient = new PublicClientApplication({ postLogoutRedirectUri: process.env.AZURE_ACTIVE_DIRECTORY_LOGOUT_REDIRECT_URI, // highlight-next-line - knownAuthorities: [process.env.AZURE_ACTIVE_DIRECTORY_KNOWN_AUTHORITY] + knownAuthorities: [process.env.AZURE_ACTIVE_DIRECTORY_KNOWN_AUTHORITY], }, }) ``` @@ -178,5 +176,6 @@ const azureActiveDirectoryClient = new PublicClientApplication({ Now you can call the `logIn` and `logOut` functions from `useAuth()`, and everything should just work. Here's a few more links to relevant documentation for reference: + - [Overview of tokens in Azure Active Directory B2C](https://docs.microsoft.com/en-us/azure/active-directory-b2c/tokens-overview) - [Working with MSAL.js and Azure AD B2C](https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-browser/docs/working-with-b2c.md) diff --git a/docs/docs/auth/clerk.md b/docs/docs/auth/clerk.md index 06266d0b4774..ec0f98555c50 100644 --- a/docs/docs/auth/clerk.md +++ b/docs/docs/auth/clerk.md @@ -13,7 +13,6 @@ See the [migration guide](https://github.com/redwoodjs/redwood/releases/tag/v5.3 ::: - To get started, run the setup command: ```text @@ -83,7 +82,6 @@ const HomePage = () => { Clicking sign up should open a sign-up box and after you sign up, you should see `{"isAuthenticated":true}` on the page. - ## Customizing the session token There's not a lot to the default session token. @@ -105,7 +103,7 @@ export const getCurrentUser = async ( // ... } -```` +``` ## Avoiding feature duplication diff --git a/docs/docs/auth/custom.md b/docs/docs/auth/custom.md index 65b5b801ab11..a694585d5ddf 100644 --- a/docs/docs/auth/custom.md +++ b/docs/docs/auth/custom.md @@ -71,7 +71,7 @@ We'll take all the work you have to do reading docs for granted here and cut to import { NhostClient } from '@nhost/nhost-js' const client = new NhostClient({ - backendUrl: '...' + backendUrl: '...', }) ``` @@ -105,7 +105,7 @@ import { NhostClient } from '@nhost/nhost-js' // ... const client = new NhostClient({ - backendUrl: process.env.NHOST_BACKEND_URL + backendUrl: process.env.NHOST_BACKEND_URL, }) ``` @@ -283,10 +283,16 @@ const HomePage = () => { {/* MetaTags, h1, paragraphs, etc. */}

{JSON.stringify({ isAuthenticated })}

- + ) } diff --git a/docs/docs/auth/dbauth.md b/docs/docs/auth/dbauth.md index 7bb395831159..b4207909941c 100644 --- a/docs/docs/auth/dbauth.md +++ b/docs/docs/auth/dbauth.md @@ -121,7 +121,7 @@ Almost all config for dbAuth lives in `api/src/functions/auth.js` in the object ### allowedUserFields ```javascript -allowedUserFields: ["id", "email"] +allowedUserFields: ['id', 'email'] ``` Most of the auth handlers accept a `user` argument that you can reference in the body of the function. These handlers also sometimes return that `user` object. As a security measure, `allowedUserFields` defines the only properties that will be available in that object so that sensitive data isn't accidentally leaked by these handlers to the client. @@ -223,13 +223,16 @@ If the password is valid, return `true`. Otherwise, throw the `PasswordValidatio ```javascript signup: { passwordValidation: (password) => { - if (password.length < 8) { - throw new PasswordValidationError('Password must be at least 8 characters') + throw new PasswordValidationError( + 'Password must be at least 8 characters' + ) } if (!password.match(/[A-Z]/)) { - throw new PasswordValidationError('Password must contain at least one capital letter') + throw new PasswordValidationError( + 'Password must contain at least one capital letter' + ) } return true @@ -299,13 +302,13 @@ login: { By default no setting is required. This is because each db has its own rules for enabling this feature. To enable please see the table below and pick the correct 'userMatchString' for your db of choice. -| DB | Default | usernameMatchString | notes | -|---|---|---|---| -| Postgres | 'default' | 'insensitive' | | -| MySQL | 'case-insensitive' | N/A | turned on by default so no setting required | -| MongoDB | 'default' | 'insensitive' | -| SQLite | N/A | N/A | [Not Supported] Insensitive checks can only be defined at a per column level | -| Microsoft SQL Server | 'case-insensitive' | N/A | turned on by default so no setting required | +| DB | Default | usernameMatchString | notes | +| -------------------- | ------------------ | ------------------- | ---------------------------------------------------------------------------- | +| Postgres | 'default' | 'insensitive' | | +| MySQL | 'case-insensitive' | N/A | turned on by default so no setting required | +| MongoDB | 'default' | 'insensitive' | +| SQLite | N/A | N/A | [Not Supported] Insensitive checks can only be defined at a per column level | +| Microsoft SQL Server | 'case-insensitive' | N/A | turned on by default so no setting required | ### Cookie config @@ -440,13 +443,13 @@ In both cases, actual scanning and matching of devices is handled by the operati WebAuthn is supported in the following browsers (as of July 2022): -| OS | Browser | Authenticator | -| ------- | ------- | ------------- | -| macOS | Firefox | Yubikey Security Key NFC (USB), Yubikey 5Ci, SoloKey | +| OS | Browser | Authenticator | +| ------- | ------- | -------------------------------------------------------------- | +| macOS | Firefox | Yubikey Security Key NFC (USB), Yubikey 5Ci, SoloKey | | macOS | Chrome | Touch ID, Yubikey Security Key NFC (USB), Yubikey 5Ci, SoloKey | | iOS | All | Face ID, Touch ID, Yubikey Security Key NFC (NFC), Yubikey 5Ci | -| Android | Chrome | Fingerprint Scanner, caBLE | -| Android | Firefox | Screen PIN | +| Android | Chrome | Fingerprint Scanner, caBLE | +| Android | Firefox | Screen PIN | ### Configuration @@ -528,7 +531,6 @@ import { db } from 'src/lib/db' import { DbAuthHandler } from '@redwoodjs/api' export const handler = async (event, context) => { - // assorted handler config here... const authHandler = new DbAuthHandler(event, context, { diff --git a/docs/docs/auth/firebase.md b/docs/docs/auth/firebase.md index dc4b3a5d95aa..6fa20136e3e4 100644 --- a/docs/docs/auth/firebase.md +++ b/docs/docs/auth/firebase.md @@ -59,10 +59,16 @@ const HomePage = () => { {/* MetaTags, h1, paragraphs, etc. */}

{JSON.stringify({ isAuthenticated })}

- + ) } diff --git a/docs/docs/auth/supabase.md b/docs/docs/auth/supabase.md index 5b4e19903f77..d9274e799773 100644 --- a/docs/docs/auth/supabase.md +++ b/docs/docs/auth/supabase.md @@ -1,6 +1,7 @@ --- sidebar_label: Supabase --- + # Supabase Authentication To get started, run the setup command: @@ -53,7 +54,6 @@ After you sign up, head to your inbox: there should be a confirmation email from Click the link, then head back to your app. Once you refresh the page, you should see `{"isAuthenticated":true}` on the page. - Let's make sure: if this is a brand new project, generate a home page. There we'll try to sign up by destructuring `signUp` from the `useAuth` hook (import that from `'src/auth'`). We'll also destructure and display `isAuthenticated` to see if it worked: @@ -69,10 +69,16 @@ const HomePage = () => { {/* MetaTags, h1, paragraphs, etc. */}

{JSON.stringify({ isAuthenticated })}

- + ) } @@ -126,14 +132,14 @@ Creates a new user with additional user metadata. const { signUp } = useAuth() await signUp({ -email: 'example@email.com', + email: 'example@email.com', password: 'example-password', options: { data: { first_name: 'John', age: 27, - } - } + }, + }, }) ``` @@ -145,11 +151,11 @@ Creates a new user with a redirect URL. const { signUp } = useAuth() await signUp({ -email: 'example@email.com', + email: 'example@email.com', password: 'example-password', options: { - emailRedirectTo: 'https://example.com/welcome' - } + emailRedirectTo: 'https://example.com/welcome', + }, }) ``` @@ -157,7 +163,7 @@ email: 'example@email.com', Log in an existing user with an email and password or phone and password. -* Requires either an email and password or a phone number and password. +- Requires either an email and password or a phone number and password. ```ts const { logIn } = useAuth() @@ -173,9 +179,9 @@ await logIn({ Log in a user using magiclink or a one-time password (OTP). -* Requires either an email or phone number. +- Requires either an email or phone number. -* This method is used for passwordless sign-ins where a OTP is sent to the user's email or phone number. +- This method is used for passwordless sign-ins where a OTP is sent to the user's email or phone number. ```ts const { logIn } = useAuth() @@ -184,8 +190,8 @@ await logIn({ authMethod: 'otp', email: 'example@email.com', options: { - emailRedirectTo: 'https://example.com/welcome' - } + emailRedirectTo: 'https://example.com/welcome', + }, }) ``` @@ -193,9 +199,9 @@ await logIn({ Log in an existing user via a third-party provider. -* This method is used for signing in using a third-party provider. +- This method is used for signing in using a third-party provider. -* Supabase supports many different [third-party providers](https://supabase.com/docs/guides/auth#providers). +- Supabase supports many different [third-party providers](https://supabase.com/docs/guides/auth#providers). ```ts const { logIn } = useAuth() @@ -270,10 +276,9 @@ logOut() Log in a user given a User supplied OTP received via mobile. -* The verifyOtp method takes in different verification types. If a phone number is used, the type can either be sms or phone_change. If an email address is used, the type can be one of the following: signup, magiclink, recovery, invite or email_change. - -* The verification type used should be determined based on the corresponding auth method called before verifyOtp to sign up / sign-in a user. +- The verifyOtp method takes in different verification types. If a phone number is used, the type can either be sms or phone_change. If an email address is used, the type can be one of the following: signup, magiclink, recovery, invite or email_change. +- The verification type used should be determined based on the corresponding auth method called before verifyOtp to sign up / sign-in a user. The RedwoodJS auth provider doesn't expose the `veriftyOtp` method from the Supabase SDK directly. @@ -285,7 +290,7 @@ So, in order to use the `verifyOtp` method, you would: const { client } = useAuth() useEffect(() => { - const { data, error } = await client.verifyOtp({ phone, token, type: 'sms'}) + const { data, error } = await client.verifyOtp({ phone, token, type: 'sms' }) }, [client]) ``` @@ -317,13 +322,15 @@ useEffect(() => { Receive a notification every time an auth event happens. -* Types of auth events: `SIGNED_IN`, `SIGNED_OUT`, `TOKEN_REFRESHED`, `USER_UPDATED`, `PASSWORD_RECOVERY` +- Types of auth events: `SIGNED_IN`, `SIGNED_OUT`, `TOKEN_REFRESHED`, `USER_UPDATED`, `PASSWORD_RECOVERY` ```ts const { client } = useAuth() useEffect(() => { - const { data: { subscription } } = client.onAuthStateChange((event, session) => { + const { + data: { subscription }, + } = client.onAuthStateChange((event, session) => { console.log(event, session) }) diff --git a/docs/docs/auth/supertokens.md b/docs/docs/auth/supertokens.md index 8b0b6b97ca8a..ecdc200726c6 100644 --- a/docs/docs/auth/supertokens.md +++ b/docs/docs/auth/supertokens.md @@ -51,6 +51,7 @@ SUPERTOKENS_API_KEY=your-api-key # The value can be omitted when self-hosting Su ``` ## Social login setup + The following environment variables have to be set up (depending on the social login options): ```bash @@ -79,7 +80,6 @@ includeEnvironmentVariables = [ ] ``` - # Page setup Let's make sure: if this is a brand new project, generate a home page. diff --git a/docs/docs/authentication.md b/docs/docs/authentication.md index b680c802a934..7c3d96e5ab1e 100644 --- a/docs/docs/authentication.md +++ b/docs/docs/authentication.md @@ -128,7 +128,6 @@ const Routes = () => { - // highlight-next-line @@ -150,16 +149,13 @@ const Routes = () => { - - // highlight-next-line - // highlight-next-line @@ -187,7 +183,6 @@ export const handler = createGraphQLHandler({ getCurrentUser, // ... }) - ``` If you're using one of Redwood's official integrations, `authDecoder` comes from the corresponding integration package (in auth0's case, `@redwoodjs/auth-auth0-api`): diff --git a/docs/docs/builds.md b/docs/docs/builds.md index 7303f1872814..b5cc87de5f0f 100644 --- a/docs/docs/builds.md +++ b/docs/docs/builds.md @@ -1,6 +1,7 @@ --- description: What happens when you build your app --- + # Builds > ⚠ **Work in Progress** ⚠️ @@ -11,7 +12,6 @@ description: What happens when you build your app > You can edit this doc [here](https://github.com/redwoodjs/redwoodjs.com/blob/main/docs/builds.md). > If you have any questions, just ask for help! We're active on the [forums](https://community.redwoodjs.com/c/contributing/9) and on [discord](https://discord.com/channels/679514959968993311/747258086569541703). - ## API The api side of Redwood is transpiled by Babel into the `./api/dist` folder. @@ -28,9 +28,10 @@ yarn zip-it-and-ship-it dist/functions/ zipballs/ Each lambda function in `./api/dist/functions` is parsed by zip-it-and-ship-it resulting in a zip file per lambda function that contains all the dependencies required for that lambda function. ->Note: The `@netlify/zip-it-and-ship-it` package needs to be installed as a dev dependency in `api/`. Use the command `yarn workspace api add -D @netlify/zip-it-and-ship-it`. ->- You can learn more about the package [here](https://www.npmjs.com/package/@netlify/zip-it-and-ship-it). ->- For more information on AWS Serverless Deploy see these [docs](/docs/deploy/serverless). +> Note: The `@netlify/zip-it-and-ship-it` package needs to be installed as a dev dependency in `api/`. Use the command `yarn workspace api add -D @netlify/zip-it-and-ship-it`. +> +> - You can learn more about the package [here](https://www.npmjs.com/package/@netlify/zip-it-and-ship-it). +> - For more information on AWS Serverless Deploy see these [docs](/docs/deploy/serverless). ## Web diff --git a/docs/docs/cells.md b/docs/docs/cells.md index 0a7377cd6b54..addfa2d6b2ac 100644 --- a/docs/docs/cells.md +++ b/docs/docs/cells.md @@ -1,6 +1,7 @@ --- description: Declarative data fetching with Cells --- + # Cells Cells are a declarative approach to data fetching and one of Redwood's signature modes of abstraction. @@ -43,7 +44,7 @@ yarn rw generate cell equipment --list ## Cells in-depth -Cells exports five constants: `QUERY`, `Loading` , `Empty` , `Failure` and `Success`. The root query in `QUERY` is the same as `` so that, if you're generating a cell based on a model in your `schema.prisma`, you can get something out of the database right away. But there's a good chance you won't generate your Cell this way, so if you need to, make sure to change the root query. See the [Cells](tutorial/chapter2/cells.md#our-first-cell) section of the Tutorial for a great example of this. +Cells exports five constants: `QUERY`, `Loading` , `Empty` , `Failure` and `Success`. The root query in `QUERY` is the same as `` so that, if you're generating a cell based on a model in your `schema.prisma`, you can get something out of the database right away. But there's a good chance you won't generate your Cell this way, so if you need to, make sure to change the root query. See the [Cells](tutorial/chapter2/cells.md#our-first-cell) section of the Tutorial for a great example of this. ## Usage @@ -114,7 +115,7 @@ export default HomePage ```jsx {2-3} export const QUERY = gql` - query($numberToShow: Int!) { + query ($numberToShow: Int!) { posts(numberToShow: $numberToShow) { id title @@ -135,8 +136,8 @@ By default, `beforeQuery` gives any props passed from the parent component to `Q export const beforeQuery = (props) => { return { variables: props, - fetchPolicy: 'cache-and-network' - } + fetchPolicy: 'cache-and-network', + } } ``` @@ -156,8 +157,8 @@ export const beforeQuery = () => { const { currentUser } = useAuth() return { - variables: { userId: currentUser.id } - } + variables: { userId: currentUser.id }, + } } ``` @@ -224,6 +225,7 @@ But, like `Loading`, Storybook is probably a better place to develop this. In production, failed cells won't break your app, they'll just be empty divs... --> In this example, we use the `errorCode` to conditionally render the error heading title, and we also use it for our translation string. + ```jsx export const Failure = ({ error, errorCode }: CellFailureProps) => { const { t } = useTranslation() @@ -282,7 +284,7 @@ client = useApolloClient() client.query({ query: gql` ... - ` + `, }) ``` @@ -347,6 +349,7 @@ And now let's say that Babel isn't going to come along and assemble our exports. We'd probably do something like this: + ```jsx const QUERY = gql` query { diff --git a/docs/docs/cli-commands.md b/docs/docs/cli-commands.md index f09be28f7a42..35afdca162ad 100644 --- a/docs/docs/cli-commands.md +++ b/docs/docs/cli-commands.md @@ -71,10 +71,10 @@ yarn redwood build [side..] We use Babel to transpile the api side into `./api/dist` and Vite to package the web side into `./web/dist`. -| Arguments & Options | Description | -| :------------------ | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `side` | Which side(s) to build. Choices are `api` and `web`. Defaults to `api` and `web` | -| `--verbose, -v` | Print more information while building | +| Arguments & Options | Description | +| :------------------ | :------------------------------------------------------------------------------- | +| `side` | Which side(s) to build. Choices are `api` and `web`. Defaults to `api` and `web` | +| `--verbose, -v` | Print more information while building | #### Usage @@ -88,9 +88,9 @@ Running `yarn redwood build` without any arguments generates the Prisma client a ~/redwood-app$ yarn redwood build yarn run v1.22.4 $ /redwood-app/node_modules/.bin/redwood build - ✔ Generating the Prisma client... - ✔ Building "api"... - ✔ Building "web"... +✔ Generating the Prisma client... +✔ Building "api"... +✔ Building "web"... Done in 17.37s. ``` @@ -192,10 +192,10 @@ yarn redwood dev [side..] `yarn redwood dev api` starts the Redwood dev server and `yarn redwood dev web` starts the Vite dev server with Redwood's config. -| Argument | Description | -| :----------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| `side` | Which dev server(s) to start. Choices are `api` and `web`. Defaults to `api` and `web` | -| `--forward, --fwd` | String of one or more Vite Dev Server config options. See example usage below | +| Argument | Description | +| :----------------- | :------------------------------------------------------------------------------------- | +| `side` | Which dev server(s) to start. Choices are `api` and `web`. Defaults to `api` and `web` | +| `--forward, --fwd` | String of one or more Vite Dev Server config options. See example usage below | #### Usage @@ -208,10 +208,10 @@ $ /redwood-app/node_modules/.bin/redwood dev api $ /redwood-app/node_modules/.bin/dev-server 15:04:51 api | Listening on http://localhost:8911 15:04:51 api | Watching /home/dominic/projects/redwood/redwood-app/api -15:04:51 api | -15:04:51 api | Now serving -15:04:51 api | -15:04:51 api | ► http://localhost:8911/graphql/ +15:04:51 api \ + | 15:04:51 api | Now serving +15:04:51 api \ + | 15:04:51 api | ► http://localhost:8911/graphql/ ``` Using `--forward` (alias `--fwd`), you can pass one or more Vite Dev Server [config options](https://vitejs.dev/guide/cli#vite). The following will run the dev server, set the port to `1234`, and disable automatic browser opening. @@ -268,7 +268,6 @@ yarn redwood deploy serverless | `--pack-only` | Only package the build for deployment | | `--first-run` | Use this flag the first time you deploy. The first deploy wizard will walk you through configuring your web side to connect to the api side | - ### deploy netlify Build command for Netlify deploy @@ -284,6 +283,7 @@ yarn redwood deploy netlify | `--data-migrate, --dm` | Migrate the data in your database [default: "true"] | #### Example + The following command will build, apply Prisma DB migrations, and skip data migrations. ``` @@ -316,6 +316,7 @@ yarn redwood deploy render | `--serve` | Run server for api in production [default: "true"] | #### Example + The following command will build the Web side for static-site CDN deployment. ``` @@ -343,6 +344,7 @@ yarn redwood deploy vercel | `--data-migrate, --dm` | Migrate the data in your database [default: "true"] | #### Example + The following command will build, apply Prisma DB migrations, and skip data migrations. ``` @@ -402,6 +404,7 @@ See [this how to](how-to/background-worker.md) for an example of using exec to r Set up and run experimental features. Some caveats: + - these features do not follow SemVer (may be breaking changes in minor and patch releases) - these features may be deprecated or removed (anytime) - your feedback is wanted and necessary! @@ -411,6 +414,7 @@ For more information, including details about specific features, see this Redwoo **Available Experimental Features** View all that can be _set up_: + ``` yarn redwood experimental --help ``` @@ -491,9 +495,9 @@ Generating a user cell: ~/redwood-app$ yarn redwood generate cell user yarn run v1.22.4 $ /redwood-app/node_modules/.bin/redwood g cell user - ✔ Generating cell files... - ✔ Writing `./web/src/components/UserCell/UserCell.test.js`... - ✔ Writing `./web/src/components/UserCell/UserCell.js`... +✔ Generating cell files... +✔ Writing $(./web/src/components/UserCell/UserCell.test.js)... +✔ Writing $(./web/src/components/UserCell/UserCell.js)... Done in 1.00s. ``` @@ -552,9 +556,9 @@ Generating a user component: ~/redwood-app$ yarn redwood generate component user yarn run v1.22.4 $ /redwood-app/node_modules/.bin/redwood g component user - ✔ Generating component files... - ✔ Writing `./web/src/components/User/User.test.js`... - ✔ Writing `./web/src/components/User/User.js`... +✔ Generating component files... +✔ Writing $(./web/src/components/User/User.test.js)... +✔ Writing $(./web/src/components/User/User.js)... Done in 1.02s. ``` @@ -660,8 +664,8 @@ Generating a `myDirective` directive using the interactive command: yarn rw g directive myDirective ? What type of directive would you like to generate? › - Use arrow-keys. Return to submit. -❯ Validator - Implement a validation: throw an error if criteria not met to stop execution - Transformer - Modify values of fields or query responses +❯ Validator - Implement a validation: throw an error if criteria not met to stop execution +Transformer - Modify values of fields or query responses ``` ### generate function @@ -699,8 +703,8 @@ Generating a user function: ~/redwood-app$ yarn redwood generate function user yarn run v1.22.4 $ /redwood-app/node_modules/.bin/redwood g function user - ✔ Generating function files... - ✔ Writing `./api/src/functions/user.js`... +✔ Generating function files... +✔ Writing $(./api/src/functions/user.js)... Done in 16.04s. ``` @@ -769,9 +773,9 @@ Generating a user layout: ~/redwood-app$ yarn redwood generate layout user yarn run v1.22.4 $ /redwood-app/node_modules/.bin/redwood g layout user - ✔ Generating layout files... - ✔ Writing `./web/src/layouts/UserLayout/UserLayout.test.js`... - ✔ Writing `./web/src/layouts/UserLayout/UserLayout.js`... +✔ Generating layout files... +✔ Writing $(./web/src/layouts/UserLayout/UserLayout.test.js)... +✔ Writing $(./web/src/layouts/UserLayout/UserLayout.js)... Done in 1.00s. ``` @@ -809,14 +813,14 @@ See the [RedwoodRecord docs](redwoodrecord.md). ~/redwood-app$ yarn redwood generate model User yarn run v1.22.4 $ /redwood-app/node_modules/.bin/redwood g model User - ✔ Generating model file... - ✔ Successfully wrote file `./api/src/models/User.js` - ✔ Parsing datamodel, generating api/src/models/index.js... +✔ Generating model file... +✔ Successfully wrote file $(./api/src/models/User.js) +✔ Parsing datamodel, generating api/src/models/index.js... - Wrote /Users/rob/Sites/redwoodjs/redwood_record/.redwood/datamodel.json - Wrote /Users/rob/Sites/redwoodjs/redwood_record/api/src/models/index.js +Wrote /Users/rob/Sites/redwoodjs/redwood_record/.redwood/datamodel.json +Wrote /Users/rob/Sites/redwoodjs/redwood_record/api/src/models/index.js -✨ Done in 3.74s. +✨ Done in 3.74s. ``` Generating a model automatically runs `yarn rw record init` as well. @@ -826,7 +830,7 @@ Generating a model automatically runs `yarn rw record init` as well. Generates a page component and updates the routes. ```bash -yarn redwood generate page [path] +yarn redwood generate page < name > [path] ``` `path` can include a route parameter which will be passed to the generated @@ -944,6 +948,7 @@ const Routes = () => { ) } ``` + ### generate realtime Generate a boilerplate subscription or live query used with RedwoodJS Realtime. @@ -952,12 +957,11 @@ Generate a boilerplate subscription or live query used with RedwoodJS Realtime. yarn redwood generate realtime ``` -| Arguments & Options | Description | -| -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `name` | Name of the realtime event to setup.post` | -| `-t, --type` | Choices: `liveQuery`, `subscription`. Optional. If not provided, you will be prompted to select. -| `--force, -f` | Overwrite existing files - +| Arguments & Options | Description | +| ------------------- | ------------------------------------------------------------------------------------------------ | +| `name` | Name of the realtime event to setup.post` | +| `-t, --type` | Choices: `liveQuery`, `subscription`. Optional. If not provided, you will be prompted to select. | +| `--force, -f` | Overwrite existing files | #### Usage @@ -970,9 +974,9 @@ Generate a live query. ```bash ~/redwood-app$ yarn rw g realtime NewLiveQuery ? What type of realtime event would you like to create? › - Use arrow-keys. Return to submit. -❯ Live Query - Create a Live Query to watch for changes in data - Subscription +❯ Live Query +Create a Live Query to watch for changes in data +Subscription ✔ What type of realtime event would you like to create? › Live Query ✔ Checking for realtime environment prerequisites ... @@ -985,8 +989,8 @@ Generate a subscription. ```bash ~/redwood-app$ yarn rw g realtime NewSub ? What type of realtime event would you like to create? › - Use arrow-keys. Return to submit. - Live Query -❯ Subscription - Create a Subscription to watch for events +Live Query +❯ Subscription - Create a Subscription to watch for events ✔ What type of realtime event would you like to create? › Subscription ✔ Checking for realtime environment prerequisites ... @@ -994,7 +998,6 @@ Generate a subscription. ✔ Generating types ... ``` - ### generate scaffold Generate Pages, SDL, and Services files based on a given DB schema Model. Also accepts ``. @@ -1223,9 +1226,9 @@ yarn redwood g sdl --force --no-tests ~/redwood-app$ yarn redwood generate sdl user --force --no-tests yarn run v1.22.4 $ /redwood-app/node_modules/.bin/redwood g sdl user - ✔ Generating SDL files... - ✔ Writing `./api/src/graphql/users.sdl.js`... - ✔ Writing `./api/src/services/users/users.js`... +✔ Generating SDL files... +✔ Writing $(./api/src/graphql/users.sdl.js)... +✔ Writing $(./api/src/services/users/users.js)... Done in 1.04s. ``` @@ -1243,11 +1246,11 @@ Generating a user sdl: ~/redwood-app$ yarn redwood generate sdl user yarn run v1.22.4 $ /redwood-app/node_modules/.bin/redwood g sdl user - ✔ Generating SDL files... - ✔ Writing `./api/src/graphql/users.sdl.js`... - ✔ Writing `./api/src/services/users/users.scenarios.js`... - ✔ Writing `./api/src/services/users/users.test.js`... - ✔ Writing `./api/src/services/users/users.js`... +✔ Generating SDL files... +✔ Writing $(./api/src/graphql/users.sdl.js)... +✔ Writing $(./api/src/services/users/users.scenarios.js)... +✔ Writing $(./api/src/services/users/users.test.js)... +✔ Writing $(./api/src/services/users/users.js)... Done in 1.04s. ``` @@ -1387,7 +1390,6 @@ Services are where Redwood puts its business logic. They can be used by your Gra | `--tests` | Generate test and scenario files [default: true] | | `--rollback` | Rollback changes if an error occurs [default: true] | - **Destroying** ``` @@ -1402,10 +1404,10 @@ Generating a user service: ~/redwood-app$ yarn redwood generate service user yarn run v1.22.4 $ /redwood-app/node_modules/.bin/redwood g service user - ✔ Generating service files... - ✔ Writing `./api/src/services/users/users.scenarios.js`... - ✔ Writing `./api/src/services/users/users.test.js`... - ✔ Writing `./api/src/services/users/users.js`... +✔ Generating service files... +✔ Writing $(./api/src/services/users/users.scenarios.js)... +✔ Writing $(./api/src/services/users/users.test.js)... +✔ Writing $(./api/src/services/users/users.js)... Done in 1.02s. ``` @@ -1839,9 +1841,9 @@ Copying the cell generator templates: ~/redwood-app$ yarn rw setup generator cell yarn run v1.22.4 $ /redwood-app/node_modules/.bin/rw setup generator cell - ✔ Copying generator templates... - ✔ Wrote templates to /web/generators/cell -✨ Done in 2.33s. +✔ Copying generator templates... +✔ Wrote templates to /web/generators/cell +✨ Done in 2.33s. ``` ### setup deploy (config) @@ -1852,11 +1854,11 @@ Set up a deployment configuration. yarn redwood setup deploy ``` -| Arguments & Options | Description | -| :------------------ | :---------------------------------------------------------------------------------------------------- | -| `provider` | Deploy provider to configure. Choices are `baremetal`, `coherence`, `edgio`, `flightcontrol`, `netlify`, `render`, `vercel`, or `aws-serverless [deprecated]`, | -| `--database, -d` | Database deployment for Render only [choices: "none", "postgresql", "sqlite"] [default: "postgresql"] | -| `--force, -f` | Overwrite existing configuration [default: false] | +| Arguments & Options | Description | +| :------------------ | :------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `provider` | Deploy provider to configure. Choices are `baremetal`, `coherence`, `edgio`, `flightcontrol`, `netlify`, `render`, `vercel`, or `aws-serverless [deprecated]`, | +| `--database, -d` | Database deployment for Render only [choices: "none", "postgresql", "sqlite"] [default: "postgresql"] | +| `--force, -f` | Overwrite existing configuration [default: false] | #### setup deploy netlify @@ -1902,10 +1904,10 @@ This command adds the necessary packages and files to get started using the Redw yarn redwood setup mailer ``` -| Arguments & Options | Description | -| :---------------------- | :----------------------------- | -| `--force, -f` | Overwrite existing files | -| `--skip-examples` | Do not include example content, such as a React email template | +| Arguments & Options | Description | +| :------------------ | :------------------------------------------------------------- | +| `--force, -f` | Overwrite existing files | +| `--skip-examples` | Do not include example content, such as a React email template | ### setup package @@ -1917,18 +1919,20 @@ This command behaves similarly to `yarn dlx` but will attempt to confirm compati yarn redwood setup package ``` -| Arguments & Options | Description | -| :------------------ | :----------------------- | +| Arguments & Options | Description | +| :------------------ | :------------------------- | | `--force, -f` | Forgo compatibility checks | #### Usage Run the made up `@redwoodjs/setup-example` package: + ```bash ~/redwood-app$ yarn rw setup package @redwoodjs/setup-example ``` Run the same package but using a particular npm tag and avoiding any compatibility checks: + ```bash ~/redwood-app$ yarn rw setup package @redwoodjs/setup-example@beta --force ``` @@ -1977,7 +1981,6 @@ Run `yarn rw setup graphql fragments` This command creates the necessary configuration to start using [GraphQL Trusted Documents](./graphql/trusted-documents.md). - ``` yarn redwood setup graphql trusted-documents ``` @@ -1995,7 +1998,6 @@ Run `yarn rw setup graphql trusted-documents` ✔ Configuring the GraphQL Handler to use a Trusted Documents store ... ``` - If you have not setup the RedwoodJS server file, it will be setup: ```bash @@ -2004,7 +2006,6 @@ If you have not setup the RedwoodJS server file, it will be setup: ✔ Adding required api packages... ``` - ### setup realtime This command creates the necessary files, installs the required packages, and provides examples to setup RedwoodJS Realtime from GraphQL live queries and subscriptions. See the Realtime docs for more information. @@ -2013,10 +2014,10 @@ This command creates the necessary files, installs the required packages, and pr yarn redwood setup realtime ``` -| Arguments & Options | Description | -| :------------------ | :----------------------- | -| `-e, --includeExamples, --examples` | Include examples of how to implement liveQueries and subscriptions. Default: true. | -| `--force, -f` | Forgo compatibility checks | +| Arguments & Options | Description | +| :---------------------------------- | :--------------------------------------------------------------------------------- | +| `-e, --includeExamples, --examples` | Include examples of how to implement liveQueries and subscriptions. Default: true. | +| `--force, -f` | Forgo compatibility checks | :::note @@ -2041,7 +2042,6 @@ Run `yarn rw setup realtime` ✔ Generating types ... ``` - If you have not setup the RedwoodJS server file, it will be setup: ```bash @@ -2062,8 +2062,6 @@ yarn redwood setup tsconfig | :------------------ | :----------------------- | | `--force, -f` | Overwrite existing files | - - ### setup ui Set up a UI design or style library. Right now the choices are [TailwindCSS](https://tailwindcss.com/), [Chakra UI](https://chakra-ui.com/), and [Mantine UI](https://ui.mantine.dev/). @@ -2072,10 +2070,10 @@ Set up a UI design or style library. Right now the choices are [TailwindCSS](htt yarn rw setup ui ``` -| Arguments & Options | Description | -| :------------------ | :-------------------------------------------------------------------------------------- | +| Arguments & Options | Description | +| :------------------ | :-------------------------------------------------------------------------- | | `library` | Library to configure. Choices are `chakra-ui`, `tailwindcss`, and `mantine` | -| `--force, -f` | Overwrite existing configuration | +| `--force, -f` | Overwrite existing configuration | ## storybook @@ -2105,15 +2103,15 @@ Run Jest tests for api and web. yarn redwood test [side..] ``` -| Arguments & Options | Description | -| ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `sides or filter` | Which side(s) to test, and/or a regular expression to match against your test files to filter by | -| `--help` | Show help | -| `--version` | Show version number | -| `--watch` | Run tests related to changed files based on hg/git (uncommitted files). Specify the name or path to a file to focus on a specific set of tests [default: true] | -| `--watchAll` | Run all tests | -| `--collectCoverage` | Show test coverage summary and output info to `coverage` directory in project root. See this directory for an .html coverage report | -| `--clearCache` | Delete the Jest cache directory and exit without running tests | +| Arguments & Options | Description | +| ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `sides or filter` | Which side(s) to test, and/or a regular expression to match against your test files to filter by | +| `--help` | Show help | +| `--version` | Show version number | +| `--watch` | Run tests related to changed files based on hg/git (uncommitted files). Specify the name or path to a file to focus on a specific set of tests [default: true] | +| `--watchAll` | Run all tests | +| `--collectCoverage` | Show test coverage summary and output info to `coverage` directory in project root. See this directory for an .html coverage report | +| `--clearCache` | Delete the Jest cache directory and exit without running tests | | `--db-push` | Syncs the test database with your Prisma schema without requiring a migration. It creates a test database if it doesn't already exist [default: true]. This flag is ignored if your project doesn't have an `api` side. [👉 More details](#prisma-db-push). | > **Note** all other flags are passed onto the jest cli. So for example if you wanted to update your snapshots you can pass the `-u` flag @@ -2215,9 +2213,9 @@ Besides upgrading to a new stable release, you can use this command to upgrade t A canary release is published to npm every time a PR is merged to the `main` branch, and when we're getting close to a new release, we publish release candidates. -| Option | Description | -| :-------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `--dry-run, -d` | Check for outdated packages without upgrading | +| Option | Description | +| :-------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `--dry-run, -d` | Check for outdated packages without upgrading | | `--tag, -t` | Choices are "rc", "canary", "latest", "next", "experimental", or a specific version (e.g. "0.19.3"). WARNING: Unstable releases in the case of "canary", "rc", "next", and "experimental". And "canary" releases include breaking changes often requiring codemods if upgrading a project. | #### Example diff --git a/docs/docs/connection-pooling.md b/docs/docs/connection-pooling.md index 750c012b3076..7f28eaed7c81 100644 --- a/docs/docs/connection-pooling.md +++ b/docs/docs/connection-pooling.md @@ -16,9 +16,9 @@ Production Redwood apps should enable connection pooling in order to properly sc ## Prisma Data Proxy -The [Prisma Data Proxy](https://www.prisma.io/docs/data-platform/data-proxy) provides database connection management and pooling for Redwood apps using Prisma. It supports MySQL and Postgres databases in either the U.S. or EU regions. +The [Prisma Data Proxy](https://www.prisma.io/docs/data-platform/data-proxy) provides database connection management and pooling for Redwood apps using Prisma. It supports MySQL and Postgres databases in either the U.S. or EU regions. -To set up a Prisma Data Proxy, sign up for the [Prisma Data Platform](https://www.prisma.io/data-platform) for free. In your onboarding workflow, plug in the connection URL for your database and choose your region. This will generate a connection string for your app. Then follow the instructions in [Prisma's documentation](https://www.prisma.io/docs/concepts/data-platform/data-proxy). +To set up a Prisma Data Proxy, sign up for the [Prisma Data Platform](https://www.prisma.io/data-platform) for free. In your onboarding workflow, plug in the connection URL for your database and choose your region. This will generate a connection string for your app. Then follow the instructions in [Prisma's documentation](https://www.prisma.io/docs/concepts/data-platform/data-proxy). > Note that the example uses npm. Rather than using npm, you can access the Prisma CLI using `yarn redwood prisma` inside a Redwood app. @@ -26,7 +26,6 @@ To set up a Prisma Data Proxy, sign up for the [Prisma Data Platform](https://ww PgBouncer holds a connection pool to the database and proxies incoming client connections by sitting between Prisma Client and the database. This reduces the number of processes a database has to handle at any given time. PgBouncer passes on a limited number of connections to the database and queues additional connections for delivery when space becomes available. - To use Prisma Client with PgBouncer from a serverless function, add the `?pgbouncer=true` flag to the PostgreSQL connection URL: ``` @@ -57,12 +56,13 @@ postgresql://postgres:mydb.supabase.co:6543/postgres?sslmode=require&pgbouncer=t ``` ## Heroku + For Postgres, see [Postgres Connection Pooling](https://devcenter.heroku.com/articles/postgres-connection-pooling). Heroku does not officially support MySQL. - ## Digital Ocean + For Postgres, see [How to Manage Connection Pools](https://www.digitalocean.com/docs/databases/postgresql/how-to/manage-connection-pools) To run migrations through a connection pool, you're required to append connection parameters to your `DATABASE_URL`. Prisma needs to know to use pgbouncer (which is part of Digital Ocean's connection pool). If omitted, you may receive the following error: @@ -77,7 +77,9 @@ To resolve this, use the following structure in your `DATABASE_URL`: ``` :25061/defaultdb?connection_limit=3&sslmode=require&pgbouncer=true&connect_timeout=10&pool_timeout=30 ``` + Here's a couple more things to be aware of: + - When using a Digital Ocean connection pool, you'll have multiple ports available. Typically the direct connection (without connection pooling) is on port `25060` and the connection through pgbouncer is served through port `25061`. Make sure you connect to your connection pool on port `25061` - Adjust the `connection_limit`. Clusters provide 25 connections per 1 GB of RAM. Three connections per cluster are reserved for maintenance, and all remaining connections can be allocated to connection pools - Both `pgbouncer=true` and `pool_timeout=30` are required to deploy successfully through your connection pool @@ -85,20 +87,21 @@ Here's a couple more things to be aware of: Connection Pooling for MySQL is not yet supported. ## AWS + Use [Amazon RDS Proxy](https://aws.amazon.com/rds/proxy) for MySQL or PostgreSQL. From the [AWS Docs](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/rds-proxy.html#rds-proxy.limitations): ->Your RDS Proxy must be in the same VPC as the database. The proxy can't be publicly accessible. -Because of this limitation, with out-of-the-box configuration, you can only use RDS Proxy if you're deploying your Lambda Functions to the same AWS account. Alternatively, you can use RDS directly, but you might require larger instances to handle your production traffic and the number of concurrent connections. +> Your RDS Proxy must be in the same VPC as the database. The proxy can't be publicly accessible. +Because of this limitation, with out-of-the-box configuration, you can only use RDS Proxy if you're deploying your Lambda Functions to the same AWS account. Alternatively, you can use RDS directly, but you might require larger instances to handle your production traffic and the number of concurrent connections. ## Why Connection Pooling? Relational databases have a maximum number of concurrent client connections. -* Postgres allows 100 by default -* MySQL allows 151 by default +- Postgres allows 100 by default +- MySQL allows 151 by default In a traditional server environment, you would need a large amount of traffic (and therefore web servers) to exhaust these connections, since each web server instance typically leverages a single connection. diff --git a/docs/docs/contributing-overview.md b/docs/docs/contributing-overview.md index 623d70ae02a3..873757c25733 100644 --- a/docs/docs/contributing-overview.md +++ b/docs/docs/contributing-overview.md @@ -26,13 +26,15 @@ _Before interacting with the Redwood community, please read and understand our [ > 3. 🪜 [Step-by-step Walkthrough](contributing-walkthrough.md) (including Video Recording) > 4. 📈 [Current Project Status](https://github.com/orgs/redwoodjs/projects/11) > 5. 🤔 What should I work on? -> - [Good First Issue](https://redwoodjs.com/good-first-issue) -> - [Discovery Process and Open Issues](#what-should-i-work-on) +> - [Good First Issue](https://redwoodjs.com/good-first-issue) +> - [Discovery Process and Open Issues](#what-should-i-work-on) ## The Characteristics of a Contributor + More than committing code, contributing is about human collaboration and relationship. Our community mantra is **“By helping each other be successful with Redwood, we make the Redwood project successful.”** We have a specific vision for the effect this project and community will have on you — it should give you superpowers to build+create, progress in skills, and help advance your career. So who do you need to become to achieve this? Specifically, what characteristics, skills, and capabilities will you need to cultivate through practice? Here are our suggestions: + - Empathy - Gratitude - Generosity @@ -42,6 +44,7 @@ All of these are applicable in relation to both others and yourself. The goal of And you thought all this was just about opening a PR 🤣 Yes, it’s a super rewarding experience. But that’s just the beginning! ## What should I work on? + Even if you know the mechanics, it’s hard to get started without a starting place. Our best advice is this — dive into the Redwood Tutorial, read the docs, and build your own experiment with Redwood. Along the way, you’ll find typos, out-of-date (or missing) documentation, code that could work better, or even opportunities for improving and adding features. You’ll be engaging in the Forums and Chat and developing a feel for priorities and needs. This way, you’ll naturally follow your own interests and sooner than later intersect “things you’re interested in” + “ways to help improve Redwood”. There are other more direct ways to get started as well, which are outlined below. @@ -51,11 +54,13 @@ There are other more direct ways to get started as well, which are outlined belo The Redwood Core Team is working publicly — progress is updated daily on the [Release Project Board](https://github.com/orgs/redwoodjs/projects/11). Eventually, all this leads you back to Redwood’s GitHub Issues page. Here you’ll find open items that need help, which are organized by labels. There are four labels helpful for contributing: + 1. [Good First Issue](https://github.com/redwoodjs/redwood/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22): these items are more likely to be an accessible entry point to the Framework. It’s less about skill level and more about focused scope. 2. [Help Wanted](https://github.com/redwoodjs/redwood/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22): these items especially need contribution help from the community. 3. [Bugs 🐛](https://github.com/redwoodjs/redwood/issues?q=is%3Aissue+is%3Aopen+label%3Abug%2Fconfirmed): last but not least, we always need help with bugs. Some are technically less challenging than others. Sometimes the best way you can help is to attempt to reproduce the bug and confirm whether or not it’s still an issue. ### Create a New Issue + Anyone can create a new Issue. If you’re not sure that your feature or idea is something to work on, start the discussion with an Issue. Describe the idea and problem + solution as clearly as possible, including examples or pseudo code if applicable. It’s also very helpful to `@` mention a maintainer or Core Team member that shares the area of interest. Just know that there’s a lot of Issues that shuffle every day. If no one replies, it’s just because people are busy. Reach out in the Forums, Chat, or comment in the Issue. We intend to reply to every Issue that’s opened. If yours doesn’t have a reply, then give us a nudge! @@ -73,26 +78,27 @@ For details on contributing to a specific package, see the package's README (lin What you want to do not on the roadmap? Well, still go for it! We love spikes and proof-of-concepts. And if you have a question, just ask! ### RedwoodJS Framework Packages -|Package|Description| -|:-|:-| -|[`@redwoodjs/api-server`](https://github.com/redwoodjs/redwood/blob/main/packages/api-server/README.md)|Run a Redwood app using Fastify server (alternative to serverless API)| -|[`@redwoodjs/api`](https://github.com/redwoodjs/redwood/blob/main/packages/api/README.md)|Infrastructure components for your applications UI including logging, webhooks, authentication decoders and parsers, as well as tools to test custom serverless functions and webhooks| -|[`@redwoodjs/auth`](https://github.com/redwoodjs/redwood/blob/main/packages/auth/README.md#contributing)|A lightweight wrapper around popular SPA authentication libraries| -|[`@redwoodjs/cli`](https://github.com/redwoodjs/redwood/blob/main/packages/cli/README.md)|All the commands for Redwood's built-in CLI| -|[`@redwoodjs/codemods`](https://github.com/redwoodjs/redwood/blob/main/packages/codemods/README.md)|Codemods that automate upgrading a Redwood project| -|[`@redwoodjs/core`](https://github.com/redwoodjs/redwood/blob/main/packages/core/README.md)|Defines babel plugins and config files| -|[`@redwoodjs/create-redwood-app`](https://github.com/redwoodjs/redwood/blob/main/packages/create-redwood-app/README.md)|Enables `yarn create redwood-app`—downloads the latest release of Redwood and extracts it into the supplied directory| -|[`@redwoodjs/eslint-config`](https://github.com/redwoodjs/redwood/blob/main/packages/eslint-config/README.md)|Defines Redwood's eslint config| -|[`@redwoodjs/forms`](https://github.com/redwoodjs/redwood/blob/main/packages/forms/README.md)|Provides Form helpers| -|[`@redwoodjs/graphql-server`](https://github.com/redwoodjs/redwood/blob/main/packages/graphql-server/README.md)|Exposes functions to build the GraphQL API, provides services with `context`, and a set of envelop plugins to supercharge your GraphQL API with logging, authentication, error handling, directives and more| -|[`@redwoodjs/internal`](https://github.com/redwoodjs/redwood/blob/main/packages/internal/README.md)|Provides tooling to parse Redwood configs and get a project's paths| -|[`@redwoodjs/prerender`](https://github.com/redwoodjs/redwood/blob/main/packages/prerender/README.md)|Defines functionality for prerendering static content| -|[`@redwoodjs/record`](https://github.com/redwoodjs/redwood/blob/main/packages/record/README.md)|ORM built on top of Prisma. It may be extended in the future to wrap other database access packages| -|[`@redwoodjs/router`](https://github.com/redwoodjs/redwood/blob/main/packages/router/README.md)|The built-in router for Redwood| -|[`@redwoodjs/structure`](https://github.com/redwoodjs/redwood/blob/main/packages/structure/README.md)|Provides a way to build, validate and inspect an object graph that represents a complete Redwood project| -|[`@redwoodjs/telemetry`](https://github.com/redwoodjs/redwood/blob/main/packages/telemetry/README.md)|Provides functionality for anonymous data collection| -|[`@redwoodjs/testing`](https://github.com/redwoodjs/redwood/blob/main/packages/testing/README.md)|Provides helpful defaults when testing a Redwood project's web side| -|[`@redwoodjs/web`](https://github.com/redwoodjs/redwood/blob/main/packages/web/README.md)|Configures a Redwood's app web side: wraps the Apollo Client in `RedwoodApolloProvider`; defines the Cell HOC| + +| Package | Description | +| :---------------------------------------------------------------------------------------------------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| [`@redwoodjs/api-server`](https://github.com/redwoodjs/redwood/blob/main/packages/api-server/README.md) | Run a Redwood app using Fastify server (alternative to serverless API) | +| [`@redwoodjs/api`](https://github.com/redwoodjs/redwood/blob/main/packages/api/README.md) | Infrastructure components for your applications UI including logging, webhooks, authentication decoders and parsers, as well as tools to test custom serverless functions and webhooks | +| [`@redwoodjs/auth`](https://github.com/redwoodjs/redwood/blob/main/packages/auth/README.md#contributing) | A lightweight wrapper around popular SPA authentication libraries | +| [`@redwoodjs/cli`](https://github.com/redwoodjs/redwood/blob/main/packages/cli/README.md) | All the commands for Redwood's built-in CLI | +| [`@redwoodjs/codemods`](https://github.com/redwoodjs/redwood/blob/main/packages/codemods/README.md) | Codemods that automate upgrading a Redwood project | +| [`@redwoodjs/core`](https://github.com/redwoodjs/redwood/blob/main/packages/core/README.md) | Defines babel plugins and config files | +| [`@redwoodjs/create-redwood-app`](https://github.com/redwoodjs/redwood/blob/main/packages/create-redwood-app/README.md) | Enables `yarn create redwood-app`—downloads the latest release of Redwood and extracts it into the supplied directory | +| [`@redwoodjs/eslint-config`](https://github.com/redwoodjs/redwood/blob/main/packages/eslint-config/README.md) | Defines Redwood's eslint config | +| [`@redwoodjs/forms`](https://github.com/redwoodjs/redwood/blob/main/packages/forms/README.md) | Provides Form helpers | +| [`@redwoodjs/graphql-server`](https://github.com/redwoodjs/redwood/blob/main/packages/graphql-server/README.md) | Exposes functions to build the GraphQL API, provides services with `context`, and a set of envelop plugins to supercharge your GraphQL API with logging, authentication, error handling, directives and more | +| [`@redwoodjs/internal`](https://github.com/redwoodjs/redwood/blob/main/packages/internal/README.md) | Provides tooling to parse Redwood configs and get a project's paths | +| [`@redwoodjs/prerender`](https://github.com/redwoodjs/redwood/blob/main/packages/prerender/README.md) | Defines functionality for prerendering static content | +| [`@redwoodjs/record`](https://github.com/redwoodjs/redwood/blob/main/packages/record/README.md) | ORM built on top of Prisma. It may be extended in the future to wrap other database access packages | +| [`@redwoodjs/router`](https://github.com/redwoodjs/redwood/blob/main/packages/router/README.md) | The built-in router for Redwood | +| [`@redwoodjs/structure`](https://github.com/redwoodjs/redwood/blob/main/packages/structure/README.md) | Provides a way to build, validate and inspect an object graph that represents a complete Redwood project | +| [`@redwoodjs/telemetry`](https://github.com/redwoodjs/redwood/blob/main/packages/telemetry/README.md) | Provides functionality for anonymous data collection | +| [`@redwoodjs/testing`](https://github.com/redwoodjs/redwood/blob/main/packages/testing/README.md) | Provides helpful defaults when testing a Redwood project's web side | +| [`@redwoodjs/web`](https://github.com/redwoodjs/redwood/blob/main/packages/web/README.md) | Configures a Redwood's app web side: wraps the Apollo Client in `RedwoodApolloProvider`; defines the Cell HOC | ## Contributing Docs @@ -146,12 +152,15 @@ These docs are in the Framework repo, redwoodjs/redwood, and explain how to cont In general, they should consist of more straightforward explanations, are allowed to be technically heavy, and should be written for a more experienced audience. But as a best practice for collaborative projects, they should still provide a Vision + Roadmap and identify the project-point person(s) (or lead(s)). ## What makes for a good Pull Request? + In general, we don’t have a formal structure for PRs. Our goal is to make it as efficient as possible for anyone to open a PR. But there are some good practices, which are flexible. Just keep in mind that after opening a PR there’s more to do before getting to the finish line: + 1. Reviews from other contributors and maintainers 2. Update code and, after maintainer approval, merge-in changes to the `main` branch 3. Once PR is merged, it will be released and added to the next version Release Notes with a link for anyone to look at the PR and understand it. Some tips and advice: + - **Connect the dots and leave a breadcrumb**: link to related Issues, Forum discussions, etc. Help others follow the trail leading up to this PR. - **A Helpful Description**: What does the code in the PR do and what problem does it solve? How can someone use the code? Code sample, Screenshot, Quick Video… Any or all of this is so so good. - **Draft or Work in Progress**: You don’t have to finish the code to open a PR. Once you have a start, open it up! Most often the best way to move an Issue forward is to see the code in action. Also, often this helps identify ways forward before you spend a lot of time polishing. @@ -162,7 +171,9 @@ Some tips and advice: The best thing you can do is look through existing PRs, which will give you a feel for how things work and what you think is helpful. ### Example PR + If you’re looking for an example of “what makes a good PR”, look no further than this one by Kim-Adeline: + - [Convert component generator to TS #632](https://github.com/redwoodjs/redwood/pull/632) Not every PR needs this much information. But it’s definitely helpful when it does! diff --git a/docs/docs/contributing-walkthrough.md b/docs/docs/contributing-walkthrough.md index 89560c3907db..5747b425e799 100644 --- a/docs/docs/contributing-walkthrough.md +++ b/docs/docs/contributing-walkthrough.md @@ -14,11 +14,11 @@ description: Watch a video of the contributing process > 3. 🪜 **Step-by-step Walkthrough** (👈 you are here) > 4. 📈 [Current Project Status: v1 Release Board](https://github.com/orgs/redwoodjs/projects/6) > 5. 🤔 What should I work on? -> - ["Help Wanted" v1 Triage Board](https://redwoodjs.com/good-first-issue) -> - [Discovery Process and Open Issues](contributing-overview.md#what-should-i-work-on) - +> - ["Help Wanted" v1 Triage Board](https://redwoodjs.com/good-first-issue) +> - [Discovery Process and Open Issues](contributing-overview.md#what-should-i-work-on) ## Video Recording of Complete Contributing Process + The following recording is from a Contributing Workshop, following through the exact steps outlined below. The Workshop includes additional topics along with Q&A discussion. ## Prologue: Getting Started with Redwood and GitHub (and git) + These are the foundations for contributing, which you should be familiar with before starting the walkthrough. [**The Redwood Tutorial**](tutorial/foreword.md) @@ -42,6 +43,7 @@ The best (and most fun) way to learn Redwood and the underlying tools and techno - And browse through [How To's](how-to/index) ### GitHub (and Git) + Diving into Git and the GitHub workflow can feel intimidating if you haven’t experienced it before. The good news is there’s a lot of great material to help you learn and be committing in no time! - [Introduction to GitHub](https://lab.github.com/githubtraining/introduction-to-github) (overview of concepts and workflow) @@ -51,7 +53,9 @@ Diving into Git and the GitHub workflow can feel intimidating if you haven’t e ## The Full Workflow: From Local Development to a New PR ### Definitions + #### Redwood “Project” + We refer to the codebase of a Redwood application as a Project. This is what you install when you run `yarn create redwood-app `. It’s the thing you are building with Redwood. Lastly, you’ll find the template used to create a new project (when you run create redwood-app) here in GitHub: [redwoodjs/redwood/packages/create-redwood-app/template/](https://github.com/redwoodjs/redwood/tree/main/packages/create-redwood-app/template) @@ -59,9 +63,11 @@ Lastly, you’ll find the template used to create a new project (when you run cr We refer to this as the **CRWA Template or Project Template**. #### Redwood “Framework” + The Framework is the codebase containing all the packages (and other code) that is published on NPMjs.com as `@redwoodjs/`. The Framework repository on GitHub is here: [https://github.com/redwoodjs/redwood](https://github.com/redwoodjs/redwood) ### Development tools + These are the tools used and recommended by the Core Team. **VS Code** @@ -80,6 +86,7 @@ There’s nothing wrong with Terminal (on Mac) and plain zsh or bash. (If you’ Unfortunately, there are a lot of “gotchas” when it comes to working with Javascript-based frameworks on Windows. We do our best to point out (and resolve) issues, but our priority focus is on developing a Redwood app vs contributing to the Framework. (If you’re interested, there’s a lengthy Forum conversation about this with many suggestions.) All that said, we highly recommend using one of the following setups to maximize your workflow: + 1. Use [Git for Windows and Git Bash](how-to/windows-development-setup.md) (included in installation) 2. Use [WSL following this setup guide on the Forums](https://community.redwoodjs.com/t/windows-subsystem-for-linux-setup/2439) @@ -93,17 +100,21 @@ But don’t skip out reading the following steps in “Local Development Setup But when you’re ready, learn how to use it in the section at the end [“GitPod: Browser-based Development”](#gitpod-browser-based-development). ### Local Development Setup + #### Step 1: Redwood Framework + 1. **Fork the [Redwood Framework](https://github.com/redwoodjs/redwood)** into a personal repo 2. Using GitHub Desktop, **open the Framework Codebase** in a VS Code workspace 3. Commands to “**start fresh**” when working on the Framework - - `yarn install`: This installs the package dependencies in /node_modules using Yarn package manager. This command is the same as just typing `yarn`. Also, if you ever switch branches and want to make sure the install dependencies are correct, you can run `yarn install --force` (shorthand `yarn -f`). - - `git clean -fxd`: *You’ll only need to do this if you’ve already been developing and want to “start over” and reset your codebase*. This command will permanently delete everything that is .gitignored, e.g. /node_modules and /dist directories with package builds. When switching between branches, this command makes sure nothing is carried over that you don’t want. (Warning: it will delete .env files in a Redwood Project. To avoid this, you can use `git clean -fxd -e .env`.) + - `yarn install`: This installs the package dependencies in /node_modules using Yarn package manager. This command is the same as just typing `yarn`. Also, if you ever switch branches and want to make sure the install dependencies are correct, you can run `yarn install --force` (shorthand `yarn -f`). + - `git clean -fxd`: _You’ll only need to do this if you’ve already been developing and want to “start over” and reset your codebase_. This command will permanently delete everything that is .gitignored, e.g. /node_modules and /dist directories with package builds. When switching between branches, this command makes sure nothing is carried over that you don’t want. (Warning: it will delete .env files in a Redwood Project. To avoid this, you can use `git clean -fxd -e .env`.) 4. **Create a new branch** from the `main` branch -First make sure you’ve pulled all changes from the remote origin (GitHub repo) into your local branch. (If you just cloned from your fork, you should be up to date.) Then create a new branch. The nomenclature used by David Price is `-description-with-hyphens`, e.g. `dsp-add-eslint-config-redwood-toml`. It's simple to use VS Code or GitHub Desktop to manage branches. You can also do this via the CLI git checkout command. + First make sure you’ve pulled all changes from the remote origin (GitHub repo) into your local branch. (If you just cloned from your fork, you should be up to date.) Then create a new branch. The nomenclature used by David Price is `-description-with-hyphens`, e.g. `dsp-add-eslint-config-redwood-toml`. It's simple to use VS Code or GitHub Desktop to manage branches. You can also do this via the CLI git checkout command. #### Step 2: Test Project + There are several options for creating a local Redwood Project to use during development. Anytime you are developing against a test project, there are some specific gotchas to keep in mind: + - New projects always use the latest stable version of the Redwood packages, which will not be up to date with the latest Framework code in the `main` branch. - To use the packages corresponding with the latest code in the Framework `main` branch, you can use the canary version published to NPM. All you need to do to install the canary versions is run `yarn rw upgrade --tag canary` in your Project - Using a cloned project or repo? Just know there are likely breaking changes in `main` that haven’t been applied. You can examine merged PRs with the “breaking” label for more info. @@ -112,44 +123,49 @@ There are several options for creating a local Redwood Project to use during dev With those details out of the way, now is the time to choose an option below that meets your needs based on functionality and codebase version. **Build a Functional Test Project [Recommended]** + 1. 👉 **Use the build script to create a test project**: From the Framework root directory, run `yarn build:test-project `. This command installs a new project using the Template codebase from your current Framework branch, it then adds Tutorial features, and finally it initializes the DB (with seed data!). It should work 90% of the time and is the recommended starting place. We also use this out-of-the-box with Gitpod. **Other Options to create a project** 2. **Install a fresh project using the local Framework template code:** Sometimes you need to create a project that uses the Template codebase in your local branch of the Framework, e.g. your changes include modifications to the CRWA Template and need to be tested. Running the command above is exactly the same as `yarn create redwood- app …`, only it runs the command from your local Framework package using the local Template codebase. Note: this is the same command used at the start of the `yarn build:test-project` command. + ``` yarn babel-node packages/create-redwood-app/src/create-redwood-app.js ``` 3. **Clone the Redwood Tutorial App repo:** This is the codebase to use when starting the Redwood Tutorial Part 2. It is updated to the latest version and has the Blog features. This is often something we use for local development. Note: be sure to upgrade to canary and look out for breaking changes coming with the next release. - 4. **Install a fresh project**: `yarn create redwood-app ` If you just need a fresh installation 1) using the latest version template codebase and 2) without any features, then just install a new Redwood project. Note: this can have the same issues regarding the need to upgrade to canary and addressing breaking changes (see Notes from items 2 and 3 above). > Note: All the options above currently set the language to JavaScript. If you would like to work with TypeScript, you can add the option `--typescript` to either of the commands that run the create-redwood-app installation. #### Step 3: Link the local Framework with the local test Project + Once you work on the Framework code, you’ll most often want to run the code in a Redwood app for testing. However, the Redwood Project you created for testing is currently using the latest version (or canary) packages of Redwood published on NPMjs.com, e.g. [@redwoodjs/core](https://www.npmjs.com/package/@redwoodjs/core) So we’ll use the Redwood Framework (rwfw) command to connect our local Framework and test Projects, which allows the Project to run on the code for Packages we are currently developing. Run this command from the CLI in your test Project: + ``` RWFW_PATH= yarn rwfw project:sync ``` For Example: + ``` cd redwood-project RWFW_PATH=~/redwood yarn rwfw project:sync ``` -RWFW_PATH is the path to your local copy of the Redwood Framework. _Once provided to rwfw, it'll remember it and you shouldn't have to provide it again unless you move it._ +RWFW*PATH is the path to your local copy of the Redwood Framework. \_Once provided to rwfw, it'll remember it and you shouldn't have to provide it again unless you move it.* > **Heads up for Windows Devs** > Depending on your dev setup, Windows might balk at you setting the env var RWFW_PATH at the beginning of the command like this. If so, try prepending with `cross-env`, e.g. `yarn cross-env RWFW_PATH=~/redwood yarn rwfw` ... Or you can add the env var and value directly to your shell before running the command. As project:sync starts up, it'll start logging to the console. In order, it: + 1. cleans and builds the framework 2. copies the framework's dependencies to your project 3. runs yarn install in your project @@ -161,11 +177,13 @@ Step two is the only explicit change you'll see to your project. You'll see that All done? You’re ready to kill the link process with “ctrl + c”. You’ll need to confirm your root package.json no longer has the added dependencies. And, if you want to reset your test-project, you should run `yarn install --force`. #### Step 4: Framework Package(s) Local Testing + Within your Framework directory, use the following tools and commands to test your code: + 1. **Build the packages**: `yarn build` - - to delete all previous build directories: yarn build:clean + - to delete all previous build directories: yarn build:clean 2. **Syntax and Formatting**: `yarn lint` - - to fix errors or warnings: `yarn lint:fix` + - to fix errors or warnings: `yarn lint:fix` 3. **Run unit tests for each package**: `yarn test` 4. **Run through the Cypress E2E integration tests**: `yarn e2e` 5. **Check Yarn resolutions and package.json format**: `yarn check` @@ -173,14 +191,17 @@ Within your Framework directory, use the following tools and commands to test yo All of these checks are included in Redwood’s GitHub PR Continuous Integration (CI) automation. However, it’s good practice to understand what they do by using them locally. The E2E tests aren’t something we use every time anymore (because it takes a while), but you should learn how to use it because it comes in handy when your code is failing tests on GitHub and you need to diagnose. > **Heads up for Windows Devs** -> The Cypress E2E does *not* work on Windows. Two options are available if needed: +> The Cypress E2E does _not_ work on Windows. Two options are available if needed: +> > 1. Use Gitpod (see related section for info) > 2. When you create a PR, just ask for help from a maintainer #### Step 5: Open a PR 🚀 + You’ve made it to the fun part! It’s time to use the code you’re working on to create a new PR into the Redwood Framework `main` branch. We use GitHub Desktop to walk through the process of: + - Committing my changes to my development branch - Publishing (pushing) my branch and changes to my GitHub repo fork of the Redwood Framework - Opening a PR requesting to merge my forked-repo branch into the Redwood Framework `main` branch @@ -200,7 +221,7 @@ You have successfully submitted your PR! **Note:** Make sure you check the box that allows project maintainers to update your branch. This option is found on the "Open a pull request" form below the description textbox. Checking this option helps move a PR forward more quickly, as branches always need to be updated from `main` before we can merge. **When is my code “ready” to open a PR?** -Most of the action, communication, and decisions happen within a PR. A common mistake new contributors make is *waiting* until their code is “perfect” before opening a PR. Assuming your PR has some code changes, it’s great practice to open a [Draft PR](https://github.blog/2019-02-14-introducing-draft-pull-requests/) (setting during the PR creation), which you can use to start discussion and ask questions. PRs are closed all the time without being merged, often because they are replaced by another PR resulting from decisions and discussion. It’s part of the process. More importantly, it means collaboration is happening! +Most of the action, communication, and decisions happen within a PR. A common mistake new contributors make is _waiting_ until their code is “perfect” before opening a PR. Assuming your PR has some code changes, it’s great practice to open a [Draft PR](https://github.blog/2019-02-14-introducing-draft-pull-requests/) (setting during the PR creation), which you can use to start discussion and ask questions. PRs are closed all the time without being merged, often because they are replaced by another PR resulting from decisions and discussion. It’s part of the process. More importantly, it means collaboration is happening! What isn’t a fun experience is spending a whole bunch of time on code that ends up not being the correct direction or is unnecessary/redundant to something that already exists. This is a part of the learning process. But it’s another reason to open a draft PR sooner than later to get confirmation and questions out of the way before investing time into refining and details. @@ -209,7 +230,9 @@ When in doubt, just try first and ask for help and direction! Refer to the [What makes for a good Pull Request?](contributing-overview.md#what-makes-for-a-good-pull-request) section in [Contributing Overview](contributing-overview.md)for general good practices when opening PR. ### Gitpod: Browser-based Development + [Gitpod](http://gitpod.io) has recently been integrated with Redwood to JustWork™ with any branch or PR. When a virtual Gitpod workspace is initialized, it automatically: + 1. Checks-out the code from your branch or PR 2. Run Yarn installation 3. Creates the functional Test Project via `yarn build:test-project` @@ -222,6 +245,7 @@ Refer to the [What makes for a good Pull Request?](contributing-overview.md#what **Demo of Gitpod** David briefly walks-through an automatically prebuilt Gitpod workspace here: + - [Gitpod + RedwoodJS 3-minute Walkthrough](https://youtu.be/_kMuTW3x--s) Make sure you watch until the end where David shows how to set up your integration with GitHub and VS Code sync. 🤩 @@ -229,12 +253,12 @@ Make sure you watch until the end where David shows how to set up your integrati **Start a Gitpod Workspace** There are two ways to get started with Gitpod + Redwood. -*Option 1: Open a PR* +_Option 1: Open a PR_ Every PR will trigger a Gitpod prebuild using the PR branch. Just look for Gitpod in the list of checks at the bottom of the PR — click the “Details” link and away you’ll go! PR Checks -*Option 2: Use the link from your project or branch* +_Option 2: Use the link from your project or branch_ You can initialize a workspace using this URL pattern: @@ -243,9 +267,9 @@ https://gitpod.io/# ``` For example, this link will start a workspace using the RedwoodJS main branch: + - https://gitpod.io/#https://github.com/redwoodjs/redwood And this link will start a workspace for a PR #3434: -- https://gitpod.io/#https://github.com/redwoodjs/redwood/pull/3434 - +- https://gitpod.io/#https://github.com/redwoodjs/redwood/pull/3434 diff --git a/docs/docs/cors.md b/docs/docs/cors.md index 5325cedc2ba0..3781aeb19fe2 100644 --- a/docs/docs/cors.md +++ b/docs/docs/cors.md @@ -19,7 +19,7 @@ This will become obvious when you point your browser to your site and see none o Dealing with CORS can complicate your app and make it harder to deploy to new hosts, run in different environments, etc. Is there a way to avoid CORS altogether? -Yes! If you can add a proxy between your web and api sides, all requests will *appear* to be going to and from the same domain (the web side, even though behind the scenes they are forwarded somewhere else). This functionality is included automatically with hosts like [Netlify](https://docs.netlify.com/routing/redirects/rewrites-proxies/#proxy-to-another-service) or [Vercel](https://vercel.com/docs/cli#project-configuration/rewrites). With a host like [Render](https://render-web.onrender.com/docs/deploy-redwood#deployment) you can enable a proxy with a simple config option. Most providers should provide this functionality through a combination of provider-specific config and/or web server configuration. +Yes! If you can add a proxy between your web and api sides, all requests will _appear_ to be going to and from the same domain (the web side, even though behind the scenes they are forwarded somewhere else). This functionality is included automatically with hosts like [Netlify](https://docs.netlify.com/routing/redirects/rewrites-proxies/#proxy-to-another-service) or [Vercel](https://vercel.com/docs/cli#project-configuration/rewrites). With a host like [Render](https://render-web.onrender.com/docs/deploy-redwood#deployment) you can enable a proxy with a simple config option. Most providers should provide this functionality through a combination of provider-specific config and/or web server configuration. ## GraphQL Config @@ -40,7 +40,7 @@ export const handler = createGraphQLHandler({ }) ``` -Note that the `origin` needs to be a complete URL including the scheme (`https`). This is the domain that requests are allowed to come *from*. In this example we assume the web side is served from `https://www.example.com`. If you have multiple servers that should be allowed to access the api, you can pass an array of them instead: +Note that the `origin` needs to be a complete URL including the scheme (`https`). This is the domain that requests are allowed to come _from_. In this example we assume the web side is served from `https://www.example.com`. If you have multiple servers that should be allowed to access the api, you can pass an array of them instead: ```jsx cors: { @@ -56,11 +56,11 @@ The following config only applies if you're using [dbAuth](authentication.md#sel You'll need to configure several things: -* Add CORS config for GraphQL -* Add CORS config for the auth function -* Cookie config for the auth function -* Allow sending of credentials in GraphQL XHR requests -* Allow sending of credentials in auth function requests +- Add CORS config for GraphQL +- Add CORS config for the auth function +- Cookie config for the auth function +- Allow sending of credentials in GraphQL XHR requests +- Allow sending of credentials in auth function requests Here's how you configure each of these: @@ -84,7 +84,7 @@ export const handler = createGraphQLHandler({ }) ``` -`origin` is the domain(s) that requests come *from* (the web side). +`origin` is the domain(s) that requests come _from_ (the web side). ### Auth CORS Config @@ -119,7 +119,7 @@ const authHandler = new DbAuthHandler(event, context, { }) ``` -Just like the GraphQL config, `origin` is the domain(s) that requests come *from* (the web side). +Just like the GraphQL config, `origin` is the domain(s) that requests come _from_ (the web side). ### Cookie Config @@ -209,7 +209,7 @@ Forwarding http://fb6d701c44b5.ngrok.io -> http://localhost:8911 Forwarding https://fb6d701c44b5.ngrok.io -> http://localhost:8911 ``` -Note the two different domains. Copy the `https` domain from the api side because we'll need it in a moment. Even if the Redwood dev server isn't running you can leave these tunnels running, and when the dev server *does* start, they'll just start on those domains again. +Note the two different domains. Copy the `https` domain from the api side because we'll need it in a moment. Even if the Redwood dev server isn't running you can leave these tunnels running, and when the dev server _does_ start, they'll just start on those domains again. ### `redwood.toml` Config @@ -255,7 +255,7 @@ Where you get this domain from will depend on how you expose your app to the out You'll need to apply an option when starting the dev server to tell it to accept requests from any host, not just `localhost`: ```bash -> yarn rw dev --fwd="--allowed-hosts all" +rw > yarn dev --fwd="--allowed-hosts all" ``` ### Wrapping Up diff --git a/docs/docs/create-redwood-app.md b/docs/docs/create-redwood-app.md index 61e2d15b5dfe..1d4fe329bde7 100644 --- a/docs/docs/create-redwood-app.md +++ b/docs/docs/create-redwood-app.md @@ -12,6 +12,7 @@ yarn create redwood-app ``` ## Set up for success + Redwood requires that you're running Node version 20 or higher. If you're running Node version 21.0.0 or higher, you can still use Create Redwood App, but it may make your project incompatible with some deploy targets, such as AWS Lambdas. @@ -35,11 +36,13 @@ To upgrade your version of yarn, [you can refer to the yarn documentation](https ## What you can expect ### Select your preferred language + Options: TypeScript (default) or JavaScript If you choose JavaScript, you can always [add TypeScript later](/docs/typescript/introduction#converting-a-javascript-project-to-typescript). ### Do you want to initialize a git repo? + Options: yes (default) or no If you mark "yes", then it will ask you to **Enter a commit message**. The default message is "Initial commit." @@ -56,6 +59,7 @@ git commit -m "Initial commit" If you're new to git, here's a recommended playlist on YouTube: [git for Beginners](https://www.youtube.com/playlist?list=PLrz61zkUHJJFmfTgOVL1mBw_NZcgGe882) ### Do you want to run `yarn install`? + Options: yes (default) or no _NOTE: This prompt will only display if you're running yarn, version 1._ @@ -83,21 +87,20 @@ yarn rw dev - You can visit the Redwood GraphQL Playground at `http://localhost:8911/graphql`. ## Flags + You can by pass these prompts by using the following flags: -| Flag | Alias | What it does | -| :--- | :--- | :--- | -| `--yarn-install` | | Run `yarn install` | -| `--typescript` | `ts` | Set TypeScript as the preferred language (pass `--no-typescript` to use JavaScript) | -| `--overwrite` | | Overwrites the existing directory, if it has the same name | -| `--git-init` | `git` | Initializes a git repository | -| `--commit-message "Initial commit"` | `m` | Specifies the initial git commit message | -| `--yes` | `y` | Automatically select all defaults | +| Flag | Alias | What it does | +| :---------------------------------- | :---- | :---------------------------------------------------------------------------------- | +| `--yarn-install` | | Run `yarn install` | +| `--typescript` | `ts` | Set TypeScript as the preferred language (pass `--no-typescript` to use JavaScript) | +| `--overwrite` | | Overwrites the existing directory, if it has the same name | +| `--git-init` | `git` | Initializes a git repository | +| `--commit-message "Initial commit"` | `m` | Specifies the initial git commit message | +| `--yes` | `y` | Automatically select all defaults | For example, here's the project with all flags enabled: ```terminal yarn create redwood-app --typescript --git-init --commit-message "Initial commit" --yarn-install ``` - - diff --git a/docs/docs/data-migrations.md b/docs/docs/data-migrations.md index 3f7d32d389fd..4f7e85e03e94 100644 --- a/docs/docs/data-migrations.md +++ b/docs/docs/data-migrations.md @@ -8,12 +8,12 @@ description: Track changes to database content There are two kinds of changes you can make to your database: -* Changes to structure -* Changes to content +- Changes to structure +- Changes to content -In Redwood, [Prisma Migrate](https://www.prisma.io/docs/reference/tools-and-interfaces/prisma-migrate) takes care of codifying changes to your database *structure* in code by creating a snapshot of changes to your database that can be reliably repeated to end up in some known state. +In Redwood, [Prisma Migrate](https://www.prisma.io/docs/reference/tools-and-interfaces/prisma-migrate) takes care of codifying changes to your database _structure_ in code by creating a snapshot of changes to your database that can be reliably repeated to end up in some known state. -To track changes to your database *content*, Redwood includes a feature we call **Data Migration**. As your app evolves and you move data around, you need a way to consistently declare how that data should move. +To track changes to your database _content_, Redwood includes a feature we call **Data Migration**. As your app evolves and you move data around, you need a way to consistently declare how that data should move. Imagine a `User` model that contains several columns for user preferences. Over time, you may end up with more and more preferences to the point that you have more preference-related columns in the table than you do data unique to the user! This is a common occurrence as applications grow. You decide that the app should have a new model, `Preference`, to keep track of them all (and `Preference` will have a foreign key `userId` to reference it back to its `User`). You'll use Prisma Migrate to create the new `Preference` model, but how do you copy the preference data to the new table? Data migrations to the rescue! @@ -22,9 +22,11 @@ Imagine a `User` model that contains several columns for user preferences. Over Just like Prisma, we will store which data migrations have run in the database itself. We'll create a new database table `DataMigration` to keep track of which ones have run already. Rather than create this model by hand, Redwood includes a CLI tool to add the model to `schema.prisma` and create the DB migration that adds the table to the database: + ``` yarn rw data-migrate install ``` + You'll see a new directory created at `api/db/dataMigrations` which will store our individual migration tasks. Take a look at `schema.prisma` to see the new model definition: @@ -39,21 +41,27 @@ model RW_DataMigration { ``` The install script also ran `yarn rw prisma migrate dev --create-only` automatically so you have a DB migration ready to go. You just need to run the `prisma migrate dev` command to apply it: + ``` yarn rw prisma migrate dev ``` + ## Creating a New Data Migration Data migrations are just plain Typescript or Javascript files which export a single anonymous function that is given a single argument—an instance of `PrismaClient` called `db` that you can use to access your database. The files have a simple naming convention: + ``` {version}-{name}.js ``` + Where `version` is a timestamp, like `20200721123456` (an ISO8601 datetime without any special characters or zone identifier), and `name` is a param-case human readable name for the migration, like `copy-preferences`. To create a data migration we have a generator: + ``` yarn rw generate dataMigration copyPreferences ``` + This will create `api/db/dataMigrations/20200721123456-copy-preferences.js`: ```jsx title="api/db/dataMigrations/20200721123456-copy-preferences.js" @@ -84,8 +92,8 @@ export default async ({ db }) => { newsletter: user.newsletter, frequency: user.frequency, theme: user.theme, - user: { connect: { id: user.id } } - } + user: { connect: { id: user.id } }, + }, }) }) } @@ -100,23 +108,25 @@ This loops through each existing `User` and creates a new `Preference` record co > > When going to production, you would need to run this as two separate deploys to ensure no data is lost. > -> The reason is that all DB migrations are run and *then* all data migrations. So if you had two DB migrations (one to create `Preference` and one to drop the unneeded columns from `User`) they would both run before the Data Migration, so the columns containing the preferences are gone before the data migration gets a chance to copy them over! +> The reason is that all DB migrations are run and _then_ all data migrations. So if you had two DB migrations (one to create `Preference` and one to drop the unneeded columns from `User`) they would both run before the Data Migration, so the columns containing the preferences are gone before the data migration gets a chance to copy them over! > > **Remember**: Any destructive action on the database (removing a table or column especially) needs to be a two step process to avoid data loss. ## Running a Data Migration When you're ready, you can execute your data migration with `data-migrate`'s `up` command: + ``` yarn rw data-migrate up ``` + This goes through each file in `api/db/dataMigrations`, compares it against the list of migrations that have already run according to the `DataMigration` table in the database, and executes any that aren't present in that table, sorted oldest to newest based on the timestamp in the filename. Any logging statements (like `console.info()`) you include in your data migration script will be output to the console as the script is running. If the script encounters an error, the process will abort, skipping any following data migrations. -> The example data migration above didn't include this for brevity, but you should always run your data migration [inside a transaction](https://www.prisma.io/docs/reference/tools-and-interfaces/prisma-client/transactions#bulk-operations-experimental) so that if any errors occur during execution the database will not be left in an inconsistent state where only *some* of your changes were performed. +> The example data migration above didn't include this for brevity, but you should always run your data migration [inside a transaction](https://www.prisma.io/docs/reference/tools-and-interfaces/prisma-client/transactions#bulk-operations-experimental) so that if any errors occur during execution the database will not be left in an inconsistent state where only _some_ of your changes were performed. ## Long-term Maintainability @@ -137,8 +147,8 @@ export default async ({ db }) => { newsletter: user.newsletter, frequency: user.frequency, theme: user.theme, - user: { connect: { id: user.id } } - } + user: { connect: { id: user.id } }, + }, }) }) } @@ -148,11 +158,14 @@ export default async ({ db }) => { ## Lifecycle Summary Run once: + ``` yarn rw data-migrate install yarn rw prisma migrate dev ``` + Run every time you need a new data migration: + ``` yarn rw generate dataMigration migrationName yarn rw data-migrate up diff --git a/docs/docs/database-seeds.md b/docs/docs/database-seeds.md index 65ffe013993a..e8cdc1917ce5 100644 --- a/docs/docs/database-seeds.md +++ b/docs/docs/database-seeds.md @@ -7,15 +7,15 @@ a new environment. Seed data are things like: -* An admin user so that you can log in to your new instance -* A list of categories that can be assigned to a Product -* Lists of roles and permissions +- An admin user so that you can log in to your new instance +- A list of categories that can be assigned to a Product +- Lists of roles and permissions Seed data is not meant for: -* Sample data to be used in development -* Data to run tests against -* Randomized data +- Sample data to be used in development +- Data to run tests against +- Randomized data ## Best Practices @@ -31,7 +31,7 @@ already exists, and if so just update it, if not then create it. But, this technique requires a separate SQL statement for each member of your data array and is less performant than `createMany()`. -You could also do a check if *any* data exists in the database first, and if +You could also do a check if _any_ data exists in the database first, and if not, create the records with `createMany()`. However, this means that any existing seed data that may have been modified will remain, and would not be updated to match what you expect in your seed. @@ -46,7 +46,7 @@ Seeds are automatically run the first time you migrate your database: yarn rw prisma migrate dev ``` -They are run *every* time you reset your database: +They are run _every_ time you reset your database: ```bash yarn rw prisma migrate reset @@ -148,14 +148,14 @@ export default async () => { { name: 'Fiction', bisacCode: 'FIC000000' }, { name: 'Nature', bisacCode: 'NAT000000' }, { name: 'Travel', bisacCode: 'TRV000000' }, - { name: 'World History', bisacCode: 'HIS037000' } + { name: 'World History', bisacCode: 'HIS037000' }, ] for (const item of data) { - await db.category.upsert({ + await db.category.upsert({ where: { name: item.name }, update: { code: item.code }, - create: { name: item.name, code: item.code } + create: { name: item.name, code: item.code }, }) } } catch (error) { @@ -167,7 +167,7 @@ export default async () => { You can now execute this seed as many times as you want and you'll end up with that exact list in the database each time. And, any additional categories you've created in the meantime will remain. Remember: seeds are meant to be the -*minimum* amount of data you need for your app to run, not necessarily *all* the +_minimum_ amount of data you need for your app to run, not necessarily _all_ the data that will ever be present in those tables. # Seeding users for dbAuth @@ -182,27 +182,27 @@ import { hashPassword } from '@redwoodjs/auth-dbauth-api' export default async () => { const users = [ { name: 'John', email: 'john@example.com', password: 'secret1' }, - { name: 'Jane', email: 'jane@example.com', password: 'secret2' } + { name: 'Jane', email: 'jane@example.com', password: 'secret2' }, ] for (const user of users) { const [hashedPassword, salt] = hashPassword(user.password) await db.user.upsert({ - where: { - email: user.email + where: { + email: user.email, }, - create: { + create: { name: user.name, email: user.email, hashedPassword, - salt + salt, }, update: { name: user.name, hashedPassword, - salt - } + salt, + }, }) } } diff --git a/docs/docs/deploy/baremetal.md b/docs/docs/deploy/baremetal.md index aec882f28381..ba99355f6fa3 100644 --- a/docs/docs/deploy/baremetal.md +++ b/docs/docs/deploy/baremetal.md @@ -48,8 +48,9 @@ The Baremetal deploy runs several commands in sequence. These can be customized, ### First Run Lifecycle If the `--first-run` flag is specified then step 6 above will execute the following commands instead: - - `pm2 start [service]` - starts the serving process(es) - - `pm2 save` - saves the running services to the deploy users config file for future startup. See [Starting on Reboot](#starting-on-reboot) for further information + +- `pm2 start [service]` - starts the serving process(es) +- `pm2 save` - saves the running services to the deploy users config file for future startup. See [Starting on Reboot](#starting-on-reboot) for further information ## Directory Structure @@ -155,29 +156,29 @@ This lists a single server, in the `production` environment, providing the hostn #### Config Options -* `host` - hostname to the server -* `port` - [optional] ssh port for server connection, defaults to 22 -* `username` - the user to login as -* `password` - [optional] if you are using password authentication, include that here -* `privateKey` - [optional] if you connect with a private key, include the content of the key here, as a buffer: `privateKey: Buffer.from('...')`. Use this *or* `privateKeyPath`, not both. -* `privateKeyPath` - [optional] if you connect with a private key, include the path to the key here: `privateKeyPath: path.join('path','to','key.pem')` Use this *or* `privateKey`, not both. -* `passphrase` - [optional] if your private key contains a passphrase, enter it here -* `agentForward` - [optional] if you have [agent forwarding](https://docs.github.com/en/developers/overview/using-ssh-agent-forwarding) enabled, set this to `true` and your own credentials will be used for further SSH connections from the server (like when connecting to GitHub) -* `sides` - An array of sides that will be built on this server -* `packageManagerCommand` - The package manager bin to call, defaults to `yarn` but could be updated to be prefixed with another command first, for example: `doppler run -- yarn` -* `monitorCommand` - The monitor bin to call, defaults to `pm2` but could be updated to be prefixed with another command first, for example: `doppler run -- pm2` -* `path` - The absolute path to the root of the application on the server -* `migrate` - [optional] Whether or not to run migration processes on this server, defaults to `true` -* `processNames` - An array of service names from `ecosystem.config.js` which will be (re)started on a successful deploy -* `repo` - The path to the git repo to clone -* `branch` - [optional] The branch to deploy (defaults to `main`) -* `keepReleases` - [optional] The number of previous releases to keep on the server, including the one currently being served (defaults to 5) +- `host` - hostname to the server +- `port` - [optional] ssh port for server connection, defaults to 22 +- `username` - the user to login as +- `password` - [optional] if you are using password authentication, include that here +- `privateKey` - [optional] if you connect with a private key, include the content of the key here, as a buffer: `privateKey: Buffer.from('...')`. Use this _or_ `privateKeyPath`, not both. +- `privateKeyPath` - [optional] if you connect with a private key, include the path to the key here: `privateKeyPath: path.join('path','to','key.pem')` Use this _or_ `privateKey`, not both. +- `passphrase` - [optional] if your private key contains a passphrase, enter it here +- `agentForward` - [optional] if you have [agent forwarding](https://docs.github.com/en/developers/overview/using-ssh-agent-forwarding) enabled, set this to `true` and your own credentials will be used for further SSH connections from the server (like when connecting to GitHub) +- `sides` - An array of sides that will be built on this server +- `packageManagerCommand` - The package manager bin to call, defaults to `yarn` but could be updated to be prefixed with another command first, for example: `doppler run -- yarn` +- `monitorCommand` - The monitor bin to call, defaults to `pm2` but could be updated to be prefixed with another command first, for example: `doppler run -- pm2` +- `path` - The absolute path to the root of the application on the server +- `migrate` - [optional] Whether or not to run migration processes on this server, defaults to `true` +- `processNames` - An array of service names from `ecosystem.config.js` which will be (re)started on a successful deploy +- `repo` - The path to the git repo to clone +- `branch` - [optional] The branch to deploy (defaults to `main`) +- `keepReleases` - [optional] The number of previous releases to keep on the server, including the one currently being served (defaults to 5) The easiest connection method is generally to include your own public key in the server's `~/.ssh/authorized_keys` mannually or by running `ssh-copy-id user@server.com` from your local machine, [enable agent forwarding](https://docs.github.com/en/developers/overview/using-ssh-agent-forwarding), and then set `agentForward = true` in `deploy.toml`. This will allow you to use your own credentials when pulling code from GitHub (required for private repos). Otherwise you can create a [deploy key](https://docs.github.com/en/developers/overview/managing-deploy-keys) and keep it on the server. #### Using Environment Variables in `deploy.toml` -Similarly to `redwood.toml`, `deploy.toml` supports interpolation of environment variables. For more details on how to use the environment variable interpolation see [Using Environment Variables in redwood.toml](/docs/app-configuration-redwood-toml#using-environment-variables-in-redwoodtoml) +Similarly to `redwood.toml`, `deploy.toml` supports interpolation of environment variables. For more details on how to use the environment variable interpolation see [Using Environment Variables in redwood.toml](/docs/app-configuration-redwood-toml#using-environment-variables-in-redwoodtoml) #### Multiple Servers @@ -278,7 +279,7 @@ You'll want to create an `.env` file in this directory containing any environmen The deployment process uses a '[non-interactive](https://tldp.org/LDP/abs/html/intandnonint.html)' SSH session to run commands on the remote server. A non-interactive session will often load a minimal amount of settings for better compatibility and speed. In some versions of Linux `.bashrc` by default does not load (by design) from a non-interactive session. This can lead to `yarn` (or other commands) not being found by the deployment script, even though they are in your path, because additional ENV vars are set in `~/.bashrc` which provide things like NPM paths and setup. -A quick fix on some distros is to edit the deployment user's `~/.bashrc` file and comment out the lines that *stop* non-interactive processing. +A quick fix on some distros is to edit the deployment user's `~/.bashrc` file and comment out the lines that _stop_ non-interactive processing. ```diff title="~/.bashrc" # If not running interactively, don't do anything @@ -322,9 +323,9 @@ If it worked, hooray! You're deployed to BAREMETAL. If not, read on... On the server you should see a new directory inside the `path` you defined in `deploy.toml`. It should be a timestamp of the deploy, like: ```bash -drwxrwxr-x 7 ubuntu ubuntu 4096 Apr 22 23:00 ./ -drwxr-xr-x 7 ubuntu ubuntu 4096 Apr 22 22:46 ../ --rw-rw-r-- 1 ubuntu ubuntu 1167 Apr 22 20:49 .env +drwxrwxr-x 7 ubuntu ubuntu 4096 Apr 22 23:00 ./ +drwxr-xr-x 7 ubuntu ubuntu 4096 Apr 22 22:46 ../ +-rw-rw-r-- 1 ubuntu ubuntu 1167 Apr 22 20:49 .env drwxrwxr-x 10 ubuntu ubuntu 4096 Apr 22 21:43 20220422214218/ ``` @@ -408,7 +409,7 @@ Note that if you have more than one process running, like we do here, requesting ## Starting Processes on Server Restart -The `pm2` service requires some system "hooks" to be installed so it can boot up using your system's service manager. Otherwise, your PM2 services will need to be manually started again on a server restart. These steps only need to be run the first time you install PM2. +The `pm2` service requires some system "hooks" to be installed so it can boot up using your system's service manager. Otherwise, your PM2 services will need to be manually started again on a server restart. These steps only need to be run the first time you install PM2. SSH into your server and then run: @@ -416,11 +417,11 @@ SSH into your server and then run: pm2 startup ``` -You will see some output similar to the output below. We care about the output after "copy/paste the following command:" You'll need to do just that: copy the command starting with `sudo` and then paste and execute it. *Note* this command uses `sudo` so you'll need the root password to the machine in order for it to complete successfully. +You will see some output similar to the output below. We care about the output after "copy/paste the following command:" You'll need to do just that: copy the command starting with `sudo` and then paste and execute it. _Note_ this command uses `sudo` so you'll need the root password to the machine in order for it to complete successfully. :::warning -The below text is *example* output, yours will be different, don't copy and paste ours! +The below text is _example_ output, yours will be different, don't copy and paste ours! ::: @@ -463,22 +464,22 @@ Baremetal supports running your own custom commands before or after the regular You can define your before/after commands in three different places: -* Globally - runs for any environment -* Environment specific - runs for only a single environment -* Server specific - runs for only a single server in a single environment +- Globally - runs for any environment +- Environment specific - runs for only a single environment +- Server specific - runs for only a single server in a single environment :::warning Custom commands are run in the new **deploy** directory, not the root of your application directory. During a deploy the `current` symlink will point to the previous directory while your code is executed in the new one, before the `current` symlink location is updated. ```bash -drwxrwxr-x 5 ubuntu ubuntu 4096 May 10 18:20 ./ -drwxr-xr-x 7 ubuntu ubuntu 4096 Apr 27 17:43 ../ -drwxrwxr-x 2 ubuntu ubuntu 4096 May 9 22:59 20220503211428/ -drwxrwxr-x 2 ubuntu ubuntu 4096 May 9 22:59 20220503211429/ -drwxrwxr-x 10 ubuntu ubuntu 4096 May 10 18:18 20220510181730/ <-- commands are run in here -lrwxrwxrwx 1 ubuntu ubuntu 14 May 10 18:19 current -> 20220503211429/ --rw-rw-r-- 1 ubuntu ubuntu 1167 Apr 22 20:49 .env +drwxrwxr-x 5 ubuntu ubuntu 4096 May 10 18:20 ./ +drwxr-xr-x 7 ubuntu ubuntu 4096 Apr 27 17:43 ../ +drwxrwxr-x 2 ubuntu ubuntu 4096 May 9 22:59 20220503211428/ +drwxrwxr-x 2 ubuntu ubuntu 4096 May 9 22:59 20220503211429/ +drwxrwxr-x 10 ubuntu ubuntu 4096 May 10 18:18 20220510181730/ commands are run in here < -- +lrwxrwxrwx 1 ubuntu ubuntu 14 May 10 18:19 current - > 20220503211429/ +-rw-rw-r-- 1 ubuntu ubuntu 1167 Apr 22 20:49 .env ``` ::: @@ -536,7 +537,6 @@ host = 'server.com' You can include commands in any/all of the three configurations (global, env and server) and they will all be stacked up and run in that order: `global -> environment -> server`. For example: - ```toml [[production.servers]] host = 'server.com' @@ -571,7 +571,7 @@ You can even rollback multiple deploys, up to the total number you still have de yarn rw deploy baremetal production --rollback 3 ``` -Note that this will *not* rollback your database—if you had a release that changed the database, that updated database will still be in effect, but with the previous version of the web and api sides. Trying to undo database migrations is a very difficult proposition and isn't even possible in many cases. +Note that this will _not_ rollback your database—if you had a release that changed the database, that updated database will still be in effect, but with the previous version of the web and api sides. Trying to undo database migrations is a very difficult proposition and isn't even possible in many cases. Make sure to thoroughly test releases that change the database before doing it for real! @@ -583,7 +583,7 @@ If you find that you have a particular complex deploy, one that may involve inco yarn rw deploy baremetal production --maintenance up ``` -It does this by replacing `web/dist/200.html` with `web/src/maintenance.html`. This means any new web requests, at any URL, will show the maintenance page. This process also stops any services listed in the `processNames` option of `deploy.toml`—this is important for the api server as it will otherwise keep serving requests to users currently running the app, even though no *new* users can get the Javascript packages required to start a new session in their browser. +It does this by replacing `web/dist/200.html` with `web/src/maintenance.html`. This means any new web requests, at any URL, will show the maintenance page. This process also stops any services listed in the `processNames` option of `deploy.toml`—this is important for the api server as it will otherwise keep serving requests to users currently running the app, even though no _new_ users can get the Javascript packages required to start a new session in their browser. You can remove the maintenance page with: @@ -613,7 +613,7 @@ The default configuration, which requires the least amount of manual configurati ### Redwood Serves Web and Api Sides, Bind to Port 80 -This is almost as easy as the default configuration, you just need to tell Redwood to bind to port 80. However, most *nix distributions will not allow a process to bind to ports lower than 1024 without root/sudo permissions. There is a command you can run to allow access to a specific binary (`node` in this case) to bind to one of those ports anyway. +This is almost as easy as the default configuration, you just need to tell Redwood to bind to port 80. However, most \*nix distributions will not allow a process to bind to ports lower than 1024 without root/sudo permissions. There is a command you can run to allow access to a specific binary (`node` in this case) to bind to one of those ports anyway. #### Tell Redwood to Bind to Port 80 @@ -729,8 +729,8 @@ module.exports = { exec_mode: 'cluster', wait_ready: true, listen_timeout: 10000, - } - ] + }, + ], } ``` diff --git a/docs/docs/deploy/coherence.md b/docs/docs/deploy/coherence.md index a2b9ec845d2a..ccd5bdc00088 100644 --- a/docs/docs/deploy/coherence.md +++ b/docs/docs/deploy/coherence.md @@ -34,6 +34,7 @@ yarn rw setup deploy coherence The command will inspect your Prisma config to determine if you're using a supported database (at the moment, only `postgres` or `mysql` are supported on Coherence). Then follow the [Coherence Redwood deploy docs](https://docs.withcoherence.com/docs/configuration/frameworks#redwood-js) for more information, including if you want to set up: + - a redis server - database migration/seeding/snapshot loading - cron jobs or async workers diff --git a/docs/docs/deploy/edgio.md b/docs/docs/deploy/edgio.md index 66df9c717529..fd115935b85b 100644 --- a/docs/docs/deploy/edgio.md +++ b/docs/docs/deploy/edgio.md @@ -1,13 +1,14 @@ # Deploy to Edgio ->⚠️ **Deprecated** +> ⚠️ **Deprecated** > ->As of Redwood v7, we are deprecating this deploy setup as an "officially" supported provider. This means: ->- For projects already using this deploy provider, there will be NO change at this time ->- Both the associated `setup` and `deploy` commands will remain in the framework as is; when setup is run, there will be a “deprecation” message ->- We will no longer run CI/CD on the Edgio deployments, which means we are no longer guaranteeing this deploy works with each new version +> As of Redwood v7, we are deprecating this deploy setup as an "officially" supported provider. This means: > ->If you have concerns or questions about our decision to deprecate this deploy provider please reach out to us on our [community forum](https://community.redwoodjs.com). +> - For projects already using this deploy provider, there will be NO change at this time +> - Both the associated `setup` and `deploy` commands will remain in the framework as is; when setup is run, there will be a “deprecation” message +> - We will no longer run CI/CD on the Edgio deployments, which means we are no longer guaranteeing this deploy works with each new version +> +> If you have concerns or questions about our decision to deprecate this deploy provider please reach out to us on our [community forum](https://community.redwoodjs.com). [Edgio](https://edg.io) extends the capabilities of a traditional CDN by not only hosting your static content, but also providing server-side rendering for progressive web applications as well as caching both your APIs and HTML at the network edge to provide your users with the fastest browsing experience. @@ -18,8 +19,8 @@ In order to deploy your RedwoodJS project to Edgio, the project must first be in 1. In your project, run the command `yarn rw setup deploy edgio`. 2. Verify the changes to your project, commit and push to your repository. 3. Deploy your project to Edgio - 1. If this is your first time deploying to Edgio, the interactive CLI will prompt to authenticate using your browser. You can start the deploy by running `yarn rw deploy edgio`. - 2. If you are deploying from a **non-interactive** environment, you will need to create an account on [Edgio Developer Console](https://app.layer0.co) first and setup a [deploy token](https://docs.edg.io/guides/deploy_apps#deploy-from-ci). Once the deploy token is created, save it as a secret to your environment. You can start the deploy by running `yarn rw deploy edgio --token=XXX`. -4. Follow the link in the output to view your site live once deployment has completed! +4. If this is your first time deploying to Edgio, the interactive CLI will prompt to authenticate using your browser. You can start the deploy by running `yarn rw deploy edgio`. +5. If you are deploying from a **non-interactive** environment, you will need to create an account on [Edgio Developer Console](https://app.layer0.co) first and setup a [deploy token](https://docs.edg.io/guides/deploy_apps#deploy-from-ci). Once the deploy token is created, save it as a secret to your environment. You can start the deploy by running `yarn rw deploy edgio --token=XXX`. +6. Follow the link in the output to view your site live once deployment has completed! For more information on deploying to Edgio, check out the [documentation](https://docs.edg.io). diff --git a/docs/docs/deploy/flightcontrol.md b/docs/docs/deploy/flightcontrol.md index ffcb0409c42e..9d1c544703a3 100644 --- a/docs/docs/deploy/flightcontrol.md +++ b/docs/docs/deploy/flightcontrol.md @@ -13,11 +13,11 @@ description: How to deploy a Redwood app to AWS via Flightcontrol 3. Commit the changes and push to github. 4. If you don't have an account, sign up at [app.flightcontrol.dev/signup](https://app.flightcontrol.dev/signup?ref=redwood). 5. Create a new project from the onboarding screen or project list. - 1. Connect your Github account and select your repo. - 2. Click "Create Project" and complete any required steps like linking your AWS account. - 3. Configuration Type should autoselect as `flightcontrol.json`. - 4. NOTE: `flightcontrol.json` is now the source of truth for your Project and its Environments. + 1. Connect your Github account and select your repo. + 2. Click "Create Project" and complete any required steps like linking your AWS account. + 3. Configuration Type should autoselect as `flightcontrol.json`. + 4. NOTE: `flightcontrol.json` is now the source of truth for your Project and its Environments. 6. Add your env vars in Flightcontrol for your Environment. 7. If using dbAuth, add the session secret key env variable in the Flightcontrol dashboard. -If you have *any* problems or questions, Flightcontrol is very responsive in [their support Discord](https://discord.gg/yY8rSPrD6q). +If you have _any_ problems or questions, Flightcontrol is very responsive in [their support Discord](https://discord.gg/yY8rSPrD6q). diff --git a/docs/docs/deploy/introduction.md b/docs/docs/deploy/introduction.md index 1cbb38e0fcd7..49eba8f4a87d 100644 --- a/docs/docs/deploy/introduction.md +++ b/docs/docs/deploy/introduction.md @@ -12,6 +12,7 @@ Redwood is designed for both serverless and traditional infrastructure deploymen 4. the hosting provider deploys the built Web static assets to a CDN and the API code to a serverless backend (e.g. AWS Lambdas) Currently, these are the officially supported deploy targets: + - Baremetal (physical server that you have SSH access to) - [Coherence](https://www.withcoherence.com/) - [Flightcontrol.dev](https://www.flightcontrol.dev?ref=redwood) @@ -22,13 +23,13 @@ Currently, these are the officially supported deploy targets: - [Vercel.com](https://vercel.com) Redwood has a CLI generator that adds the code and configuration required by the specified provider (see the [CLI Doc](cli-commands.md#deploy-config) for more information): + ```shell yarn rw setup deploy ``` There are examples of deploying Redwood on other providers such as Google Cloud and direct to AWS. You can find more information by searching the [GitHub Issues](https://github.com/redwoodjs/redwood/issues) and [Forums](https://community.redwoodjs.com). - ## General Deployment Setup Deploying Redwood requires setup for the following four categories. diff --git a/docs/docs/deploy/netlify.md b/docs/docs/deploy/netlify.md index ad62b9b5d8f5..3f779f1b6ab4 100644 --- a/docs/docs/deploy/netlify.md +++ b/docs/docs/deploy/netlify.md @@ -18,7 +18,6 @@ While you may be tempted to use the [Netlify CLI](https://cli.netlify.com) comma The main reason for this is that these Netlify CLI commands simply build and deploy -- they build your project locally and then push the dist folder. That means that when building a RedwoodJS project, the [Prisma client is generated with binaries matching the operating system at build time](https://cli.netlify.com/commands/link) -- and not the [OS compatible](https://www.prisma.io/docs/reference/api-reference/prisma-schema-reference#binarytargets-options) with running functions on Netlify. Your Prisma client engine may be `darwin` for OSX or `windows` for Windows, but it needs to be `debian-openssl-1.1.x` or `rhel-openssl-1.1.x`. If the client is incompatible, your functions will fail. - Therefore, **please follow the [Tutorial Deployment section](tutorial/chapter4/deployment.md)** to sync your GitHub (or other compatible source control service) repository with Netlify andalllow their build and deploy system to manage deployments. ::: diff --git a/docs/docs/deploy/render.md b/docs/docs/deploy/render.md index 705ec3dec80f..46ae652e35e8 100644 --- a/docs/docs/deploy/render.md +++ b/docs/docs/deploy/render.md @@ -9,6 +9,7 @@ Render is a unified cloud to build and run all your apps and websites with free ## Render tl;dr Deploy If you simply want to experience the Render deployment process, including a Postgres or SQLite database, you can do the following: + 1. create a new redwood project: `yarn create redwood-app ./render-deploy` 2. after your "render-deploy" project installation is complete, init git, commit, and add it as a new repo to GitHub or GitLab 3. run the command `yarn rw setup deploy render`, use the flag `--database` to select from `postgresql`, `sqlite` or `none` to proceed without a database [default : `postgresql`] diff --git a/docs/docs/deploy/serverless.md b/docs/docs/deploy/serverless.md index d854ff791f7c..ed9a1d108ca4 100644 --- a/docs/docs/deploy/serverless.md +++ b/docs/docs/deploy/serverless.md @@ -4,16 +4,17 @@ description: Deploy to AWS with Serverless Framework # Deploy to AWS with Serverless Framework ->⚠️ **Deprecated** ->As of Redwood v5, we are deprecating this deploy setup as an "officially" supported provider. This means: ->- For projects already using this deploy provider, there will be NO change at this time ->- Both the associated `setup` and `deploy` commands will remain in the framework as is; when setup is run, there will be a “deprecation” message ->- We will no longer run CI/CD on the Serverless-AWS deployments, which means we are no longer guaranteeing this deploy works with each new version ->- We are exploring better options to deploy directly to AWS Lambdas; the current deploy commands will not be removed until we find a replacement +> ⚠️ **Deprecated** +> As of Redwood v5, we are deprecating this deploy setup as an "officially" supported provider. This means: > ->For more details (e.g. why?) and current status, see the Forum post ["Deprecating support for Serverless Framework Deployments to AWS Lambdas"](https://community.redwoodjs.com/t/deprecating-support-for-serverless-framework-deployments-to-aws-lambdas/4755/10) +> - For projects already using this deploy provider, there will be NO change at this time +> - Both the associated `setup` and `deploy` commands will remain in the framework as is; when setup is run, there will be a “deprecation” message +> - We will no longer run CI/CD on the Serverless-AWS deployments, which means we are no longer guaranteeing this deploy works with each new version +> - We are exploring better options to deploy directly to AWS Lambdas; the current deploy commands will not be removed until we find a replacement +> +> For more details (e.g. why?) and current status, see the Forum post ["Deprecating support for Serverless Framework Deployments to AWS Lambdas"](https://community.redwoodjs.com/t/deprecating-support-for-serverless-framework-deployments-to-aws-lambdas/4755/10) ->The following instructions assume you have read the [General Deployment Setup](./introduction.md#general-deployment-setup) section above. +> The following instructions assume you have read the [General Deployment Setup](./introduction.md#general-deployment-setup) section above. Yes, the name is confusing, but Serverless provides a very interesting option—deploy to your own cloud service account and skip the middleman entirely! By default, Serverless just orchestrates starting up services in your cloud provider of choice and pushing your code up to them. Any bill you receive is from your hosting provider (although many offer a generous free tier). You can optionally use the [Serverless Dashboard](https://www.serverless.com/dashboard/) to monitor your deploys and setup CI/CD to automatically deploy when pushing to your repo of choice. If you don't setup CI/CD you actually deploy from your development machine (or another designated machine you've setup to do the deployment). @@ -64,7 +65,6 @@ Once that command completes you should see a message including the URL of your s From now on you can simply run `yarn rw deploy serverless` when you're ready to deploy (which will also be much faster). - :::info Remember, if you add or generate new serverless functions (or endpoints), you'll need to update the configuration in your serverless.yml in `./api/serverless.yml`. @@ -88,7 +88,7 @@ There are even more places you can get environment variables from, check out Ser To integrate your site into the Serverless Dashboard, there are two ways: -1. Run `yarn serverless login` and a browser *should* open asking you to allow permission. However, in our experience, this command will fail nearly 50% of the time complaining about an invalid URL. If it *does* work you can then run `yarn serverless` in both the `api` and `web` directories to link to them an existing app in the Dashboard, or you'll be prompted to create a new one. Future deploys will now be monitored on the Dashboard. +1. Run `yarn serverless login` and a browser _should_ open asking you to allow permission. However, in our experience, this command will fail nearly 50% of the time complaining about an invalid URL. If it _does_ work you can then run `yarn serverless` in both the `api` and `web` directories to link to them an existing app in the Dashboard, or you'll be prompted to create a new one. Future deploys will now be monitored on the Dashboard. 2. You can manually add the `org` and `app` lines in `api/serverless.yml` and `web/serverless.yml`. You'll see example ones commented out near the top of the file. ## Environments Besides Production diff --git a/docs/docs/deploy/vercel.md b/docs/docs/deploy/vercel.md index 5720c2225b5c..060627e4c224 100644 --- a/docs/docs/deploy/vercel.md +++ b/docs/docs/deploy/vercel.md @@ -4,11 +4,12 @@ description: Deploy serverless in an instant with Vercel # Deploy to Vercel ->The following instructions assume you have read the [General Deployment Setup](./introduction.md#general-deployment-setup) section above. +> The following instructions assume you have read the [General Deployment Setup](./introduction.md#general-deployment-setup) section above. ## Vercel tl;dr Deploy If you simply want to experience the Vercel deployment process without a database and/or adding custom code, you can do the following: + 1. create a new redwood project: `yarn create redwood-app ./vercel-deploy` 2. after your "vercel-deploy" project installation is complete, init git, commit, and add it as a new repo to GitHub, BitBucket, or GitLab 3. run the command `yarn rw setup deploy vercel` and commit and push changes @@ -29,6 +30,7 @@ Complete the following two steps. Then save, commit, and push your changes. ### Step 1. Serverless Functions Path Run the following CLI Command: + ```shell yarn rw setup deploy vercel ``` @@ -50,6 +52,7 @@ yarn rw deploy vercel --prisma=false --data-migrate=false ::: ### Vercel Initial Setup and Configuration + Either [login](https://vercel.com/login) to your Vercel account and select "Import Project" or use the Vercel [quick start](https://vercel.com/#get-started). Then select the "Continue" button within the "From Git Repository" section: @@ -60,6 +63,7 @@ Next, select the provider where your repo is hosted: GitHub, GitLab, or Bitbucke You'll then need to provide permissions for Vercel to access the repo on your hosting provider. ### Import and Deploy your Project + Vercel will recognize your repo as a Redwood project and take care of most configuration heavy lifting. You should see the following options and, most importantly, the "Framework Preset" showing RedwoodJS. @@ -121,13 +125,13 @@ export const handler = async (event: APIGatewayEvent, _context: Context) => { }), } } - ``` :::tip important Since Redwood has it's own handling of the api directory, the Vercel flavored api directory is disabled. Therefore you don't use the "functions" config in `vercel.json` with Redwood. Also, be sure to use Node version 20.x or greater or set the `runtime` in the function config: + ```ts export const config = { runtime: 'nodejs20.x', diff --git a/docs/docs/directives.md b/docs/docs/directives.md index c4b9e97f403a..d9c0d1d50119 100644 --- a/docs/docs/directives.md +++ b/docs/docs/directives.md @@ -251,14 +251,14 @@ As noted in the [GraphQL spec](https://graphql.org/learn/queries/#directives): Here's a helpful guide for deciding when you should use one of Redwood's Validator or Transformer directives: -| | Use | Directive | Custom? | Type | -| --- | ---------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- | ------------ | -| ✅ | Check if the request is authenticated? | `@requireAuth` | Built-in | Validator | -| ✅ | Check if the user belongs to a role? | `@requireAuth(roles: ["AUTHOR"])` | Built-in | Validator | -| ✅ | Only allow admins to see emails, but others get a masked value like "###@######.###" | `@maskedEmail(roles: ["ADMIN"])` | Custom | Transformer | -| 🙅 | Know if the logged in user can edit the record, and/or values | N/A - Instead do this check in your service | +| | Use | Directive | Custom? | Type | +| --- | ---------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- | ------------ | +| ✅ | Check if the request is authenticated? | `@requireAuth` | Built-in | Validator | +| ✅ | Check if the user belongs to a role? | `@requireAuth(roles: ["AUTHOR"])` | Built-in | Validator | +| ✅ | Only allow admins to see emails, but others get a masked value like "###@######.###" | `@maskedEmail(roles: ["ADMIN"])` | Custom | Transformer | +| 🙅 | Know if the logged in user can edit the record, and/or values | N/A - Instead do this check in your service | | 🙅 | Is my input a valid email address format? | N/A - Instead do this check in your service using [Service Validations](services.md#service-validations) or consider [GraphQL Scalars](https://www.graphql-scalars.dev) | -| 🙅 | I want to remove a field from the response for data filtering; for example, do not include the title of the post | `@skip(if: true )` or `@include(if: false)` | Instead use [core directives](https://graphql.org/learn/queries/#directives) on the GraphQL client query, not the SDL | Core GraphQL | +| 🙅 | I want to remove a field from the response for data filtering; for example, do not include the title of the post | `@skip(if: true )` or `@include(if: false)` | Instead use [core directives](https://graphql.org/learn/queries/#directives) on the GraphQL client query, not the SDL | Core GraphQL | ## Combining, Chaining and Cascading Directives @@ -412,11 +412,11 @@ When your app builds and your server starts up, Redwood checks that **all** quer If not, then your build will fail: ```bash - ✖ Verifying graphql schema... - Building API... - Cleaning Web... - Building Web... - Prerendering Web... +✖ Verifying graphql schema... +Building API... +Cleaning Web... +Building Web... +Prerendering Web... You must specify one of @requireAuth, @skipAuth or a custom directive for - contacts Query - posts Query @@ -490,8 +490,8 @@ you'll be presented with a choice of creating a Validator or a Transformer direc yarn redwood generate directive myDirective ? What type of directive would you like to generate? › - Use arrow-keys. Return to submit. -❯ Validator - Implement a validation: throw an error if criteria not met to stop execution - Transformer - Modify values of fields or query responses +❯ Validator - Implement a validation: throw an error if criteria not met to stop execution +Transformer - Modify values of fields or query responses ``` > **Note:** You can pass the `--type` flag with either `validator` or `transformer` to create the desired directive type. @@ -586,7 +586,9 @@ describe('isSubscriber directive', () => { it('has a isSubscriber throws an error if validation does not pass', () => { const mockExecution = mockRedwoodDirective(isSubscriber, {}) - expect(mockExecution).toThrowError('Implementation missing for isSubscriber') + expect(mockExecution).toThrowError( + 'Implementation missing for isSubscriber' + ) }) }) ``` @@ -675,7 +677,6 @@ describe('maskedEmail directive', () => { If your Transformer Directive is asynchronous, you can use `resolves` to handle the result. - ```ts import maskedEmail from './maskedEmail' @@ -689,4 +690,5 @@ describe('maskedEmail directive', () => { }) }) ``` + ::: diff --git a/docs/docs/docker.md b/docs/docs/docker.md index 70a534e8703e..f2d013a56b93 100644 --- a/docs/docs/docker.md +++ b/docs/docs/docker.md @@ -15,6 +15,7 @@ yarn rw setup docker ``` The setup commands does several things: + - writes four files: `Dockerfile`, `.dockerignore`, `docker-compose.dev.yml`, and `docker-compose.prod.yml` - adds the `@redwoodjs/api-server` and `@redwoodjs/web-server` packages to the api and web sides respectively - edits the `browser.open` setting in the `redwood.toml` (right now, if it's set to `true`, it'll break the dev server when running the `docker-compose.dev.yml`) @@ -52,7 +53,7 @@ root@...:/home/node/app# yarn rw prisma migrate dev The docker setup command assumes that you are using Postgres as your database provider and sets up a local Postgres database for you. You may have to switch from SQLite to Postgres if you have not done so and want to continue with the default setup. ::: -:::important +:::important If you are using a [Server File](#using-the-server-file) then you should [change the command](#command) that runs the `api_serve` service. ::: @@ -131,7 +132,7 @@ COPY --chown=node:node yarn.lock . Here we copy the minimum set of files that the `yarn install` step needs. The order isn't completely arbitrary—it tries to maximize [Docker's layer caching](https://docs.docker.com/build/cache/). -We expect `yarn.lock` to change more than the `package.json`s and the `package.json`s to change more than `.yarnrc.yml`. +We expect `yarn.lock` to change more than the `package.json`s and the `package.json`s to change more than `.yarnrc.yml`. That said, it's hard to argue that these files couldn't be arranged differently, or that the `COPY` instructions couldn't be combined. The important thing is that they're all here, before the `yarn install` step: @@ -275,19 +276,16 @@ ENV NODE_ENV=production CMD [ "node_modules/.bin/rw-server", "api" ] ``` -:::important +:::important If you are using a [Server File](#using-the-server-file) then you must change the command that runs the `api_serve` service to `./api/dist/server.js` as shown above. Not updating the command will not completely configure the GraphQL Server and not setup [Redwood Realtime](./realtime.md), if you are using that. ::: - Note that the Redwood CLI isn't available anymore because it is a dev dependency. To access the server bin, we have to find its path in `node_modules`. Though this is somewhat discouraged in modern yarn, since we're using the `node-modules` node linker, it's in `node_modules/.bin`. - - ### The `web_build` stage This `web_build` builds the web side: @@ -370,7 +368,7 @@ Lastly, note that we use the shell form of `CMD` here for its variable expansion The `console` stage is an optional stage for debugging: -```Dockerfile +````Dockerfile FROM base as console # To add more packages: @@ -387,7 +385,7 @@ FROM base as console COPY --chown=node:node api api COPY --chown=node:node web web COPY --chown=node:node scripts scripts -``` +```` The console stage completes the base stage by copying in the rest of your Redwood app. But then it pretty much leaves you to your own devices. @@ -529,13 +527,11 @@ yarn node api/dist/server.js You can't run the server file directly with Node.js; it has to be built first: - ``` yarn rw build api ``` -The api serve stage in the Dockerfile pulls from the api build stage, so things are already in the right order there. Similarly, for `yarn rw dev`, the dev server will build and reload the server file for you. - +The api serve stage in the Dockerfile pulls from the api build stage, so things are already in the right order there. Similarly, for `yarn rw dev`, the dev server will build and reload the server file for you. ### Command @@ -548,7 +544,7 @@ That means you will swap the `CMD` instruction in the api server stage: + CMD [ "api/dist/server.js" ] ``` -:::important +:::important If you are using a [Server File](#using-the-server-file) then you must change the command that runs the `api_serve` service to `./api/dist/server.js` as shown above. Not updating the command will not completely configure the GraphQL Server and not setup [Redwood Realtime](./realtime.md), if you are using that. @@ -559,6 +555,7 @@ Not updating the command will not completely configure the GraphQL Server and no There are three ways you may wish to configure the server. #### Underlying Fastify server + First, you can configure how the underlying Fastify server is instantiated via the`fastifyServerOptions` passed to the `createServer` function: ```ts title="api/src/server.ts" @@ -567,7 +564,7 @@ const server = await createServer({ // highlight-start fastifyServerOptions: { // ... - } + }, // highlight-end }) ``` @@ -575,6 +572,7 @@ const server = await createServer({ For the complete list of options, see [Fastify's documentation](https://fastify.dev/docs/latest/Reference/Server/#factory). #### Configure the redwood API plugin + Second, you may want to alter the behavior of redwood's API plugin itself. To do this we provide a `configureApiServer(server)` option where you can do anything you wish to the fastify instance before the API plugin is registered. Two examples are given below. ##### Example: Compressing Payloads and Rate Limiting @@ -601,14 +599,13 @@ const server = await createServer({ threshold: 1024, encodings: ['deflate', 'gzip'], }) - + await server.register(import('@fastify/rate-limit'), { max: 100, timeWindow: '5 minutes', }) - } + }, }) - ``` ##### Example: File Uploads @@ -625,7 +622,7 @@ If you try to POST file content to the api server such as images or PDFs, you ma ``` This's because Fastify [only supports `application/json` and `text/plain` content types natively](https://www.fastify.io/docs/latest/Reference/ContentTypeParser/). -While Redwood configures the api server to also accept `application/x-www-form-urlencoded` and `multipart/form-data`, if you want to support other content or MIME types (likes images or PDFs), you'll need to configure them here in the server file. +While Redwood configures the api server to also accept `application/x-www-form-urlencoded` and `multipart/form-data`, if you want to support other content or MIME types (likes images or PDFs), you'll need to configure them here in the server file. You can use Fastify's `addContentTypeParser` function to allow uploads of the content types your application needs. For example, to support image file uploads you'd tell Fastify to allow `/^image\/.*/` content types: @@ -633,13 +630,13 @@ For example, to support image file uploads you'd tell Fastify to allow `/^image\ ```ts title="api/src/server.ts" const server = await createServer({ logger, - configureApiServer(server){ + configureApiServer(server) { server.addContentTypeParser(/^image\/.*/, (_req, payload, done) => { payload.on('end', () => { done() }) }) - } + }, }) ``` @@ -648,6 +645,7 @@ The regular expression (`/^image\/.*/`) above allows all image content or MIME t Now, when you POST those content types to a function served by the api server, you can access the file content on `event.body`. #### Additional Fastify plugins + Finally, you can register additional Fastify plugins on the server instance: ```ts title="api/src/server.ts" @@ -657,11 +655,11 @@ const server = await createServer({ // highlight-next-line server.register(myFastifyPlugin) -``` +``` :::note Fastify encapsulation -Fastify is built around the concept of [encapsulation](https://fastify.dev/docs/latest/Reference/Encapsulation/). It is important to note that redwood's API plugin cannot be mutated after it is registered, see [here](https://fastify.dev/docs/latest/Reference/Plugins/#asyncawait). This is why you must use the `configureApiServer` option to do as shown above. +Fastify is built around the concept of [encapsulation](https://fastify.dev/docs/latest/Reference/Encapsulation/). It is important to note that redwood's API plugin cannot be mutated after it is registered, see [here](https://fastify.dev/docs/latest/Reference/Plugins/#asyncawait). This is why you must use the `configureApiServer` option to do as shown above. ::: @@ -678,25 +676,25 @@ It takes the same arguments as `listen`, except for host and port. It computes t 1. `--apiHost` or `--apiPort` flags: - ``` - yarn node api/dist/server.js --apiHost 0.0.0.0 --apiPort 8913 - ``` +``` +yarn node api/dist/server.js --apiHost 0.0.0.0 --apiPort 8913 +``` 2. `REDWOOD_API_HOST` or `REDWOOD_API_PORT` env vars: - ``` - export REDWOOD_API_HOST='0.0.0.0' - export REDWOOD_API_PORT='8913' - yarn node api/dist/server.js - ``` +``` +export REDWOOD_API_HOST='0.0.0.0' +export REDWOOD_API_PORT='8913' +yarn node api/dist/server.js +``` 3. `[api].host` and `[api].port` in `redwood.toml`: - ```toml title="redwood.toml" - [api] - host = '0.0.0.0' - port = 8913 - ``` +```toml title="redwood.toml" +[api] + host = '0.0.0.0' + port = 8913 +``` If you'd rather not have `createServer` parsing `process.argv`, you can disable it via `parseArgv`: diff --git a/docs/docs/environment-variables.md b/docs/docs/environment-variables.md index 537d7d259930..1e6534bbdc60 100644 --- a/docs/docs/environment-variables.md +++ b/docs/docs/environment-variables.md @@ -22,6 +22,7 @@ Redwood also configures Vite, so that all references to `process.env` vars on th ## Web ### Including environment variables + > **Heads Up:** for Web to access environment variables in production, you _must_ configure one of the options below. > > Redwood recommends **Option 1: `redwood.toml`** as it is the most robust. @@ -47,13 +48,12 @@ By adding environment variables to this array, they'll be available to Web in pr Note: if someone inspects your site's source, _they could see your `REDWOOD_ENV_SECRET_API_KEY` in plain text._ This is a limitation of delivering static JS and HTML to the browser. -#### Option 2: Prefixing with REDWOOD\_ENV\_ +#### Option 2: Prefixing with REDWOOD_ENV\_ In `.env`, if you prefix your environment variables with `REDWOOD_ENV_`, they'll be available via `process.env.REDWOOD_ENV_MY_VAR_NAME`, and will be dynamically replaced at build-time. Like the option above, these are also removed and replaced with the _actual value_ during build in order to be available in production. - ### Accessing API URLs Redwood automatically makes your API URL configurations from the web section of your `redwood.toml` available globally. diff --git a/docs/docs/forms.md b/docs/docs/forms.md index db7b39ce2657..22575b27c69e 100644 --- a/docs/docs/forms.md +++ b/docs/docs/forms.md @@ -26,7 +26,7 @@ import { `@redwoodjs/forms` exports the following components: | Component | Description | -|:------------------|:---------------------------------------------------------------------------------------------------------------------------------------------------| +| :---------------- | :------------------------------------------------------------------------------------------------------------------------------------------------- | | `
` | Surrounds all components, providing form and error contexts | | `` | Displays error messages from the server. Typically placed at the top of your form | | `