From 174e48a5045216714d4aef86105aa06a648d9a05 Mon Sep 17 00:00:00 2001 From: Akshata Mohanty Date: Wed, 13 Mar 2024 18:39:56 +0800 Subject: [PATCH 01/20] Fix typo in deployment instructions (#1886) --- web/versioned_docs/version-0.12.0/advanced/deployment/cli.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/versioned_docs/version-0.12.0/advanced/deployment/cli.md b/web/versioned_docs/version-0.12.0/advanced/deployment/cli.md index 03187804ed..822179d650 100644 --- a/web/versioned_docs/version-0.12.0/advanced/deployment/cli.md +++ b/web/versioned_docs/version-0.12.0/advanced/deployment/cli.md @@ -238,7 +238,7 @@ If you are deploying an app that requires any other environment variables (like wasp deploy fly cmd secrets set GOOGLE_CLIENT_ID=<...> GOOGLE_CLIENT_SECRET=<...> --context=server ``` -### Mutliple Fly Organizations +### Multiple Fly Organizations If you have multiple organizations, you can specify a `--org` option. For example: From 4c3216f3497e002eb7ed58771420779b3f6bf848 Mon Sep 17 00:00:00 2001 From: Mihovil Ilakovac Date: Mon, 18 Mar 2024 12:52:24 +0100 Subject: [PATCH 02/20] Replaces `jsonwebtoken` with `oslo/jwt` (#1852) --- .../Generator/templates/sdk/wasp/auth/jwt.ts | 24 +++++++---- .../templates/sdk/wasp/auth/utils.ts | 6 --- .../sdk/wasp/server/auth/email/utils.ts | 10 ++--- .../src/auth/providers/email/resetPassword.ts | 42 +++++++++---------- .../server/src/auth/providers/email/types.ts | 3 -- .../src/auth/providers/email/verifyEmail.ts | 33 +++++++-------- .../templates/server/src/auth/utils.ts | 5 --- .../waspBuild/.wasp/build/.waspchecksums | 4 +- .../.wasp/build/installedNpmDepsLog.json | 2 +- .../build/sdk/wasp/dist/api/index.js.map | 2 +- .../client/operations/actions/core.js.map | 2 +- .../wasp/dist/client/operations/core.js.map | 2 +- .../client/operations/internal/index.js.map | 2 +- .../operations/internal/resources.js.map | 2 +- .../internal/updateHandlersMap.js.map | 2 +- .../dist/client/operations/queryClient.js.map | 2 +- .../dist/client/router/linkHelpers.js.map | 2 +- .../dist/client/test/vitest/helpers.jsx.map | 2 +- .../build/sdk/wasp/dist/core/storage.js.map | 2 +- .../sdk/wasp/dist/server/HttpError.js.map | 2 +- .../build/sdk/wasp/dist/server/utils.js.map | 2 +- .../sdk/wasp/dist/universal/validators.js.map | 2 +- .../.wasp/build/sdk/wasp/package.json | 1 - .../waspBuild/.wasp/build/server/package.json | 1 - .../.wasp/out/sdk/wasp/dist/api/index.js.map | 2 +- .../client/operations/actions/core.js.map | 2 +- .../wasp/dist/client/operations/core.js.map | 2 +- .../client/operations/internal/index.js.map | 2 +- .../operations/internal/resources.js.map | 2 +- .../internal/updateHandlersMap.js.map | 2 +- .../dist/client/operations/queryClient.js.map | 2 +- .../dist/client/router/linkHelpers.js.map | 2 +- .../dist/client/test/vitest/helpers.jsx.map | 2 +- .../out/sdk/wasp/dist/core/storage.js.map | 2 +- .../out/sdk/wasp/dist/server/HttpError.js.map | 2 +- .../out/sdk/wasp/dist/server/utils.js.map | 2 +- .../sdk/wasp/dist/universal/validators.js.map | 2 +- .../waspBuild/.wasp/out/sdk/wasp/package.json | 1 - .../waspCompile/.wasp/out/.waspchecksums | 4 +- .../.wasp/out/installedNpmDepsLog.json | 2 +- .../.wasp/out/sdk/wasp/dist/api/index.js.map | 2 +- .../client/operations/actions/core.js.map | 2 +- .../wasp/dist/client/operations/core.js.map | 2 +- .../client/operations/internal/index.js.map | 2 +- .../operations/internal/resources.js.map | 2 +- .../internal/updateHandlersMap.js.map | 2 +- .../dist/client/operations/queryClient.js.map | 2 +- .../dist/client/router/linkHelpers.js.map | 2 +- .../dist/client/test/vitest/helpers.jsx.map | 2 +- .../out/sdk/wasp/dist/core/storage.js.map | 2 +- .../out/sdk/wasp/dist/server/HttpError.js.map | 2 +- .../out/sdk/wasp/dist/server/utils.js.map | 2 +- .../sdk/wasp/dist/universal/validators.js.map | 2 +- .../.wasp/out/sdk/wasp/package.json | 1 - .../waspCompile/.wasp/out/server/package.json | 1 - .../waspComplexTest/.wasp/out/.waspchecksums | 8 ++-- .../.wasp/out/installedNpmDepsLog.json | 2 +- .../.wasp/out/sdk/wasp/auth/jwt.ts | 24 +++++++---- .../.wasp/out/sdk/wasp/auth/utils.ts | 6 --- .../.wasp/out/sdk/wasp/dist/api/index.js.map | 2 +- .../internal/common/LoginSignupForm.jsx.map | 2 +- .../.wasp/out/sdk/wasp/dist/auth/jwt.d.ts | 6 ++- .../.wasp/out/sdk/wasp/dist/auth/jwt.js | 19 +++++---- .../.wasp/out/sdk/wasp/dist/auth/jwt.js.map | 2 +- .../out/sdk/wasp/dist/auth/logout.js.map | 2 +- .../out/sdk/wasp/dist/auth/password.js.map | 2 +- .../out/sdk/wasp/dist/auth/session.js.map | 2 +- .../out/sdk/wasp/dist/auth/useAuth.js.map | 2 +- .../.wasp/out/sdk/wasp/dist/auth/user.js.map | 2 +- .../.wasp/out/sdk/wasp/dist/auth/utils.d.ts | 1 - .../.wasp/out/sdk/wasp/dist/auth/utils.js | 5 --- .../.wasp/out/sdk/wasp/dist/auth/utils.js.map | 2 +- .../out/sdk/wasp/dist/auth/validation.js.map | 2 +- .../client/operations/actions/core.js.map | 2 +- .../wasp/dist/client/operations/core.js.map | 2 +- .../client/operations/internal/index.js.map | 2 +- .../operations/internal/resources.js.map | 2 +- .../internal/updateHandlersMap.js.map | 2 +- .../dist/client/operations/queryClient.js.map | 2 +- .../dist/client/router/linkHelpers.js.map | 2 +- .../dist/client/test/vitest/helpers.jsx.map | 2 +- .../.wasp/out/sdk/wasp/dist/core/auth.js.map | 2 +- .../out/sdk/wasp/dist/core/storage.js.map | 2 +- .../out/sdk/wasp/dist/server/HttpError.js.map | 2 +- .../dist/server/email/core/helpers.js.map | 2 +- .../server/jobs/core/pgBoss/pgBoss.js.map | 2 +- .../server/jobs/core/pgBoss/pgBossJob.js.map | 2 +- .../wasp/dist/server/jobs/mySpecialJob.d.ts | 2 +- .../wasp/dist/server/jobs/returnHelloJob.d.ts | 2 +- .../out/sdk/wasp/dist/server/utils.js.map | 2 +- .../sdk/wasp/dist/universal/validators.js.map | 2 +- .../.wasp/out/sdk/wasp/package.json | 1 - .../.wasp/out/server/package.json | 1 - .../waspJob/.wasp/out/.waspchecksums | 4 +- .../.wasp/out/installedNpmDepsLog.json | 2 +- .../.wasp/out/sdk/wasp/dist/api/index.js.map | 2 +- .../client/operations/actions/core.js.map | 2 +- .../wasp/dist/client/operations/core.js.map | 2 +- .../client/operations/internal/index.js.map | 2 +- .../operations/internal/resources.js.map | 2 +- .../internal/updateHandlersMap.js.map | 2 +- .../dist/client/operations/queryClient.js.map | 2 +- .../dist/client/router/linkHelpers.js.map | 2 +- .../dist/client/test/vitest/helpers.jsx.map | 2 +- .../out/sdk/wasp/dist/core/storage.js.map | 2 +- .../out/sdk/wasp/dist/server/HttpError.js.map | 2 +- .../server/jobs/core/pgBoss/pgBoss.js.map | 2 +- .../server/jobs/core/pgBoss/pgBossJob.js.map | 2 +- .../wasp/dist/server/jobs/mySpecialJob.d.ts | 2 +- .../out/sdk/wasp/dist/server/utils.js.map | 2 +- .../sdk/wasp/dist/universal/validators.js.map | 2 +- .../waspJob/.wasp/out/sdk/wasp/package.json | 1 - .../waspJob/.wasp/out/server/package.json | 1 - .../waspMigrate/.wasp/out/.waspchecksums | 4 +- .../.wasp/out/installedNpmDepsLog.json | 2 +- .../.wasp/out/sdk/wasp/dist/api/index.js.map | 2 +- .../client/operations/actions/core.js.map | 2 +- .../wasp/dist/client/operations/core.js.map | 2 +- .../client/operations/internal/index.js.map | 2 +- .../operations/internal/resources.js.map | 2 +- .../internal/updateHandlersMap.js.map | 2 +- .../dist/client/operations/queryClient.js.map | 2 +- .../dist/client/router/linkHelpers.js.map | 2 +- .../dist/client/test/vitest/helpers.jsx.map | 2 +- .../out/sdk/wasp/dist/core/storage.js.map | 2 +- .../out/sdk/wasp/dist/server/HttpError.js.map | 2 +- .../out/sdk/wasp/dist/server/utils.js.map | 2 +- .../sdk/wasp/dist/universal/validators.js.map | 2 +- .../.wasp/out/sdk/wasp/package.json | 1 - .../waspMigrate/.wasp/out/server/package.json | 1 - waspc/src/Wasp/Generator/SdkGenerator.hs | 1 - waspc/src/Wasp/Generator/ServerGenerator.hs | 1 - .../ServerGenerator/Auth/EmailAuthG.hs | 9 +--- 133 files changed, 202 insertions(+), 230 deletions(-) delete mode 100644 waspc/data/Generator/templates/server/src/auth/providers/email/types.ts diff --git a/waspc/data/Generator/templates/sdk/wasp/auth/jwt.ts b/waspc/data/Generator/templates/sdk/wasp/auth/jwt.ts index 8ed702e4c0..ef3e77fa26 100644 --- a/waspc/data/Generator/templates/sdk/wasp/auth/jwt.ts +++ b/waspc/data/Generator/templates/sdk/wasp/auth/jwt.ts @@ -1,14 +1,22 @@ -import jwt from 'jsonwebtoken' -import util from 'util' - +import * as jwt from 'oslo/jwt' import { config } from 'wasp/server' -const jwtSign = util.promisify(jwt.sign) -const jwtVerify = util.promisify(jwt.verify) +const JWT_SECRET = new TextEncoder().encode(config.auth.jwtSecret) +const JWT_ALGORITHM = 'HS256' -const JWT_SECRET = config.auth.jwtSecret +// PRIVATE API +export function createJWT( + data: Parameters[2], + options: Parameters[3], +): Promise { + return jwt.createJWT(JWT_ALGORITHM, JWT_SECRET, data, options) +} // PRIVATE API -export const signData = (data, options) => jwtSign(data, JWT_SECRET, options) +export async function validateJWT(token: string): Promise { + const { payload } = await jwt.validateJWT(JWT_ALGORITHM, JWT_SECRET, token) + return payload as Payload +} + // PRIVATE API -export const verify = (token) => jwtVerify(token, JWT_SECRET) +export { TimeSpan } from 'oslo' diff --git a/waspc/data/Generator/templates/sdk/wasp/auth/utils.ts b/waspc/data/Generator/templates/sdk/wasp/auth/utils.ts index 6de20334c7..f6248f737c 100644 --- a/waspc/data/Generator/templates/sdk/wasp/auth/utils.ts +++ b/waspc/data/Generator/templates/sdk/wasp/auth/utils.ts @@ -1,6 +1,5 @@ {{={= =}=}} import { hashPassword } from './password.js' -import { verify } from './jwt.js' import { prisma, HttpError } from 'wasp/server' import { sleep } from 'wasp/server/utils' import { @@ -174,11 +173,6 @@ export async function deleteUserByAuthId(authId: string): Promise<{ count: numbe } } }) } -// PRIVATE API -export async function verifyToken(token: string): Promise { - return verify(token); -} - // PRIVATE API // If an user exists, we don't want to leak information // about it. Pretending that we're doing some work diff --git a/waspc/data/Generator/templates/sdk/wasp/server/auth/email/utils.ts b/waspc/data/Generator/templates/sdk/wasp/server/auth/email/utils.ts index 5b2bfbee56..2d07a706bd 100644 --- a/waspc/data/Generator/templates/sdk/wasp/server/auth/email/utils.ts +++ b/waspc/data/Generator/templates/sdk/wasp/server/auth/email/utils.ts @@ -1,5 +1,5 @@ {{={= =}=}} -import { signData } from 'wasp/auth/jwt' +import { createJWT, TimeSpan } from 'wasp/auth/jwt' import { emailSender } from 'wasp/server/email'; import { Email } from 'wasp/server/email/core/types'; import { @@ -17,7 +17,7 @@ export async function createEmailVerificationLink( email: string, clientRoute: string, ): Promise { - const { jwtToken } = await createEmailJwtToken(email); + const { jwtToken } = await createEmailJWT(email); return `${waspServerConfig.frontendUrl}${clientRoute}?token=${jwtToken}`; } @@ -26,12 +26,12 @@ export async function createPasswordResetLink( email: string, clientRoute: string, ): Promise { - const { jwtToken } = await createEmailJwtToken(email); + const { jwtToken } = await createEmailJWT(email); return `${waspServerConfig.frontendUrl}${clientRoute}?token=${jwtToken}`; } -async function createEmailJwtToken(email: string): Promise<{ jwtToken: string; }> { - const jwtToken = await signData({ email }, { expiresIn: '30m' }); +async function createEmailJWT(email: string): Promise<{ jwtToken: string; }> { + const jwtToken = await createJWT({ email }, { expiresIn: new TimeSpan(30, "m") }); return { jwtToken }; } diff --git a/waspc/data/Generator/templates/server/src/auth/providers/email/resetPassword.ts b/waspc/data/Generator/templates/server/src/auth/providers/email/resetPassword.ts index 8f5681a994..7b1d479005 100644 --- a/waspc/data/Generator/templates/server/src/auth/providers/email/resetPassword.ts +++ b/waspc/data/Generator/templates/server/src/auth/providers/email/resetPassword.ts @@ -3,11 +3,10 @@ import { createProviderId, findAuthIdentity, updateAuthIdentityProviderData, - verifyToken, deserializeAndSanitizeProviderData, } from 'wasp/auth/utils'; +import { validateJWT } from 'wasp/auth/jwt' import { ensureTokenIsPresent, ensurePasswordIsPresent, ensureValidPassword } from 'wasp/auth/validation'; -import { tokenVerificationErrors } from "./types.js"; import { HttpError } from 'wasp/server'; export async function resetPassword( @@ -18,30 +17,27 @@ export async function resetPassword( ensureValidArgs(args); const { token, password } = args; - try { - const { email } = await verifyToken<{ email: string }>(token); - - const providerId = createProviderId('email', email); - const authIdentity = await findAuthIdentity(providerId); - if (!authIdentity) { + const { email } = await validateJWT<{ email: string }>(token) + .catch(() => { throw new HttpError(400, "Password reset failed, invalid token"); - } - - const providerData = deserializeAndSanitizeProviderData<'email'>(authIdentity.providerData); - - await updateAuthIdentityProviderData(providerId, providerData, { - // The act of resetting the password verifies the email - isEmailVerified: true, - // The password will be hashed when saving the providerData - // in the DB - hashedPassword: password, }); - } catch (e) { - const reason = e.name === tokenVerificationErrors.TokenExpiredError - ? 'expired' - : 'invalid'; - throw new HttpError(400, `Password reset failed, ${reason} token`); + + const providerId = createProviderId('email', email); + const authIdentity = await findAuthIdentity(providerId); + if (!authIdentity) { + throw new HttpError(400, "Password reset failed, invalid token"); } + + const providerData = deserializeAndSanitizeProviderData<'email'>(authIdentity.providerData); + + await updateAuthIdentityProviderData(providerId, providerData, { + // The act of resetting the password verifies the email + isEmailVerified: true, + // The password will be hashed when saving the providerData + // in the DB + hashedPassword: password, + }); + return res.json({ success: true }); }; diff --git a/waspc/data/Generator/templates/server/src/auth/providers/email/types.ts b/waspc/data/Generator/templates/server/src/auth/providers/email/types.ts deleted file mode 100644 index 67e2ec8273..0000000000 --- a/waspc/data/Generator/templates/server/src/auth/providers/email/types.ts +++ /dev/null @@ -1,3 +0,0 @@ -export const tokenVerificationErrors = { - TokenExpiredError: 'TokenExpiredError', -}; diff --git a/waspc/data/Generator/templates/server/src/auth/providers/email/verifyEmail.ts b/waspc/data/Generator/templates/server/src/auth/providers/email/verifyEmail.ts index a337b6e616..bfa2f208a4 100644 --- a/waspc/data/Generator/templates/server/src/auth/providers/email/verifyEmail.ts +++ b/waspc/data/Generator/templates/server/src/auth/providers/email/verifyEmail.ts @@ -1,12 +1,11 @@ import { Request, Response } from 'express'; import { - verifyToken, createProviderId, findAuthIdentity, updateAuthIdentityProviderData, deserializeAndSanitizeProviderData, } from 'wasp/auth/utils'; -import { tokenVerificationErrors } from './types.js'; +import { validateJWT } from 'wasp/auth/jwt' import { HttpError } from 'wasp/server'; @@ -14,24 +13,24 @@ export async function verifyEmail( req: Request<{ token: string }>, res: Response, ): Promise> { - try { - const { token } = req.body; - const { email } = await verifyToken<{ email: string }>(token); - - const providerId = createProviderId('email', email); - const authIdentity = await findAuthIdentity(providerId); - const providerData = deserializeAndSanitizeProviderData<'email'>(authIdentity.providerData); - - await updateAuthIdentityProviderData(providerId, providerData, { - isEmailVerified: true, + const { token } = req.body; + const { email } = await validateJWT<{ email: string }>(token) + .catch(() => { + throw new HttpError(400, "Email verification failed, invalid token"); }); - } catch (e) { - const reason = e.name === tokenVerificationErrors.TokenExpiredError - ? 'expired' - : 'invalid'; - throw new HttpError(400, `Token is ${reason}`); + + const providerId = createProviderId('email', email); + const authIdentity = await findAuthIdentity(providerId); + if (!authIdentity) { + throw new HttpError(400, "Email verification failed, invalid token"); } + const providerData = deserializeAndSanitizeProviderData<'email'>(authIdentity.providerData); + + await updateAuthIdentityProviderData(providerId, providerData, { + isEmailVerified: true, + }); + return res.json({ success: true }); }; diff --git a/waspc/data/Generator/templates/server/src/auth/utils.ts b/waspc/data/Generator/templates/server/src/auth/utils.ts index c3030aef0f..4d870a02d9 100644 --- a/waspc/data/Generator/templates/server/src/auth/utils.ts +++ b/waspc/data/Generator/templates/server/src/auth/utils.ts @@ -1,6 +1,5 @@ {{={= =}=}} import { hashPassword } from 'wasp/auth/password' -import { verify } from 'wasp/auth/jwt' import { prisma, HttpError } from 'wasp/server' import { sleep } from 'wasp/server/utils' import { @@ -160,10 +159,6 @@ export async function deleteUserByAuthId(authId: string): Promise<{ count: numbe } } }) } -export async function verifyToken(token: string): Promise { - return verify(token); -} - // If an user exists, we don't want to leak information // about it. Pretending that we're doing some work // will make it harder for an attacker to determine diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/.waspchecksums b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/.waspchecksums index 12952fdbbc..cccecec5ff 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/.waspchecksums +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/.waspchecksums @@ -207,7 +207,7 @@ "file", "../out/sdk/wasp/package.json" ], - "c955fa158905668984f65806b587b8455abc60ef82807bfd7137a3e7dc839902" + "d0db918bf9df0766992ba13933d847853b330e3b601e5f367c3ad25eaecddc87" ], [ [ @@ -410,7 +410,7 @@ "file", "server/package.json" ], - "b6f49a347b56b9c7215e65f2d982ff99c6e444c40e649b802bb1af3ead772d15" + "c33727afcd03aa83fbd2c4b213a05cf7a2c53525e3b1daa72521d8c1312033a5" ], [ [ diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/installedNpmDepsLog.json b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/installedNpmDepsLog.json index 4b37fb6e15..7880e96505 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/installedNpmDepsLog.json +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/installedNpmDepsLog.json @@ -1 +1 @@ -{"_waspSdkNpmDeps":{"dependencies":[{"name":"@prisma/client","version":"4.16.2"},{"name":"prisma","version":"4.16.2"},{"name":"@tanstack/react-query","version":"^4.29.0"},{"name":"axios","version":"^1.4.0"},{"name":"express","version":"~4.18.1"},{"name":"jsonwebtoken","version":"^8.5.1"},{"name":"mitt","version":"3.0.0"},{"name":"react","version":"^18.2.0"},{"name":"lodash.merge","version":"^4.6.2"},{"name":"react-router-dom","version":"^5.3.3"},{"name":"react-hook-form","version":"^7.45.4"},{"name":"superjson","version":"^1.12.2"},{"name":"@types/express-serve-static-core","version":"^4.17.13"},{"name":"@types/react-router-dom","version":"^5.3.3"},{"name":"uuid","version":"^9.0.0"},{"name":"vitest","version":"^1.2.1"},{"name":"@vitest/ui","version":"^1.2.1"},{"name":"jsdom","version":"^21.1.1"},{"name":"@testing-library/react","version":"^14.1.2"},{"name":"@testing-library/jest-dom","version":"^6.3.0"},{"name":"msw","version":"^1.1.0"}],"devDependencies":[{"name":"@tsconfig/node18","version":"latest"}]},"_userNpmDeps":{"userDependencies":[{"name":"react","version":"^18.2.0"},{"name":"wasp","version":"file:.wasp/out/sdk/wasp"}],"userDevDependencies":[{"name":"@types/react","version":"^18.0.37"},{"name":"prisma","version":"4.16.2"},{"name":"typescript","version":"^5.1.0"},{"name":"vite","version":"^4.3.9"}]},"_waspFrameworkNpmDeps":{"npmDepsForWebApp":{"dependencies":[{"name":"@tanstack/react-query","version":"^4.29.0"},{"name":"axios","version":"^1.4.0"},{"name":"mitt","version":"3.0.0"},{"name":"react-dom","version":"^18.2.0"},{"name":"react-hook-form","version":"^7.45.4"},{"name":"react-router-dom","version":"^5.3.3"},{"name":"superjson","version":"^1.12.2"}],"devDependencies":[{"name":"@tsconfig/vite-react","version":"^2.0.0"},{"name":"@types/react-dom","version":"^18.0.11"},{"name":"@types/react-router-dom","version":"^5.3.3"},{"name":"@vitejs/plugin-react","version":"^4.2.1"},{"name":"dotenv","version":"^16.0.3"}]},"npmDepsForServer":{"dependencies":[{"name":"cookie-parser","version":"~1.4.6"},{"name":"cors","version":"^2.8.5"},{"name":"dotenv","version":"16.0.2"},{"name":"express","version":"~4.18.1"},{"name":"helmet","version":"^6.0.0"},{"name":"jsonwebtoken","version":"^8.5.1"},{"name":"morgan","version":"~1.10.0"},{"name":"rate-limiter-flexible","version":"^2.4.1"},{"name":"superjson","version":"^1.12.2"}],"devDependencies":[{"name":"@tsconfig/node18","version":"latest"},{"name":"@types/cors","version":"^2.8.5"},{"name":"@types/express","version":"^4.17.13"},{"name":"@types/express-serve-static-core","version":"^4.17.13"},{"name":"@types/node","version":"^18.0.0"},{"name":"nodemon","version":"^2.0.19"},{"name":"rollup","version":"^4.9.6"},{"name":"rollup-plugin-esbuild","version":"^6.1.1"},{"name":"standard","version":"^17.0.0"}]}}} \ No newline at end of file +{"_waspSdkNpmDeps":{"dependencies":[{"name":"@prisma/client","version":"4.16.2"},{"name":"prisma","version":"4.16.2"},{"name":"@tanstack/react-query","version":"^4.29.0"},{"name":"axios","version":"^1.4.0"},{"name":"express","version":"~4.18.1"},{"name":"mitt","version":"3.0.0"},{"name":"react","version":"^18.2.0"},{"name":"lodash.merge","version":"^4.6.2"},{"name":"react-router-dom","version":"^5.3.3"},{"name":"react-hook-form","version":"^7.45.4"},{"name":"superjson","version":"^1.12.2"},{"name":"@types/express-serve-static-core","version":"^4.17.13"},{"name":"@types/react-router-dom","version":"^5.3.3"},{"name":"uuid","version":"^9.0.0"},{"name":"vitest","version":"^1.2.1"},{"name":"@vitest/ui","version":"^1.2.1"},{"name":"jsdom","version":"^21.1.1"},{"name":"@testing-library/react","version":"^14.1.2"},{"name":"@testing-library/jest-dom","version":"^6.3.0"},{"name":"msw","version":"^1.1.0"}],"devDependencies":[{"name":"@tsconfig/node18","version":"latest"}]},"_userNpmDeps":{"userDependencies":[{"name":"react","version":"^18.2.0"},{"name":"wasp","version":"file:.wasp/out/sdk/wasp"}],"userDevDependencies":[{"name":"@types/react","version":"^18.0.37"},{"name":"prisma","version":"4.16.2"},{"name":"typescript","version":"^5.1.0"},{"name":"vite","version":"^4.3.9"}]},"_waspFrameworkNpmDeps":{"npmDepsForWebApp":{"dependencies":[{"name":"@tanstack/react-query","version":"^4.29.0"},{"name":"axios","version":"^1.4.0"},{"name":"mitt","version":"3.0.0"},{"name":"react-dom","version":"^18.2.0"},{"name":"react-hook-form","version":"^7.45.4"},{"name":"react-router-dom","version":"^5.3.3"},{"name":"superjson","version":"^1.12.2"}],"devDependencies":[{"name":"@tsconfig/vite-react","version":"^2.0.0"},{"name":"@types/react-dom","version":"^18.0.11"},{"name":"@types/react-router-dom","version":"^5.3.3"},{"name":"@vitejs/plugin-react","version":"^4.2.1"},{"name":"dotenv","version":"^16.0.3"}]},"npmDepsForServer":{"dependencies":[{"name":"cookie-parser","version":"~1.4.6"},{"name":"cors","version":"^2.8.5"},{"name":"dotenv","version":"16.0.2"},{"name":"express","version":"~4.18.1"},{"name":"helmet","version":"^6.0.0"},{"name":"morgan","version":"~1.10.0"},{"name":"rate-limiter-flexible","version":"^2.4.1"},{"name":"superjson","version":"^1.12.2"}],"devDependencies":[{"name":"@tsconfig/node18","version":"latest"},{"name":"@types/cors","version":"^2.8.5"},{"name":"@types/express","version":"^4.17.13"},{"name":"@types/express-serve-static-core","version":"^4.17.13"},{"name":"@types/node","version":"^18.0.0"},{"name":"nodemon","version":"^2.0.19"},{"name":"rollup","version":"^4.9.6"},{"name":"rollup-plugin-esbuild","version":"^6.1.1"},{"name":"standard","version":"^17.0.0"}]}}} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/api/index.js.map b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/api/index.js.map index b4ae2eba65..fab323a0b2 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/api/index.js.map +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/api/index.js.map @@ -1 +1 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["../../api/index.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"index.js","sourceRoot":"","sources":["../../api/index.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/actions/core.js.map b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/actions/core.js.map index 5834336f1d..b13c7d6712 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/actions/core.js.map +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/actions/core.js.map @@ -1 +1 @@ -{"version":3,"file":"core.js","sourceRoot":"","sources":["../../../../client/operations/actions/core.js"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAA;AACxE,OAAO,EACL,wBAAwB,EACxB,kBAAkB,GACnB,MAAM,0BAA0B,CAAA;AAEjC,cAAc;AACd,MAAM,UAAU,YAAY,CAAC,mBAAmB,EAAE,YAAY;IAC5D,MAAM,WAAW,GAAG,kBAAkB,CAAC,mBAAmB,CAAC,CAAA;IAE3D,KAAK,UAAU,cAAc,CAAC,IAAI,EAAE,mCAAmC;QACrE,wBAAwB,CAAC,mCAAmC,CAAC,CAAA;QAC7D,IAAI;YACF,yEAAyE;YACzE,wEAAwE;YACxE,kCAAkC;YAClC,OAAO,MAAM,aAAa,CAAC,WAAW,EAAE,IAAI,CAAC,CAAA;SAC9C;gBAAS;YACR,MAAM,kBAAkB,CAAC,YAAY,EAAE,mCAAmC,CAAC,CAAA;SAC5E;IACH,CAAC;IAED,0EAA0E;IAC1E,yEAAyE;IACzE,6EAA6E;IAC7E,yEAAyE;IACzE,gBAAgB;IAChB,EAAE;IACF,0EAA0E;IAC1E,8EAA8E;IAC9E,wCAAwC;IACxC,MAAM,MAAM,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC,cAAc,CAAC,IAAI,EAAE,EAAE,CAAC,CAAA;IACjD,MAAM,CAAC,QAAQ,GAAG,cAAc,CAAA;IAEhC,OAAO,MAAM,CAAA;AACf,CAAC"} \ No newline at end of file +{"version":3,"file":"core.js","sourceRoot":"","sources":["../../../../client/operations/actions/core.js"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAA;AACxE,OAAO,EACL,wBAAwB,EACxB,kBAAkB,GACnB,MAAM,0BAA0B,CAAA;AAEjC,cAAc;AACd,MAAM,UAAU,YAAY,CAAC,mBAAmB,EAAE,YAAY;IAC5D,MAAM,WAAW,GAAG,kBAAkB,CAAC,mBAAmB,CAAC,CAAA;IAE3D,KAAK,UAAU,cAAc,CAAC,IAAI,EAAE,mCAAmC;QACrE,wBAAwB,CAAC,mCAAmC,CAAC,CAAA;QAC7D,IAAI,CAAC;YACH,yEAAyE;YACzE,wEAAwE;YACxE,kCAAkC;YAClC,OAAO,MAAM,aAAa,CAAC,WAAW,EAAE,IAAI,CAAC,CAAA;QAC/C,CAAC;gBAAS,CAAC;YACT,MAAM,kBAAkB,CAAC,YAAY,EAAE,mCAAmC,CAAC,CAAA;QAC7E,CAAC;IACH,CAAC;IAED,0EAA0E;IAC1E,yEAAyE;IACzE,6EAA6E;IAC7E,yEAAyE;IACzE,gBAAgB;IAChB,EAAE;IACF,0EAA0E;IAC1E,8EAA8E;IAC9E,wCAAwC;IACxC,MAAM,MAAM,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC,cAAc,CAAC,IAAI,EAAE,EAAE,CAAC,CAAA;IACjD,MAAM,CAAC,QAAQ,GAAG,cAAc,CAAA;IAEhC,OAAO,MAAM,CAAA;AACf,CAAC"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/core.js.map b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/core.js.map index 68ea114aa9..20d72dc15e 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/core.js.map +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/core.js.map @@ -1 +1 @@ -{"version":3,"file":"core.js","sourceRoot":"","sources":["../../../client/operations/core.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"core.js","sourceRoot":"","sources":["../../../client/operations/core.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,WAAW,EAEX,cAAc,EACd,QAAQ,IAAI,UAAU,GAEvB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAcrD,aAAa;AACb,MAAM,UAAU,QAAQ,CAAC,OAAO,EAAE,WAAW,EAAE,OAAO;IACpD,IAAI,OAAO,OAAO,KAAK,UAAU,EAAE,CAAC;QAClC,MAAM,IAAI,SAAS,CAAC,6CAA6C,CAAC,CAAC;IACrE,CAAC;IACD,IAAI,CAAC,OAAO,CAAC,aAAa,EAAE,CAAC;QAC3B,MAAM,IAAI,SAAS,CACjB,uDAAuD,CACxD,CAAC;IACJ,CAAC;IAED,MAAM,QAAQ,GACZ,WAAW,KAAK,SAAS;QACvB,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,aAAa,EAAE,WAAW,CAAC;QACzC,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC;IAC5B,OAAO,UAAU,iBACf,QAAQ,EACR,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,QAAQ,EAAE,WAAW,CAAC,IAC1C,OAAO,EACV,CAAC;AACL,CAAC;AAmDD,aAAa;AACb;;;;;;GAMG;AACH,MAAM,UAAU,SAAS,CACvB,QAA+B,EAC/B,aAAoC;IAEpC,MAAM,WAAW,GAAG,cAAc,EAAE,CAAC;IAErC,IAAI,UAAU,GAAG,QAAQ,CAAC;IAC1B,IAAI,OAAO,GAAG,EAAE,CAAC;IACjB,IAAI,aAAa,aAAb,aAAa,uBAAb,aAAa,CAAE,iBAAiB,EAAE,CAAC;QACrC,MAAM,4BAA4B,GAAG,aAAa,CAAC,iBAAiB,CAAC,GAAG,CACtE,6BAA6B,CAC9B,CAAC;QACF,UAAU,GAAG,8BAA8B,CACzC,QAAQ,EACR,4BAA4B,CAC7B,CAAC;QACF,OAAO,GAAG,6BAA6B,CACrC,WAAW,EACX,4BAA4B,CAC7B,CAAC;IACJ,CAAC;IAED,wEAAwE;IACxE,2EAA2E;IAC3E,wEAAwE;IACxE,4EAA4E;IAC5E,4EAA4E;IAC5E,sEAAsE;IACtE,0CAA0C;IAC1C,MAAM,QAAQ,GAAG,WAAW,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;IAClD,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;AAC9C,CAAC;AAiCD;;;;;;;;GAQG;AACH,SAAS,6BAA6B,CACpC,gCAA8E;IAE9E,MAAM,EAAE,iBAAiB,EAAE,WAAW,EAAE,GAAG,gCAAgC,CAAC;IAE5E,MAAM,gBAAgB,GAAG,EAAE,CAAC;IAC5B,IAAI,OAAO,iBAAiB,KAAK,UAAU,EAAE,CAAC;QAC5C,gBAAgB,CAAC,IAAI,CAAC,wCAAwC,CAAC,CAAC;IAClE,CAAC;IACD,IAAI,OAAO,WAAW,KAAK,UAAU,EAAE,CAAC;QACtC,gBAAgB,CAAC,IAAI,CAAC,kCAAkC,CAAC,CAAC;IAC5D,CAAC;IACD,IAAI,gBAAgB,CAAC,MAAM,EAAE,CAAC;QAC5B,MAAM,IAAI,SAAS,CACjB,yCAAyC,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CACxE,CAAC;IACJ,CAAC;IAED,OAAO;QACL,WAAW,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,0BAA0B,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC;QAC1E,WAAW;KACZ,CAAC;AACJ,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,8BAA8B,CACrC,QAA+B,EAC/B,2BAGG;IAEH,OAAO,SAAS,kCAAkC,CAAC,IAAI;QACrD,MAAM,mCAAmC,GAAG,2BAA2B,CAAC,GAAG,CACzE,CAAC,iBAAiB,EAAE,EAAE,CACpB,4CAA4C,CAAC,iBAAiB,EAAE,IAAI,CAAC,CACxE,CAAC;QACF,OAAQ,QAA0C,CAAC,QAAQ,CACzD,IAAI,EACJ,mCAAmC,CACpC,CAAC;IACJ,CAAC,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;;;;GAeG;AACH,SAAS,6BAA6B,CACpC,WAAwB,EACxB,2BAGG;IAEH,KAAK,UAAU,QAAQ,CAAC,IAAI;QAC1B,MAAM,mCAAmC,GAAG,2BAA2B,CAAC,GAAG,CACzE,CAAC,iBAAiB,EAAE,EAAE,CACpB,4CAA4C,CAAC,iBAAiB,EAAE,IAAI,CAAC,CACxE,CAAC;QAEF,iFAAiF;QACjF,iEAAiE;QACjE,4EAA4E;QAC5E,mFAAmF;QACnF,MAAM,OAAO,CAAC,GAAG,CACf,mCAAmC,CAAC,GAAG,CAAC,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,CACvD,WAAW,CAAC,aAAa,CAAC,QAAQ,CAAC,CACpC,CACF,CAAC;QAEF,4EAA4E;QAC5E,MAAM,YAAY,GAAG,IAAI,GAAG,EAAE,CAAC;QAC/B,mCAAmC,CAAC,OAAO,CAAC,CAAC,EAAE,QAAQ,EAAE,WAAW,EAAE,EAAE,EAAE;YACxE,uCAAuC;YACvC,MAAM,oBAAoB,GACxB,WAAW,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;YAErC,kEAAkE;YAClE,IAAI,CAAC;gBACH,WAAW,CAAC,YAAY,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;YAClD,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACX,OAAO,CAAC,KAAK,CACX,4EAA4E,CAC7E,CAAC;gBACF,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YACnB,CAAC;YAED,iEAAiE;YACjE,YAAY,CAAC,GAAG,CAAC,QAAQ,EAAE,oBAAoB,CAAC,CAAC;QACnD,CAAC,CAAC,CAAC;QAEH,OAAO,EAAE,YAAY,EAAE,CAAC;IAC1B,CAAC;IAED,SAAS,OAAO,CAAC,IAAI,EAAE,KAAK,EAAE,OAAO;QACnC,+EAA+E;QAC/E,8EAA8E;QAC9E,8EAA8E;QAC9E,+EAA+E;QAC/E,YAAY;QACZ,OAAO,CAAC,YAAY,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE;YACpD,MAAM,WAAW,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;YAC1C,WAAW,CAAC,YAAY,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;QAC3C,CAAC,CAAC,CAAC;IACL,CAAC;IAED,OAAO;QACL,QAAQ;QACR,OAAO;KACR,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;GAWG;AACH,SAAS,4CAA4C,CACnD,0BAGC,EACD,IAAiB;IAEjB,MAAM,EAAE,WAAW,EAAE,WAAW,EAAE,GAAG,0BAA0B,CAAC;IAChE,OAAO;QACL,QAAQ,EAAE,WAAW,CAAC,IAAI,CAAC;QAC3B,WAAW,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,WAAW,CAAC,IAAI,EAAE,GAAG,CAAC;KAC7C,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,SAAS,0BAA0B,CACjC,cAAgD;IAEhD,MAAM,CAAC,OAAO,EAAE,GAAG,SAAS,CAAC,GAAG,cAAc,CAAC;IAC/C,OAAO,CAAC,GAAI,OAAe,CAAC,aAAa,EAAE,GAAG,SAAS,CAAC,CAAC;AAC3D,CAAC"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/internal/index.js.map b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/internal/index.js.map index a4097ef8cb..a7cf9e445b 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/internal/index.js.map +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/internal/index.js.map @@ -1 +1 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../client/operations/internal/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AACxC,OAAO,EACL,SAAS,IAAI,kBAAkB,EAC/B,WAAW,IAAI,oBAAoB,GACnC,MAAM,WAAW,CAAA;AAKnB,cAAc;AACd,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,cAA4D,EAAE,IAAS;IACzG,IAAI;QACF,MAAM,aAAa,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAA;QAC9C,MAAM,QAAQ,GAAG,MAAM,GAAG,CAAC,IAAI,CAAC,cAAc,CAAC,IAAI,EAAE,aAAa,CAAC,CAAA;QACnE,OAAO,oBAAoB,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAA;KAC3C;IAAC,OAAO,KAAK,EAAE;QACd,cAAc,CAAC,KAAK,CAAC,CAAA;KACtB;AACH,CAAC;AAED,cAAc;AACd,MAAM,UAAU,kBAAkB,CAAC,sBAA8B;IAC/D,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,sBAAsB,EAAE,EAAE,CAAA;AACxE,CAAC"} \ No newline at end of file +{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../client/operations/internal/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AACxC,OAAO,EACL,SAAS,IAAI,kBAAkB,EAC/B,WAAW,IAAI,oBAAoB,GACnC,MAAM,WAAW,CAAA;AAKnB,cAAc;AACd,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,cAA4D,EAAE,IAAS;IACzG,IAAI,CAAC;QACH,MAAM,aAAa,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAA;QAC9C,MAAM,QAAQ,GAAG,MAAM,GAAG,CAAC,IAAI,CAAC,cAAc,CAAC,IAAI,EAAE,aAAa,CAAC,CAAA;QACnE,OAAO,oBAAoB,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAA;IAC5C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,cAAc,CAAC,KAAK,CAAC,CAAA;IACvB,CAAC;AACH,CAAC;AAED,cAAc;AACd,MAAM,UAAU,kBAAkB,CAAC,sBAA8B;IAC/D,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,sBAAsB,EAAE,EAAE,CAAA;AACxE,CAAC"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/internal/resources.js.map b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/internal/resources.js.map index c91fecd3c7..61f8241c3e 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/internal/resources.js.map +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/internal/resources.js.map @@ -1 +1 @@ -{"version":3,"file":"resources.js","sourceRoot":"","sources":["../../../../client/operations/internal/resources.js"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAA;AAC1D,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAA;AAC3D,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAA;AAEpD,kDAAkD;AAClD,mDAAmD;AACnD,iBAAiB;AACjB,MAAM,wBAAwB,GAAG,IAAI,GAAG,EAAE,CAAA;AAE1C,MAAM,cAAc,GAAG,qBAAqB,CAAC,YAAY,CAAC,CAAA;AAE1D,cAAc;AACd;;;;;GAKG;AACH,MAAM,UAAU,uBAAuB,CAAC,aAAa,EAAE,SAAS;IAC9D,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE;QAChC,IAAI,SAAS,GAAG,wBAAwB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;QACtD,IAAI,CAAC,SAAS,EAAE;YACd,SAAS,GAAG,IAAI,GAAG,EAAE,CAAA;YACrB,wBAAwB,CAAC,GAAG,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAA;SAClD;QACD,SAAS,CAAC,GAAG,CAAC,aAAa,CAAC,CAAA;KAC7B;AACH,CAAC;AAED,MAAM,UAAU,wBAAwB,CAAC,sBAAsB;IAC7D,sBAAsB,CAAC,OAAO,CAC5B,CAAC,EAAE,QAAQ,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC,cAAc,CAAC,GAAG,CAAC,QAAQ,EAAE,WAAW,CAAC,CACzE,CAAA;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,SAAS,EAAE,sBAAsB;IACxE,sBAAsB,CAAC,OAAO,CAAC,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,cAAc,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAA;IACjF,MAAM,sBAAsB,CAAC,SAAS,CAAC,CAAA;AACzC,CAAC;AAED,MAAM,UAAU,0BAA0B,CAAC,QAAQ;IACjD,OAAO,cAAc,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAA;AACnD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,0BAA0B;IAC9C,MAAM,WAAW,GAAG,MAAM,sBAAsB,CAAA;IAChD,wEAAwE;IACxE,8EAA8E;IAC9E,eAAe;IACf,iFAAiF;IACjF,6EAA6E;IAC7E,wFAAwF;IACxF,kFAAkF;IAClF,WAAW,CAAC,YAAY,EAAE,CAAA;IAC1B,6EAA6E;IAC7E,2DAA2D;IAC3D,WAAW,CAAC,aAAa,EAAE,CAAA;AAC7B,CAAC;AAED;;;GAGG;AACH,KAAK,UAAU,sBAAsB,CAAC,SAAS;IAC7C,MAAM,WAAW,GAAG,MAAM,sBAAsB,CAAA;IAEhD,MAAM,0BAA0B,GAAG,wBAAwB,CAAC,SAAS,CAAC,CAAA;IACtE,0BAA0B,CAAC,OAAO,CAChC,aAAa,CAAC,EAAE,CAAC,WAAW,CAAC,iBAAiB,CAAC,aAAa,CAAC,CAC9D,CAAA;AACH,CAAC;AAED;;;GAGG;AACH,SAAS,uBAAuB,CAAC,QAAQ;IACvC,OAAO,KAAK,CAAC,IAAI,CAAC,wBAAwB,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAA;AACjE,CAAC;AAED,SAAS,wBAAwB,CAAC,SAAS;IACzC,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,uBAAuB,CAAC,CAAC,CAAC,CAAA;AACxE,CAAC"} \ No newline at end of file +{"version":3,"file":"resources.js","sourceRoot":"","sources":["../../../../client/operations/internal/resources.js"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAA;AAC1D,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAA;AAC3D,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAA;AAEpD,kDAAkD;AAClD,mDAAmD;AACnD,iBAAiB;AACjB,MAAM,wBAAwB,GAAG,IAAI,GAAG,EAAE,CAAA;AAE1C,MAAM,cAAc,GAAG,qBAAqB,CAAC,YAAY,CAAC,CAAA;AAE1D,cAAc;AACd;;;;;GAKG;AACH,MAAM,UAAU,uBAAuB,CAAC,aAAa,EAAE,SAAS;IAC9D,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;QACjC,IAAI,SAAS,GAAG,wBAAwB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;QACtD,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,SAAS,GAAG,IAAI,GAAG,EAAE,CAAA;YACrB,wBAAwB,CAAC,GAAG,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAA;QACnD,CAAC;QACD,SAAS,CAAC,GAAG,CAAC,aAAa,CAAC,CAAA;IAC9B,CAAC;AACH,CAAC;AAED,MAAM,UAAU,wBAAwB,CAAC,sBAAsB;IAC7D,sBAAsB,CAAC,OAAO,CAC5B,CAAC,EAAE,QAAQ,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC,cAAc,CAAC,GAAG,CAAC,QAAQ,EAAE,WAAW,CAAC,CACzE,CAAA;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,SAAS,EAAE,sBAAsB;IACxE,sBAAsB,CAAC,OAAO,CAAC,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,cAAc,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAA;IACjF,MAAM,sBAAsB,CAAC,SAAS,CAAC,CAAA;AACzC,CAAC;AAED,MAAM,UAAU,0BAA0B,CAAC,QAAQ;IACjD,OAAO,cAAc,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAA;AACnD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,0BAA0B;IAC9C,MAAM,WAAW,GAAG,MAAM,sBAAsB,CAAA;IAChD,wEAAwE;IACxE,8EAA8E;IAC9E,eAAe;IACf,iFAAiF;IACjF,6EAA6E;IAC7E,wFAAwF;IACxF,kFAAkF;IAClF,WAAW,CAAC,YAAY,EAAE,CAAA;IAC1B,6EAA6E;IAC7E,2DAA2D;IAC3D,WAAW,CAAC,aAAa,EAAE,CAAA;AAC7B,CAAC;AAED;;;GAGG;AACH,KAAK,UAAU,sBAAsB,CAAC,SAAS;IAC7C,MAAM,WAAW,GAAG,MAAM,sBAAsB,CAAA;IAEhD,MAAM,0BAA0B,GAAG,wBAAwB,CAAC,SAAS,CAAC,CAAA;IACtE,0BAA0B,CAAC,OAAO,CAChC,aAAa,CAAC,EAAE,CAAC,WAAW,CAAC,iBAAiB,CAAC,aAAa,CAAC,CAC9D,CAAA;AACH,CAAC;AAED;;;GAGG;AACH,SAAS,uBAAuB,CAAC,QAAQ;IACvC,OAAO,KAAK,CAAC,IAAI,CAAC,wBAAwB,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAA;AACjE,CAAC;AAED,SAAS,wBAAwB,CAAC,SAAS;IACzC,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,uBAAuB,CAAC,CAAC,CAAC,CAAA;AACxE,CAAC"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/internal/updateHandlersMap.js.map b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/internal/updateHandlersMap.js.map index 7940fcd972..950c377452 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/internal/updateHandlersMap.js.map +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/internal/updateHandlersMap.js.map @@ -1 +1 @@ -{"version":3,"file":"updateHandlersMap.js","sourceRoot":"","sources":["../../../../client/operations/internal/updateHandlersMap.js"],"names":[],"mappings":"AAAA,MAAM,UAAU,qBAAqB,CAAC,aAAa;IACjD,MAAM,cAAc,GAAG,IAAI,GAAG,EAAE,CAAA;IAEhC,SAAS,gBAAgB,CAAC,YAAY;QACpC,OAAO,cAAc,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC;IAChD,CAAC;IAED,SAAS,GAAG,CAAC,QAAQ,EAAE,WAAW;QAChC,MAAM,YAAY,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAA;QAC5C,MAAM,QAAQ,GAAG,gBAAgB,CAAC,YAAY,CAAC,CAAC;QAChD,cAAc,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC,GAAG,QAAQ,EAAE,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC,CAAC,CAAA;IAC5E,CAAC;IAED,SAAS,iBAAiB,CAAC,QAAQ;QACjC,MAAM,YAAY,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAA;QAC5C,OAAO,gBAAgB,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC,WAAW,CAAC,CAAA;IAC7E,CAAC;IAED,SAAS,MAAM,CAAC,gBAAgB;QAC9B,MAAM,YAAY,GAAG,aAAa,CAAC,gBAAgB,CAAC,CAAA;QACpD,MAAM,gBAAgB,GAAG,gBAAgB,CAAC,YAAY,CAAC,CAAC,MAAM,CAC5D,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,QAAQ,KAAK,gBAAgB,CAChD,CAAA;QAED,IAAI,gBAAgB,CAAC,MAAM,GAAG,CAAC,EAAE;YAC/B,cAAc,CAAC,GAAG,CAAC,YAAY,EAAE,gBAAgB,CAAC,CAAA;SACnD;aAAM;YACL,cAAc,CAAC,MAAM,CAAC,YAAY,CAAC,CAAA;SACpC;IACH,CAAC;IAED,OAAO;QACL,GAAG;QACH,MAAM;QACN,iBAAiB;KAClB,CAAA;AACH,CAAC"} \ No newline at end of file +{"version":3,"file":"updateHandlersMap.js","sourceRoot":"","sources":["../../../../client/operations/internal/updateHandlersMap.js"],"names":[],"mappings":"AAAA,MAAM,UAAU,qBAAqB,CAAC,aAAa;IACjD,MAAM,cAAc,GAAG,IAAI,GAAG,EAAE,CAAA;IAEhC,SAAS,gBAAgB,CAAC,YAAY;QACpC,OAAO,cAAc,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC;IAChD,CAAC;IAED,SAAS,GAAG,CAAC,QAAQ,EAAE,WAAW;QAChC,MAAM,YAAY,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAA;QAC5C,MAAM,QAAQ,GAAG,gBAAgB,CAAC,YAAY,CAAC,CAAC;QAChD,cAAc,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC,GAAG,QAAQ,EAAE,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC,CAAC,CAAA;IAC5E,CAAC;IAED,SAAS,iBAAiB,CAAC,QAAQ;QACjC,MAAM,YAAY,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAA;QAC5C,OAAO,gBAAgB,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC,WAAW,CAAC,CAAA;IAC7E,CAAC;IAED,SAAS,MAAM,CAAC,gBAAgB;QAC9B,MAAM,YAAY,GAAG,aAAa,CAAC,gBAAgB,CAAC,CAAA;QACpD,MAAM,gBAAgB,GAAG,gBAAgB,CAAC,YAAY,CAAC,CAAC,MAAM,CAC5D,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,QAAQ,KAAK,gBAAgB,CAChD,CAAA;QAED,IAAI,gBAAgB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAChC,cAAc,CAAC,GAAG,CAAC,YAAY,EAAE,gBAAgB,CAAC,CAAA;QACpD,CAAC;aAAM,CAAC;YACN,cAAc,CAAC,MAAM,CAAC,YAAY,CAAC,CAAA;QACrC,CAAC;IACH,CAAC;IAED,OAAO;QACL,GAAG;QACH,MAAM;QACN,iBAAiB;KAClB,CAAA;AACH,CAAC"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/queryClient.js.map b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/queryClient.js.map index 82e2b19139..15d3f12588 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/queryClient.js.map +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/queryClient.js.map @@ -1 +1 @@ -{"version":3,"file":"queryClient.js","sourceRoot":"","sources":["../../../client/operations/queryClient.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAqB,MAAM,uBAAuB,CAAA;AAEtE,MAAM,wBAAwB,GAAG,EAAE,CAAC;AAEpC,IAAI,iBAAoC,EACtC,6BAAsD,EACtD,wBAAiC,CAAC;AAEpC,+BAA+B;AAC/B,MAAM,CAAC,MAAM,sBAAsB,GAAyB,IAAI,OAAO,CACrE,CAAC,OAAO,EAAE,EAAE;IACV,6BAA6B,GAAG,OAAO,CAAC;AAC1C,CAAC,CACF,CAAC;AAEF,aAAa;AACb,MAAM,UAAU,oBAAoB,CAAC,MAAyB;IAC5D,IAAI,wBAAwB,EAAE;QAC5B,MAAM,IAAI,KAAK,CACb,6DAA6D,CAC9D,CAAC;KACH;IAED,iBAAiB,GAAG,MAAM,CAAC;AAC7B,CAAC;AAED,+BAA+B;AAC/B,MAAM,UAAU,qBAAqB;IACnC,MAAM,WAAW,GAAG,IAAI,WAAW,CACjC,iBAAiB,aAAjB,iBAAiB,cAAjB,iBAAiB,GAAI,wBAAwB,CAC9C,CAAC;IACF,wBAAwB,GAAG,IAAI,CAAC;IAChC,6BAA6B,CAAC,WAAW,CAAC,CAAC;AAC7C,CAAC"} \ No newline at end of file +{"version":3,"file":"queryClient.js","sourceRoot":"","sources":["../../../client/operations/queryClient.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAqB,MAAM,uBAAuB,CAAA;AAEtE,MAAM,wBAAwB,GAAG,EAAE,CAAC;AAEpC,IAAI,iBAAoC,EACtC,6BAAsD,EACtD,wBAAiC,CAAC;AAEpC,+BAA+B;AAC/B,MAAM,CAAC,MAAM,sBAAsB,GAAyB,IAAI,OAAO,CACrE,CAAC,OAAO,EAAE,EAAE;IACV,6BAA6B,GAAG,OAAO,CAAC;AAC1C,CAAC,CACF,CAAC;AAEF,aAAa;AACb,MAAM,UAAU,oBAAoB,CAAC,MAAyB;IAC5D,IAAI,wBAAwB,EAAE,CAAC;QAC7B,MAAM,IAAI,KAAK,CACb,6DAA6D,CAC9D,CAAC;IACJ,CAAC;IAED,iBAAiB,GAAG,MAAM,CAAC;AAC7B,CAAC;AAED,+BAA+B;AAC/B,MAAM,UAAU,qBAAqB;IACnC,MAAM,WAAW,GAAG,IAAI,WAAW,CACjC,iBAAiB,aAAjB,iBAAiB,cAAjB,iBAAiB,GAAI,wBAAwB,CAC9C,CAAC;IACF,wBAAwB,GAAG,IAAI,CAAC;IAChC,6BAA6B,CAAC,WAAW,CAAC,CAAC;AAC7C,CAAC"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/router/linkHelpers.js.map b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/router/linkHelpers.js.map index 064bcce597..c532d39f5e 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/router/linkHelpers.js.map +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/router/linkHelpers.js.map @@ -1 +1 @@ -{"version":3,"file":"linkHelpers.js","sourceRoot":"","sources":["../../../client/router/linkHelpers.ts"],"names":[],"mappings":"AAEA,cAAc;AACd,MAAM,UAAU,eAAe,CAC7B,IAAY,EACZ,MAAe,EACf,MAAe,EACf,IAAa;IAEb,MAAM,gBAAgB,GAAG,MAAM,CAAC,CAAC,CAAC,qBAAqB,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;IAC5E,MAAM,kBAAkB,GAAG,MAAM;QAC/B,CAAC,CAAC,IAAI,IAAI,eAAe,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,EAAE;QAC9C,CAAC,CAAC,EAAE,CAAA;IACN,MAAM,gBAAgB,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAA;IAC/C,OAAO,gBAAgB,GAAG,kBAAkB,GAAG,gBAAgB,CAAA;AACjE,CAAC;AAED,SAAS,qBAAqB,CAAC,IAAY,EAAE,MAAc;IACzD,SAAS,WAAW,CAAC,IAAY;QAC/B,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE;YACxB,MAAM,SAAS,GAAG,4BAA4B,CAAC,IAAI,CAAC,CAAC;YACrD,OAAO,MAAM,CAAC,SAAS,CAAC,CAAC;SAC1B;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,gBAAgB,GAAG,IAAI;SAC1B,KAAK,CAAC,GAAG,CAAC;SACV,GAAG,CAAC,WAAW,CAAC;SAChB,MAAM,CAAC,eAAe,CAAC;SACvB,IAAI,CAAC,GAAG,CAAC,CAAC;IAEb,OAAO,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,gBAAgB,EAAE,CAAC,CAAC,CAAC,gBAAgB,CAAC;AAC1E,CAAC;AAED,SAAS,eAAe,CAAC,IAAS;IAChC,OAAO,CAAC,CAAC,IAAI,CAAC;AAChB,CAAC;AAED,SAAS,4BAA4B,CAAC,WAAmB;IACvD,IAAI,WAAW,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE;QAC7B,OAAO,WAAW,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;KACjC;IACD,OAAO,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC9B,CAAC"} \ No newline at end of file +{"version":3,"file":"linkHelpers.js","sourceRoot":"","sources":["../../../client/router/linkHelpers.ts"],"names":[],"mappings":"AAEA,cAAc;AACd,MAAM,UAAU,eAAe,CAC7B,IAAY,EACZ,MAAe,EACf,MAAe,EACf,IAAa;IAEb,MAAM,gBAAgB,GAAG,MAAM,CAAC,CAAC,CAAC,qBAAqB,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;IAC5E,MAAM,kBAAkB,GAAG,MAAM;QAC/B,CAAC,CAAC,IAAI,IAAI,eAAe,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,EAAE;QAC9C,CAAC,CAAC,EAAE,CAAA;IACN,MAAM,gBAAgB,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAA;IAC/C,OAAO,gBAAgB,GAAG,kBAAkB,GAAG,gBAAgB,CAAA;AACjE,CAAC;AAED,SAAS,qBAAqB,CAAC,IAAY,EAAE,MAAc;IACzD,SAAS,WAAW,CAAC,IAAY;QAC/B,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YACzB,MAAM,SAAS,GAAG,4BAA4B,CAAC,IAAI,CAAC,CAAC;YACrD,OAAO,MAAM,CAAC,SAAS,CAAC,CAAC;QAC3B,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,gBAAgB,GAAG,IAAI;SAC1B,KAAK,CAAC,GAAG,CAAC;SACV,GAAG,CAAC,WAAW,CAAC;SAChB,MAAM,CAAC,eAAe,CAAC;SACvB,IAAI,CAAC,GAAG,CAAC,CAAC;IAEb,OAAO,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,gBAAgB,EAAE,CAAC,CAAC,CAAC,gBAAgB,CAAC;AAC1E,CAAC;AAED,SAAS,eAAe,CAAC,IAAS;IAChC,OAAO,CAAC,CAAC,IAAI,CAAC;AAChB,CAAC;AAED,SAAS,4BAA4B,CAAC,WAAmB;IACvD,IAAI,WAAW,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QAC9B,OAAO,WAAW,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAClC,CAAC;IACD,OAAO,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC9B,CAAC"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/test/vitest/helpers.jsx.map b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/test/vitest/helpers.jsx.map index b7ab2a906f..375c4629a2 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/test/vitest/helpers.jsx.map +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/test/vitest/helpers.jsx.map @@ -1 +1 @@ -{"version":3,"file":"helpers.jsx","sourceRoot":"","sources":["../../../../client/test/vitest/helpers.tsx"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"helpers.jsx","sourceRoot":"","sources":["../../../../client/test/vitest/helpers.tsx"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/core/storage.js.map b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/core/storage.js.map index b7cd5db441..73a6773d4f 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/core/storage.js.map +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/core/storage.js.map @@ -1 +1 @@ -{"version":3,"file":"storage.js","sourceRoot":"","sources":["../../core/storage.ts"],"names":[],"mappings":"AAQA,SAAS,2BAA2B,CAAC,MAAc;IACjD,SAAS,cAAc,CAAC,GAAW;QACjC,OAAO,GAAG,MAAM,IAAI,GAAG,EAAE,CAAA;IAC3B,CAAC;IAED,OAAO;QACL,cAAc;QACd,GAAG,CAAC,GAAG,EAAE,KAAK;YACZ,6BAA6B,EAAE,CAAA;YAC/B,YAAY,CAAC,OAAO,CAAC,cAAc,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAA;QAClE,CAAC;QACD,GAAG,CAAC,GAAG;YACL,6BAA6B,EAAE,CAAA;YAC/B,MAAM,KAAK,GAAG,YAAY,CAAC,OAAO,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAA;YACvD,IAAI;gBACF,OAAO,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;aAC7C;YAAC,OAAO,CAAM,EAAE;gBACf,OAAO,SAAS,CAAA;aACjB;QACH,CAAC;QACD,MAAM,CAAC,GAAG;YACR,6BAA6B,EAAE,CAAA;YAC/B,YAAY,CAAC,UAAU,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAA;QAC9C,CAAC;QACD,KAAK;YACH,6BAA6B,EAAE,CAAA;YAC/B,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE;gBACxC,IAAI,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE;oBAC1B,YAAY,CAAC,UAAU,CAAC,GAAG,CAAC,CAAA;iBAC7B;YACH,CAAC,CAAC,CAAA;QACJ,CAAC;KACF,CAAA;AACH,CAAC;AAED,MAAM,CAAC,MAAM,OAAO,GAAG,2BAA2B,CAAC,MAAM,CAAC,CAAA;AAE1D,SAAS,6BAA6B;IACpC,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE;QACxB,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAA;KACnD;AACH,CAAC"} \ No newline at end of file +{"version":3,"file":"storage.js","sourceRoot":"","sources":["../../core/storage.ts"],"names":[],"mappings":"AAQA,SAAS,2BAA2B,CAAC,MAAc;IACjD,SAAS,cAAc,CAAC,GAAW;QACjC,OAAO,GAAG,MAAM,IAAI,GAAG,EAAE,CAAA;IAC3B,CAAC;IAED,OAAO;QACL,cAAc;QACd,GAAG,CAAC,GAAG,EAAE,KAAK;YACZ,6BAA6B,EAAE,CAAA;YAC/B,YAAY,CAAC,OAAO,CAAC,cAAc,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAA;QAClE,CAAC;QACD,GAAG,CAAC,GAAG;YACL,6BAA6B,EAAE,CAAA;YAC/B,MAAM,KAAK,GAAG,YAAY,CAAC,OAAO,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAA;YACvD,IAAI,CAAC;gBACH,OAAO,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;YAC9C,CAAC;YAAC,OAAO,CAAM,EAAE,CAAC;gBAChB,OAAO,SAAS,CAAA;YAClB,CAAC;QACH,CAAC;QACD,MAAM,CAAC,GAAG;YACR,6BAA6B,EAAE,CAAA;YAC/B,YAAY,CAAC,UAAU,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAA;QAC9C,CAAC;QACD,KAAK;YACH,6BAA6B,EAAE,CAAA;YAC/B,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE;gBACxC,IAAI,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;oBAC3B,YAAY,CAAC,UAAU,CAAC,GAAG,CAAC,CAAA;gBAC9B,CAAC;YACH,CAAC,CAAC,CAAA;QACJ,CAAC;KACF,CAAA;AACH,CAAC;AAED,MAAM,CAAC,MAAM,OAAO,GAAG,2BAA2B,CAAC,MAAM,CAAC,CAAA;AAE1D,SAAS,6BAA6B;IACpC,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAA;IACpD,CAAC;AACH,CAAC"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/server/HttpError.js.map b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/server/HttpError.js.map index 34064e924c..3cc7095281 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/server/HttpError.js.map +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/server/HttpError.js.map @@ -1 +1 @@ -{"version":3,"file":"HttpError.js","sourceRoot":"","sources":["../../server/HttpError.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,SAAU,SAAQ,KAAK;IAIlC,YAAa,UAAkB,EAAE,OAAgB,EAAE,IAA8B,EAAE,GAAG,MAAiB;QACrG,KAAK,CAAC,OAAO,EAAE,GAAG,MAAM,CAAC,CAAA;QAEzB,IAAI,KAAK,CAAC,iBAAiB,EAAE;YAC3B,KAAK,CAAC,iBAAiB,CAAC,IAAI,EAAE,SAAS,CAAC,CAAA;SACzC;QAED,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,CAAA;QAEjC,IAAI,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC,IAAI,UAAU,IAAI,GAAG,IAAI,UAAU,GAAG,GAAG,CAAC,EAAE;YAC5E,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAA;SACrE;QACD,IAAI,CAAC,UAAU,GAAG,UAAU,CAAA;QAE5B,IAAI,IAAI,EAAE;YACR,IAAI,CAAC,IAAI,GAAG,IAAI,CAAA;SACjB;IACH,CAAC;CACF"} \ No newline at end of file +{"version":3,"file":"HttpError.js","sourceRoot":"","sources":["../../server/HttpError.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,SAAU,SAAQ,KAAK;IAIlC,YAAa,UAAkB,EAAE,OAAgB,EAAE,IAA8B,EAAE,GAAG,MAAiB;QACrG,KAAK,CAAC,OAAO,EAAE,GAAG,MAAM,CAAC,CAAA;QAEzB,IAAI,KAAK,CAAC,iBAAiB,EAAE,CAAC;YAC5B,KAAK,CAAC,iBAAiB,CAAC,IAAI,EAAE,SAAS,CAAC,CAAA;QAC1C,CAAC;QAED,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,CAAA;QAEjC,IAAI,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC,IAAI,UAAU,IAAI,GAAG,IAAI,UAAU,GAAG,GAAG,CAAC,EAAE,CAAC;YAC7E,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAA;QACtE,CAAC;QACD,IAAI,CAAC,UAAU,GAAG,UAAU,CAAA;QAE5B,IAAI,IAAI,EAAE,CAAC;YACT,IAAI,CAAC,IAAI,GAAG,IAAI,CAAA;QAClB,CAAC;IACH,CAAC;CACF"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/server/utils.js.map b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/server/utils.js.map index f3af561141..17121f586d 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/server/utils.js.map +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/server/utils.js.map @@ -1 +1 @@ -{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../server/utils.ts"],"names":[],"mappings":"AAWA;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAC7B,UAIQ,EACR,EAAE,CACJ,KAAK,EAAE,GAA2B,EAAE,GAAa,EAAE,IAAkB,EAAE,EAAE;IACvE,IAAI;QACF,MAAM,UAAU,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,CAAA;KACjC;IAAC,OAAO,KAAK,EAAE;QACd,IAAI,CAAC,KAAK,CAAC,CAAA;KACZ;AACH,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,EAAU,EAAoB,EAAE,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAA"} \ No newline at end of file +{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../server/utils.ts"],"names":[],"mappings":"AAWA;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAC7B,UAIQ,EACR,EAAE,CACJ,KAAK,EAAE,GAA2B,EAAE,GAAa,EAAE,IAAkB,EAAE,EAAE;IACvE,IAAI,CAAC;QACH,MAAM,UAAU,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,CAAA;IAClC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,CAAC,KAAK,CAAC,CAAA;IACb,CAAC;AACH,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,EAAU,EAAoB,EAAE,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAA"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/universal/validators.js.map b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/universal/validators.js.map index 313c98cef4..f020413e43 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/universal/validators.js.map +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/universal/validators.js.map @@ -1 +1 @@ -{"version":3,"file":"validators.js","sourceRoot":"","sources":["../../universal/validators.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,kBAAkB,CAAC,MAAc;IAC7C,IAAI;QACA,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC;QAC5B;;;;;;UAME;QACF,OAAO,GAAG,CAAC,QAAQ,KAAK,OAAO,IAAI,GAAG,CAAC,QAAQ,KAAK,QAAQ,CAAC;KAChE;IAAC,OAAO,CAAC,EAAE;QACR,OAAO,KAAK,CAAC;KAChB;AACL,CAAC;AAED,MAAM,UAAU,0BAA0B,CAAC,KAAyB,EAAE,IAAY;IAC9E,IAAI,KAAK,IAAI,CAAC,kBAAkB,CAAC,KAAK,CAAC,EAAE;QACrC,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,+BAA+B,CAAC,CAAC;KAC3D;AACL,CAAC"} \ No newline at end of file +{"version":3,"file":"validators.js","sourceRoot":"","sources":["../../universal/validators.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,kBAAkB,CAAC,MAAc;IAC7C,IAAI,CAAC;QACD,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC;QAC5B;;;;;;UAME;QACF,OAAO,GAAG,CAAC,QAAQ,KAAK,OAAO,IAAI,GAAG,CAAC,QAAQ,KAAK,QAAQ,CAAC;IACjE,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACT,OAAO,KAAK,CAAC;IACjB,CAAC;AACL,CAAC;AAED,MAAM,UAAU,0BAA0B,CAAC,KAAyB,EAAE,IAAY;IAC9E,IAAI,KAAK,IAAI,CAAC,kBAAkB,CAAC,KAAK,CAAC,EAAE,CAAC;QACtC,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,+BAA+B,CAAC,CAAC;IAC5D,CAAC;AACL,CAAC"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/package.json b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/package.json index 3f9c859316..e290f61ea9 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/package.json +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/package.json @@ -10,7 +10,6 @@ "axios": "^1.4.0", "express": "~4.18.1", "jsdom": "^21.1.1", - "jsonwebtoken": "^8.5.1", "lodash.merge": "^4.6.2", "mitt": "3.0.0", "msw": "^1.1.0", diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/server/package.json b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/server/package.json index 009928aa42..af6031d33e 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/server/package.json +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/server/package.json @@ -6,7 +6,6 @@ "dotenv": "16.0.2", "express": "~4.18.1", "helmet": "^6.0.0", - "jsonwebtoken": "^8.5.1", "morgan": "~1.10.0", "rate-limiter-flexible": "^2.4.1", "superjson": "^1.12.2" diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/api/index.js.map b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/api/index.js.map index b4ae2eba65..fab323a0b2 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/api/index.js.map +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/api/index.js.map @@ -1 +1 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["../../api/index.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"index.js","sourceRoot":"","sources":["../../api/index.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/actions/core.js.map b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/actions/core.js.map index 5834336f1d..b13c7d6712 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/actions/core.js.map +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/actions/core.js.map @@ -1 +1 @@ -{"version":3,"file":"core.js","sourceRoot":"","sources":["../../../../client/operations/actions/core.js"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAA;AACxE,OAAO,EACL,wBAAwB,EACxB,kBAAkB,GACnB,MAAM,0BAA0B,CAAA;AAEjC,cAAc;AACd,MAAM,UAAU,YAAY,CAAC,mBAAmB,EAAE,YAAY;IAC5D,MAAM,WAAW,GAAG,kBAAkB,CAAC,mBAAmB,CAAC,CAAA;IAE3D,KAAK,UAAU,cAAc,CAAC,IAAI,EAAE,mCAAmC;QACrE,wBAAwB,CAAC,mCAAmC,CAAC,CAAA;QAC7D,IAAI;YACF,yEAAyE;YACzE,wEAAwE;YACxE,kCAAkC;YAClC,OAAO,MAAM,aAAa,CAAC,WAAW,EAAE,IAAI,CAAC,CAAA;SAC9C;gBAAS;YACR,MAAM,kBAAkB,CAAC,YAAY,EAAE,mCAAmC,CAAC,CAAA;SAC5E;IACH,CAAC;IAED,0EAA0E;IAC1E,yEAAyE;IACzE,6EAA6E;IAC7E,yEAAyE;IACzE,gBAAgB;IAChB,EAAE;IACF,0EAA0E;IAC1E,8EAA8E;IAC9E,wCAAwC;IACxC,MAAM,MAAM,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC,cAAc,CAAC,IAAI,EAAE,EAAE,CAAC,CAAA;IACjD,MAAM,CAAC,QAAQ,GAAG,cAAc,CAAA;IAEhC,OAAO,MAAM,CAAA;AACf,CAAC"} \ No newline at end of file +{"version":3,"file":"core.js","sourceRoot":"","sources":["../../../../client/operations/actions/core.js"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAA;AACxE,OAAO,EACL,wBAAwB,EACxB,kBAAkB,GACnB,MAAM,0BAA0B,CAAA;AAEjC,cAAc;AACd,MAAM,UAAU,YAAY,CAAC,mBAAmB,EAAE,YAAY;IAC5D,MAAM,WAAW,GAAG,kBAAkB,CAAC,mBAAmB,CAAC,CAAA;IAE3D,KAAK,UAAU,cAAc,CAAC,IAAI,EAAE,mCAAmC;QACrE,wBAAwB,CAAC,mCAAmC,CAAC,CAAA;QAC7D,IAAI,CAAC;YACH,yEAAyE;YACzE,wEAAwE;YACxE,kCAAkC;YAClC,OAAO,MAAM,aAAa,CAAC,WAAW,EAAE,IAAI,CAAC,CAAA;QAC/C,CAAC;gBAAS,CAAC;YACT,MAAM,kBAAkB,CAAC,YAAY,EAAE,mCAAmC,CAAC,CAAA;QAC7E,CAAC;IACH,CAAC;IAED,0EAA0E;IAC1E,yEAAyE;IACzE,6EAA6E;IAC7E,yEAAyE;IACzE,gBAAgB;IAChB,EAAE;IACF,0EAA0E;IAC1E,8EAA8E;IAC9E,wCAAwC;IACxC,MAAM,MAAM,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC,cAAc,CAAC,IAAI,EAAE,EAAE,CAAC,CAAA;IACjD,MAAM,CAAC,QAAQ,GAAG,cAAc,CAAA;IAEhC,OAAO,MAAM,CAAA;AACf,CAAC"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/core.js.map b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/core.js.map index 68ea114aa9..20d72dc15e 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/core.js.map +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/core.js.map @@ -1 +1 @@ -{"version":3,"file":"core.js","sourceRoot":"","sources":["../../../client/operations/core.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"core.js","sourceRoot":"","sources":["../../../client/operations/core.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/internal/index.js.map b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/internal/index.js.map index a4097ef8cb..a7cf9e445b 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/internal/index.js.map +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/internal/index.js.map @@ -1 +1 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../client/operations/internal/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AACxC,OAAO,EACL,SAAS,IAAI,kBAAkB,EAC/B,WAAW,IAAI,oBAAoB,GACnC,MAAM,WAAW,CAAA;AAKnB,cAAc;AACd,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,cAA4D,EAAE,IAAS;IACzG,IAAI;QACF,MAAM,aAAa,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAA;QAC9C,MAAM,QAAQ,GAAG,MAAM,GAAG,CAAC,IAAI,CAAC,cAAc,CAAC,IAAI,EAAE,aAAa,CAAC,CAAA;QACnE,OAAO,oBAAoB,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAA;KAC3C;IAAC,OAAO,KAAK,EAAE;QACd,cAAc,CAAC,KAAK,CAAC,CAAA;KACtB;AACH,CAAC;AAED,cAAc;AACd,MAAM,UAAU,kBAAkB,CAAC,sBAA8B;IAC/D,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,sBAAsB,EAAE,EAAE,CAAA;AACxE,CAAC"} \ No newline at end of file +{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../client/operations/internal/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AACxC,OAAO,EACL,SAAS,IAAI,kBAAkB,EAC/B,WAAW,IAAI,oBAAoB,GACnC,MAAM,WAAW,CAAA;AAKnB,cAAc;AACd,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,cAA4D,EAAE,IAAS;IACzG,IAAI,CAAC;QACH,MAAM,aAAa,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAA;QAC9C,MAAM,QAAQ,GAAG,MAAM,GAAG,CAAC,IAAI,CAAC,cAAc,CAAC,IAAI,EAAE,aAAa,CAAC,CAAA;QACnE,OAAO,oBAAoB,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAA;IAC5C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,cAAc,CAAC,KAAK,CAAC,CAAA;IACvB,CAAC;AACH,CAAC;AAED,cAAc;AACd,MAAM,UAAU,kBAAkB,CAAC,sBAA8B;IAC/D,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,sBAAsB,EAAE,EAAE,CAAA;AACxE,CAAC"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/internal/resources.js.map b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/internal/resources.js.map index c91fecd3c7..61f8241c3e 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/internal/resources.js.map +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/internal/resources.js.map @@ -1 +1 @@ -{"version":3,"file":"resources.js","sourceRoot":"","sources":["../../../../client/operations/internal/resources.js"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAA;AAC1D,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAA;AAC3D,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAA;AAEpD,kDAAkD;AAClD,mDAAmD;AACnD,iBAAiB;AACjB,MAAM,wBAAwB,GAAG,IAAI,GAAG,EAAE,CAAA;AAE1C,MAAM,cAAc,GAAG,qBAAqB,CAAC,YAAY,CAAC,CAAA;AAE1D,cAAc;AACd;;;;;GAKG;AACH,MAAM,UAAU,uBAAuB,CAAC,aAAa,EAAE,SAAS;IAC9D,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE;QAChC,IAAI,SAAS,GAAG,wBAAwB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;QACtD,IAAI,CAAC,SAAS,EAAE;YACd,SAAS,GAAG,IAAI,GAAG,EAAE,CAAA;YACrB,wBAAwB,CAAC,GAAG,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAA;SAClD;QACD,SAAS,CAAC,GAAG,CAAC,aAAa,CAAC,CAAA;KAC7B;AACH,CAAC;AAED,MAAM,UAAU,wBAAwB,CAAC,sBAAsB;IAC7D,sBAAsB,CAAC,OAAO,CAC5B,CAAC,EAAE,QAAQ,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC,cAAc,CAAC,GAAG,CAAC,QAAQ,EAAE,WAAW,CAAC,CACzE,CAAA;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,SAAS,EAAE,sBAAsB;IACxE,sBAAsB,CAAC,OAAO,CAAC,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,cAAc,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAA;IACjF,MAAM,sBAAsB,CAAC,SAAS,CAAC,CAAA;AACzC,CAAC;AAED,MAAM,UAAU,0BAA0B,CAAC,QAAQ;IACjD,OAAO,cAAc,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAA;AACnD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,0BAA0B;IAC9C,MAAM,WAAW,GAAG,MAAM,sBAAsB,CAAA;IAChD,wEAAwE;IACxE,8EAA8E;IAC9E,eAAe;IACf,iFAAiF;IACjF,6EAA6E;IAC7E,wFAAwF;IACxF,kFAAkF;IAClF,WAAW,CAAC,YAAY,EAAE,CAAA;IAC1B,6EAA6E;IAC7E,2DAA2D;IAC3D,WAAW,CAAC,aAAa,EAAE,CAAA;AAC7B,CAAC;AAED;;;GAGG;AACH,KAAK,UAAU,sBAAsB,CAAC,SAAS;IAC7C,MAAM,WAAW,GAAG,MAAM,sBAAsB,CAAA;IAEhD,MAAM,0BAA0B,GAAG,wBAAwB,CAAC,SAAS,CAAC,CAAA;IACtE,0BAA0B,CAAC,OAAO,CAChC,aAAa,CAAC,EAAE,CAAC,WAAW,CAAC,iBAAiB,CAAC,aAAa,CAAC,CAC9D,CAAA;AACH,CAAC;AAED;;;GAGG;AACH,SAAS,uBAAuB,CAAC,QAAQ;IACvC,OAAO,KAAK,CAAC,IAAI,CAAC,wBAAwB,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAA;AACjE,CAAC;AAED,SAAS,wBAAwB,CAAC,SAAS;IACzC,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,uBAAuB,CAAC,CAAC,CAAC,CAAA;AACxE,CAAC"} \ No newline at end of file +{"version":3,"file":"resources.js","sourceRoot":"","sources":["../../../../client/operations/internal/resources.js"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAA;AAC1D,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAA;AAC3D,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAA;AAEpD,kDAAkD;AAClD,mDAAmD;AACnD,iBAAiB;AACjB,MAAM,wBAAwB,GAAG,IAAI,GAAG,EAAE,CAAA;AAE1C,MAAM,cAAc,GAAG,qBAAqB,CAAC,YAAY,CAAC,CAAA;AAE1D,cAAc;AACd;;;;;GAKG;AACH,MAAM,UAAU,uBAAuB,CAAC,aAAa,EAAE,SAAS;IAC9D,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;QACjC,IAAI,SAAS,GAAG,wBAAwB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;QACtD,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,SAAS,GAAG,IAAI,GAAG,EAAE,CAAA;YACrB,wBAAwB,CAAC,GAAG,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAA;QACnD,CAAC;QACD,SAAS,CAAC,GAAG,CAAC,aAAa,CAAC,CAAA;IAC9B,CAAC;AACH,CAAC;AAED,MAAM,UAAU,wBAAwB,CAAC,sBAAsB;IAC7D,sBAAsB,CAAC,OAAO,CAC5B,CAAC,EAAE,QAAQ,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC,cAAc,CAAC,GAAG,CAAC,QAAQ,EAAE,WAAW,CAAC,CACzE,CAAA;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,SAAS,EAAE,sBAAsB;IACxE,sBAAsB,CAAC,OAAO,CAAC,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,cAAc,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAA;IACjF,MAAM,sBAAsB,CAAC,SAAS,CAAC,CAAA;AACzC,CAAC;AAED,MAAM,UAAU,0BAA0B,CAAC,QAAQ;IACjD,OAAO,cAAc,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAA;AACnD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,0BAA0B;IAC9C,MAAM,WAAW,GAAG,MAAM,sBAAsB,CAAA;IAChD,wEAAwE;IACxE,8EAA8E;IAC9E,eAAe;IACf,iFAAiF;IACjF,6EAA6E;IAC7E,wFAAwF;IACxF,kFAAkF;IAClF,WAAW,CAAC,YAAY,EAAE,CAAA;IAC1B,6EAA6E;IAC7E,2DAA2D;IAC3D,WAAW,CAAC,aAAa,EAAE,CAAA;AAC7B,CAAC;AAED;;;GAGG;AACH,KAAK,UAAU,sBAAsB,CAAC,SAAS;IAC7C,MAAM,WAAW,GAAG,MAAM,sBAAsB,CAAA;IAEhD,MAAM,0BAA0B,GAAG,wBAAwB,CAAC,SAAS,CAAC,CAAA;IACtE,0BAA0B,CAAC,OAAO,CAChC,aAAa,CAAC,EAAE,CAAC,WAAW,CAAC,iBAAiB,CAAC,aAAa,CAAC,CAC9D,CAAA;AACH,CAAC;AAED;;;GAGG;AACH,SAAS,uBAAuB,CAAC,QAAQ;IACvC,OAAO,KAAK,CAAC,IAAI,CAAC,wBAAwB,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAA;AACjE,CAAC;AAED,SAAS,wBAAwB,CAAC,SAAS;IACzC,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,uBAAuB,CAAC,CAAC,CAAC,CAAA;AACxE,CAAC"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/internal/updateHandlersMap.js.map b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/internal/updateHandlersMap.js.map index 7940fcd972..950c377452 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/internal/updateHandlersMap.js.map +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/internal/updateHandlersMap.js.map @@ -1 +1 @@ -{"version":3,"file":"updateHandlersMap.js","sourceRoot":"","sources":["../../../../client/operations/internal/updateHandlersMap.js"],"names":[],"mappings":"AAAA,MAAM,UAAU,qBAAqB,CAAC,aAAa;IACjD,MAAM,cAAc,GAAG,IAAI,GAAG,EAAE,CAAA;IAEhC,SAAS,gBAAgB,CAAC,YAAY;QACpC,OAAO,cAAc,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC;IAChD,CAAC;IAED,SAAS,GAAG,CAAC,QAAQ,EAAE,WAAW;QAChC,MAAM,YAAY,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAA;QAC5C,MAAM,QAAQ,GAAG,gBAAgB,CAAC,YAAY,CAAC,CAAC;QAChD,cAAc,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC,GAAG,QAAQ,EAAE,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC,CAAC,CAAA;IAC5E,CAAC;IAED,SAAS,iBAAiB,CAAC,QAAQ;QACjC,MAAM,YAAY,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAA;QAC5C,OAAO,gBAAgB,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC,WAAW,CAAC,CAAA;IAC7E,CAAC;IAED,SAAS,MAAM,CAAC,gBAAgB;QAC9B,MAAM,YAAY,GAAG,aAAa,CAAC,gBAAgB,CAAC,CAAA;QACpD,MAAM,gBAAgB,GAAG,gBAAgB,CAAC,YAAY,CAAC,CAAC,MAAM,CAC5D,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,QAAQ,KAAK,gBAAgB,CAChD,CAAA;QAED,IAAI,gBAAgB,CAAC,MAAM,GAAG,CAAC,EAAE;YAC/B,cAAc,CAAC,GAAG,CAAC,YAAY,EAAE,gBAAgB,CAAC,CAAA;SACnD;aAAM;YACL,cAAc,CAAC,MAAM,CAAC,YAAY,CAAC,CAAA;SACpC;IACH,CAAC;IAED,OAAO;QACL,GAAG;QACH,MAAM;QACN,iBAAiB;KAClB,CAAA;AACH,CAAC"} \ No newline at end of file +{"version":3,"file":"updateHandlersMap.js","sourceRoot":"","sources":["../../../../client/operations/internal/updateHandlersMap.js"],"names":[],"mappings":"AAAA,MAAM,UAAU,qBAAqB,CAAC,aAAa;IACjD,MAAM,cAAc,GAAG,IAAI,GAAG,EAAE,CAAA;IAEhC,SAAS,gBAAgB,CAAC,YAAY;QACpC,OAAO,cAAc,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC;IAChD,CAAC;IAED,SAAS,GAAG,CAAC,QAAQ,EAAE,WAAW;QAChC,MAAM,YAAY,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAA;QAC5C,MAAM,QAAQ,GAAG,gBAAgB,CAAC,YAAY,CAAC,CAAC;QAChD,cAAc,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC,GAAG,QAAQ,EAAE,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC,CAAC,CAAA;IAC5E,CAAC;IAED,SAAS,iBAAiB,CAAC,QAAQ;QACjC,MAAM,YAAY,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAA;QAC5C,OAAO,gBAAgB,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC,WAAW,CAAC,CAAA;IAC7E,CAAC;IAED,SAAS,MAAM,CAAC,gBAAgB;QAC9B,MAAM,YAAY,GAAG,aAAa,CAAC,gBAAgB,CAAC,CAAA;QACpD,MAAM,gBAAgB,GAAG,gBAAgB,CAAC,YAAY,CAAC,CAAC,MAAM,CAC5D,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,QAAQ,KAAK,gBAAgB,CAChD,CAAA;QAED,IAAI,gBAAgB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAChC,cAAc,CAAC,GAAG,CAAC,YAAY,EAAE,gBAAgB,CAAC,CAAA;QACpD,CAAC;aAAM,CAAC;YACN,cAAc,CAAC,MAAM,CAAC,YAAY,CAAC,CAAA;QACrC,CAAC;IACH,CAAC;IAED,OAAO;QACL,GAAG;QACH,MAAM;QACN,iBAAiB;KAClB,CAAA;AACH,CAAC"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/queryClient.js.map b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/queryClient.js.map index 82e2b19139..15d3f12588 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/queryClient.js.map +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/queryClient.js.map @@ -1 +1 @@ -{"version":3,"file":"queryClient.js","sourceRoot":"","sources":["../../../client/operations/queryClient.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAqB,MAAM,uBAAuB,CAAA;AAEtE,MAAM,wBAAwB,GAAG,EAAE,CAAC;AAEpC,IAAI,iBAAoC,EACtC,6BAAsD,EACtD,wBAAiC,CAAC;AAEpC,+BAA+B;AAC/B,MAAM,CAAC,MAAM,sBAAsB,GAAyB,IAAI,OAAO,CACrE,CAAC,OAAO,EAAE,EAAE;IACV,6BAA6B,GAAG,OAAO,CAAC;AAC1C,CAAC,CACF,CAAC;AAEF,aAAa;AACb,MAAM,UAAU,oBAAoB,CAAC,MAAyB;IAC5D,IAAI,wBAAwB,EAAE;QAC5B,MAAM,IAAI,KAAK,CACb,6DAA6D,CAC9D,CAAC;KACH;IAED,iBAAiB,GAAG,MAAM,CAAC;AAC7B,CAAC;AAED,+BAA+B;AAC/B,MAAM,UAAU,qBAAqB;IACnC,MAAM,WAAW,GAAG,IAAI,WAAW,CACjC,iBAAiB,aAAjB,iBAAiB,cAAjB,iBAAiB,GAAI,wBAAwB,CAC9C,CAAC;IACF,wBAAwB,GAAG,IAAI,CAAC;IAChC,6BAA6B,CAAC,WAAW,CAAC,CAAC;AAC7C,CAAC"} \ No newline at end of file +{"version":3,"file":"queryClient.js","sourceRoot":"","sources":["../../../client/operations/queryClient.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAqB,MAAM,uBAAuB,CAAA;AAEtE,MAAM,wBAAwB,GAAG,EAAE,CAAC;AAEpC,IAAI,iBAAoC,EACtC,6BAAsD,EACtD,wBAAiC,CAAC;AAEpC,+BAA+B;AAC/B,MAAM,CAAC,MAAM,sBAAsB,GAAyB,IAAI,OAAO,CACrE,CAAC,OAAO,EAAE,EAAE;IACV,6BAA6B,GAAG,OAAO,CAAC;AAC1C,CAAC,CACF,CAAC;AAEF,aAAa;AACb,MAAM,UAAU,oBAAoB,CAAC,MAAyB;IAC5D,IAAI,wBAAwB,EAAE,CAAC;QAC7B,MAAM,IAAI,KAAK,CACb,6DAA6D,CAC9D,CAAC;IACJ,CAAC;IAED,iBAAiB,GAAG,MAAM,CAAC;AAC7B,CAAC;AAED,+BAA+B;AAC/B,MAAM,UAAU,qBAAqB;IACnC,MAAM,WAAW,GAAG,IAAI,WAAW,CACjC,iBAAiB,aAAjB,iBAAiB,cAAjB,iBAAiB,GAAI,wBAAwB,CAC9C,CAAC;IACF,wBAAwB,GAAG,IAAI,CAAC;IAChC,6BAA6B,CAAC,WAAW,CAAC,CAAC;AAC7C,CAAC"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/router/linkHelpers.js.map b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/router/linkHelpers.js.map index 064bcce597..c532d39f5e 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/router/linkHelpers.js.map +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/router/linkHelpers.js.map @@ -1 +1 @@ -{"version":3,"file":"linkHelpers.js","sourceRoot":"","sources":["../../../client/router/linkHelpers.ts"],"names":[],"mappings":"AAEA,cAAc;AACd,MAAM,UAAU,eAAe,CAC7B,IAAY,EACZ,MAAe,EACf,MAAe,EACf,IAAa;IAEb,MAAM,gBAAgB,GAAG,MAAM,CAAC,CAAC,CAAC,qBAAqB,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;IAC5E,MAAM,kBAAkB,GAAG,MAAM;QAC/B,CAAC,CAAC,IAAI,IAAI,eAAe,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,EAAE;QAC9C,CAAC,CAAC,EAAE,CAAA;IACN,MAAM,gBAAgB,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAA;IAC/C,OAAO,gBAAgB,GAAG,kBAAkB,GAAG,gBAAgB,CAAA;AACjE,CAAC;AAED,SAAS,qBAAqB,CAAC,IAAY,EAAE,MAAc;IACzD,SAAS,WAAW,CAAC,IAAY;QAC/B,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE;YACxB,MAAM,SAAS,GAAG,4BAA4B,CAAC,IAAI,CAAC,CAAC;YACrD,OAAO,MAAM,CAAC,SAAS,CAAC,CAAC;SAC1B;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,gBAAgB,GAAG,IAAI;SAC1B,KAAK,CAAC,GAAG,CAAC;SACV,GAAG,CAAC,WAAW,CAAC;SAChB,MAAM,CAAC,eAAe,CAAC;SACvB,IAAI,CAAC,GAAG,CAAC,CAAC;IAEb,OAAO,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,gBAAgB,EAAE,CAAC,CAAC,CAAC,gBAAgB,CAAC;AAC1E,CAAC;AAED,SAAS,eAAe,CAAC,IAAS;IAChC,OAAO,CAAC,CAAC,IAAI,CAAC;AAChB,CAAC;AAED,SAAS,4BAA4B,CAAC,WAAmB;IACvD,IAAI,WAAW,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE;QAC7B,OAAO,WAAW,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;KACjC;IACD,OAAO,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC9B,CAAC"} \ No newline at end of file +{"version":3,"file":"linkHelpers.js","sourceRoot":"","sources":["../../../client/router/linkHelpers.ts"],"names":[],"mappings":"AAEA,cAAc;AACd,MAAM,UAAU,eAAe,CAC7B,IAAY,EACZ,MAAe,EACf,MAAe,EACf,IAAa;IAEb,MAAM,gBAAgB,GAAG,MAAM,CAAC,CAAC,CAAC,qBAAqB,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;IAC5E,MAAM,kBAAkB,GAAG,MAAM;QAC/B,CAAC,CAAC,IAAI,IAAI,eAAe,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,EAAE;QAC9C,CAAC,CAAC,EAAE,CAAA;IACN,MAAM,gBAAgB,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAA;IAC/C,OAAO,gBAAgB,GAAG,kBAAkB,GAAG,gBAAgB,CAAA;AACjE,CAAC;AAED,SAAS,qBAAqB,CAAC,IAAY,EAAE,MAAc;IACzD,SAAS,WAAW,CAAC,IAAY;QAC/B,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YACzB,MAAM,SAAS,GAAG,4BAA4B,CAAC,IAAI,CAAC,CAAC;YACrD,OAAO,MAAM,CAAC,SAAS,CAAC,CAAC;QAC3B,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,gBAAgB,GAAG,IAAI;SAC1B,KAAK,CAAC,GAAG,CAAC;SACV,GAAG,CAAC,WAAW,CAAC;SAChB,MAAM,CAAC,eAAe,CAAC;SACvB,IAAI,CAAC,GAAG,CAAC,CAAC;IAEb,OAAO,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,gBAAgB,EAAE,CAAC,CAAC,CAAC,gBAAgB,CAAC;AAC1E,CAAC;AAED,SAAS,eAAe,CAAC,IAAS;IAChC,OAAO,CAAC,CAAC,IAAI,CAAC;AAChB,CAAC;AAED,SAAS,4BAA4B,CAAC,WAAmB;IACvD,IAAI,WAAW,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QAC9B,OAAO,WAAW,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAClC,CAAC;IACD,OAAO,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC9B,CAAC"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/test/vitest/helpers.jsx.map b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/test/vitest/helpers.jsx.map index b7ab2a906f..375c4629a2 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/test/vitest/helpers.jsx.map +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/test/vitest/helpers.jsx.map @@ -1 +1 @@ -{"version":3,"file":"helpers.jsx","sourceRoot":"","sources":["../../../../client/test/vitest/helpers.tsx"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"helpers.jsx","sourceRoot":"","sources":["../../../../client/test/vitest/helpers.tsx"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/core/storage.js.map b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/core/storage.js.map index b7cd5db441..73a6773d4f 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/core/storage.js.map +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/core/storage.js.map @@ -1 +1 @@ -{"version":3,"file":"storage.js","sourceRoot":"","sources":["../../core/storage.ts"],"names":[],"mappings":"AAQA,SAAS,2BAA2B,CAAC,MAAc;IACjD,SAAS,cAAc,CAAC,GAAW;QACjC,OAAO,GAAG,MAAM,IAAI,GAAG,EAAE,CAAA;IAC3B,CAAC;IAED,OAAO;QACL,cAAc;QACd,GAAG,CAAC,GAAG,EAAE,KAAK;YACZ,6BAA6B,EAAE,CAAA;YAC/B,YAAY,CAAC,OAAO,CAAC,cAAc,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAA;QAClE,CAAC;QACD,GAAG,CAAC,GAAG;YACL,6BAA6B,EAAE,CAAA;YAC/B,MAAM,KAAK,GAAG,YAAY,CAAC,OAAO,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAA;YACvD,IAAI;gBACF,OAAO,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;aAC7C;YAAC,OAAO,CAAM,EAAE;gBACf,OAAO,SAAS,CAAA;aACjB;QACH,CAAC;QACD,MAAM,CAAC,GAAG;YACR,6BAA6B,EAAE,CAAA;YAC/B,YAAY,CAAC,UAAU,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAA;QAC9C,CAAC;QACD,KAAK;YACH,6BAA6B,EAAE,CAAA;YAC/B,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE;gBACxC,IAAI,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE;oBAC1B,YAAY,CAAC,UAAU,CAAC,GAAG,CAAC,CAAA;iBAC7B;YACH,CAAC,CAAC,CAAA;QACJ,CAAC;KACF,CAAA;AACH,CAAC;AAED,MAAM,CAAC,MAAM,OAAO,GAAG,2BAA2B,CAAC,MAAM,CAAC,CAAA;AAE1D,SAAS,6BAA6B;IACpC,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE;QACxB,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAA;KACnD;AACH,CAAC"} \ No newline at end of file +{"version":3,"file":"storage.js","sourceRoot":"","sources":["../../core/storage.ts"],"names":[],"mappings":"AAQA,SAAS,2BAA2B,CAAC,MAAc;IACjD,SAAS,cAAc,CAAC,GAAW;QACjC,OAAO,GAAG,MAAM,IAAI,GAAG,EAAE,CAAA;IAC3B,CAAC;IAED,OAAO;QACL,cAAc;QACd,GAAG,CAAC,GAAG,EAAE,KAAK;YACZ,6BAA6B,EAAE,CAAA;YAC/B,YAAY,CAAC,OAAO,CAAC,cAAc,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAA;QAClE,CAAC;QACD,GAAG,CAAC,GAAG;YACL,6BAA6B,EAAE,CAAA;YAC/B,MAAM,KAAK,GAAG,YAAY,CAAC,OAAO,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAA;YACvD,IAAI,CAAC;gBACH,OAAO,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;YAC9C,CAAC;YAAC,OAAO,CAAM,EAAE,CAAC;gBAChB,OAAO,SAAS,CAAA;YAClB,CAAC;QACH,CAAC;QACD,MAAM,CAAC,GAAG;YACR,6BAA6B,EAAE,CAAA;YAC/B,YAAY,CAAC,UAAU,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAA;QAC9C,CAAC;QACD,KAAK;YACH,6BAA6B,EAAE,CAAA;YAC/B,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE;gBACxC,IAAI,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;oBAC3B,YAAY,CAAC,UAAU,CAAC,GAAG,CAAC,CAAA;gBAC9B,CAAC;YACH,CAAC,CAAC,CAAA;QACJ,CAAC;KACF,CAAA;AACH,CAAC;AAED,MAAM,CAAC,MAAM,OAAO,GAAG,2BAA2B,CAAC,MAAM,CAAC,CAAA;AAE1D,SAAS,6BAA6B;IACpC,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAA;IACpD,CAAC;AACH,CAAC"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/server/HttpError.js.map b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/server/HttpError.js.map index 34064e924c..3cc7095281 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/server/HttpError.js.map +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/server/HttpError.js.map @@ -1 +1 @@ -{"version":3,"file":"HttpError.js","sourceRoot":"","sources":["../../server/HttpError.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,SAAU,SAAQ,KAAK;IAIlC,YAAa,UAAkB,EAAE,OAAgB,EAAE,IAA8B,EAAE,GAAG,MAAiB;QACrG,KAAK,CAAC,OAAO,EAAE,GAAG,MAAM,CAAC,CAAA;QAEzB,IAAI,KAAK,CAAC,iBAAiB,EAAE;YAC3B,KAAK,CAAC,iBAAiB,CAAC,IAAI,EAAE,SAAS,CAAC,CAAA;SACzC;QAED,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,CAAA;QAEjC,IAAI,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC,IAAI,UAAU,IAAI,GAAG,IAAI,UAAU,GAAG,GAAG,CAAC,EAAE;YAC5E,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAA;SACrE;QACD,IAAI,CAAC,UAAU,GAAG,UAAU,CAAA;QAE5B,IAAI,IAAI,EAAE;YACR,IAAI,CAAC,IAAI,GAAG,IAAI,CAAA;SACjB;IACH,CAAC;CACF"} \ No newline at end of file +{"version":3,"file":"HttpError.js","sourceRoot":"","sources":["../../server/HttpError.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,SAAU,SAAQ,KAAK;IAIlC,YAAa,UAAkB,EAAE,OAAgB,EAAE,IAA8B,EAAE,GAAG,MAAiB;QACrG,KAAK,CAAC,OAAO,EAAE,GAAG,MAAM,CAAC,CAAA;QAEzB,IAAI,KAAK,CAAC,iBAAiB,EAAE,CAAC;YAC5B,KAAK,CAAC,iBAAiB,CAAC,IAAI,EAAE,SAAS,CAAC,CAAA;QAC1C,CAAC;QAED,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,CAAA;QAEjC,IAAI,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC,IAAI,UAAU,IAAI,GAAG,IAAI,UAAU,GAAG,GAAG,CAAC,EAAE,CAAC;YAC7E,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAA;QACtE,CAAC;QACD,IAAI,CAAC,UAAU,GAAG,UAAU,CAAA;QAE5B,IAAI,IAAI,EAAE,CAAC;YACT,IAAI,CAAC,IAAI,GAAG,IAAI,CAAA;QAClB,CAAC;IACH,CAAC;CACF"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/server/utils.js.map b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/server/utils.js.map index f3af561141..17121f586d 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/server/utils.js.map +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/server/utils.js.map @@ -1 +1 @@ -{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../server/utils.ts"],"names":[],"mappings":"AAWA;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAC7B,UAIQ,EACR,EAAE,CACJ,KAAK,EAAE,GAA2B,EAAE,GAAa,EAAE,IAAkB,EAAE,EAAE;IACvE,IAAI;QACF,MAAM,UAAU,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,CAAA;KACjC;IAAC,OAAO,KAAK,EAAE;QACd,IAAI,CAAC,KAAK,CAAC,CAAA;KACZ;AACH,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,EAAU,EAAoB,EAAE,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAA"} \ No newline at end of file +{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../server/utils.ts"],"names":[],"mappings":"AAWA;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAC7B,UAIQ,EACR,EAAE,CACJ,KAAK,EAAE,GAA2B,EAAE,GAAa,EAAE,IAAkB,EAAE,EAAE;IACvE,IAAI,CAAC;QACH,MAAM,UAAU,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,CAAA;IAClC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,CAAC,KAAK,CAAC,CAAA;IACb,CAAC;AACH,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,EAAU,EAAoB,EAAE,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAA"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/universal/validators.js.map b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/universal/validators.js.map index 313c98cef4..f020413e43 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/universal/validators.js.map +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/universal/validators.js.map @@ -1 +1 @@ -{"version":3,"file":"validators.js","sourceRoot":"","sources":["../../universal/validators.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,kBAAkB,CAAC,MAAc;IAC7C,IAAI;QACA,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC;QAC5B;;;;;;UAME;QACF,OAAO,GAAG,CAAC,QAAQ,KAAK,OAAO,IAAI,GAAG,CAAC,QAAQ,KAAK,QAAQ,CAAC;KAChE;IAAC,OAAO,CAAC,EAAE;QACR,OAAO,KAAK,CAAC;KAChB;AACL,CAAC;AAED,MAAM,UAAU,0BAA0B,CAAC,KAAyB,EAAE,IAAY;IAC9E,IAAI,KAAK,IAAI,CAAC,kBAAkB,CAAC,KAAK,CAAC,EAAE;QACrC,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,+BAA+B,CAAC,CAAC;KAC3D;AACL,CAAC"} \ No newline at end of file +{"version":3,"file":"validators.js","sourceRoot":"","sources":["../../universal/validators.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,kBAAkB,CAAC,MAAc;IAC7C,IAAI,CAAC;QACD,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC;QAC5B;;;;;;UAME;QACF,OAAO,GAAG,CAAC,QAAQ,KAAK,OAAO,IAAI,GAAG,CAAC,QAAQ,KAAK,QAAQ,CAAC;IACjE,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACT,OAAO,KAAK,CAAC;IACjB,CAAC;AACL,CAAC;AAED,MAAM,UAAU,0BAA0B,CAAC,KAAyB,EAAE,IAAY;IAC9E,IAAI,KAAK,IAAI,CAAC,kBAAkB,CAAC,KAAK,CAAC,EAAE,CAAC;QACtC,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,+BAA+B,CAAC,CAAC;IAC5D,CAAC;AACL,CAAC"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/package.json b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/package.json index 3f9c859316..e290f61ea9 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/package.json +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/package.json @@ -10,7 +10,6 @@ "axios": "^1.4.0", "express": "~4.18.1", "jsdom": "^21.1.1", - "jsonwebtoken": "^8.5.1", "lodash.merge": "^4.6.2", "mitt": "3.0.0", "msw": "^1.1.0", diff --git a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/.waspchecksums b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/.waspchecksums index c443b31e2a..49b42b1ff9 100644 --- a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/.waspchecksums +++ b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/.waspchecksums @@ -207,7 +207,7 @@ "file", "../out/sdk/wasp/package.json" ], - "c955fa158905668984f65806b587b8455abc60ef82807bfd7137a3e7dc839902" + "d0db918bf9df0766992ba13933d847853b330e3b601e5f367c3ad25eaecddc87" ], [ [ @@ -417,7 +417,7 @@ "file", "server/package.json" ], - "b6f49a347b56b9c7215e65f2d982ff99c6e444c40e649b802bb1af3ead772d15" + "c33727afcd03aa83fbd2c4b213a05cf7a2c53525e3b1daa72521d8c1312033a5" ], [ [ diff --git a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/installedNpmDepsLog.json b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/installedNpmDepsLog.json index 4b37fb6e15..7880e96505 100644 --- a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/installedNpmDepsLog.json +++ b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/installedNpmDepsLog.json @@ -1 +1 @@ -{"_waspSdkNpmDeps":{"dependencies":[{"name":"@prisma/client","version":"4.16.2"},{"name":"prisma","version":"4.16.2"},{"name":"@tanstack/react-query","version":"^4.29.0"},{"name":"axios","version":"^1.4.0"},{"name":"express","version":"~4.18.1"},{"name":"jsonwebtoken","version":"^8.5.1"},{"name":"mitt","version":"3.0.0"},{"name":"react","version":"^18.2.0"},{"name":"lodash.merge","version":"^4.6.2"},{"name":"react-router-dom","version":"^5.3.3"},{"name":"react-hook-form","version":"^7.45.4"},{"name":"superjson","version":"^1.12.2"},{"name":"@types/express-serve-static-core","version":"^4.17.13"},{"name":"@types/react-router-dom","version":"^5.3.3"},{"name":"uuid","version":"^9.0.0"},{"name":"vitest","version":"^1.2.1"},{"name":"@vitest/ui","version":"^1.2.1"},{"name":"jsdom","version":"^21.1.1"},{"name":"@testing-library/react","version":"^14.1.2"},{"name":"@testing-library/jest-dom","version":"^6.3.0"},{"name":"msw","version":"^1.1.0"}],"devDependencies":[{"name":"@tsconfig/node18","version":"latest"}]},"_userNpmDeps":{"userDependencies":[{"name":"react","version":"^18.2.0"},{"name":"wasp","version":"file:.wasp/out/sdk/wasp"}],"userDevDependencies":[{"name":"@types/react","version":"^18.0.37"},{"name":"prisma","version":"4.16.2"},{"name":"typescript","version":"^5.1.0"},{"name":"vite","version":"^4.3.9"}]},"_waspFrameworkNpmDeps":{"npmDepsForWebApp":{"dependencies":[{"name":"@tanstack/react-query","version":"^4.29.0"},{"name":"axios","version":"^1.4.0"},{"name":"mitt","version":"3.0.0"},{"name":"react-dom","version":"^18.2.0"},{"name":"react-hook-form","version":"^7.45.4"},{"name":"react-router-dom","version":"^5.3.3"},{"name":"superjson","version":"^1.12.2"}],"devDependencies":[{"name":"@tsconfig/vite-react","version":"^2.0.0"},{"name":"@types/react-dom","version":"^18.0.11"},{"name":"@types/react-router-dom","version":"^5.3.3"},{"name":"@vitejs/plugin-react","version":"^4.2.1"},{"name":"dotenv","version":"^16.0.3"}]},"npmDepsForServer":{"dependencies":[{"name":"cookie-parser","version":"~1.4.6"},{"name":"cors","version":"^2.8.5"},{"name":"dotenv","version":"16.0.2"},{"name":"express","version":"~4.18.1"},{"name":"helmet","version":"^6.0.0"},{"name":"jsonwebtoken","version":"^8.5.1"},{"name":"morgan","version":"~1.10.0"},{"name":"rate-limiter-flexible","version":"^2.4.1"},{"name":"superjson","version":"^1.12.2"}],"devDependencies":[{"name":"@tsconfig/node18","version":"latest"},{"name":"@types/cors","version":"^2.8.5"},{"name":"@types/express","version":"^4.17.13"},{"name":"@types/express-serve-static-core","version":"^4.17.13"},{"name":"@types/node","version":"^18.0.0"},{"name":"nodemon","version":"^2.0.19"},{"name":"rollup","version":"^4.9.6"},{"name":"rollup-plugin-esbuild","version":"^6.1.1"},{"name":"standard","version":"^17.0.0"}]}}} \ No newline at end of file +{"_waspSdkNpmDeps":{"dependencies":[{"name":"@prisma/client","version":"4.16.2"},{"name":"prisma","version":"4.16.2"},{"name":"@tanstack/react-query","version":"^4.29.0"},{"name":"axios","version":"^1.4.0"},{"name":"express","version":"~4.18.1"},{"name":"mitt","version":"3.0.0"},{"name":"react","version":"^18.2.0"},{"name":"lodash.merge","version":"^4.6.2"},{"name":"react-router-dom","version":"^5.3.3"},{"name":"react-hook-form","version":"^7.45.4"},{"name":"superjson","version":"^1.12.2"},{"name":"@types/express-serve-static-core","version":"^4.17.13"},{"name":"@types/react-router-dom","version":"^5.3.3"},{"name":"uuid","version":"^9.0.0"},{"name":"vitest","version":"^1.2.1"},{"name":"@vitest/ui","version":"^1.2.1"},{"name":"jsdom","version":"^21.1.1"},{"name":"@testing-library/react","version":"^14.1.2"},{"name":"@testing-library/jest-dom","version":"^6.3.0"},{"name":"msw","version":"^1.1.0"}],"devDependencies":[{"name":"@tsconfig/node18","version":"latest"}]},"_userNpmDeps":{"userDependencies":[{"name":"react","version":"^18.2.0"},{"name":"wasp","version":"file:.wasp/out/sdk/wasp"}],"userDevDependencies":[{"name":"@types/react","version":"^18.0.37"},{"name":"prisma","version":"4.16.2"},{"name":"typescript","version":"^5.1.0"},{"name":"vite","version":"^4.3.9"}]},"_waspFrameworkNpmDeps":{"npmDepsForWebApp":{"dependencies":[{"name":"@tanstack/react-query","version":"^4.29.0"},{"name":"axios","version":"^1.4.0"},{"name":"mitt","version":"3.0.0"},{"name":"react-dom","version":"^18.2.0"},{"name":"react-hook-form","version":"^7.45.4"},{"name":"react-router-dom","version":"^5.3.3"},{"name":"superjson","version":"^1.12.2"}],"devDependencies":[{"name":"@tsconfig/vite-react","version":"^2.0.0"},{"name":"@types/react-dom","version":"^18.0.11"},{"name":"@types/react-router-dom","version":"^5.3.3"},{"name":"@vitejs/plugin-react","version":"^4.2.1"},{"name":"dotenv","version":"^16.0.3"}]},"npmDepsForServer":{"dependencies":[{"name":"cookie-parser","version":"~1.4.6"},{"name":"cors","version":"^2.8.5"},{"name":"dotenv","version":"16.0.2"},{"name":"express","version":"~4.18.1"},{"name":"helmet","version":"^6.0.0"},{"name":"morgan","version":"~1.10.0"},{"name":"rate-limiter-flexible","version":"^2.4.1"},{"name":"superjson","version":"^1.12.2"}],"devDependencies":[{"name":"@tsconfig/node18","version":"latest"},{"name":"@types/cors","version":"^2.8.5"},{"name":"@types/express","version":"^4.17.13"},{"name":"@types/express-serve-static-core","version":"^4.17.13"},{"name":"@types/node","version":"^18.0.0"},{"name":"nodemon","version":"^2.0.19"},{"name":"rollup","version":"^4.9.6"},{"name":"rollup-plugin-esbuild","version":"^6.1.1"},{"name":"standard","version":"^17.0.0"}]}}} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/api/index.js.map b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/api/index.js.map index b4ae2eba65..fab323a0b2 100644 --- a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/api/index.js.map +++ b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/api/index.js.map @@ -1 +1 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["../../api/index.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"index.js","sourceRoot":"","sources":["../../api/index.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/actions/core.js.map b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/actions/core.js.map index 5834336f1d..b13c7d6712 100644 --- a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/actions/core.js.map +++ b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/actions/core.js.map @@ -1 +1 @@ -{"version":3,"file":"core.js","sourceRoot":"","sources":["../../../../client/operations/actions/core.js"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAA;AACxE,OAAO,EACL,wBAAwB,EACxB,kBAAkB,GACnB,MAAM,0BAA0B,CAAA;AAEjC,cAAc;AACd,MAAM,UAAU,YAAY,CAAC,mBAAmB,EAAE,YAAY;IAC5D,MAAM,WAAW,GAAG,kBAAkB,CAAC,mBAAmB,CAAC,CAAA;IAE3D,KAAK,UAAU,cAAc,CAAC,IAAI,EAAE,mCAAmC;QACrE,wBAAwB,CAAC,mCAAmC,CAAC,CAAA;QAC7D,IAAI;YACF,yEAAyE;YACzE,wEAAwE;YACxE,kCAAkC;YAClC,OAAO,MAAM,aAAa,CAAC,WAAW,EAAE,IAAI,CAAC,CAAA;SAC9C;gBAAS;YACR,MAAM,kBAAkB,CAAC,YAAY,EAAE,mCAAmC,CAAC,CAAA;SAC5E;IACH,CAAC;IAED,0EAA0E;IAC1E,yEAAyE;IACzE,6EAA6E;IAC7E,yEAAyE;IACzE,gBAAgB;IAChB,EAAE;IACF,0EAA0E;IAC1E,8EAA8E;IAC9E,wCAAwC;IACxC,MAAM,MAAM,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC,cAAc,CAAC,IAAI,EAAE,EAAE,CAAC,CAAA;IACjD,MAAM,CAAC,QAAQ,GAAG,cAAc,CAAA;IAEhC,OAAO,MAAM,CAAA;AACf,CAAC"} \ No newline at end of file +{"version":3,"file":"core.js","sourceRoot":"","sources":["../../../../client/operations/actions/core.js"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAA;AACxE,OAAO,EACL,wBAAwB,EACxB,kBAAkB,GACnB,MAAM,0BAA0B,CAAA;AAEjC,cAAc;AACd,MAAM,UAAU,YAAY,CAAC,mBAAmB,EAAE,YAAY;IAC5D,MAAM,WAAW,GAAG,kBAAkB,CAAC,mBAAmB,CAAC,CAAA;IAE3D,KAAK,UAAU,cAAc,CAAC,IAAI,EAAE,mCAAmC;QACrE,wBAAwB,CAAC,mCAAmC,CAAC,CAAA;QAC7D,IAAI,CAAC;YACH,yEAAyE;YACzE,wEAAwE;YACxE,kCAAkC;YAClC,OAAO,MAAM,aAAa,CAAC,WAAW,EAAE,IAAI,CAAC,CAAA;QAC/C,CAAC;gBAAS,CAAC;YACT,MAAM,kBAAkB,CAAC,YAAY,EAAE,mCAAmC,CAAC,CAAA;QAC7E,CAAC;IACH,CAAC;IAED,0EAA0E;IAC1E,yEAAyE;IACzE,6EAA6E;IAC7E,yEAAyE;IACzE,gBAAgB;IAChB,EAAE;IACF,0EAA0E;IAC1E,8EAA8E;IAC9E,wCAAwC;IACxC,MAAM,MAAM,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC,cAAc,CAAC,IAAI,EAAE,EAAE,CAAC,CAAA;IACjD,MAAM,CAAC,QAAQ,GAAG,cAAc,CAAA;IAEhC,OAAO,MAAM,CAAA;AACf,CAAC"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/core.js.map b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/core.js.map index 68ea114aa9..20d72dc15e 100644 --- a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/core.js.map +++ b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/core.js.map @@ -1 +1 @@ -{"version":3,"file":"core.js","sourceRoot":"","sources":["../../../client/operations/core.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"core.js","sourceRoot":"","sources":["../../../client/operations/core.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/internal/index.js.map b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/internal/index.js.map index a4097ef8cb..a7cf9e445b 100644 --- a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/internal/index.js.map +++ b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/internal/index.js.map @@ -1 +1 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../client/operations/internal/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AACxC,OAAO,EACL,SAAS,IAAI,kBAAkB,EAC/B,WAAW,IAAI,oBAAoB,GACnC,MAAM,WAAW,CAAA;AAKnB,cAAc;AACd,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,cAA4D,EAAE,IAAS;IACzG,IAAI;QACF,MAAM,aAAa,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAA;QAC9C,MAAM,QAAQ,GAAG,MAAM,GAAG,CAAC,IAAI,CAAC,cAAc,CAAC,IAAI,EAAE,aAAa,CAAC,CAAA;QACnE,OAAO,oBAAoB,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAA;KAC3C;IAAC,OAAO,KAAK,EAAE;QACd,cAAc,CAAC,KAAK,CAAC,CAAA;KACtB;AACH,CAAC;AAED,cAAc;AACd,MAAM,UAAU,kBAAkB,CAAC,sBAA8B;IAC/D,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,sBAAsB,EAAE,EAAE,CAAA;AACxE,CAAC"} \ No newline at end of file +{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../client/operations/internal/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AACxC,OAAO,EACL,SAAS,IAAI,kBAAkB,EAC/B,WAAW,IAAI,oBAAoB,GACnC,MAAM,WAAW,CAAA;AAKnB,cAAc;AACd,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,cAA4D,EAAE,IAAS;IACzG,IAAI,CAAC;QACH,MAAM,aAAa,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAA;QAC9C,MAAM,QAAQ,GAAG,MAAM,GAAG,CAAC,IAAI,CAAC,cAAc,CAAC,IAAI,EAAE,aAAa,CAAC,CAAA;QACnE,OAAO,oBAAoB,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAA;IAC5C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,cAAc,CAAC,KAAK,CAAC,CAAA;IACvB,CAAC;AACH,CAAC;AAED,cAAc;AACd,MAAM,UAAU,kBAAkB,CAAC,sBAA8B;IAC/D,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,sBAAsB,EAAE,EAAE,CAAA;AACxE,CAAC"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/internal/resources.js.map b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/internal/resources.js.map index c91fecd3c7..61f8241c3e 100644 --- a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/internal/resources.js.map +++ b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/internal/resources.js.map @@ -1 +1 @@ -{"version":3,"file":"resources.js","sourceRoot":"","sources":["../../../../client/operations/internal/resources.js"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAA;AAC1D,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAA;AAC3D,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAA;AAEpD,kDAAkD;AAClD,mDAAmD;AACnD,iBAAiB;AACjB,MAAM,wBAAwB,GAAG,IAAI,GAAG,EAAE,CAAA;AAE1C,MAAM,cAAc,GAAG,qBAAqB,CAAC,YAAY,CAAC,CAAA;AAE1D,cAAc;AACd;;;;;GAKG;AACH,MAAM,UAAU,uBAAuB,CAAC,aAAa,EAAE,SAAS;IAC9D,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE;QAChC,IAAI,SAAS,GAAG,wBAAwB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;QACtD,IAAI,CAAC,SAAS,EAAE;YACd,SAAS,GAAG,IAAI,GAAG,EAAE,CAAA;YACrB,wBAAwB,CAAC,GAAG,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAA;SAClD;QACD,SAAS,CAAC,GAAG,CAAC,aAAa,CAAC,CAAA;KAC7B;AACH,CAAC;AAED,MAAM,UAAU,wBAAwB,CAAC,sBAAsB;IAC7D,sBAAsB,CAAC,OAAO,CAC5B,CAAC,EAAE,QAAQ,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC,cAAc,CAAC,GAAG,CAAC,QAAQ,EAAE,WAAW,CAAC,CACzE,CAAA;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,SAAS,EAAE,sBAAsB;IACxE,sBAAsB,CAAC,OAAO,CAAC,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,cAAc,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAA;IACjF,MAAM,sBAAsB,CAAC,SAAS,CAAC,CAAA;AACzC,CAAC;AAED,MAAM,UAAU,0BAA0B,CAAC,QAAQ;IACjD,OAAO,cAAc,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAA;AACnD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,0BAA0B;IAC9C,MAAM,WAAW,GAAG,MAAM,sBAAsB,CAAA;IAChD,wEAAwE;IACxE,8EAA8E;IAC9E,eAAe;IACf,iFAAiF;IACjF,6EAA6E;IAC7E,wFAAwF;IACxF,kFAAkF;IAClF,WAAW,CAAC,YAAY,EAAE,CAAA;IAC1B,6EAA6E;IAC7E,2DAA2D;IAC3D,WAAW,CAAC,aAAa,EAAE,CAAA;AAC7B,CAAC;AAED;;;GAGG;AACH,KAAK,UAAU,sBAAsB,CAAC,SAAS;IAC7C,MAAM,WAAW,GAAG,MAAM,sBAAsB,CAAA;IAEhD,MAAM,0BAA0B,GAAG,wBAAwB,CAAC,SAAS,CAAC,CAAA;IACtE,0BAA0B,CAAC,OAAO,CAChC,aAAa,CAAC,EAAE,CAAC,WAAW,CAAC,iBAAiB,CAAC,aAAa,CAAC,CAC9D,CAAA;AACH,CAAC;AAED;;;GAGG;AACH,SAAS,uBAAuB,CAAC,QAAQ;IACvC,OAAO,KAAK,CAAC,IAAI,CAAC,wBAAwB,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAA;AACjE,CAAC;AAED,SAAS,wBAAwB,CAAC,SAAS;IACzC,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,uBAAuB,CAAC,CAAC,CAAC,CAAA;AACxE,CAAC"} \ No newline at end of file +{"version":3,"file":"resources.js","sourceRoot":"","sources":["../../../../client/operations/internal/resources.js"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAA;AAC1D,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAA;AAC3D,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAA;AAEpD,kDAAkD;AAClD,mDAAmD;AACnD,iBAAiB;AACjB,MAAM,wBAAwB,GAAG,IAAI,GAAG,EAAE,CAAA;AAE1C,MAAM,cAAc,GAAG,qBAAqB,CAAC,YAAY,CAAC,CAAA;AAE1D,cAAc;AACd;;;;;GAKG;AACH,MAAM,UAAU,uBAAuB,CAAC,aAAa,EAAE,SAAS;IAC9D,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;QACjC,IAAI,SAAS,GAAG,wBAAwB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;QACtD,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,SAAS,GAAG,IAAI,GAAG,EAAE,CAAA;YACrB,wBAAwB,CAAC,GAAG,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAA;QACnD,CAAC;QACD,SAAS,CAAC,GAAG,CAAC,aAAa,CAAC,CAAA;IAC9B,CAAC;AACH,CAAC;AAED,MAAM,UAAU,wBAAwB,CAAC,sBAAsB;IAC7D,sBAAsB,CAAC,OAAO,CAC5B,CAAC,EAAE,QAAQ,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC,cAAc,CAAC,GAAG,CAAC,QAAQ,EAAE,WAAW,CAAC,CACzE,CAAA;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,SAAS,EAAE,sBAAsB;IACxE,sBAAsB,CAAC,OAAO,CAAC,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,cAAc,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAA;IACjF,MAAM,sBAAsB,CAAC,SAAS,CAAC,CAAA;AACzC,CAAC;AAED,MAAM,UAAU,0BAA0B,CAAC,QAAQ;IACjD,OAAO,cAAc,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAA;AACnD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,0BAA0B;IAC9C,MAAM,WAAW,GAAG,MAAM,sBAAsB,CAAA;IAChD,wEAAwE;IACxE,8EAA8E;IAC9E,eAAe;IACf,iFAAiF;IACjF,6EAA6E;IAC7E,wFAAwF;IACxF,kFAAkF;IAClF,WAAW,CAAC,YAAY,EAAE,CAAA;IAC1B,6EAA6E;IAC7E,2DAA2D;IAC3D,WAAW,CAAC,aAAa,EAAE,CAAA;AAC7B,CAAC;AAED;;;GAGG;AACH,KAAK,UAAU,sBAAsB,CAAC,SAAS;IAC7C,MAAM,WAAW,GAAG,MAAM,sBAAsB,CAAA;IAEhD,MAAM,0BAA0B,GAAG,wBAAwB,CAAC,SAAS,CAAC,CAAA;IACtE,0BAA0B,CAAC,OAAO,CAChC,aAAa,CAAC,EAAE,CAAC,WAAW,CAAC,iBAAiB,CAAC,aAAa,CAAC,CAC9D,CAAA;AACH,CAAC;AAED;;;GAGG;AACH,SAAS,uBAAuB,CAAC,QAAQ;IACvC,OAAO,KAAK,CAAC,IAAI,CAAC,wBAAwB,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAA;AACjE,CAAC;AAED,SAAS,wBAAwB,CAAC,SAAS;IACzC,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,uBAAuB,CAAC,CAAC,CAAC,CAAA;AACxE,CAAC"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/internal/updateHandlersMap.js.map b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/internal/updateHandlersMap.js.map index 7940fcd972..950c377452 100644 --- a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/internal/updateHandlersMap.js.map +++ b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/internal/updateHandlersMap.js.map @@ -1 +1 @@ -{"version":3,"file":"updateHandlersMap.js","sourceRoot":"","sources":["../../../../client/operations/internal/updateHandlersMap.js"],"names":[],"mappings":"AAAA,MAAM,UAAU,qBAAqB,CAAC,aAAa;IACjD,MAAM,cAAc,GAAG,IAAI,GAAG,EAAE,CAAA;IAEhC,SAAS,gBAAgB,CAAC,YAAY;QACpC,OAAO,cAAc,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC;IAChD,CAAC;IAED,SAAS,GAAG,CAAC,QAAQ,EAAE,WAAW;QAChC,MAAM,YAAY,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAA;QAC5C,MAAM,QAAQ,GAAG,gBAAgB,CAAC,YAAY,CAAC,CAAC;QAChD,cAAc,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC,GAAG,QAAQ,EAAE,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC,CAAC,CAAA;IAC5E,CAAC;IAED,SAAS,iBAAiB,CAAC,QAAQ;QACjC,MAAM,YAAY,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAA;QAC5C,OAAO,gBAAgB,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC,WAAW,CAAC,CAAA;IAC7E,CAAC;IAED,SAAS,MAAM,CAAC,gBAAgB;QAC9B,MAAM,YAAY,GAAG,aAAa,CAAC,gBAAgB,CAAC,CAAA;QACpD,MAAM,gBAAgB,GAAG,gBAAgB,CAAC,YAAY,CAAC,CAAC,MAAM,CAC5D,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,QAAQ,KAAK,gBAAgB,CAChD,CAAA;QAED,IAAI,gBAAgB,CAAC,MAAM,GAAG,CAAC,EAAE;YAC/B,cAAc,CAAC,GAAG,CAAC,YAAY,EAAE,gBAAgB,CAAC,CAAA;SACnD;aAAM;YACL,cAAc,CAAC,MAAM,CAAC,YAAY,CAAC,CAAA;SACpC;IACH,CAAC;IAED,OAAO;QACL,GAAG;QACH,MAAM;QACN,iBAAiB;KAClB,CAAA;AACH,CAAC"} \ No newline at end of file +{"version":3,"file":"updateHandlersMap.js","sourceRoot":"","sources":["../../../../client/operations/internal/updateHandlersMap.js"],"names":[],"mappings":"AAAA,MAAM,UAAU,qBAAqB,CAAC,aAAa;IACjD,MAAM,cAAc,GAAG,IAAI,GAAG,EAAE,CAAA;IAEhC,SAAS,gBAAgB,CAAC,YAAY;QACpC,OAAO,cAAc,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC;IAChD,CAAC;IAED,SAAS,GAAG,CAAC,QAAQ,EAAE,WAAW;QAChC,MAAM,YAAY,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAA;QAC5C,MAAM,QAAQ,GAAG,gBAAgB,CAAC,YAAY,CAAC,CAAC;QAChD,cAAc,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC,GAAG,QAAQ,EAAE,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC,CAAC,CAAA;IAC5E,CAAC;IAED,SAAS,iBAAiB,CAAC,QAAQ;QACjC,MAAM,YAAY,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAA;QAC5C,OAAO,gBAAgB,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC,WAAW,CAAC,CAAA;IAC7E,CAAC;IAED,SAAS,MAAM,CAAC,gBAAgB;QAC9B,MAAM,YAAY,GAAG,aAAa,CAAC,gBAAgB,CAAC,CAAA;QACpD,MAAM,gBAAgB,GAAG,gBAAgB,CAAC,YAAY,CAAC,CAAC,MAAM,CAC5D,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,QAAQ,KAAK,gBAAgB,CAChD,CAAA;QAED,IAAI,gBAAgB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAChC,cAAc,CAAC,GAAG,CAAC,YAAY,EAAE,gBAAgB,CAAC,CAAA;QACpD,CAAC;aAAM,CAAC;YACN,cAAc,CAAC,MAAM,CAAC,YAAY,CAAC,CAAA;QACrC,CAAC;IACH,CAAC;IAED,OAAO;QACL,GAAG;QACH,MAAM;QACN,iBAAiB;KAClB,CAAA;AACH,CAAC"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/queryClient.js.map b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/queryClient.js.map index 82e2b19139..15d3f12588 100644 --- a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/queryClient.js.map +++ b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/queryClient.js.map @@ -1 +1 @@ -{"version":3,"file":"queryClient.js","sourceRoot":"","sources":["../../../client/operations/queryClient.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAqB,MAAM,uBAAuB,CAAA;AAEtE,MAAM,wBAAwB,GAAG,EAAE,CAAC;AAEpC,IAAI,iBAAoC,EACtC,6BAAsD,EACtD,wBAAiC,CAAC;AAEpC,+BAA+B;AAC/B,MAAM,CAAC,MAAM,sBAAsB,GAAyB,IAAI,OAAO,CACrE,CAAC,OAAO,EAAE,EAAE;IACV,6BAA6B,GAAG,OAAO,CAAC;AAC1C,CAAC,CACF,CAAC;AAEF,aAAa;AACb,MAAM,UAAU,oBAAoB,CAAC,MAAyB;IAC5D,IAAI,wBAAwB,EAAE;QAC5B,MAAM,IAAI,KAAK,CACb,6DAA6D,CAC9D,CAAC;KACH;IAED,iBAAiB,GAAG,MAAM,CAAC;AAC7B,CAAC;AAED,+BAA+B;AAC/B,MAAM,UAAU,qBAAqB;IACnC,MAAM,WAAW,GAAG,IAAI,WAAW,CACjC,iBAAiB,aAAjB,iBAAiB,cAAjB,iBAAiB,GAAI,wBAAwB,CAC9C,CAAC;IACF,wBAAwB,GAAG,IAAI,CAAC;IAChC,6BAA6B,CAAC,WAAW,CAAC,CAAC;AAC7C,CAAC"} \ No newline at end of file +{"version":3,"file":"queryClient.js","sourceRoot":"","sources":["../../../client/operations/queryClient.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAqB,MAAM,uBAAuB,CAAA;AAEtE,MAAM,wBAAwB,GAAG,EAAE,CAAC;AAEpC,IAAI,iBAAoC,EACtC,6BAAsD,EACtD,wBAAiC,CAAC;AAEpC,+BAA+B;AAC/B,MAAM,CAAC,MAAM,sBAAsB,GAAyB,IAAI,OAAO,CACrE,CAAC,OAAO,EAAE,EAAE;IACV,6BAA6B,GAAG,OAAO,CAAC;AAC1C,CAAC,CACF,CAAC;AAEF,aAAa;AACb,MAAM,UAAU,oBAAoB,CAAC,MAAyB;IAC5D,IAAI,wBAAwB,EAAE,CAAC;QAC7B,MAAM,IAAI,KAAK,CACb,6DAA6D,CAC9D,CAAC;IACJ,CAAC;IAED,iBAAiB,GAAG,MAAM,CAAC;AAC7B,CAAC;AAED,+BAA+B;AAC/B,MAAM,UAAU,qBAAqB;IACnC,MAAM,WAAW,GAAG,IAAI,WAAW,CACjC,iBAAiB,aAAjB,iBAAiB,cAAjB,iBAAiB,GAAI,wBAAwB,CAC9C,CAAC;IACF,wBAAwB,GAAG,IAAI,CAAC;IAChC,6BAA6B,CAAC,WAAW,CAAC,CAAC;AAC7C,CAAC"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/router/linkHelpers.js.map b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/router/linkHelpers.js.map index 064bcce597..c532d39f5e 100644 --- a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/router/linkHelpers.js.map +++ b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/router/linkHelpers.js.map @@ -1 +1 @@ -{"version":3,"file":"linkHelpers.js","sourceRoot":"","sources":["../../../client/router/linkHelpers.ts"],"names":[],"mappings":"AAEA,cAAc;AACd,MAAM,UAAU,eAAe,CAC7B,IAAY,EACZ,MAAe,EACf,MAAe,EACf,IAAa;IAEb,MAAM,gBAAgB,GAAG,MAAM,CAAC,CAAC,CAAC,qBAAqB,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;IAC5E,MAAM,kBAAkB,GAAG,MAAM;QAC/B,CAAC,CAAC,IAAI,IAAI,eAAe,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,EAAE;QAC9C,CAAC,CAAC,EAAE,CAAA;IACN,MAAM,gBAAgB,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAA;IAC/C,OAAO,gBAAgB,GAAG,kBAAkB,GAAG,gBAAgB,CAAA;AACjE,CAAC;AAED,SAAS,qBAAqB,CAAC,IAAY,EAAE,MAAc;IACzD,SAAS,WAAW,CAAC,IAAY;QAC/B,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE;YACxB,MAAM,SAAS,GAAG,4BAA4B,CAAC,IAAI,CAAC,CAAC;YACrD,OAAO,MAAM,CAAC,SAAS,CAAC,CAAC;SAC1B;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,gBAAgB,GAAG,IAAI;SAC1B,KAAK,CAAC,GAAG,CAAC;SACV,GAAG,CAAC,WAAW,CAAC;SAChB,MAAM,CAAC,eAAe,CAAC;SACvB,IAAI,CAAC,GAAG,CAAC,CAAC;IAEb,OAAO,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,gBAAgB,EAAE,CAAC,CAAC,CAAC,gBAAgB,CAAC;AAC1E,CAAC;AAED,SAAS,eAAe,CAAC,IAAS;IAChC,OAAO,CAAC,CAAC,IAAI,CAAC;AAChB,CAAC;AAED,SAAS,4BAA4B,CAAC,WAAmB;IACvD,IAAI,WAAW,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE;QAC7B,OAAO,WAAW,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;KACjC;IACD,OAAO,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC9B,CAAC"} \ No newline at end of file +{"version":3,"file":"linkHelpers.js","sourceRoot":"","sources":["../../../client/router/linkHelpers.ts"],"names":[],"mappings":"AAEA,cAAc;AACd,MAAM,UAAU,eAAe,CAC7B,IAAY,EACZ,MAAe,EACf,MAAe,EACf,IAAa;IAEb,MAAM,gBAAgB,GAAG,MAAM,CAAC,CAAC,CAAC,qBAAqB,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;IAC5E,MAAM,kBAAkB,GAAG,MAAM;QAC/B,CAAC,CAAC,IAAI,IAAI,eAAe,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,EAAE;QAC9C,CAAC,CAAC,EAAE,CAAA;IACN,MAAM,gBAAgB,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAA;IAC/C,OAAO,gBAAgB,GAAG,kBAAkB,GAAG,gBAAgB,CAAA;AACjE,CAAC;AAED,SAAS,qBAAqB,CAAC,IAAY,EAAE,MAAc;IACzD,SAAS,WAAW,CAAC,IAAY;QAC/B,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YACzB,MAAM,SAAS,GAAG,4BAA4B,CAAC,IAAI,CAAC,CAAC;YACrD,OAAO,MAAM,CAAC,SAAS,CAAC,CAAC;QAC3B,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,gBAAgB,GAAG,IAAI;SAC1B,KAAK,CAAC,GAAG,CAAC;SACV,GAAG,CAAC,WAAW,CAAC;SAChB,MAAM,CAAC,eAAe,CAAC;SACvB,IAAI,CAAC,GAAG,CAAC,CAAC;IAEb,OAAO,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,gBAAgB,EAAE,CAAC,CAAC,CAAC,gBAAgB,CAAC;AAC1E,CAAC;AAED,SAAS,eAAe,CAAC,IAAS;IAChC,OAAO,CAAC,CAAC,IAAI,CAAC;AAChB,CAAC;AAED,SAAS,4BAA4B,CAAC,WAAmB;IACvD,IAAI,WAAW,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QAC9B,OAAO,WAAW,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAClC,CAAC;IACD,OAAO,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC9B,CAAC"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/test/vitest/helpers.jsx.map b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/test/vitest/helpers.jsx.map index b7ab2a906f..375c4629a2 100644 --- a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/test/vitest/helpers.jsx.map +++ b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/test/vitest/helpers.jsx.map @@ -1 +1 @@ -{"version":3,"file":"helpers.jsx","sourceRoot":"","sources":["../../../../client/test/vitest/helpers.tsx"],"names":[],"mappings":";;;;;;;;;;;AACA,OAAO,EAAE,SAAS,IAAI,kBAAkB,EAAE,MAAM,WAAW,CAAA;AAC3D,OAAO,EAAE,IAAI,EAA2C,MAAM,KAAK,CAAA;AACnE,OAAO,EAAE,WAAW,EAAoB,MAAM,UAAU,CAAA;AACxD,OAAO,EAAE,aAAa,IAAI,MAAM,EAAE,MAAM,kBAAkB,CAAA;AAC1D,OAAO,EAAE,MAAM,EAAgB,OAAO,EAAE,MAAM,wBAAwB,CAAA;AACtE,OAAO,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAA;AACxE,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAA;AAEvD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACpC,OAAO,EAAE,UAAU,EAAS,MAAM,aAAa,CAAA;AAW/C,aAAa;AACb,+CAA+C;AAC/C,sIAAsI;AACtI,MAAM,UAAU,eAAe,CAAC,EAAgB;IAC9C,MAAM,MAAM,GAAG,IAAI,WAAW,EAAE,CAAA;IAChC,MAAM,KAA0B,MAAM,CACpC,CAAC,mBAAmB,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAClC;MAAA,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,MAAM,CACtB;IAAA,EAAE,mBAAmB,CAAC,CACvB,EAJK,EAAE,QAAQ,OAIf,EAJoB,MAAM,cAArB,YAAuB,CAI5B,CAAA;IACD,uCACK,MAAM,KACT,QAAQ,EAAE,CAAC,UAAwB,EAAE,EAAE,CACrC,QAAQ,CACN,CAAC,mBAAmB,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAClC;UAAA,CAAC,MAAM,CAAC,CAAC,UAAU,CAAC,EAAE,MAAM,CAC9B;QAAA,EAAE,mBAAmB,CAAC,CACvB,IACJ;AACH,CAAC;AAED,aAAa;AACb,MAAM,UAAU,UAAU;IAKxB,MAAM,MAAM,GAAgB,WAAW,EAAE,CAAA;IAEzC,SAAS,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAA;IAChC,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,CAAC,aAAa,EAAE,CAAA;QACtB,OAAO,EAAE,CAAA;IACX,CAAC,CAAC,CAAA;IACF,QAAQ,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAA;IAE9B,MAAM,SAAS,GAAc,CAAC,KAAK,EAAE,QAAQ,EAAE,EAAE;QAC/C,MAAM,KAAK,GAAI,KAAqC,CAAC,KAAK,CAAA;QAC1D,SAAS,CAAC,MAAM,EAAE,KAAK,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,CAC1C,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,kBAAkB,CAAC,QAAQ,CAAC,CAAC,CAAC,CAC5C,CAAA;IACH,CAAC,CAAA;IAED,MAAM,OAAO,GAAY,CAAC,KAAK,EAAE,QAAQ,EAAE,EAAE;QAC3C,SAAS,CAAC,MAAM,EAAE,KAAK,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAA;IACvE,CAAC,CAAA;IAED,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,CAAA;AACvC,CAAC;AAED,SAAS,SAAS,CAChB,MAAmB,EACnB,KAAY,EACZ,eAAwD;IAExD,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE;QACrD,MAAM,IAAI,KAAK,CACb,yCACE,KAAK,CAAC,MACR,mCAAmC,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAC3E,CAAA;KACF;IAED,MAAM,GAAG,GAAG,GAAG,MAAM,CAAC,MAAM,GAAG,KAAK,CAAC,IAAI,EAAE,CAAA;IAE3C,MAAM,QAAQ,GAAyD;QACrE,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,eAAe,CAAC;QAChD,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,eAAe,CAAC;QAClD,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,eAAe,CAAC;QAChD,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,eAAe,CAAC;KACvD,CAAA;IAED,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAA;AACpC,CAAC"} \ No newline at end of file +{"version":3,"file":"helpers.jsx","sourceRoot":"","sources":["../../../../client/test/vitest/helpers.tsx"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/core/storage.js.map b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/core/storage.js.map index b7cd5db441..73a6773d4f 100644 --- a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/core/storage.js.map +++ b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/core/storage.js.map @@ -1 +1 @@ -{"version":3,"file":"storage.js","sourceRoot":"","sources":["../../core/storage.ts"],"names":[],"mappings":"AAQA,SAAS,2BAA2B,CAAC,MAAc;IACjD,SAAS,cAAc,CAAC,GAAW;QACjC,OAAO,GAAG,MAAM,IAAI,GAAG,EAAE,CAAA;IAC3B,CAAC;IAED,OAAO;QACL,cAAc;QACd,GAAG,CAAC,GAAG,EAAE,KAAK;YACZ,6BAA6B,EAAE,CAAA;YAC/B,YAAY,CAAC,OAAO,CAAC,cAAc,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAA;QAClE,CAAC;QACD,GAAG,CAAC,GAAG;YACL,6BAA6B,EAAE,CAAA;YAC/B,MAAM,KAAK,GAAG,YAAY,CAAC,OAAO,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAA;YACvD,IAAI;gBACF,OAAO,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;aAC7C;YAAC,OAAO,CAAM,EAAE;gBACf,OAAO,SAAS,CAAA;aACjB;QACH,CAAC;QACD,MAAM,CAAC,GAAG;YACR,6BAA6B,EAAE,CAAA;YAC/B,YAAY,CAAC,UAAU,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAA;QAC9C,CAAC;QACD,KAAK;YACH,6BAA6B,EAAE,CAAA;YAC/B,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE;gBACxC,IAAI,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE;oBAC1B,YAAY,CAAC,UAAU,CAAC,GAAG,CAAC,CAAA;iBAC7B;YACH,CAAC,CAAC,CAAA;QACJ,CAAC;KACF,CAAA;AACH,CAAC;AAED,MAAM,CAAC,MAAM,OAAO,GAAG,2BAA2B,CAAC,MAAM,CAAC,CAAA;AAE1D,SAAS,6BAA6B;IACpC,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE;QACxB,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAA;KACnD;AACH,CAAC"} \ No newline at end of file +{"version":3,"file":"storage.js","sourceRoot":"","sources":["../../core/storage.ts"],"names":[],"mappings":"AAQA,SAAS,2BAA2B,CAAC,MAAc;IACjD,SAAS,cAAc,CAAC,GAAW;QACjC,OAAO,GAAG,MAAM,IAAI,GAAG,EAAE,CAAA;IAC3B,CAAC;IAED,OAAO;QACL,cAAc;QACd,GAAG,CAAC,GAAG,EAAE,KAAK;YACZ,6BAA6B,EAAE,CAAA;YAC/B,YAAY,CAAC,OAAO,CAAC,cAAc,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAA;QAClE,CAAC;QACD,GAAG,CAAC,GAAG;YACL,6BAA6B,EAAE,CAAA;YAC/B,MAAM,KAAK,GAAG,YAAY,CAAC,OAAO,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAA;YACvD,IAAI,CAAC;gBACH,OAAO,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;YAC9C,CAAC;YAAC,OAAO,CAAM,EAAE,CAAC;gBAChB,OAAO,SAAS,CAAA;YAClB,CAAC;QACH,CAAC;QACD,MAAM,CAAC,GAAG;YACR,6BAA6B,EAAE,CAAA;YAC/B,YAAY,CAAC,UAAU,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAA;QAC9C,CAAC;QACD,KAAK;YACH,6BAA6B,EAAE,CAAA;YAC/B,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE;gBACxC,IAAI,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;oBAC3B,YAAY,CAAC,UAAU,CAAC,GAAG,CAAC,CAAA;gBAC9B,CAAC;YACH,CAAC,CAAC,CAAA;QACJ,CAAC;KACF,CAAA;AACH,CAAC;AAED,MAAM,CAAC,MAAM,OAAO,GAAG,2BAA2B,CAAC,MAAM,CAAC,CAAA;AAE1D,SAAS,6BAA6B;IACpC,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAA;IACpD,CAAC;AACH,CAAC"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/server/HttpError.js.map b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/server/HttpError.js.map index 34064e924c..3cc7095281 100644 --- a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/server/HttpError.js.map +++ b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/server/HttpError.js.map @@ -1 +1 @@ -{"version":3,"file":"HttpError.js","sourceRoot":"","sources":["../../server/HttpError.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,SAAU,SAAQ,KAAK;IAIlC,YAAa,UAAkB,EAAE,OAAgB,EAAE,IAA8B,EAAE,GAAG,MAAiB;QACrG,KAAK,CAAC,OAAO,EAAE,GAAG,MAAM,CAAC,CAAA;QAEzB,IAAI,KAAK,CAAC,iBAAiB,EAAE;YAC3B,KAAK,CAAC,iBAAiB,CAAC,IAAI,EAAE,SAAS,CAAC,CAAA;SACzC;QAED,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,CAAA;QAEjC,IAAI,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC,IAAI,UAAU,IAAI,GAAG,IAAI,UAAU,GAAG,GAAG,CAAC,EAAE;YAC5E,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAA;SACrE;QACD,IAAI,CAAC,UAAU,GAAG,UAAU,CAAA;QAE5B,IAAI,IAAI,EAAE;YACR,IAAI,CAAC,IAAI,GAAG,IAAI,CAAA;SACjB;IACH,CAAC;CACF"} \ No newline at end of file +{"version":3,"file":"HttpError.js","sourceRoot":"","sources":["../../server/HttpError.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,SAAU,SAAQ,KAAK;IAIlC,YAAa,UAAkB,EAAE,OAAgB,EAAE,IAA8B,EAAE,GAAG,MAAiB;QACrG,KAAK,CAAC,OAAO,EAAE,GAAG,MAAM,CAAC,CAAA;QAEzB,IAAI,KAAK,CAAC,iBAAiB,EAAE,CAAC;YAC5B,KAAK,CAAC,iBAAiB,CAAC,IAAI,EAAE,SAAS,CAAC,CAAA;QAC1C,CAAC;QAED,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,CAAA;QAEjC,IAAI,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC,IAAI,UAAU,IAAI,GAAG,IAAI,UAAU,GAAG,GAAG,CAAC,EAAE,CAAC;YAC7E,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAA;QACtE,CAAC;QACD,IAAI,CAAC,UAAU,GAAG,UAAU,CAAA;QAE5B,IAAI,IAAI,EAAE,CAAC;YACT,IAAI,CAAC,IAAI,GAAG,IAAI,CAAA;QAClB,CAAC;IACH,CAAC;CACF"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/server/utils.js.map b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/server/utils.js.map index f3af561141..17121f586d 100644 --- a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/server/utils.js.map +++ b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/server/utils.js.map @@ -1 +1 @@ -{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../server/utils.ts"],"names":[],"mappings":"AAWA;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAC7B,UAIQ,EACR,EAAE,CACJ,KAAK,EAAE,GAA2B,EAAE,GAAa,EAAE,IAAkB,EAAE,EAAE;IACvE,IAAI;QACF,MAAM,UAAU,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,CAAA;KACjC;IAAC,OAAO,KAAK,EAAE;QACd,IAAI,CAAC,KAAK,CAAC,CAAA;KACZ;AACH,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,EAAU,EAAoB,EAAE,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAA"} \ No newline at end of file +{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../server/utils.ts"],"names":[],"mappings":"AAWA;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAC7B,UAIQ,EACR,EAAE,CACJ,KAAK,EAAE,GAA2B,EAAE,GAAa,EAAE,IAAkB,EAAE,EAAE;IACvE,IAAI,CAAC;QACH,MAAM,UAAU,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,CAAA;IAClC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,CAAC,KAAK,CAAC,CAAA;IACb,CAAC;AACH,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,EAAU,EAAoB,EAAE,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAA"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/universal/validators.js.map b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/universal/validators.js.map index 313c98cef4..f020413e43 100644 --- a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/universal/validators.js.map +++ b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/universal/validators.js.map @@ -1 +1 @@ -{"version":3,"file":"validators.js","sourceRoot":"","sources":["../../universal/validators.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,kBAAkB,CAAC,MAAc;IAC7C,IAAI;QACA,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC;QAC5B;;;;;;UAME;QACF,OAAO,GAAG,CAAC,QAAQ,KAAK,OAAO,IAAI,GAAG,CAAC,QAAQ,KAAK,QAAQ,CAAC;KAChE;IAAC,OAAO,CAAC,EAAE;QACR,OAAO,KAAK,CAAC;KAChB;AACL,CAAC;AAED,MAAM,UAAU,0BAA0B,CAAC,KAAyB,EAAE,IAAY;IAC9E,IAAI,KAAK,IAAI,CAAC,kBAAkB,CAAC,KAAK,CAAC,EAAE;QACrC,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,+BAA+B,CAAC,CAAC;KAC3D;AACL,CAAC"} \ No newline at end of file +{"version":3,"file":"validators.js","sourceRoot":"","sources":["../../universal/validators.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,kBAAkB,CAAC,MAAc;IAC7C,IAAI,CAAC;QACD,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC;QAC5B;;;;;;UAME;QACF,OAAO,GAAG,CAAC,QAAQ,KAAK,OAAO,IAAI,GAAG,CAAC,QAAQ,KAAK,QAAQ,CAAC;IACjE,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACT,OAAO,KAAK,CAAC;IACjB,CAAC;AACL,CAAC;AAED,MAAM,UAAU,0BAA0B,CAAC,KAAyB,EAAE,IAAY;IAC9E,IAAI,KAAK,IAAI,CAAC,kBAAkB,CAAC,KAAK,CAAC,EAAE,CAAC;QACtC,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,+BAA+B,CAAC,CAAC;IAC5D,CAAC;AACL,CAAC"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/package.json b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/package.json index 3f9c859316..e290f61ea9 100644 --- a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/package.json +++ b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/package.json @@ -10,7 +10,6 @@ "axios": "^1.4.0", "express": "~4.18.1", "jsdom": "^21.1.1", - "jsonwebtoken": "^8.5.1", "lodash.merge": "^4.6.2", "mitt": "3.0.0", "msw": "^1.1.0", diff --git a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/server/package.json b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/server/package.json index 009928aa42..af6031d33e 100644 --- a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/server/package.json +++ b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/server/package.json @@ -6,7 +6,6 @@ "dotenv": "16.0.2", "express": "~4.18.1", "helmet": "^6.0.0", - "jsonwebtoken": "^8.5.1", "morgan": "~1.10.0", "rate-limiter-flexible": "^2.4.1", "superjson": "^1.12.2" diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/.waspchecksums b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/.waspchecksums index 9dbff2671e..882a3b1180 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/.waspchecksums +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/.waspchecksums @@ -102,7 +102,7 @@ "file", "../out/sdk/wasp/auth/jwt.ts" ], - "adced7d9cc058bdf5832ad1bafdf5150c0c7dd2e6454148ddaa345f7a48d2738" + "4ebc9aa5b9986270a6b49ce2a9fd56dc45a9beed0e3eb3ddaba45a384f17b28d" ], [ [ @@ -165,7 +165,7 @@ "file", "../out/sdk/wasp/auth/utils.ts" ], - "d09d1b32eee179eefe96f34b52d520065a50a3617195de07b75c59e6c1705f69" + "014159c084202532b1da84bcd945f77960fe1f7acd383afc905e8fbea35b9d71" ], [ [ @@ -480,7 +480,7 @@ "file", "../out/sdk/wasp/package.json" ], - "c72ca2c19c1645e2af88e41cd6968de95acb8d736cc48dd3c1a98203164ea6b3" + "970b830be8de1b4a896fbd5ea192b8382a049325d6f4127bd092c7b794f5955e" ], [ [ @@ -809,7 +809,7 @@ "file", "server/package.json" ], - "1d4701392e6f6b5031b685ac98f038395f0fa36bd8c9039f8434c7f3790d7203" + "c5a9447608033195282d5d9625fe84525d58e986d11b03f56f3d8570d8381347" ], [ [ diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/installedNpmDepsLog.json b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/installedNpmDepsLog.json index f4cdcf97ac..8442e36fd1 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/installedNpmDepsLog.json +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/installedNpmDepsLog.json @@ -1 +1 @@ -{"_waspSdkNpmDeps":{"dependencies":[{"name":"@prisma/client","version":"4.16.2"},{"name":"prisma","version":"4.16.2"},{"name":"@tanstack/react-query","version":"^4.29.0"},{"name":"axios","version":"^1.4.0"},{"name":"express","version":"~4.18.1"},{"name":"jsonwebtoken","version":"^8.5.1"},{"name":"mitt","version":"3.0.0"},{"name":"react","version":"^18.2.0"},{"name":"lodash.merge","version":"^4.6.2"},{"name":"react-router-dom","version":"^5.3.3"},{"name":"react-hook-form","version":"^7.45.4"},{"name":"superjson","version":"^1.12.2"},{"name":"@types/express-serve-static-core","version":"^4.17.13"},{"name":"@types/react-router-dom","version":"^5.3.3"},{"name":"@stitches/react","version":"^1.2.8"},{"name":"lucia","version":"^3.0.1"},{"name":"@lucia-auth/adapter-prisma","version":"^4.0.0"},{"name":"oslo","version":"^1.1.2"},{"name":"@sendgrid/mail","version":"^7.7.0"},{"name":"uuid","version":"^9.0.0"},{"name":"vitest","version":"^1.2.1"},{"name":"@vitest/ui","version":"^1.2.1"},{"name":"jsdom","version":"^21.1.1"},{"name":"@testing-library/react","version":"^14.1.2"},{"name":"@testing-library/jest-dom","version":"^6.3.0"},{"name":"msw","version":"^1.1.0"},{"name":"pg-boss","version":"^8.4.2"}],"devDependencies":[{"name":"@tsconfig/node18","version":"latest"}]},"_userNpmDeps":{"userDependencies":[{"name":"react","version":"^18.2.0"},{"name":"wasp","version":"file:.wasp/out/sdk/wasp"}],"userDevDependencies":[{"name":"@types/react","version":"^18.0.37"},{"name":"prisma","version":"4.16.2"},{"name":"typescript","version":"^5.1.0"},{"name":"vite","version":"^4.3.9"}]},"_waspFrameworkNpmDeps":{"npmDepsForWebApp":{"dependencies":[{"name":"@tanstack/react-query","version":"^4.29.0"},{"name":"axios","version":"^1.4.0"},{"name":"mitt","version":"3.0.0"},{"name":"react-dom","version":"^18.2.0"},{"name":"react-hook-form","version":"^7.45.4"},{"name":"react-router-dom","version":"^5.3.3"},{"name":"superjson","version":"^1.12.2"}],"devDependencies":[{"name":"@tsconfig/vite-react","version":"^2.0.0"},{"name":"@types/react-dom","version":"^18.0.11"},{"name":"@types/react-router-dom","version":"^5.3.3"},{"name":"@vitejs/plugin-react","version":"^4.2.1"},{"name":"dotenv","version":"^16.0.3"}]},"npmDepsForServer":{"dependencies":[{"name":"cookie-parser","version":"~1.4.6"},{"name":"cors","version":"^2.8.5"},{"name":"dotenv","version":"16.0.2"},{"name":"express","version":"~4.18.1"},{"name":"helmet","version":"^6.0.0"},{"name":"jsonwebtoken","version":"^8.5.1"},{"name":"morgan","version":"~1.10.0"},{"name":"passport","version":"0.6.0"},{"name":"passport-google-oauth20","version":"2.0.0"},{"name":"rate-limiter-flexible","version":"^2.4.1"},{"name":"superjson","version":"^1.12.2"}],"devDependencies":[{"name":"@tsconfig/node18","version":"latest"},{"name":"@types/cors","version":"^2.8.5"},{"name":"@types/express","version":"^4.17.13"},{"name":"@types/express-serve-static-core","version":"^4.17.13"},{"name":"@types/node","version":"^18.0.0"},{"name":"nodemon","version":"^2.0.19"},{"name":"rollup","version":"^4.9.6"},{"name":"rollup-plugin-esbuild","version":"^6.1.1"},{"name":"standard","version":"^17.0.0"}]}}} \ No newline at end of file +{"_waspSdkNpmDeps":{"dependencies":[{"name":"@prisma/client","version":"4.16.2"},{"name":"prisma","version":"4.16.2"},{"name":"@tanstack/react-query","version":"^4.29.0"},{"name":"axios","version":"^1.4.0"},{"name":"express","version":"~4.18.1"},{"name":"mitt","version":"3.0.0"},{"name":"react","version":"^18.2.0"},{"name":"lodash.merge","version":"^4.6.2"},{"name":"react-router-dom","version":"^5.3.3"},{"name":"react-hook-form","version":"^7.45.4"},{"name":"superjson","version":"^1.12.2"},{"name":"@types/express-serve-static-core","version":"^4.17.13"},{"name":"@types/react-router-dom","version":"^5.3.3"},{"name":"@stitches/react","version":"^1.2.8"},{"name":"lucia","version":"^3.0.1"},{"name":"@lucia-auth/adapter-prisma","version":"^4.0.0"},{"name":"oslo","version":"^1.1.2"},{"name":"@sendgrid/mail","version":"^7.7.0"},{"name":"uuid","version":"^9.0.0"},{"name":"vitest","version":"^1.2.1"},{"name":"@vitest/ui","version":"^1.2.1"},{"name":"jsdom","version":"^21.1.1"},{"name":"@testing-library/react","version":"^14.1.2"},{"name":"@testing-library/jest-dom","version":"^6.3.0"},{"name":"msw","version":"^1.1.0"},{"name":"pg-boss","version":"^8.4.2"}],"devDependencies":[{"name":"@tsconfig/node18","version":"latest"}]},"_userNpmDeps":{"userDependencies":[{"name":"react","version":"^18.2.0"},{"name":"wasp","version":"file:.wasp/out/sdk/wasp"}],"userDevDependencies":[{"name":"@types/react","version":"^18.0.37"},{"name":"prisma","version":"4.16.2"},{"name":"typescript","version":"^5.1.0"},{"name":"vite","version":"^4.3.9"}]},"_waspFrameworkNpmDeps":{"npmDepsForWebApp":{"dependencies":[{"name":"@tanstack/react-query","version":"^4.29.0"},{"name":"axios","version":"^1.4.0"},{"name":"mitt","version":"3.0.0"},{"name":"react-dom","version":"^18.2.0"},{"name":"react-hook-form","version":"^7.45.4"},{"name":"react-router-dom","version":"^5.3.3"},{"name":"superjson","version":"^1.12.2"}],"devDependencies":[{"name":"@tsconfig/vite-react","version":"^2.0.0"},{"name":"@types/react-dom","version":"^18.0.11"},{"name":"@types/react-router-dom","version":"^5.3.3"},{"name":"@vitejs/plugin-react","version":"^4.2.1"},{"name":"dotenv","version":"^16.0.3"}]},"npmDepsForServer":{"dependencies":[{"name":"cookie-parser","version":"~1.4.6"},{"name":"cors","version":"^2.8.5"},{"name":"dotenv","version":"16.0.2"},{"name":"express","version":"~4.18.1"},{"name":"helmet","version":"^6.0.0"},{"name":"morgan","version":"~1.10.0"},{"name":"passport","version":"0.6.0"},{"name":"passport-google-oauth20","version":"2.0.0"},{"name":"rate-limiter-flexible","version":"^2.4.1"},{"name":"superjson","version":"^1.12.2"}],"devDependencies":[{"name":"@tsconfig/node18","version":"latest"},{"name":"@types/cors","version":"^2.8.5"},{"name":"@types/express","version":"^4.17.13"},{"name":"@types/express-serve-static-core","version":"^4.17.13"},{"name":"@types/node","version":"^18.0.0"},{"name":"nodemon","version":"^2.0.19"},{"name":"rollup","version":"^4.9.6"},{"name":"rollup-plugin-esbuild","version":"^6.1.1"},{"name":"standard","version":"^17.0.0"}]}}} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/auth/jwt.ts b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/auth/jwt.ts index 8ed702e4c0..ef3e77fa26 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/auth/jwt.ts +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/auth/jwt.ts @@ -1,14 +1,22 @@ -import jwt from 'jsonwebtoken' -import util from 'util' - +import * as jwt from 'oslo/jwt' import { config } from 'wasp/server' -const jwtSign = util.promisify(jwt.sign) -const jwtVerify = util.promisify(jwt.verify) +const JWT_SECRET = new TextEncoder().encode(config.auth.jwtSecret) +const JWT_ALGORITHM = 'HS256' -const JWT_SECRET = config.auth.jwtSecret +// PRIVATE API +export function createJWT( + data: Parameters[2], + options: Parameters[3], +): Promise { + return jwt.createJWT(JWT_ALGORITHM, JWT_SECRET, data, options) +} // PRIVATE API -export const signData = (data, options) => jwtSign(data, JWT_SECRET, options) +export async function validateJWT(token: string): Promise { + const { payload } = await jwt.validateJWT(JWT_ALGORITHM, JWT_SECRET, token) + return payload as Payload +} + // PRIVATE API -export const verify = (token) => jwtVerify(token, JWT_SECRET) +export { TimeSpan } from 'oslo' diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/auth/utils.ts b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/auth/utils.ts index 6187bf87fa..da601d5b09 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/auth/utils.ts +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/auth/utils.ts @@ -1,5 +1,4 @@ import { hashPassword } from './password.js' -import { verify } from './jwt.js' import { prisma, HttpError } from 'wasp/server' import { sleep } from 'wasp/server/utils' import { @@ -173,11 +172,6 @@ export async function deleteUserByAuthId(authId: string): Promise<{ count: numbe } } }) } -// PRIVATE API -export async function verifyToken(token: string): Promise { - return verify(token); -} - // PRIVATE API // If an user exists, we don't want to leak information // about it. Pretending that we're doing some work diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/api/index.js.map b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/api/index.js.map index b4ae2eba65..fab323a0b2 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/api/index.js.map +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/api/index.js.map @@ -1 +1 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["../../api/index.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"index.js","sourceRoot":"","sources":["../../api/index.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/auth/forms/internal/common/LoginSignupForm.jsx.map b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/auth/forms/internal/common/LoginSignupForm.jsx.map index 8ff9ee0569..c92ad8b4e7 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/auth/forms/internal/common/LoginSignupForm.jsx.map +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/auth/forms/internal/common/LoginSignupForm.jsx.map @@ -1 +1 @@ -{"version":3,"file":"LoginSignupForm.jsx","sourceRoot":"","sources":["../../../../../auth/forms/internal/common/LoginSignupForm.tsx"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"LoginSignupForm.jsx","sourceRoot":"","sources":["../../../../../auth/forms/internal/common/LoginSignupForm.tsx"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/auth/jwt.d.ts b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/auth/jwt.d.ts index 0982a1dbd2..2ee2973264 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/auth/jwt.d.ts +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/auth/jwt.d.ts @@ -1,2 +1,4 @@ -export declare const signData: (data: any, options: any) => any; -export declare const verify: (token: any) => any; +import * as jwt from 'oslo/jwt'; +export declare function createJWT(data: Parameters[2], options: Parameters[3]): Promise; +export declare function validateJWT(token: string): Promise; +export { TimeSpan } from 'oslo'; diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/auth/jwt.js b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/auth/jwt.js index f4d5ae7158..b49d5acdc3 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/auth/jwt.js +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/auth/jwt.js @@ -1,11 +1,16 @@ -import jwt from 'jsonwebtoken'; -import util from 'util'; +import * as jwt from 'oslo/jwt'; import { config } from 'wasp/server'; -const jwtSign = util.promisify(jwt.sign); -const jwtVerify = util.promisify(jwt.verify); -const JWT_SECRET = config.auth.jwtSecret; +const JWT_SECRET = new TextEncoder().encode(config.auth.jwtSecret); +const JWT_ALGORITHM = 'HS256'; // PRIVATE API -export const signData = (data, options) => jwtSign(data, JWT_SECRET, options); +export function createJWT(data, options) { + return jwt.createJWT(JWT_ALGORITHM, JWT_SECRET, data, options); +} // PRIVATE API -export const verify = (token) => jwtVerify(token, JWT_SECRET); +export async function validateJWT(token) { + const { payload } = await jwt.validateJWT(JWT_ALGORITHM, JWT_SECRET, token); + return payload; +} +// PRIVATE API +export { TimeSpan } from 'oslo'; //# sourceMappingURL=jwt.js.map \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/auth/jwt.js.map b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/auth/jwt.js.map index 50f922bf32..091d7277e3 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/auth/jwt.js.map +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/auth/jwt.js.map @@ -1 +1 @@ -{"version":3,"file":"jwt.js","sourceRoot":"","sources":["../../auth/jwt.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,cAAc,CAAA;AAC9B,OAAO,IAAI,MAAM,MAAM,CAAA;AAEvB,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAEpC,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;AACxC,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;AAE5C,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,SAAS,CAAA;AAExC,cAAc;AACd,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,UAAU,EAAE,OAAO,CAAC,CAAA;AAC7E,cAAc;AACd,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,KAAK,EAAE,EAAE,CAAC,SAAS,CAAC,KAAK,EAAE,UAAU,CAAC,CAAA"} \ No newline at end of file +{"version":3,"file":"jwt.js","sourceRoot":"","sources":["../../auth/jwt.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,GAAG,MAAM,UAAU,CAAA;AAC/B,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAEpC,MAAM,UAAU,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;AAClE,MAAM,aAAa,GAAG,OAAO,CAAA;AAE7B,cAAc;AACd,MAAM,UAAU,SAAS,CACvB,IAAyC,EACzC,OAA4C;IAE5C,OAAO,GAAG,CAAC,SAAS,CAAC,aAAa,EAAE,UAAU,EAAE,IAAI,EAAE,OAAO,CAAC,CAAA;AAChE,CAAC;AAED,cAAc;AACd,MAAM,CAAC,KAAK,UAAU,WAAW,CAAU,KAAa;IACtD,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,GAAG,CAAC,WAAW,CAAC,aAAa,EAAE,UAAU,EAAE,KAAK,CAAC,CAAA;IAC3E,OAAO,OAAkB,CAAA;AAC3B,CAAC;AAED,cAAc;AACd,OAAO,EAAE,QAAQ,EAAE,MAAM,MAAM,CAAA"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/auth/logout.js.map b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/auth/logout.js.map index 9a273d47e5..a105ee30c9 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/auth/logout.js.map +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/auth/logout.js.map @@ -1 +1 @@ -{"version":3,"file":"logout.js","sourceRoot":"","sources":["../../auth/logout.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAA;AAC1D,OAAO,EAAE,0BAA0B,EAAE,MAAM,4CAA4C,CAAA;AAEvF,aAAa;AACb,MAAM,CAAC,OAAO,CAAC,KAAK,UAAU,MAAM;IAClC,IAAI;QACF,MAAM,GAAG,CAAC,IAAI,CAAC,cAAc,CAAC,CAAA;KAC/B;YAAS;QACR,gFAAgF;QAChF,gFAAgF;QAChF,qBAAqB;QACrB,mBAAmB,EAAE,CAAA;QAErB,gFAAgF;QAChF,6DAA6D;QAC7D,MAAM,0BAA0B,EAAE,CAAA;KACnC;AACH,CAAC"} \ No newline at end of file +{"version":3,"file":"logout.js","sourceRoot":"","sources":["../../auth/logout.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAA;AAC1D,OAAO,EAAE,0BAA0B,EAAE,MAAM,4CAA4C,CAAA;AAEvF,aAAa;AACb,MAAM,CAAC,OAAO,CAAC,KAAK,UAAU,MAAM;IAClC,IAAI,CAAC;QACH,MAAM,GAAG,CAAC,IAAI,CAAC,cAAc,CAAC,CAAA;IAChC,CAAC;YAAS,CAAC;QACT,gFAAgF;QAChF,gFAAgF;QAChF,qBAAqB;QACrB,mBAAmB,EAAE,CAAA;QAErB,gFAAgF;QAChF,6DAA6D;QAC7D,MAAM,0BAA0B,EAAE,CAAA;IACpC,CAAC;AACH,CAAC"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/auth/password.js.map b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/auth/password.js.map index 0467f840d3..6ec595f17e 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/auth/password.js.map +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/auth/password.js.map @@ -1 +1 @@ -{"version":3,"file":"password.js","sourceRoot":"","sources":["../../auth/password.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AAExC,MAAM,QAAQ,GAAG,IAAI,QAAQ,EAAE,CAAA;AAE/B,cAAc;AACd,MAAM,CAAC,MAAM,YAAY,GAAG,KAAK,EAAE,QAAgB,EAAmB,EAAE;IACtE,OAAO,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;AAChC,CAAC,CAAA;AAED,cAAc;AACd,MAAM,CAAC,MAAM,cAAc,GAAG,KAAK,EAAE,cAAsB,EAAE,QAAgB,EAAiB,EAAE;IAC9F,MAAM,eAAe,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC,cAAc,EAAE,QAAQ,CAAC,CAAA;IACvE,IAAI,CAAC,eAAe,EAAE;QACpB,MAAM,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAA;KACrC;AACH,CAAC,CAAA"} \ No newline at end of file +{"version":3,"file":"password.js","sourceRoot":"","sources":["../../auth/password.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AAExC,MAAM,QAAQ,GAAG,IAAI,QAAQ,EAAE,CAAA;AAE/B,cAAc;AACd,MAAM,CAAC,MAAM,YAAY,GAAG,KAAK,EAAE,QAAgB,EAAmB,EAAE;IACtE,OAAO,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;AAChC,CAAC,CAAA;AAED,cAAc;AACd,MAAM,CAAC,MAAM,cAAc,GAAG,KAAK,EAAE,cAAsB,EAAE,QAAgB,EAAiB,EAAE;IAC9F,MAAM,eAAe,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC,cAAc,EAAE,QAAQ,CAAC,CAAA;IACvE,IAAI,CAAC,eAAe,EAAE,CAAC;QACrB,MAAM,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAA;IACtC,CAAC;AACH,CAAC,CAAA"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/auth/session.js.map b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/auth/session.js.map index 62a2542c41..5308f3b729 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/auth/session.js.map +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/auth/session.js.map @@ -1 +1 @@ -{"version":3,"file":"session.js","sourceRoot":"","sources":["../../auth/session.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAElC,OAAO,EACL,4BAA4B,EAC5B,kCAAkC,GACnC,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,cAAc;AACd,yDAAyD;AACzD,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,MAAc;IAChD,OAAO,IAAI,CAAC,aAAa,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;AACxC,CAAC;AAED,cAAc;AACd,MAAM,CAAC,KAAK,UAAU,gCAAgC,CAAC,GAAmB;IAIxE,MAAM,mBAAmB,GAAG,GAAG,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;IAEzD,IAAI,OAAO,mBAAmB,KAAK,QAAQ,EAAE;QAC3C,OAAO;YACL,IAAI,EAAE,IAAI;YACV,OAAO,EAAE,IAAI;SACd,CAAC;KACH;IAED,MAAM,SAAS,GAAG,IAAI,CAAC,eAAe,CAAC,mBAAmB,CAAC,CAAC;IAC5D,IAAI,CAAC,SAAS,EAAE;QACd,OAAO;YACL,IAAI,EAAE,IAAI;YACV,OAAO,EAAE,IAAI;SACd,CAAC;KACH;IAED,OAAO,8BAA8B,CAAC,SAAS,CAAC,CAAC;AACnD,CAAC;AAED,cAAc;AACd,MAAM,CAAC,KAAK,UAAU,8BAA8B,CAAC,SAAiB;IAIpE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,MAAM,IAAI,CAAC,eAAe,CAAC,SAAS,CAAC,CAAC;IAE5E,IAAI,CAAC,OAAO,IAAI,CAAC,UAAU,EAAE;QAC3B,OAAO;YACL,IAAI,EAAE,IAAI;YACV,OAAO,EAAE,IAAI;SACd,CAAC;KACH;IAED,OAAO;QACL,OAAO;QACP,IAAI,EAAE,MAAM,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC;KACvC,CAAA;AACH,CAAC;AAED,KAAK,UAAU,OAAO,CAAC,MAAkB;IACvC,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,IAAI;SAC3B,UAAU,CAAC;QACV,KAAK,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE;QACrB,OAAO,EAAE;YACP,IAAI,EAAE;gBACJ,OAAO,EAAE;oBACP,UAAU,EAAE,IAAI;iBACjB;aACF;SACF;KACF,CAAC,CAAA;IAEJ,IAAI,CAAC,IAAI,EAAE;QACT,4BAA4B,EAAE,CAAA;KAC/B;IAED,4EAA4E;IAC5E,sEAAsE;IACtE,0DAA0D;IAC1D,+CAA+C;IAC/C,MAAM,sBAAsB,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE;QACnE,MAAM,wBAAwB,GAAG,kCAAkC,CACjE,QAAQ,CAAC,YAAY,EACrB;YACE,yBAAyB,EAAE,IAAI;SAChC,CACF,CAAA;QACD,uCACK,QAAQ,KACX,YAAY,EAAE,wBAAwB,IACvC;IACH,CAAC,CAAC,CAAA;IACF,uCACK,IAAI,KACP,IAAI,kCACC,IAAI,CAAC,IAAI,KACZ,UAAU,EAAE,sBAAsB,OAErC;AACH,CAAC;AAED,cAAc;AACd,MAAM,UAAU,iBAAiB,CAAC,SAAiB;IACjD,OAAO,IAAI,CAAC,iBAAiB,CAAC,SAAS,CAAC,CAAC;AAC3C,CAAC"} \ No newline at end of file +{"version":3,"file":"session.js","sourceRoot":"","sources":["../../auth/session.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAElC,OAAO,EACL,4BAA4B,EAC5B,kCAAkC,GACnC,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,cAAc;AACd,yDAAyD;AACzD,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,MAAc;IAChD,OAAO,IAAI,CAAC,aAAa,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;AACxC,CAAC;AAED,cAAc;AACd,MAAM,CAAC,KAAK,UAAU,gCAAgC,CAAC,GAAmB;IAIxE,MAAM,mBAAmB,GAAG,GAAG,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;IAEzD,IAAI,OAAO,mBAAmB,KAAK,QAAQ,EAAE,CAAC;QAC5C,OAAO;YACL,IAAI,EAAE,IAAI;YACV,OAAO,EAAE,IAAI;SACd,CAAC;IACJ,CAAC;IAED,MAAM,SAAS,GAAG,IAAI,CAAC,eAAe,CAAC,mBAAmB,CAAC,CAAC;IAC5D,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,OAAO;YACL,IAAI,EAAE,IAAI;YACV,OAAO,EAAE,IAAI;SACd,CAAC;IACJ,CAAC;IAED,OAAO,8BAA8B,CAAC,SAAS,CAAC,CAAC;AACnD,CAAC;AAED,cAAc;AACd,MAAM,CAAC,KAAK,UAAU,8BAA8B,CAAC,SAAiB;IAIpE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,MAAM,IAAI,CAAC,eAAe,CAAC,SAAS,CAAC,CAAC;IAE5E,IAAI,CAAC,OAAO,IAAI,CAAC,UAAU,EAAE,CAAC;QAC5B,OAAO;YACL,IAAI,EAAE,IAAI;YACV,OAAO,EAAE,IAAI;SACd,CAAC;IACJ,CAAC;IAED,OAAO;QACL,OAAO;QACP,IAAI,EAAE,MAAM,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC;KACvC,CAAA;AACH,CAAC;AAED,KAAK,UAAU,OAAO,CAAC,MAAkB;IACvC,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,IAAI;SAC3B,UAAU,CAAC;QACV,KAAK,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE;QACrB,OAAO,EAAE;YACP,IAAI,EAAE;gBACJ,OAAO,EAAE;oBACP,UAAU,EAAE,IAAI;iBACjB;aACF;SACF;KACF,CAAC,CAAA;IAEJ,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,4BAA4B,EAAE,CAAA;IAChC,CAAC;IAED,4EAA4E;IAC5E,sEAAsE;IACtE,0DAA0D;IAC1D,+CAA+C;IAC/C,MAAM,sBAAsB,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE;QACnE,MAAM,wBAAwB,GAAG,kCAAkC,CACjE,QAAQ,CAAC,YAAY,EACrB;YACE,yBAAyB,EAAE,IAAI;SAChC,CACF,CAAA;QACD,uCACK,QAAQ,KACX,YAAY,EAAE,wBAAwB,IACvC;IACH,CAAC,CAAC,CAAA;IACF,uCACK,IAAI,KACP,IAAI,kCACC,IAAI,CAAC,IAAI,KACZ,UAAU,EAAE,sBAAsB,OAErC;AACH,CAAC;AAED,cAAc;AACd,MAAM,UAAU,iBAAiB,CAAC,SAAiB;IACjD,OAAO,IAAI,CAAC,iBAAiB,CAAC,SAAS,CAAC,CAAC;AAC3C,CAAC"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/auth/useAuth.js.map b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/auth/useAuth.js.map index b735970c81..63c147e58d 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/auth/useAuth.js.map +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/auth/useAuth.js.map @@ -1 +1 @@ -{"version":3,"file":"useAuth.js","sourceRoot":"","sources":["../../auth/useAuth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,IAAI,oBAAoB,EAAE,MAAM,WAAW,CAAA;AAC/D,OAAO,EAAE,QAAQ,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAA;AACrE,OAAO,EAAE,GAAG,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAGxC,aAAa;AACb,MAAM,CAAC,MAAM,KAAK,GAAG,gBAAgB,EAAE,CAAA;AAEvC,aAAa;AACb,MAAM,CAAC,OAAO,UAAU,OAAO,CAAC,WAAqB,EAAE,MAAY;IACjE,OAAO,QAAQ,CAAC,KAAK,EAAE,WAAW,EAAE,MAAM,CAAC,CAAA;AAC7C,CAAC;AAED,SAAS,gBAAgB;IACvB,MAAM,iBAAiB,GAAG,SAAS,CAAA;IACnC,MAAM,UAAU,GAAG,EAAE,MAAM,EAAE,UAAU,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,iBAAiB,EAAE,EAAE,CAAA;IAC5E,KAAK,UAAU,KAAK;;QAClB,IAAI;YACF,MAAM,QAAQ,GAAG,MAAM,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,CAAA;YAE/C,OAAO,oBAAoB,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAA;SAC3C;QAAC,OAAO,KAAK,EAAE;YACd,IAAI,CAAA,MAAA,KAAK,CAAC,QAAQ,0CAAE,MAAM,MAAK,GAAG,EAAE;gBAClC,OAAO,IAAI,CAAA;aACZ;iBAAM;gBACL,cAAc,CAAC,KAAK,CAAC,CAAA;aACtB;SACF;IACH,CAAC;IAED,kBAAkB,CAAC,KAAK,EAAE;QACxB,iBAAiB,EAAE,iBAAiB;QACpC,UAAU,EAAE,UAAU;QACtB,YAAY,EAAE,CAAC,MAAM,CAAC;KACvB,CAAC,CAAA;IAEF,OAAO,KAAK,CAAA;AACd,CAAC"} \ No newline at end of file +{"version":3,"file":"useAuth.js","sourceRoot":"","sources":["../../auth/useAuth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,IAAI,oBAAoB,EAAE,MAAM,WAAW,CAAA;AAC/D,OAAO,EAAE,QAAQ,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAA;AACrE,OAAO,EAAE,GAAG,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAGxC,aAAa;AACb,MAAM,CAAC,MAAM,KAAK,GAAG,gBAAgB,EAAE,CAAA;AAEvC,aAAa;AACb,MAAM,CAAC,OAAO,UAAU,OAAO,CAAC,WAAqB,EAAE,MAAY;IACjE,OAAO,QAAQ,CAAC,KAAK,EAAE,WAAW,EAAE,MAAM,CAAC,CAAA;AAC7C,CAAC;AAED,SAAS,gBAAgB;IACvB,MAAM,iBAAiB,GAAG,SAAS,CAAA;IACnC,MAAM,UAAU,GAAG,EAAE,MAAM,EAAE,UAAU,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,iBAAiB,EAAE,EAAE,CAAA;IAC5E,KAAK,UAAU,KAAK;;QAClB,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,CAAA;YAE/C,OAAO,oBAAoB,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAA;QAC5C,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAA,MAAA,KAAK,CAAC,QAAQ,0CAAE,MAAM,MAAK,GAAG,EAAE,CAAC;gBACnC,OAAO,IAAI,CAAA;YACb,CAAC;iBAAM,CAAC;gBACN,cAAc,CAAC,KAAK,CAAC,CAAA;YACvB,CAAC;QACH,CAAC;IACH,CAAC;IAED,kBAAkB,CAAC,KAAK,EAAE;QACxB,iBAAiB,EAAE,iBAAiB;QACpC,UAAU,EAAE,UAAU;QACtB,YAAY,EAAE,CAAC,MAAM,CAAC;KACvB,CAAC,CAAA;IAEF,OAAO,KAAK,CAAA;AACd,CAAC"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/auth/user.js.map b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/auth/user.js.map index 1a5670967f..b653f3e19c 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/auth/user.js.map +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/auth/user.js.map @@ -1 +1 @@ -{"version":3,"file":"user.js","sourceRoot":"","sources":["../../auth/user.ts"],"names":[],"mappings":"AAEA,aAAa;AACb,MAAM,UAAU,QAAQ,CAAC,IAAc;;IACrC,OAAO,MAAA,MAAA,gBAAgB,CAAC,IAAI,EAAE,OAAO,CAAC,0CAAE,cAAc,mCAAI,IAAI,CAAC;AACjE,CAAC;AAED,aAAa;AACb,MAAM,UAAU,WAAW,CAAC,IAAc;;IACxC,OAAO,MAAA,MAAA,gBAAgB,CAAC,IAAI,EAAE,UAAU,CAAC,0CAAE,cAAc,mCAAI,IAAI,CAAC;AACpE,CAAC;AAED,aAAa;AACb,MAAM,UAAU,sBAAsB,CAAC,IAAe;;IACpD,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE;QACrF,OAAO,IAAI,CAAC;KACb;IAED,OAAO,MAAA,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,cAAc,mCAAI,IAAI,CAAC;AACxD,CAAC;AAED,aAAa;AACb,MAAM,UAAU,gBAAgB,CAAC,IAAc,EAAE,YAA0B;IACzE,OAAO,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAC9B,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,YAAY,KAAK,YAAY,CACrD,CAAC;AACJ,CAAC"} \ No newline at end of file +{"version":3,"file":"user.js","sourceRoot":"","sources":["../../auth/user.ts"],"names":[],"mappings":"AAEA,aAAa;AACb,MAAM,UAAU,QAAQ,CAAC,IAAc;;IACrC,OAAO,MAAA,MAAA,gBAAgB,CAAC,IAAI,EAAE,OAAO,CAAC,0CAAE,cAAc,mCAAI,IAAI,CAAC;AACjE,CAAC;AAED,aAAa;AACb,MAAM,UAAU,WAAW,CAAC,IAAc;;IACxC,OAAO,MAAA,MAAA,gBAAgB,CAAC,IAAI,EAAE,UAAU,CAAC,0CAAE,cAAc,mCAAI,IAAI,CAAC;AACpE,CAAC;AAED,aAAa;AACb,MAAM,UAAU,sBAAsB,CAAC,IAAe;;IACpD,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtF,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,MAAA,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,cAAc,mCAAI,IAAI,CAAC;AACxD,CAAC;AAED,aAAa;AACb,MAAM,UAAU,gBAAgB,CAAC,IAAc,EAAE,YAA0B;IACzE,OAAO,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAC9B,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,YAAY,KAAK,YAAY,CACrD,CAAC;AACJ,CAAC"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/auth/utils.d.ts b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/auth/utils.d.ts index 52a7b1147c..9b5f61b442 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/auth/utils.d.ts +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/auth/utils.d.ts @@ -68,7 +68,6 @@ export declare function createUser(providerId: ProviderId, serializedProviderDat export declare function deleteUserByAuthId(authId: string): Promise<{ count: number; }>; -export declare function verifyToken(token: string): Promise; export declare function doFakeWork(): Promise; export declare function rethrowPossibleAuthError(e: unknown): void; export declare function validateAndGetUserFields(data: { diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/auth/utils.js b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/auth/utils.js index 1ccee30746..3aa4651799 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/auth/utils.js +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/auth/utils.js @@ -10,7 +10,6 @@ var __rest = (this && this.__rest) || function (s, e) { return t; }; import { hashPassword } from './password.js'; -import { verify } from './jwt.js'; import { prisma, HttpError } from 'wasp/server'; import { sleep } from 'wasp/server/utils'; import { Prisma } from '@prisma/client'; @@ -95,10 +94,6 @@ export async function deleteUserByAuthId(authId) { } } }); } // PRIVATE API -export async function verifyToken(token) { - return verify(token); -} -// PRIVATE API // If an user exists, we don't want to leak information // about it. Pretending that we're doing some work // will make it harder for an attacker to determine diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/auth/utils.js.map b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/auth/utils.js.map index 0e94c0625e..f40d13ba7a 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/auth/utils.js.map +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/auth/utils.js.map @@ -1 +1 @@ -{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../auth/utils.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../auth/utils.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/auth/validation.js.map b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/auth/validation.js.map index efa7527731..67e6e2151c 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/auth/validation.js.map +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/auth/validation.js.map @@ -1 +1 @@ -{"version":3,"file":"validation.js","sourceRoot":"","sources":["../../auth/validation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAExC,MAAM,CAAC,MAAM,cAAc,GAAG,UAAU,CAAC;AACzC,MAAM,cAAc,GAAG,UAAU,CAAC;AAClC,MAAM,WAAW,GAAG,OAAO,CAAC;AAC5B,MAAM,WAAW,GAAG,OAAO,CAAC;AAE5B,aAAa;AACb,MAAM,UAAU,gBAAgB,CAAC,IAAa;IAC5C,QAAQ,CAAC,IAAI,EAAE;QACb,EAAE,SAAS,EAAE,WAAW,EAAE,OAAO,EAAE,uBAAuB,EAAE,SAAS,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,EAAE;QACzF,EAAE,SAAS,EAAE,WAAW,EAAE,OAAO,EAAE,6BAA6B,EAAE,SAAS,EAAE,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,KAAK,CAAC,EAAE;KAC5G,CAAC,CAAC;AACL,CAAC;AAED,aAAa;AACb,MAAM,UAAU,mBAAmB,CAAC,IAAa;IAC/C,QAAQ,CAAC,IAAI,EAAE;QACb,EAAE,SAAS,EAAE,cAAc,EAAE,OAAO,EAAE,0BAA0B,EAAE,SAAS,EAAE,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,EAAE;KACtG,CAAC,CAAC;AACL,CAAC;AAED,aAAa;AACb,MAAM,UAAU,uBAAuB,CAAC,IAAa;IACnD,QAAQ,CAAC,IAAI,EAAE;QACb,EAAE,SAAS,EAAE,cAAc,EAAE,OAAO,EAAE,0BAA0B,EAAE,SAAS,EAAE,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,EAAE;KACtG,CAAC,CAAC;AACL,CAAC;AAED,aAAa;AACb,MAAM,UAAU,mBAAmB,CAAC,IAAa;IAC/C,QAAQ,CAAC,IAAI,EAAE;QACb,EAAE,SAAS,EAAE,cAAc,EAAE,OAAO,EAAE,wCAAwC,EAAE,SAAS,EAAE,QAAQ,CAAC,EAAE,CAAC,WAAW,CAAC,QAAQ,EAAE,CAAC,CAAC,EAAE;QACjI,EAAE,SAAS,EAAE,cAAc,EAAE,OAAO,EAAE,gCAAgC,EAAE,SAAS,EAAE,QAAQ,CAAC,EAAE,CAAC,cAAc,CAAC,QAAQ,CAAC,EAAE;KAC1H,CAAC,CAAC;AACL,CAAC;AAED,aAAa;AACb,MAAM,UAAU,oBAAoB,CAAC,IAAa;IAChD,QAAQ,CAAC,IAAI,EAAE;QACb,EAAE,SAAS,EAAE,WAAW,EAAE,OAAO,EAAE,uBAAuB,EAAE,SAAS,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,EAAE;KAC1F,CAAC,CAAC;AACL,CAAC;AAED,cAAc;AACd,MAAM,UAAU,oBAAoB,CAAC,OAAe;IAClD,MAAM,IAAI,SAAS,CAAC,GAAG,EAAE,mBAAmB,EAAE,EAAE,OAAO,EAAE,CAAC,CAAA;AAC5D,CAAC;AAED,SAAS,QAAQ,CAAC,IAAa,EAAE,UAA4F;IAC3H,KAAK,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,IAAI,UAAU,EAAE;QAC1D,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE;YAC/B,oBAAoB,CAAC,OAAO,CAAC,CAAC;SAC/B;KACF;AACH,CAAC;AAED,+EAA+E;AAE/E,MAAM,eAAe,GAAG,gcAAgc,CAAA;AACxd,SAAS,YAAY,CAAC,KAAc;IAChC,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE;QAC3B,OAAO,KAAK,CAAA;KACf;IAED,OAAO,KAAK,CAAC,KAAK,CAAC,eAAe,CAAC,KAAK,IAAI,CAAA;AAChD,CAAC;AAED,SAAS,WAAW,CAAC,KAAc,EAAE,SAAiB;IAClD,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE;QAC3B,OAAO,KAAK,CAAA;KACf;IAED,OAAO,KAAK,CAAC,MAAM,IAAI,SAAS,CAAA;AACpC,CAAC;AAED,SAAS,cAAc,CAAC,KAAc;IAClC,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE;QAC3B,OAAO,KAAK,CAAA;KACf;IAED,OAAO,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;AAC3B,CAAC"} \ No newline at end of file +{"version":3,"file":"validation.js","sourceRoot":"","sources":["../../auth/validation.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/actions/core.js.map b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/actions/core.js.map index 5834336f1d..b13c7d6712 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/actions/core.js.map +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/actions/core.js.map @@ -1 +1 @@ -{"version":3,"file":"core.js","sourceRoot":"","sources":["../../../../client/operations/actions/core.js"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAA;AACxE,OAAO,EACL,wBAAwB,EACxB,kBAAkB,GACnB,MAAM,0BAA0B,CAAA;AAEjC,cAAc;AACd,MAAM,UAAU,YAAY,CAAC,mBAAmB,EAAE,YAAY;IAC5D,MAAM,WAAW,GAAG,kBAAkB,CAAC,mBAAmB,CAAC,CAAA;IAE3D,KAAK,UAAU,cAAc,CAAC,IAAI,EAAE,mCAAmC;QACrE,wBAAwB,CAAC,mCAAmC,CAAC,CAAA;QAC7D,IAAI;YACF,yEAAyE;YACzE,wEAAwE;YACxE,kCAAkC;YAClC,OAAO,MAAM,aAAa,CAAC,WAAW,EAAE,IAAI,CAAC,CAAA;SAC9C;gBAAS;YACR,MAAM,kBAAkB,CAAC,YAAY,EAAE,mCAAmC,CAAC,CAAA;SAC5E;IACH,CAAC;IAED,0EAA0E;IAC1E,yEAAyE;IACzE,6EAA6E;IAC7E,yEAAyE;IACzE,gBAAgB;IAChB,EAAE;IACF,0EAA0E;IAC1E,8EAA8E;IAC9E,wCAAwC;IACxC,MAAM,MAAM,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC,cAAc,CAAC,IAAI,EAAE,EAAE,CAAC,CAAA;IACjD,MAAM,CAAC,QAAQ,GAAG,cAAc,CAAA;IAEhC,OAAO,MAAM,CAAA;AACf,CAAC"} \ No newline at end of file +{"version":3,"file":"core.js","sourceRoot":"","sources":["../../../../client/operations/actions/core.js"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAA;AACxE,OAAO,EACL,wBAAwB,EACxB,kBAAkB,GACnB,MAAM,0BAA0B,CAAA;AAEjC,cAAc;AACd,MAAM,UAAU,YAAY,CAAC,mBAAmB,EAAE,YAAY;IAC5D,MAAM,WAAW,GAAG,kBAAkB,CAAC,mBAAmB,CAAC,CAAA;IAE3D,KAAK,UAAU,cAAc,CAAC,IAAI,EAAE,mCAAmC;QACrE,wBAAwB,CAAC,mCAAmC,CAAC,CAAA;QAC7D,IAAI,CAAC;YACH,yEAAyE;YACzE,wEAAwE;YACxE,kCAAkC;YAClC,OAAO,MAAM,aAAa,CAAC,WAAW,EAAE,IAAI,CAAC,CAAA;QAC/C,CAAC;gBAAS,CAAC;YACT,MAAM,kBAAkB,CAAC,YAAY,EAAE,mCAAmC,CAAC,CAAA;QAC7E,CAAC;IACH,CAAC;IAED,0EAA0E;IAC1E,yEAAyE;IACzE,6EAA6E;IAC7E,yEAAyE;IACzE,gBAAgB;IAChB,EAAE;IACF,0EAA0E;IAC1E,8EAA8E;IAC9E,wCAAwC;IACxC,MAAM,MAAM,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC,cAAc,CAAC,IAAI,EAAE,EAAE,CAAC,CAAA;IACjD,MAAM,CAAC,QAAQ,GAAG,cAAc,CAAA;IAEhC,OAAO,MAAM,CAAA;AACf,CAAC"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/core.js.map b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/core.js.map index 68ea114aa9..20d72dc15e 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/core.js.map +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/core.js.map @@ -1 +1 @@ -{"version":3,"file":"core.js","sourceRoot":"","sources":["../../../client/operations/core.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"core.js","sourceRoot":"","sources":["../../../client/operations/core.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/internal/index.js.map b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/internal/index.js.map index a4097ef8cb..a7cf9e445b 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/internal/index.js.map +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/internal/index.js.map @@ -1 +1 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../client/operations/internal/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AACxC,OAAO,EACL,SAAS,IAAI,kBAAkB,EAC/B,WAAW,IAAI,oBAAoB,GACnC,MAAM,WAAW,CAAA;AAKnB,cAAc;AACd,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,cAA4D,EAAE,IAAS;IACzG,IAAI;QACF,MAAM,aAAa,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAA;QAC9C,MAAM,QAAQ,GAAG,MAAM,GAAG,CAAC,IAAI,CAAC,cAAc,CAAC,IAAI,EAAE,aAAa,CAAC,CAAA;QACnE,OAAO,oBAAoB,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAA;KAC3C;IAAC,OAAO,KAAK,EAAE;QACd,cAAc,CAAC,KAAK,CAAC,CAAA;KACtB;AACH,CAAC;AAED,cAAc;AACd,MAAM,UAAU,kBAAkB,CAAC,sBAA8B;IAC/D,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,sBAAsB,EAAE,EAAE,CAAA;AACxE,CAAC"} \ No newline at end of file +{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../client/operations/internal/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AACxC,OAAO,EACL,SAAS,IAAI,kBAAkB,EAC/B,WAAW,IAAI,oBAAoB,GACnC,MAAM,WAAW,CAAA;AAKnB,cAAc;AACd,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,cAA4D,EAAE,IAAS;IACzG,IAAI,CAAC;QACH,MAAM,aAAa,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAA;QAC9C,MAAM,QAAQ,GAAG,MAAM,GAAG,CAAC,IAAI,CAAC,cAAc,CAAC,IAAI,EAAE,aAAa,CAAC,CAAA;QACnE,OAAO,oBAAoB,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAA;IAC5C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,cAAc,CAAC,KAAK,CAAC,CAAA;IACvB,CAAC;AACH,CAAC;AAED,cAAc;AACd,MAAM,UAAU,kBAAkB,CAAC,sBAA8B;IAC/D,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,sBAAsB,EAAE,EAAE,CAAA;AACxE,CAAC"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/internal/resources.js.map b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/internal/resources.js.map index c91fecd3c7..61f8241c3e 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/internal/resources.js.map +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/internal/resources.js.map @@ -1 +1 @@ -{"version":3,"file":"resources.js","sourceRoot":"","sources":["../../../../client/operations/internal/resources.js"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAA;AAC1D,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAA;AAC3D,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAA;AAEpD,kDAAkD;AAClD,mDAAmD;AACnD,iBAAiB;AACjB,MAAM,wBAAwB,GAAG,IAAI,GAAG,EAAE,CAAA;AAE1C,MAAM,cAAc,GAAG,qBAAqB,CAAC,YAAY,CAAC,CAAA;AAE1D,cAAc;AACd;;;;;GAKG;AACH,MAAM,UAAU,uBAAuB,CAAC,aAAa,EAAE,SAAS;IAC9D,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE;QAChC,IAAI,SAAS,GAAG,wBAAwB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;QACtD,IAAI,CAAC,SAAS,EAAE;YACd,SAAS,GAAG,IAAI,GAAG,EAAE,CAAA;YACrB,wBAAwB,CAAC,GAAG,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAA;SAClD;QACD,SAAS,CAAC,GAAG,CAAC,aAAa,CAAC,CAAA;KAC7B;AACH,CAAC;AAED,MAAM,UAAU,wBAAwB,CAAC,sBAAsB;IAC7D,sBAAsB,CAAC,OAAO,CAC5B,CAAC,EAAE,QAAQ,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC,cAAc,CAAC,GAAG,CAAC,QAAQ,EAAE,WAAW,CAAC,CACzE,CAAA;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,SAAS,EAAE,sBAAsB;IACxE,sBAAsB,CAAC,OAAO,CAAC,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,cAAc,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAA;IACjF,MAAM,sBAAsB,CAAC,SAAS,CAAC,CAAA;AACzC,CAAC;AAED,MAAM,UAAU,0BAA0B,CAAC,QAAQ;IACjD,OAAO,cAAc,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAA;AACnD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,0BAA0B;IAC9C,MAAM,WAAW,GAAG,MAAM,sBAAsB,CAAA;IAChD,wEAAwE;IACxE,8EAA8E;IAC9E,eAAe;IACf,iFAAiF;IACjF,6EAA6E;IAC7E,wFAAwF;IACxF,kFAAkF;IAClF,WAAW,CAAC,YAAY,EAAE,CAAA;IAC1B,6EAA6E;IAC7E,2DAA2D;IAC3D,WAAW,CAAC,aAAa,EAAE,CAAA;AAC7B,CAAC;AAED;;;GAGG;AACH,KAAK,UAAU,sBAAsB,CAAC,SAAS;IAC7C,MAAM,WAAW,GAAG,MAAM,sBAAsB,CAAA;IAEhD,MAAM,0BAA0B,GAAG,wBAAwB,CAAC,SAAS,CAAC,CAAA;IACtE,0BAA0B,CAAC,OAAO,CAChC,aAAa,CAAC,EAAE,CAAC,WAAW,CAAC,iBAAiB,CAAC,aAAa,CAAC,CAC9D,CAAA;AACH,CAAC;AAED;;;GAGG;AACH,SAAS,uBAAuB,CAAC,QAAQ;IACvC,OAAO,KAAK,CAAC,IAAI,CAAC,wBAAwB,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAA;AACjE,CAAC;AAED,SAAS,wBAAwB,CAAC,SAAS;IACzC,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,uBAAuB,CAAC,CAAC,CAAC,CAAA;AACxE,CAAC"} \ No newline at end of file +{"version":3,"file":"resources.js","sourceRoot":"","sources":["../../../../client/operations/internal/resources.js"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAA;AAC1D,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAA;AAC3D,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAA;AAEpD,kDAAkD;AAClD,mDAAmD;AACnD,iBAAiB;AACjB,MAAM,wBAAwB,GAAG,IAAI,GAAG,EAAE,CAAA;AAE1C,MAAM,cAAc,GAAG,qBAAqB,CAAC,YAAY,CAAC,CAAA;AAE1D,cAAc;AACd;;;;;GAKG;AACH,MAAM,UAAU,uBAAuB,CAAC,aAAa,EAAE,SAAS;IAC9D,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;QACjC,IAAI,SAAS,GAAG,wBAAwB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;QACtD,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,SAAS,GAAG,IAAI,GAAG,EAAE,CAAA;YACrB,wBAAwB,CAAC,GAAG,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAA;QACnD,CAAC;QACD,SAAS,CAAC,GAAG,CAAC,aAAa,CAAC,CAAA;IAC9B,CAAC;AACH,CAAC;AAED,MAAM,UAAU,wBAAwB,CAAC,sBAAsB;IAC7D,sBAAsB,CAAC,OAAO,CAC5B,CAAC,EAAE,QAAQ,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC,cAAc,CAAC,GAAG,CAAC,QAAQ,EAAE,WAAW,CAAC,CACzE,CAAA;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,SAAS,EAAE,sBAAsB;IACxE,sBAAsB,CAAC,OAAO,CAAC,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,cAAc,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAA;IACjF,MAAM,sBAAsB,CAAC,SAAS,CAAC,CAAA;AACzC,CAAC;AAED,MAAM,UAAU,0BAA0B,CAAC,QAAQ;IACjD,OAAO,cAAc,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAA;AACnD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,0BAA0B;IAC9C,MAAM,WAAW,GAAG,MAAM,sBAAsB,CAAA;IAChD,wEAAwE;IACxE,8EAA8E;IAC9E,eAAe;IACf,iFAAiF;IACjF,6EAA6E;IAC7E,wFAAwF;IACxF,kFAAkF;IAClF,WAAW,CAAC,YAAY,EAAE,CAAA;IAC1B,6EAA6E;IAC7E,2DAA2D;IAC3D,WAAW,CAAC,aAAa,EAAE,CAAA;AAC7B,CAAC;AAED;;;GAGG;AACH,KAAK,UAAU,sBAAsB,CAAC,SAAS;IAC7C,MAAM,WAAW,GAAG,MAAM,sBAAsB,CAAA;IAEhD,MAAM,0BAA0B,GAAG,wBAAwB,CAAC,SAAS,CAAC,CAAA;IACtE,0BAA0B,CAAC,OAAO,CAChC,aAAa,CAAC,EAAE,CAAC,WAAW,CAAC,iBAAiB,CAAC,aAAa,CAAC,CAC9D,CAAA;AACH,CAAC;AAED;;;GAGG;AACH,SAAS,uBAAuB,CAAC,QAAQ;IACvC,OAAO,KAAK,CAAC,IAAI,CAAC,wBAAwB,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAA;AACjE,CAAC;AAED,SAAS,wBAAwB,CAAC,SAAS;IACzC,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,uBAAuB,CAAC,CAAC,CAAC,CAAA;AACxE,CAAC"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/internal/updateHandlersMap.js.map b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/internal/updateHandlersMap.js.map index 7940fcd972..950c377452 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/internal/updateHandlersMap.js.map +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/internal/updateHandlersMap.js.map @@ -1 +1 @@ -{"version":3,"file":"updateHandlersMap.js","sourceRoot":"","sources":["../../../../client/operations/internal/updateHandlersMap.js"],"names":[],"mappings":"AAAA,MAAM,UAAU,qBAAqB,CAAC,aAAa;IACjD,MAAM,cAAc,GAAG,IAAI,GAAG,EAAE,CAAA;IAEhC,SAAS,gBAAgB,CAAC,YAAY;QACpC,OAAO,cAAc,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC;IAChD,CAAC;IAED,SAAS,GAAG,CAAC,QAAQ,EAAE,WAAW;QAChC,MAAM,YAAY,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAA;QAC5C,MAAM,QAAQ,GAAG,gBAAgB,CAAC,YAAY,CAAC,CAAC;QAChD,cAAc,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC,GAAG,QAAQ,EAAE,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC,CAAC,CAAA;IAC5E,CAAC;IAED,SAAS,iBAAiB,CAAC,QAAQ;QACjC,MAAM,YAAY,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAA;QAC5C,OAAO,gBAAgB,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC,WAAW,CAAC,CAAA;IAC7E,CAAC;IAED,SAAS,MAAM,CAAC,gBAAgB;QAC9B,MAAM,YAAY,GAAG,aAAa,CAAC,gBAAgB,CAAC,CAAA;QACpD,MAAM,gBAAgB,GAAG,gBAAgB,CAAC,YAAY,CAAC,CAAC,MAAM,CAC5D,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,QAAQ,KAAK,gBAAgB,CAChD,CAAA;QAED,IAAI,gBAAgB,CAAC,MAAM,GAAG,CAAC,EAAE;YAC/B,cAAc,CAAC,GAAG,CAAC,YAAY,EAAE,gBAAgB,CAAC,CAAA;SACnD;aAAM;YACL,cAAc,CAAC,MAAM,CAAC,YAAY,CAAC,CAAA;SACpC;IACH,CAAC;IAED,OAAO;QACL,GAAG;QACH,MAAM;QACN,iBAAiB;KAClB,CAAA;AACH,CAAC"} \ No newline at end of file +{"version":3,"file":"updateHandlersMap.js","sourceRoot":"","sources":["../../../../client/operations/internal/updateHandlersMap.js"],"names":[],"mappings":"AAAA,MAAM,UAAU,qBAAqB,CAAC,aAAa;IACjD,MAAM,cAAc,GAAG,IAAI,GAAG,EAAE,CAAA;IAEhC,SAAS,gBAAgB,CAAC,YAAY;QACpC,OAAO,cAAc,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC;IAChD,CAAC;IAED,SAAS,GAAG,CAAC,QAAQ,EAAE,WAAW;QAChC,MAAM,YAAY,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAA;QAC5C,MAAM,QAAQ,GAAG,gBAAgB,CAAC,YAAY,CAAC,CAAC;QAChD,cAAc,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC,GAAG,QAAQ,EAAE,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC,CAAC,CAAA;IAC5E,CAAC;IAED,SAAS,iBAAiB,CAAC,QAAQ;QACjC,MAAM,YAAY,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAA;QAC5C,OAAO,gBAAgB,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC,WAAW,CAAC,CAAA;IAC7E,CAAC;IAED,SAAS,MAAM,CAAC,gBAAgB;QAC9B,MAAM,YAAY,GAAG,aAAa,CAAC,gBAAgB,CAAC,CAAA;QACpD,MAAM,gBAAgB,GAAG,gBAAgB,CAAC,YAAY,CAAC,CAAC,MAAM,CAC5D,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,QAAQ,KAAK,gBAAgB,CAChD,CAAA;QAED,IAAI,gBAAgB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAChC,cAAc,CAAC,GAAG,CAAC,YAAY,EAAE,gBAAgB,CAAC,CAAA;QACpD,CAAC;aAAM,CAAC;YACN,cAAc,CAAC,MAAM,CAAC,YAAY,CAAC,CAAA;QACrC,CAAC;IACH,CAAC;IAED,OAAO;QACL,GAAG;QACH,MAAM;QACN,iBAAiB;KAClB,CAAA;AACH,CAAC"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/queryClient.js.map b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/queryClient.js.map index 82e2b19139..15d3f12588 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/queryClient.js.map +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/queryClient.js.map @@ -1 +1 @@ -{"version":3,"file":"queryClient.js","sourceRoot":"","sources":["../../../client/operations/queryClient.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAqB,MAAM,uBAAuB,CAAA;AAEtE,MAAM,wBAAwB,GAAG,EAAE,CAAC;AAEpC,IAAI,iBAAoC,EACtC,6BAAsD,EACtD,wBAAiC,CAAC;AAEpC,+BAA+B;AAC/B,MAAM,CAAC,MAAM,sBAAsB,GAAyB,IAAI,OAAO,CACrE,CAAC,OAAO,EAAE,EAAE;IACV,6BAA6B,GAAG,OAAO,CAAC;AAC1C,CAAC,CACF,CAAC;AAEF,aAAa;AACb,MAAM,UAAU,oBAAoB,CAAC,MAAyB;IAC5D,IAAI,wBAAwB,EAAE;QAC5B,MAAM,IAAI,KAAK,CACb,6DAA6D,CAC9D,CAAC;KACH;IAED,iBAAiB,GAAG,MAAM,CAAC;AAC7B,CAAC;AAED,+BAA+B;AAC/B,MAAM,UAAU,qBAAqB;IACnC,MAAM,WAAW,GAAG,IAAI,WAAW,CACjC,iBAAiB,aAAjB,iBAAiB,cAAjB,iBAAiB,GAAI,wBAAwB,CAC9C,CAAC;IACF,wBAAwB,GAAG,IAAI,CAAC;IAChC,6BAA6B,CAAC,WAAW,CAAC,CAAC;AAC7C,CAAC"} \ No newline at end of file +{"version":3,"file":"queryClient.js","sourceRoot":"","sources":["../../../client/operations/queryClient.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAqB,MAAM,uBAAuB,CAAA;AAEtE,MAAM,wBAAwB,GAAG,EAAE,CAAC;AAEpC,IAAI,iBAAoC,EACtC,6BAAsD,EACtD,wBAAiC,CAAC;AAEpC,+BAA+B;AAC/B,MAAM,CAAC,MAAM,sBAAsB,GAAyB,IAAI,OAAO,CACrE,CAAC,OAAO,EAAE,EAAE;IACV,6BAA6B,GAAG,OAAO,CAAC;AAC1C,CAAC,CACF,CAAC;AAEF,aAAa;AACb,MAAM,UAAU,oBAAoB,CAAC,MAAyB;IAC5D,IAAI,wBAAwB,EAAE,CAAC;QAC7B,MAAM,IAAI,KAAK,CACb,6DAA6D,CAC9D,CAAC;IACJ,CAAC;IAED,iBAAiB,GAAG,MAAM,CAAC;AAC7B,CAAC;AAED,+BAA+B;AAC/B,MAAM,UAAU,qBAAqB;IACnC,MAAM,WAAW,GAAG,IAAI,WAAW,CACjC,iBAAiB,aAAjB,iBAAiB,cAAjB,iBAAiB,GAAI,wBAAwB,CAC9C,CAAC;IACF,wBAAwB,GAAG,IAAI,CAAC;IAChC,6BAA6B,CAAC,WAAW,CAAC,CAAC;AAC7C,CAAC"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/router/linkHelpers.js.map b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/router/linkHelpers.js.map index 064bcce597..c532d39f5e 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/router/linkHelpers.js.map +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/router/linkHelpers.js.map @@ -1 +1 @@ -{"version":3,"file":"linkHelpers.js","sourceRoot":"","sources":["../../../client/router/linkHelpers.ts"],"names":[],"mappings":"AAEA,cAAc;AACd,MAAM,UAAU,eAAe,CAC7B,IAAY,EACZ,MAAe,EACf,MAAe,EACf,IAAa;IAEb,MAAM,gBAAgB,GAAG,MAAM,CAAC,CAAC,CAAC,qBAAqB,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;IAC5E,MAAM,kBAAkB,GAAG,MAAM;QAC/B,CAAC,CAAC,IAAI,IAAI,eAAe,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,EAAE;QAC9C,CAAC,CAAC,EAAE,CAAA;IACN,MAAM,gBAAgB,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAA;IAC/C,OAAO,gBAAgB,GAAG,kBAAkB,GAAG,gBAAgB,CAAA;AACjE,CAAC;AAED,SAAS,qBAAqB,CAAC,IAAY,EAAE,MAAc;IACzD,SAAS,WAAW,CAAC,IAAY;QAC/B,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE;YACxB,MAAM,SAAS,GAAG,4BAA4B,CAAC,IAAI,CAAC,CAAC;YACrD,OAAO,MAAM,CAAC,SAAS,CAAC,CAAC;SAC1B;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,gBAAgB,GAAG,IAAI;SAC1B,KAAK,CAAC,GAAG,CAAC;SACV,GAAG,CAAC,WAAW,CAAC;SAChB,MAAM,CAAC,eAAe,CAAC;SACvB,IAAI,CAAC,GAAG,CAAC,CAAC;IAEb,OAAO,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,gBAAgB,EAAE,CAAC,CAAC,CAAC,gBAAgB,CAAC;AAC1E,CAAC;AAED,SAAS,eAAe,CAAC,IAAS;IAChC,OAAO,CAAC,CAAC,IAAI,CAAC;AAChB,CAAC;AAED,SAAS,4BAA4B,CAAC,WAAmB;IACvD,IAAI,WAAW,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE;QAC7B,OAAO,WAAW,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;KACjC;IACD,OAAO,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC9B,CAAC"} \ No newline at end of file +{"version":3,"file":"linkHelpers.js","sourceRoot":"","sources":["../../../client/router/linkHelpers.ts"],"names":[],"mappings":"AAEA,cAAc;AACd,MAAM,UAAU,eAAe,CAC7B,IAAY,EACZ,MAAe,EACf,MAAe,EACf,IAAa;IAEb,MAAM,gBAAgB,GAAG,MAAM,CAAC,CAAC,CAAC,qBAAqB,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;IAC5E,MAAM,kBAAkB,GAAG,MAAM;QAC/B,CAAC,CAAC,IAAI,IAAI,eAAe,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,EAAE;QAC9C,CAAC,CAAC,EAAE,CAAA;IACN,MAAM,gBAAgB,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAA;IAC/C,OAAO,gBAAgB,GAAG,kBAAkB,GAAG,gBAAgB,CAAA;AACjE,CAAC;AAED,SAAS,qBAAqB,CAAC,IAAY,EAAE,MAAc;IACzD,SAAS,WAAW,CAAC,IAAY;QAC/B,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YACzB,MAAM,SAAS,GAAG,4BAA4B,CAAC,IAAI,CAAC,CAAC;YACrD,OAAO,MAAM,CAAC,SAAS,CAAC,CAAC;QAC3B,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,gBAAgB,GAAG,IAAI;SAC1B,KAAK,CAAC,GAAG,CAAC;SACV,GAAG,CAAC,WAAW,CAAC;SAChB,MAAM,CAAC,eAAe,CAAC;SACvB,IAAI,CAAC,GAAG,CAAC,CAAC;IAEb,OAAO,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,gBAAgB,EAAE,CAAC,CAAC,CAAC,gBAAgB,CAAC;AAC1E,CAAC;AAED,SAAS,eAAe,CAAC,IAAS;IAChC,OAAO,CAAC,CAAC,IAAI,CAAC;AAChB,CAAC;AAED,SAAS,4BAA4B,CAAC,WAAmB;IACvD,IAAI,WAAW,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QAC9B,OAAO,WAAW,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAClC,CAAC;IACD,OAAO,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC9B,CAAC"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/test/vitest/helpers.jsx.map b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/test/vitest/helpers.jsx.map index b7ab2a906f..375c4629a2 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/test/vitest/helpers.jsx.map +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/test/vitest/helpers.jsx.map @@ -1 +1 @@ -{"version":3,"file":"helpers.jsx","sourceRoot":"","sources":["../../../../client/test/vitest/helpers.tsx"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"helpers.jsx","sourceRoot":"","sources":["../../../../client/test/vitest/helpers.tsx"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/core/auth.js.map b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/core/auth.js.map index 2a4d43ebee..47dc574608 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/core/auth.js.map +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/core/auth.js.map @@ -1 +1 @@ -{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../core/auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;AACnD,OAAO,EAAE,gCAAgC,EAAE,MAAM,mBAAmB,CAAA;AACpE,OAAO,EAAE,4BAA4B,EAAE,MAAM,iBAAiB,CAAA;AAE9D;;;;;;;;;;;GAWG;AACH,MAAM,IAAI,GAAG,eAAe,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;IACpD,MAAM,UAAU,GAAG,GAAG,CAAC,GAAG,CAAC,eAAe,CAAC,CAAA;IAC3C,IAAI,CAAC,UAAU,EAAE;QACf,kFAAkF;QAClF,sFAAsF;QACtF,yDAAyD;QACzD,OAAO,IAAI,EAAE,CAAA;KACd;IAED,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,MAAM,gCAAgC,CAAC,GAAG,CAAC,CAAC;IAEtE,IAAI,CAAC,OAAO,IAAI,CAAC,IAAI,EAAE;QACrB,4BAA4B,EAAE,CAAA;KAC/B;IAED,GAAG,CAAC,SAAS,GAAG,OAAO,CAAC,EAAE,CAAA;IAC1B,GAAG,CAAC,IAAI,GAAG,IAAI,CAAA;IAEf,IAAI,EAAE,CAAA;AACR,CAAC,CAAC,CAAA;AAEF,eAAe,IAAI,CAAA"} \ No newline at end of file +{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../core/auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;AACnD,OAAO,EAAE,gCAAgC,EAAE,MAAM,mBAAmB,CAAA;AACpE,OAAO,EAAE,4BAA4B,EAAE,MAAM,iBAAiB,CAAA;AAE9D;;;;;;;;;;;GAWG;AACH,MAAM,IAAI,GAAG,eAAe,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;IACpD,MAAM,UAAU,GAAG,GAAG,CAAC,GAAG,CAAC,eAAe,CAAC,CAAA;IAC3C,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,kFAAkF;QAClF,sFAAsF;QACtF,yDAAyD;QACzD,OAAO,IAAI,EAAE,CAAA;IACf,CAAC;IAED,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,MAAM,gCAAgC,CAAC,GAAG,CAAC,CAAC;IAEtE,IAAI,CAAC,OAAO,IAAI,CAAC,IAAI,EAAE,CAAC;QACtB,4BAA4B,EAAE,CAAA;IAChC,CAAC;IAED,GAAG,CAAC,SAAS,GAAG,OAAO,CAAC,EAAE,CAAA;IAC1B,GAAG,CAAC,IAAI,GAAG,IAAI,CAAA;IAEf,IAAI,EAAE,CAAA;AACR,CAAC,CAAC,CAAA;AAEF,eAAe,IAAI,CAAA"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/core/storage.js.map b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/core/storage.js.map index b7cd5db441..73a6773d4f 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/core/storage.js.map +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/core/storage.js.map @@ -1 +1 @@ -{"version":3,"file":"storage.js","sourceRoot":"","sources":["../../core/storage.ts"],"names":[],"mappings":"AAQA,SAAS,2BAA2B,CAAC,MAAc;IACjD,SAAS,cAAc,CAAC,GAAW;QACjC,OAAO,GAAG,MAAM,IAAI,GAAG,EAAE,CAAA;IAC3B,CAAC;IAED,OAAO;QACL,cAAc;QACd,GAAG,CAAC,GAAG,EAAE,KAAK;YACZ,6BAA6B,EAAE,CAAA;YAC/B,YAAY,CAAC,OAAO,CAAC,cAAc,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAA;QAClE,CAAC;QACD,GAAG,CAAC,GAAG;YACL,6BAA6B,EAAE,CAAA;YAC/B,MAAM,KAAK,GAAG,YAAY,CAAC,OAAO,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAA;YACvD,IAAI;gBACF,OAAO,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;aAC7C;YAAC,OAAO,CAAM,EAAE;gBACf,OAAO,SAAS,CAAA;aACjB;QACH,CAAC;QACD,MAAM,CAAC,GAAG;YACR,6BAA6B,EAAE,CAAA;YAC/B,YAAY,CAAC,UAAU,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAA;QAC9C,CAAC;QACD,KAAK;YACH,6BAA6B,EAAE,CAAA;YAC/B,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE;gBACxC,IAAI,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE;oBAC1B,YAAY,CAAC,UAAU,CAAC,GAAG,CAAC,CAAA;iBAC7B;YACH,CAAC,CAAC,CAAA;QACJ,CAAC;KACF,CAAA;AACH,CAAC;AAED,MAAM,CAAC,MAAM,OAAO,GAAG,2BAA2B,CAAC,MAAM,CAAC,CAAA;AAE1D,SAAS,6BAA6B;IACpC,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE;QACxB,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAA;KACnD;AACH,CAAC"} \ No newline at end of file +{"version":3,"file":"storage.js","sourceRoot":"","sources":["../../core/storage.ts"],"names":[],"mappings":"AAQA,SAAS,2BAA2B,CAAC,MAAc;IACjD,SAAS,cAAc,CAAC,GAAW;QACjC,OAAO,GAAG,MAAM,IAAI,GAAG,EAAE,CAAA;IAC3B,CAAC;IAED,OAAO;QACL,cAAc;QACd,GAAG,CAAC,GAAG,EAAE,KAAK;YACZ,6BAA6B,EAAE,CAAA;YAC/B,YAAY,CAAC,OAAO,CAAC,cAAc,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAA;QAClE,CAAC;QACD,GAAG,CAAC,GAAG;YACL,6BAA6B,EAAE,CAAA;YAC/B,MAAM,KAAK,GAAG,YAAY,CAAC,OAAO,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAA;YACvD,IAAI,CAAC;gBACH,OAAO,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;YAC9C,CAAC;YAAC,OAAO,CAAM,EAAE,CAAC;gBAChB,OAAO,SAAS,CAAA;YAClB,CAAC;QACH,CAAC;QACD,MAAM,CAAC,GAAG;YACR,6BAA6B,EAAE,CAAA;YAC/B,YAAY,CAAC,UAAU,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAA;QAC9C,CAAC;QACD,KAAK;YACH,6BAA6B,EAAE,CAAA;YAC/B,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE;gBACxC,IAAI,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;oBAC3B,YAAY,CAAC,UAAU,CAAC,GAAG,CAAC,CAAA;gBAC9B,CAAC;YACH,CAAC,CAAC,CAAA;QACJ,CAAC;KACF,CAAA;AACH,CAAC;AAED,MAAM,CAAC,MAAM,OAAO,GAAG,2BAA2B,CAAC,MAAM,CAAC,CAAA;AAE1D,SAAS,6BAA6B;IACpC,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAA;IACpD,CAAC;AACH,CAAC"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/server/HttpError.js.map b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/server/HttpError.js.map index 34064e924c..3cc7095281 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/server/HttpError.js.map +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/server/HttpError.js.map @@ -1 +1 @@ -{"version":3,"file":"HttpError.js","sourceRoot":"","sources":["../../server/HttpError.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,SAAU,SAAQ,KAAK;IAIlC,YAAa,UAAkB,EAAE,OAAgB,EAAE,IAA8B,EAAE,GAAG,MAAiB;QACrG,KAAK,CAAC,OAAO,EAAE,GAAG,MAAM,CAAC,CAAA;QAEzB,IAAI,KAAK,CAAC,iBAAiB,EAAE;YAC3B,KAAK,CAAC,iBAAiB,CAAC,IAAI,EAAE,SAAS,CAAC,CAAA;SACzC;QAED,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,CAAA;QAEjC,IAAI,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC,IAAI,UAAU,IAAI,GAAG,IAAI,UAAU,GAAG,GAAG,CAAC,EAAE;YAC5E,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAA;SACrE;QACD,IAAI,CAAC,UAAU,GAAG,UAAU,CAAA;QAE5B,IAAI,IAAI,EAAE;YACR,IAAI,CAAC,IAAI,GAAG,IAAI,CAAA;SACjB;IACH,CAAC;CACF"} \ No newline at end of file +{"version":3,"file":"HttpError.js","sourceRoot":"","sources":["../../server/HttpError.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,SAAU,SAAQ,KAAK;IAIlC,YAAa,UAAkB,EAAE,OAAgB,EAAE,IAA8B,EAAE,GAAG,MAAiB;QACrG,KAAK,CAAC,OAAO,EAAE,GAAG,MAAM,CAAC,CAAA;QAEzB,IAAI,KAAK,CAAC,iBAAiB,EAAE,CAAC;YAC5B,KAAK,CAAC,iBAAiB,CAAC,IAAI,EAAE,SAAS,CAAC,CAAA;QAC1C,CAAC;QAED,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,CAAA;QAEjC,IAAI,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC,IAAI,UAAU,IAAI,GAAG,IAAI,UAAU,GAAG,GAAG,CAAC,EAAE,CAAC;YAC7E,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAA;QACtE,CAAC;QACD,IAAI,CAAC,UAAU,GAAG,UAAU,CAAA;QAE5B,IAAI,IAAI,EAAE,CAAC;YACT,IAAI,CAAC,IAAI,GAAG,IAAI,CAAA;QAClB,CAAC;IACH,CAAC;CACF"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/server/email/core/helpers.js.map b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/server/email/core/helpers.js.map index 5775d5cdc6..72b0f4c5de 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/server/email/core/helpers.js.map +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/server/email/core/helpers.js.map @@ -1 +1 @@ -{"version":3,"file":"helpers.js","sourceRoot":"","sources":["../../../../server/email/core/helpers.ts"],"names":[],"mappings":"AAEA,cAAc;AACd,+EAA+E;AAC/E,mCAAmC;AACnC,oEAAoE;AACpE,MAAM,UAAU,eAAe,CAAC,EAC9B,KAAK,EACL,IAAI,GAIL;IACC,IAAI,IAAI,EAAE;QACR,OAAO,GAAG,IAAI,KAAK,KAAK,GAAG,CAAC;KAC7B;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,cAAc;AACd,MAAM,UAAU,mBAAmB;IACjC,OAAO;QACL,KAAK,EAAE,iBAAiB;QACxB,IAAI,EAAE,OAAO;KACd,CAAA;AACH,CAAC"} \ No newline at end of file +{"version":3,"file":"helpers.js","sourceRoot":"","sources":["../../../../server/email/core/helpers.ts"],"names":[],"mappings":"AAEA,cAAc;AACd,+EAA+E;AAC/E,mCAAmC;AACnC,oEAAoE;AACpE,MAAM,UAAU,eAAe,CAAC,EAC9B,KAAK,EACL,IAAI,GAIL;IACC,IAAI,IAAI,EAAE,CAAC;QACT,OAAO,GAAG,IAAI,KAAK,KAAK,GAAG,CAAC;IAC9B,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,cAAc;AACd,MAAM,UAAU,mBAAmB;IACjC,OAAO;QACL,KAAK,EAAE,iBAAiB;QACxB,IAAI,EAAE,OAAO;KACd,CAAA;AACH,CAAC"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/server/jobs/core/pgBoss/pgBoss.js.map b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/server/jobs/core/pgBoss/pgBoss.js.map index 6db706ac2b..ebe3e7b855 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/server/jobs/core/pgBoss/pgBoss.js.map +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/server/jobs/core/pgBoss/pgBoss.js.map @@ -1 +1 @@ -{"version":3,"file":"pgBoss.js","sourceRoot":"","sources":["../../../../../server/jobs/core/pgBoss/pgBoss.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,SAAS,CAAA;AAC5B,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAEpC,MAAM,IAAI,GAAG,YAAY,EAAE,CAAA;AAE3B,SAAS,YAAY;IACnB,IAAI,gBAAgB,GAAG;QACrB,gBAAgB,EAAE,MAAM,CAAC,WAAW;KACrC,CAAA;IAED,uFAAuF;IACvF,IAAI,OAAO,CAAC,GAAG,CAAC,mBAAmB,EAAE;QACnC,IAAI;YACF,gBAAgB,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAA;SAC/D;QAAC,WAAM;YACN,OAAO,CAAC,KAAK,CACX,4EAA4E,CAC7E,CAAA;SACF;KACF;IAED,OAAO,IAAI,MAAM,CAAC,gBAAgB,CAAC,CAAA;AACrC,CAAC;AAED,IAAI,oBAA4C,CAAA;AAChD,IAAI,mBAA2C,CAAA;AAC/C,cAAc;AACd,yEAAyE;AACzE,MAAM,CAAC,MAAM,aAAa,GAAG,IAAI,OAAO,CAAS,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;IACnE,oBAAoB,GAAG,OAAO,CAAA;IAC9B,mBAAmB,GAAG,MAAM,CAAA;AAC9B,CAAC,CAAC,CAAA;AAEF,IAAK,YAKJ;AALD,WAAK,YAAY;IACf,uCAAuB,CAAA;IACvB,qCAAqB,CAAA;IACrB,mCAAmB,CAAA;IACnB,+BAAe,CAAA;AACjB,CAAC,EALI,YAAY,KAAZ,YAAY,QAKhB;AAED,IAAI,YAAY,GAAiB,YAAY,CAAC,SAAS,CAAA;AAEvD,cAAc;AACd;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW;IAC/B,sEAAsE;IACtE,IAAI,YAAY,KAAK,YAAY,CAAC,SAAS,EAAE;QAC3C,OAAM;KACP;IACD,YAAY,GAAG,YAAY,CAAC,QAAQ,CAAA;IACpC,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAA;IAElC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAA;IACjD,IAAI;QACF,MAAM,IAAI,CAAC,KAAK,EAAE,CAAA;KACnB;IAAC,OAAO,KAAK,EAAE;QACd,OAAO,CAAC,KAAK,CAAC,0BAA0B,CAAC,CAAA;QACzC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;QACpB,YAAY,GAAG,YAAY,CAAC,KAAK,CAAA;QACjC,mBAAmB,CAAC,IAAI,CAAC,CAAA;QACzB,OAAM;KACP;IAED,oBAAoB,CAAC,IAAI,CAAC,CAAA;IAE1B,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAA;IAC/B,YAAY,GAAG,YAAY,CAAC,OAAO,CAAA;AACrC,CAAC"} \ No newline at end of file +{"version":3,"file":"pgBoss.js","sourceRoot":"","sources":["../../../../../server/jobs/core/pgBoss/pgBoss.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,SAAS,CAAA;AAC5B,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAEpC,MAAM,IAAI,GAAG,YAAY,EAAE,CAAA;AAE3B,SAAS,YAAY;IACnB,IAAI,gBAAgB,GAAG;QACrB,gBAAgB,EAAE,MAAM,CAAC,WAAW;KACrC,CAAA;IAED,uFAAuF;IACvF,IAAI,OAAO,CAAC,GAAG,CAAC,mBAAmB,EAAE,CAAC;QACpC,IAAI,CAAC;YACH,gBAAgB,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAA;QAChE,CAAC;QAAC,WAAM,CAAC;YACP,OAAO,CAAC,KAAK,CACX,4EAA4E,CAC7E,CAAA;QACH,CAAC;IACH,CAAC;IAED,OAAO,IAAI,MAAM,CAAC,gBAAgB,CAAC,CAAA;AACrC,CAAC;AAED,IAAI,oBAA4C,CAAA;AAChD,IAAI,mBAA2C,CAAA;AAC/C,cAAc;AACd,yEAAyE;AACzE,MAAM,CAAC,MAAM,aAAa,GAAG,IAAI,OAAO,CAAS,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;IACnE,oBAAoB,GAAG,OAAO,CAAA;IAC9B,mBAAmB,GAAG,MAAM,CAAA;AAC9B,CAAC,CAAC,CAAA;AAEF,IAAK,YAKJ;AALD,WAAK,YAAY;IACf,uCAAuB,CAAA;IACvB,qCAAqB,CAAA;IACrB,mCAAmB,CAAA;IACnB,+BAAe,CAAA;AACjB,CAAC,EALI,YAAY,KAAZ,YAAY,QAKhB;AAED,IAAI,YAAY,GAAiB,YAAY,CAAC,SAAS,CAAA;AAEvD,cAAc;AACd;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW;IAC/B,sEAAsE;IACtE,IAAI,YAAY,KAAK,YAAY,CAAC,SAAS,EAAE,CAAC;QAC5C,OAAM;IACR,CAAC;IACD,YAAY,GAAG,YAAY,CAAC,QAAQ,CAAA;IACpC,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAA;IAElC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAA;IACjD,IAAI,CAAC;QACH,MAAM,IAAI,CAAC,KAAK,EAAE,CAAA;IACpB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,0BAA0B,CAAC,CAAA;QACzC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;QACpB,YAAY,GAAG,YAAY,CAAC,KAAK,CAAA;QACjC,mBAAmB,CAAC,IAAI,CAAC,CAAA;QACzB,OAAM;IACR,CAAC;IAED,oBAAoB,CAAC,IAAI,CAAC,CAAA;IAE1B,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAA;IAC/B,YAAY,GAAG,YAAY,CAAC,OAAO,CAAA;AACrC,CAAC"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/server/jobs/core/pgBoss/pgBossJob.js.map b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/server/jobs/core/pgBoss/pgBossJob.js.map index 4b8eb79a28..7f0a871aaa 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/server/jobs/core/pgBoss/pgBossJob.js.map +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/server/jobs/core/pgBoss/pgBossJob.js.map @@ -1 +1 @@ -{"version":3,"file":"pgBossJob.js","sourceRoot":"","sources":["../../../../../server/jobs/core/pgBoss/pgBossJob.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"pgBossJob.js","sourceRoot":"","sources":["../../../../../server/jobs/core/pgBoss/pgBossJob.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/server/jobs/mySpecialJob.d.ts b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/server/jobs/mySpecialJob.d.ts index 4f9f5b1763..929b907b4b 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/server/jobs/mySpecialJob.d.ts +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/server/jobs/mySpecialJob.d.ts @@ -22,7 +22,7 @@ export declare const mySpecialJob: { state: "failed"; output: object; } | { - state: "retry" | "created" | "active" | "expired" | "cancelled"; + state: "retry" | "active" | "created" | "expired" | "cancelled"; output: null; } | { state: "completed"; diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/server/jobs/returnHelloJob.d.ts b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/server/jobs/returnHelloJob.d.ts index 8d6814af9d..2e16bc2084 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/server/jobs/returnHelloJob.d.ts +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/server/jobs/returnHelloJob.d.ts @@ -26,7 +26,7 @@ export declare const returnHelloJob: { state: "failed"; output: object; } | { - state: "retry" | "created" | "active" | "expired" | "cancelled"; + state: "retry" | "active" | "created" | "expired" | "cancelled"; output: null; } | { state: "completed"; diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/server/utils.js.map b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/server/utils.js.map index 3239be7b10..0bc5cd9384 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/server/utils.js.map +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/server/utils.js.map @@ -1 +1 @@ -{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../server/utils.ts"],"names":[],"mappings":"AAcA;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAC7B,UAIQ,EACR,EAAE,CACJ,KAAK,EAAE,GAA2B,EAAE,GAAa,EAAE,IAAkB,EAAE,EAAE;IACvE,IAAI;QACF,MAAM,UAAU,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,CAAA;KACjC;IAAC,OAAO,KAAK,EAAE;QACd,IAAI,CAAC,KAAK,CAAC,CAAA;KACZ;AACH,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,EAAU,EAAoB,EAAE,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAA"} \ No newline at end of file +{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../server/utils.ts"],"names":[],"mappings":"AAcA;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAC7B,UAIQ,EACR,EAAE,CACJ,KAAK,EAAE,GAA2B,EAAE,GAAa,EAAE,IAAkB,EAAE,EAAE;IACvE,IAAI,CAAC;QACH,MAAM,UAAU,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,CAAA;IAClC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,CAAC,KAAK,CAAC,CAAA;IACb,CAAC;AACH,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,EAAU,EAAoB,EAAE,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAA"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/universal/validators.js.map b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/universal/validators.js.map index 313c98cef4..f020413e43 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/universal/validators.js.map +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/universal/validators.js.map @@ -1 +1 @@ -{"version":3,"file":"validators.js","sourceRoot":"","sources":["../../universal/validators.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,kBAAkB,CAAC,MAAc;IAC7C,IAAI;QACA,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC;QAC5B;;;;;;UAME;QACF,OAAO,GAAG,CAAC,QAAQ,KAAK,OAAO,IAAI,GAAG,CAAC,QAAQ,KAAK,QAAQ,CAAC;KAChE;IAAC,OAAO,CAAC,EAAE;QACR,OAAO,KAAK,CAAC;KAChB;AACL,CAAC;AAED,MAAM,UAAU,0BAA0B,CAAC,KAAyB,EAAE,IAAY;IAC9E,IAAI,KAAK,IAAI,CAAC,kBAAkB,CAAC,KAAK,CAAC,EAAE;QACrC,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,+BAA+B,CAAC,CAAC;KAC3D;AACL,CAAC"} \ No newline at end of file +{"version":3,"file":"validators.js","sourceRoot":"","sources":["../../universal/validators.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,kBAAkB,CAAC,MAAc;IAC7C,IAAI,CAAC;QACD,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC;QAC5B;;;;;;UAME;QACF,OAAO,GAAG,CAAC,QAAQ,KAAK,OAAO,IAAI,GAAG,CAAC,QAAQ,KAAK,QAAQ,CAAC;IACjE,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACT,OAAO,KAAK,CAAC;IACjB,CAAC;AACL,CAAC;AAED,MAAM,UAAU,0BAA0B,CAAC,KAAyB,EAAE,IAAY;IAC9E,IAAI,KAAK,IAAI,CAAC,kBAAkB,CAAC,KAAK,CAAC,EAAE,CAAC;QACtC,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,+BAA+B,CAAC,CAAC;IAC5D,CAAC;AACL,CAAC"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/package.json b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/package.json index e3e8f3fcd0..e0a49d578b 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/package.json +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/package.json @@ -13,7 +13,6 @@ "axios": "^1.4.0", "express": "~4.18.1", "jsdom": "^21.1.1", - "jsonwebtoken": "^8.5.1", "lodash.merge": "^4.6.2", "lucia": "^3.0.1", "mitt": "3.0.0", diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/server/package.json b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/server/package.json index 5e682c8f16..3751cb8c6b 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/server/package.json +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/server/package.json @@ -6,7 +6,6 @@ "dotenv": "16.0.2", "express": "~4.18.1", "helmet": "^6.0.0", - "jsonwebtoken": "^8.5.1", "morgan": "~1.10.0", "passport": "0.6.0", "passport-google-oauth20": "2.0.0", diff --git a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/.waspchecksums b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/.waspchecksums index 3a23b9516d..351b1c914f 100644 --- a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/.waspchecksums +++ b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/.waspchecksums @@ -214,7 +214,7 @@ "file", "../out/sdk/wasp/package.json" ], - "9e51b91427d0b4d41b972033943939c0c66642354b39272d28088bea97a7ee24" + "59c5483e1079ca2ef0ede748d975ddd47050854c61d162c5d86843e7d48dd7da" ], [ [ @@ -473,7 +473,7 @@ "file", "server/package.json" ], - "b6f49a347b56b9c7215e65f2d982ff99c6e444c40e649b802bb1af3ead772d15" + "c33727afcd03aa83fbd2c4b213a05cf7a2c53525e3b1daa72521d8c1312033a5" ], [ [ diff --git a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/installedNpmDepsLog.json b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/installedNpmDepsLog.json index 0e542a4188..91b719d429 100644 --- a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/installedNpmDepsLog.json +++ b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/installedNpmDepsLog.json @@ -1 +1 @@ -{"_waspSdkNpmDeps":{"dependencies":[{"name":"@prisma/client","version":"4.16.2"},{"name":"prisma","version":"4.16.2"},{"name":"@tanstack/react-query","version":"^4.29.0"},{"name":"axios","version":"^1.4.0"},{"name":"express","version":"~4.18.1"},{"name":"jsonwebtoken","version":"^8.5.1"},{"name":"mitt","version":"3.0.0"},{"name":"react","version":"^18.2.0"},{"name":"lodash.merge","version":"^4.6.2"},{"name":"react-router-dom","version":"^5.3.3"},{"name":"react-hook-form","version":"^7.45.4"},{"name":"superjson","version":"^1.12.2"},{"name":"@types/express-serve-static-core","version":"^4.17.13"},{"name":"@types/react-router-dom","version":"^5.3.3"},{"name":"uuid","version":"^9.0.0"},{"name":"vitest","version":"^1.2.1"},{"name":"@vitest/ui","version":"^1.2.1"},{"name":"jsdom","version":"^21.1.1"},{"name":"@testing-library/react","version":"^14.1.2"},{"name":"@testing-library/jest-dom","version":"^6.3.0"},{"name":"msw","version":"^1.1.0"},{"name":"pg-boss","version":"^8.4.2"}],"devDependencies":[{"name":"@tsconfig/node18","version":"latest"}]},"_userNpmDeps":{"userDependencies":[{"name":"react","version":"^18.2.0"},{"name":"wasp","version":"file:.wasp/out/sdk/wasp"}],"userDevDependencies":[{"name":"@types/react","version":"^18.0.37"},{"name":"prisma","version":"4.16.2"},{"name":"typescript","version":"^5.1.0"},{"name":"vite","version":"^4.3.9"}]},"_waspFrameworkNpmDeps":{"npmDepsForWebApp":{"dependencies":[{"name":"@tanstack/react-query","version":"^4.29.0"},{"name":"axios","version":"^1.4.0"},{"name":"mitt","version":"3.0.0"},{"name":"react-dom","version":"^18.2.0"},{"name":"react-hook-form","version":"^7.45.4"},{"name":"react-router-dom","version":"^5.3.3"},{"name":"superjson","version":"^1.12.2"}],"devDependencies":[{"name":"@tsconfig/vite-react","version":"^2.0.0"},{"name":"@types/react-dom","version":"^18.0.11"},{"name":"@types/react-router-dom","version":"^5.3.3"},{"name":"@vitejs/plugin-react","version":"^4.2.1"},{"name":"dotenv","version":"^16.0.3"}]},"npmDepsForServer":{"dependencies":[{"name":"cookie-parser","version":"~1.4.6"},{"name":"cors","version":"^2.8.5"},{"name":"dotenv","version":"16.0.2"},{"name":"express","version":"~4.18.1"},{"name":"helmet","version":"^6.0.0"},{"name":"jsonwebtoken","version":"^8.5.1"},{"name":"morgan","version":"~1.10.0"},{"name":"rate-limiter-flexible","version":"^2.4.1"},{"name":"superjson","version":"^1.12.2"}],"devDependencies":[{"name":"@tsconfig/node18","version":"latest"},{"name":"@types/cors","version":"^2.8.5"},{"name":"@types/express","version":"^4.17.13"},{"name":"@types/express-serve-static-core","version":"^4.17.13"},{"name":"@types/node","version":"^18.0.0"},{"name":"nodemon","version":"^2.0.19"},{"name":"rollup","version":"^4.9.6"},{"name":"rollup-plugin-esbuild","version":"^6.1.1"},{"name":"standard","version":"^17.0.0"}]}}} \ No newline at end of file +{"_waspSdkNpmDeps":{"dependencies":[{"name":"@prisma/client","version":"4.16.2"},{"name":"prisma","version":"4.16.2"},{"name":"@tanstack/react-query","version":"^4.29.0"},{"name":"axios","version":"^1.4.0"},{"name":"express","version":"~4.18.1"},{"name":"mitt","version":"3.0.0"},{"name":"react","version":"^18.2.0"},{"name":"lodash.merge","version":"^4.6.2"},{"name":"react-router-dom","version":"^5.3.3"},{"name":"react-hook-form","version":"^7.45.4"},{"name":"superjson","version":"^1.12.2"},{"name":"@types/express-serve-static-core","version":"^4.17.13"},{"name":"@types/react-router-dom","version":"^5.3.3"},{"name":"uuid","version":"^9.0.0"},{"name":"vitest","version":"^1.2.1"},{"name":"@vitest/ui","version":"^1.2.1"},{"name":"jsdom","version":"^21.1.1"},{"name":"@testing-library/react","version":"^14.1.2"},{"name":"@testing-library/jest-dom","version":"^6.3.0"},{"name":"msw","version":"^1.1.0"},{"name":"pg-boss","version":"^8.4.2"}],"devDependencies":[{"name":"@tsconfig/node18","version":"latest"}]},"_userNpmDeps":{"userDependencies":[{"name":"react","version":"^18.2.0"},{"name":"wasp","version":"file:.wasp/out/sdk/wasp"}],"userDevDependencies":[{"name":"@types/react","version":"^18.0.37"},{"name":"prisma","version":"4.16.2"},{"name":"typescript","version":"^5.1.0"},{"name":"vite","version":"^4.3.9"}]},"_waspFrameworkNpmDeps":{"npmDepsForWebApp":{"dependencies":[{"name":"@tanstack/react-query","version":"^4.29.0"},{"name":"axios","version":"^1.4.0"},{"name":"mitt","version":"3.0.0"},{"name":"react-dom","version":"^18.2.0"},{"name":"react-hook-form","version":"^7.45.4"},{"name":"react-router-dom","version":"^5.3.3"},{"name":"superjson","version":"^1.12.2"}],"devDependencies":[{"name":"@tsconfig/vite-react","version":"^2.0.0"},{"name":"@types/react-dom","version":"^18.0.11"},{"name":"@types/react-router-dom","version":"^5.3.3"},{"name":"@vitejs/plugin-react","version":"^4.2.1"},{"name":"dotenv","version":"^16.0.3"}]},"npmDepsForServer":{"dependencies":[{"name":"cookie-parser","version":"~1.4.6"},{"name":"cors","version":"^2.8.5"},{"name":"dotenv","version":"16.0.2"},{"name":"express","version":"~4.18.1"},{"name":"helmet","version":"^6.0.0"},{"name":"morgan","version":"~1.10.0"},{"name":"rate-limiter-flexible","version":"^2.4.1"},{"name":"superjson","version":"^1.12.2"}],"devDependencies":[{"name":"@tsconfig/node18","version":"latest"},{"name":"@types/cors","version":"^2.8.5"},{"name":"@types/express","version":"^4.17.13"},{"name":"@types/express-serve-static-core","version":"^4.17.13"},{"name":"@types/node","version":"^18.0.0"},{"name":"nodemon","version":"^2.0.19"},{"name":"rollup","version":"^4.9.6"},{"name":"rollup-plugin-esbuild","version":"^6.1.1"},{"name":"standard","version":"^17.0.0"}]}}} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/api/index.js.map b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/api/index.js.map index b4ae2eba65..fab323a0b2 100644 --- a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/api/index.js.map +++ b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/api/index.js.map @@ -1 +1 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["../../api/index.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"index.js","sourceRoot":"","sources":["../../api/index.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/actions/core.js.map b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/actions/core.js.map index 5834336f1d..b13c7d6712 100644 --- a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/actions/core.js.map +++ b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/actions/core.js.map @@ -1 +1 @@ -{"version":3,"file":"core.js","sourceRoot":"","sources":["../../../../client/operations/actions/core.js"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAA;AACxE,OAAO,EACL,wBAAwB,EACxB,kBAAkB,GACnB,MAAM,0BAA0B,CAAA;AAEjC,cAAc;AACd,MAAM,UAAU,YAAY,CAAC,mBAAmB,EAAE,YAAY;IAC5D,MAAM,WAAW,GAAG,kBAAkB,CAAC,mBAAmB,CAAC,CAAA;IAE3D,KAAK,UAAU,cAAc,CAAC,IAAI,EAAE,mCAAmC;QACrE,wBAAwB,CAAC,mCAAmC,CAAC,CAAA;QAC7D,IAAI;YACF,yEAAyE;YACzE,wEAAwE;YACxE,kCAAkC;YAClC,OAAO,MAAM,aAAa,CAAC,WAAW,EAAE,IAAI,CAAC,CAAA;SAC9C;gBAAS;YACR,MAAM,kBAAkB,CAAC,YAAY,EAAE,mCAAmC,CAAC,CAAA;SAC5E;IACH,CAAC;IAED,0EAA0E;IAC1E,yEAAyE;IACzE,6EAA6E;IAC7E,yEAAyE;IACzE,gBAAgB;IAChB,EAAE;IACF,0EAA0E;IAC1E,8EAA8E;IAC9E,wCAAwC;IACxC,MAAM,MAAM,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC,cAAc,CAAC,IAAI,EAAE,EAAE,CAAC,CAAA;IACjD,MAAM,CAAC,QAAQ,GAAG,cAAc,CAAA;IAEhC,OAAO,MAAM,CAAA;AACf,CAAC"} \ No newline at end of file +{"version":3,"file":"core.js","sourceRoot":"","sources":["../../../../client/operations/actions/core.js"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAA;AACxE,OAAO,EACL,wBAAwB,EACxB,kBAAkB,GACnB,MAAM,0BAA0B,CAAA;AAEjC,cAAc;AACd,MAAM,UAAU,YAAY,CAAC,mBAAmB,EAAE,YAAY;IAC5D,MAAM,WAAW,GAAG,kBAAkB,CAAC,mBAAmB,CAAC,CAAA;IAE3D,KAAK,UAAU,cAAc,CAAC,IAAI,EAAE,mCAAmC;QACrE,wBAAwB,CAAC,mCAAmC,CAAC,CAAA;QAC7D,IAAI,CAAC;YACH,yEAAyE;YACzE,wEAAwE;YACxE,kCAAkC;YAClC,OAAO,MAAM,aAAa,CAAC,WAAW,EAAE,IAAI,CAAC,CAAA;QAC/C,CAAC;gBAAS,CAAC;YACT,MAAM,kBAAkB,CAAC,YAAY,EAAE,mCAAmC,CAAC,CAAA;QAC7E,CAAC;IACH,CAAC;IAED,0EAA0E;IAC1E,yEAAyE;IACzE,6EAA6E;IAC7E,yEAAyE;IACzE,gBAAgB;IAChB,EAAE;IACF,0EAA0E;IAC1E,8EAA8E;IAC9E,wCAAwC;IACxC,MAAM,MAAM,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC,cAAc,CAAC,IAAI,EAAE,EAAE,CAAC,CAAA;IACjD,MAAM,CAAC,QAAQ,GAAG,cAAc,CAAA;IAEhC,OAAO,MAAM,CAAA;AACf,CAAC"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/core.js.map b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/core.js.map index 68ea114aa9..20d72dc15e 100644 --- a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/core.js.map +++ b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/core.js.map @@ -1 +1 @@ -{"version":3,"file":"core.js","sourceRoot":"","sources":["../../../client/operations/core.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"core.js","sourceRoot":"","sources":["../../../client/operations/core.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/internal/index.js.map b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/internal/index.js.map index a4097ef8cb..a7cf9e445b 100644 --- a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/internal/index.js.map +++ b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/internal/index.js.map @@ -1 +1 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../client/operations/internal/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AACxC,OAAO,EACL,SAAS,IAAI,kBAAkB,EAC/B,WAAW,IAAI,oBAAoB,GACnC,MAAM,WAAW,CAAA;AAKnB,cAAc;AACd,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,cAA4D,EAAE,IAAS;IACzG,IAAI;QACF,MAAM,aAAa,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAA;QAC9C,MAAM,QAAQ,GAAG,MAAM,GAAG,CAAC,IAAI,CAAC,cAAc,CAAC,IAAI,EAAE,aAAa,CAAC,CAAA;QACnE,OAAO,oBAAoB,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAA;KAC3C;IAAC,OAAO,KAAK,EAAE;QACd,cAAc,CAAC,KAAK,CAAC,CAAA;KACtB;AACH,CAAC;AAED,cAAc;AACd,MAAM,UAAU,kBAAkB,CAAC,sBAA8B;IAC/D,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,sBAAsB,EAAE,EAAE,CAAA;AACxE,CAAC"} \ No newline at end of file +{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../client/operations/internal/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AACxC,OAAO,EACL,SAAS,IAAI,kBAAkB,EAC/B,WAAW,IAAI,oBAAoB,GACnC,MAAM,WAAW,CAAA;AAKnB,cAAc;AACd,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,cAA4D,EAAE,IAAS;IACzG,IAAI,CAAC;QACH,MAAM,aAAa,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAA;QAC9C,MAAM,QAAQ,GAAG,MAAM,GAAG,CAAC,IAAI,CAAC,cAAc,CAAC,IAAI,EAAE,aAAa,CAAC,CAAA;QACnE,OAAO,oBAAoB,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAA;IAC5C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,cAAc,CAAC,KAAK,CAAC,CAAA;IACvB,CAAC;AACH,CAAC;AAED,cAAc;AACd,MAAM,UAAU,kBAAkB,CAAC,sBAA8B;IAC/D,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,sBAAsB,EAAE,EAAE,CAAA;AACxE,CAAC"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/internal/resources.js.map b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/internal/resources.js.map index c91fecd3c7..61f8241c3e 100644 --- a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/internal/resources.js.map +++ b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/internal/resources.js.map @@ -1 +1 @@ -{"version":3,"file":"resources.js","sourceRoot":"","sources":["../../../../client/operations/internal/resources.js"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAA;AAC1D,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAA;AAC3D,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAA;AAEpD,kDAAkD;AAClD,mDAAmD;AACnD,iBAAiB;AACjB,MAAM,wBAAwB,GAAG,IAAI,GAAG,EAAE,CAAA;AAE1C,MAAM,cAAc,GAAG,qBAAqB,CAAC,YAAY,CAAC,CAAA;AAE1D,cAAc;AACd;;;;;GAKG;AACH,MAAM,UAAU,uBAAuB,CAAC,aAAa,EAAE,SAAS;IAC9D,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE;QAChC,IAAI,SAAS,GAAG,wBAAwB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;QACtD,IAAI,CAAC,SAAS,EAAE;YACd,SAAS,GAAG,IAAI,GAAG,EAAE,CAAA;YACrB,wBAAwB,CAAC,GAAG,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAA;SAClD;QACD,SAAS,CAAC,GAAG,CAAC,aAAa,CAAC,CAAA;KAC7B;AACH,CAAC;AAED,MAAM,UAAU,wBAAwB,CAAC,sBAAsB;IAC7D,sBAAsB,CAAC,OAAO,CAC5B,CAAC,EAAE,QAAQ,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC,cAAc,CAAC,GAAG,CAAC,QAAQ,EAAE,WAAW,CAAC,CACzE,CAAA;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,SAAS,EAAE,sBAAsB;IACxE,sBAAsB,CAAC,OAAO,CAAC,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,cAAc,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAA;IACjF,MAAM,sBAAsB,CAAC,SAAS,CAAC,CAAA;AACzC,CAAC;AAED,MAAM,UAAU,0BAA0B,CAAC,QAAQ;IACjD,OAAO,cAAc,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAA;AACnD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,0BAA0B;IAC9C,MAAM,WAAW,GAAG,MAAM,sBAAsB,CAAA;IAChD,wEAAwE;IACxE,8EAA8E;IAC9E,eAAe;IACf,iFAAiF;IACjF,6EAA6E;IAC7E,wFAAwF;IACxF,kFAAkF;IAClF,WAAW,CAAC,YAAY,EAAE,CAAA;IAC1B,6EAA6E;IAC7E,2DAA2D;IAC3D,WAAW,CAAC,aAAa,EAAE,CAAA;AAC7B,CAAC;AAED;;;GAGG;AACH,KAAK,UAAU,sBAAsB,CAAC,SAAS;IAC7C,MAAM,WAAW,GAAG,MAAM,sBAAsB,CAAA;IAEhD,MAAM,0BAA0B,GAAG,wBAAwB,CAAC,SAAS,CAAC,CAAA;IACtE,0BAA0B,CAAC,OAAO,CAChC,aAAa,CAAC,EAAE,CAAC,WAAW,CAAC,iBAAiB,CAAC,aAAa,CAAC,CAC9D,CAAA;AACH,CAAC;AAED;;;GAGG;AACH,SAAS,uBAAuB,CAAC,QAAQ;IACvC,OAAO,KAAK,CAAC,IAAI,CAAC,wBAAwB,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAA;AACjE,CAAC;AAED,SAAS,wBAAwB,CAAC,SAAS;IACzC,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,uBAAuB,CAAC,CAAC,CAAC,CAAA;AACxE,CAAC"} \ No newline at end of file +{"version":3,"file":"resources.js","sourceRoot":"","sources":["../../../../client/operations/internal/resources.js"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAA;AAC1D,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAA;AAC3D,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAA;AAEpD,kDAAkD;AAClD,mDAAmD;AACnD,iBAAiB;AACjB,MAAM,wBAAwB,GAAG,IAAI,GAAG,EAAE,CAAA;AAE1C,MAAM,cAAc,GAAG,qBAAqB,CAAC,YAAY,CAAC,CAAA;AAE1D,cAAc;AACd;;;;;GAKG;AACH,MAAM,UAAU,uBAAuB,CAAC,aAAa,EAAE,SAAS;IAC9D,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;QACjC,IAAI,SAAS,GAAG,wBAAwB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;QACtD,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,SAAS,GAAG,IAAI,GAAG,EAAE,CAAA;YACrB,wBAAwB,CAAC,GAAG,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAA;QACnD,CAAC;QACD,SAAS,CAAC,GAAG,CAAC,aAAa,CAAC,CAAA;IAC9B,CAAC;AACH,CAAC;AAED,MAAM,UAAU,wBAAwB,CAAC,sBAAsB;IAC7D,sBAAsB,CAAC,OAAO,CAC5B,CAAC,EAAE,QAAQ,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC,cAAc,CAAC,GAAG,CAAC,QAAQ,EAAE,WAAW,CAAC,CACzE,CAAA;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,SAAS,EAAE,sBAAsB;IACxE,sBAAsB,CAAC,OAAO,CAAC,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,cAAc,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAA;IACjF,MAAM,sBAAsB,CAAC,SAAS,CAAC,CAAA;AACzC,CAAC;AAED,MAAM,UAAU,0BAA0B,CAAC,QAAQ;IACjD,OAAO,cAAc,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAA;AACnD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,0BAA0B;IAC9C,MAAM,WAAW,GAAG,MAAM,sBAAsB,CAAA;IAChD,wEAAwE;IACxE,8EAA8E;IAC9E,eAAe;IACf,iFAAiF;IACjF,6EAA6E;IAC7E,wFAAwF;IACxF,kFAAkF;IAClF,WAAW,CAAC,YAAY,EAAE,CAAA;IAC1B,6EAA6E;IAC7E,2DAA2D;IAC3D,WAAW,CAAC,aAAa,EAAE,CAAA;AAC7B,CAAC;AAED;;;GAGG;AACH,KAAK,UAAU,sBAAsB,CAAC,SAAS;IAC7C,MAAM,WAAW,GAAG,MAAM,sBAAsB,CAAA;IAEhD,MAAM,0BAA0B,GAAG,wBAAwB,CAAC,SAAS,CAAC,CAAA;IACtE,0BAA0B,CAAC,OAAO,CAChC,aAAa,CAAC,EAAE,CAAC,WAAW,CAAC,iBAAiB,CAAC,aAAa,CAAC,CAC9D,CAAA;AACH,CAAC;AAED;;;GAGG;AACH,SAAS,uBAAuB,CAAC,QAAQ;IACvC,OAAO,KAAK,CAAC,IAAI,CAAC,wBAAwB,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAA;AACjE,CAAC;AAED,SAAS,wBAAwB,CAAC,SAAS;IACzC,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,uBAAuB,CAAC,CAAC,CAAC,CAAA;AACxE,CAAC"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/internal/updateHandlersMap.js.map b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/internal/updateHandlersMap.js.map index 7940fcd972..950c377452 100644 --- a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/internal/updateHandlersMap.js.map +++ b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/internal/updateHandlersMap.js.map @@ -1 +1 @@ -{"version":3,"file":"updateHandlersMap.js","sourceRoot":"","sources":["../../../../client/operations/internal/updateHandlersMap.js"],"names":[],"mappings":"AAAA,MAAM,UAAU,qBAAqB,CAAC,aAAa;IACjD,MAAM,cAAc,GAAG,IAAI,GAAG,EAAE,CAAA;IAEhC,SAAS,gBAAgB,CAAC,YAAY;QACpC,OAAO,cAAc,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC;IAChD,CAAC;IAED,SAAS,GAAG,CAAC,QAAQ,EAAE,WAAW;QAChC,MAAM,YAAY,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAA;QAC5C,MAAM,QAAQ,GAAG,gBAAgB,CAAC,YAAY,CAAC,CAAC;QAChD,cAAc,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC,GAAG,QAAQ,EAAE,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC,CAAC,CAAA;IAC5E,CAAC;IAED,SAAS,iBAAiB,CAAC,QAAQ;QACjC,MAAM,YAAY,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAA;QAC5C,OAAO,gBAAgB,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC,WAAW,CAAC,CAAA;IAC7E,CAAC;IAED,SAAS,MAAM,CAAC,gBAAgB;QAC9B,MAAM,YAAY,GAAG,aAAa,CAAC,gBAAgB,CAAC,CAAA;QACpD,MAAM,gBAAgB,GAAG,gBAAgB,CAAC,YAAY,CAAC,CAAC,MAAM,CAC5D,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,QAAQ,KAAK,gBAAgB,CAChD,CAAA;QAED,IAAI,gBAAgB,CAAC,MAAM,GAAG,CAAC,EAAE;YAC/B,cAAc,CAAC,GAAG,CAAC,YAAY,EAAE,gBAAgB,CAAC,CAAA;SACnD;aAAM;YACL,cAAc,CAAC,MAAM,CAAC,YAAY,CAAC,CAAA;SACpC;IACH,CAAC;IAED,OAAO;QACL,GAAG;QACH,MAAM;QACN,iBAAiB;KAClB,CAAA;AACH,CAAC"} \ No newline at end of file +{"version":3,"file":"updateHandlersMap.js","sourceRoot":"","sources":["../../../../client/operations/internal/updateHandlersMap.js"],"names":[],"mappings":"AAAA,MAAM,UAAU,qBAAqB,CAAC,aAAa;IACjD,MAAM,cAAc,GAAG,IAAI,GAAG,EAAE,CAAA;IAEhC,SAAS,gBAAgB,CAAC,YAAY;QACpC,OAAO,cAAc,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC;IAChD,CAAC;IAED,SAAS,GAAG,CAAC,QAAQ,EAAE,WAAW;QAChC,MAAM,YAAY,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAA;QAC5C,MAAM,QAAQ,GAAG,gBAAgB,CAAC,YAAY,CAAC,CAAC;QAChD,cAAc,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC,GAAG,QAAQ,EAAE,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC,CAAC,CAAA;IAC5E,CAAC;IAED,SAAS,iBAAiB,CAAC,QAAQ;QACjC,MAAM,YAAY,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAA;QAC5C,OAAO,gBAAgB,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC,WAAW,CAAC,CAAA;IAC7E,CAAC;IAED,SAAS,MAAM,CAAC,gBAAgB;QAC9B,MAAM,YAAY,GAAG,aAAa,CAAC,gBAAgB,CAAC,CAAA;QACpD,MAAM,gBAAgB,GAAG,gBAAgB,CAAC,YAAY,CAAC,CAAC,MAAM,CAC5D,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,QAAQ,KAAK,gBAAgB,CAChD,CAAA;QAED,IAAI,gBAAgB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAChC,cAAc,CAAC,GAAG,CAAC,YAAY,EAAE,gBAAgB,CAAC,CAAA;QACpD,CAAC;aAAM,CAAC;YACN,cAAc,CAAC,MAAM,CAAC,YAAY,CAAC,CAAA;QACrC,CAAC;IACH,CAAC;IAED,OAAO;QACL,GAAG;QACH,MAAM;QACN,iBAAiB;KAClB,CAAA;AACH,CAAC"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/queryClient.js.map b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/queryClient.js.map index 82e2b19139..15d3f12588 100644 --- a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/queryClient.js.map +++ b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/queryClient.js.map @@ -1 +1 @@ -{"version":3,"file":"queryClient.js","sourceRoot":"","sources":["../../../client/operations/queryClient.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAqB,MAAM,uBAAuB,CAAA;AAEtE,MAAM,wBAAwB,GAAG,EAAE,CAAC;AAEpC,IAAI,iBAAoC,EACtC,6BAAsD,EACtD,wBAAiC,CAAC;AAEpC,+BAA+B;AAC/B,MAAM,CAAC,MAAM,sBAAsB,GAAyB,IAAI,OAAO,CACrE,CAAC,OAAO,EAAE,EAAE;IACV,6BAA6B,GAAG,OAAO,CAAC;AAC1C,CAAC,CACF,CAAC;AAEF,aAAa;AACb,MAAM,UAAU,oBAAoB,CAAC,MAAyB;IAC5D,IAAI,wBAAwB,EAAE;QAC5B,MAAM,IAAI,KAAK,CACb,6DAA6D,CAC9D,CAAC;KACH;IAED,iBAAiB,GAAG,MAAM,CAAC;AAC7B,CAAC;AAED,+BAA+B;AAC/B,MAAM,UAAU,qBAAqB;IACnC,MAAM,WAAW,GAAG,IAAI,WAAW,CACjC,iBAAiB,aAAjB,iBAAiB,cAAjB,iBAAiB,GAAI,wBAAwB,CAC9C,CAAC;IACF,wBAAwB,GAAG,IAAI,CAAC;IAChC,6BAA6B,CAAC,WAAW,CAAC,CAAC;AAC7C,CAAC"} \ No newline at end of file +{"version":3,"file":"queryClient.js","sourceRoot":"","sources":["../../../client/operations/queryClient.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAqB,MAAM,uBAAuB,CAAA;AAEtE,MAAM,wBAAwB,GAAG,EAAE,CAAC;AAEpC,IAAI,iBAAoC,EACtC,6BAAsD,EACtD,wBAAiC,CAAC;AAEpC,+BAA+B;AAC/B,MAAM,CAAC,MAAM,sBAAsB,GAAyB,IAAI,OAAO,CACrE,CAAC,OAAO,EAAE,EAAE;IACV,6BAA6B,GAAG,OAAO,CAAC;AAC1C,CAAC,CACF,CAAC;AAEF,aAAa;AACb,MAAM,UAAU,oBAAoB,CAAC,MAAyB;IAC5D,IAAI,wBAAwB,EAAE,CAAC;QAC7B,MAAM,IAAI,KAAK,CACb,6DAA6D,CAC9D,CAAC;IACJ,CAAC;IAED,iBAAiB,GAAG,MAAM,CAAC;AAC7B,CAAC;AAED,+BAA+B;AAC/B,MAAM,UAAU,qBAAqB;IACnC,MAAM,WAAW,GAAG,IAAI,WAAW,CACjC,iBAAiB,aAAjB,iBAAiB,cAAjB,iBAAiB,GAAI,wBAAwB,CAC9C,CAAC;IACF,wBAAwB,GAAG,IAAI,CAAC;IAChC,6BAA6B,CAAC,WAAW,CAAC,CAAC;AAC7C,CAAC"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/router/linkHelpers.js.map b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/router/linkHelpers.js.map index 064bcce597..c532d39f5e 100644 --- a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/router/linkHelpers.js.map +++ b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/router/linkHelpers.js.map @@ -1 +1 @@ -{"version":3,"file":"linkHelpers.js","sourceRoot":"","sources":["../../../client/router/linkHelpers.ts"],"names":[],"mappings":"AAEA,cAAc;AACd,MAAM,UAAU,eAAe,CAC7B,IAAY,EACZ,MAAe,EACf,MAAe,EACf,IAAa;IAEb,MAAM,gBAAgB,GAAG,MAAM,CAAC,CAAC,CAAC,qBAAqB,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;IAC5E,MAAM,kBAAkB,GAAG,MAAM;QAC/B,CAAC,CAAC,IAAI,IAAI,eAAe,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,EAAE;QAC9C,CAAC,CAAC,EAAE,CAAA;IACN,MAAM,gBAAgB,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAA;IAC/C,OAAO,gBAAgB,GAAG,kBAAkB,GAAG,gBAAgB,CAAA;AACjE,CAAC;AAED,SAAS,qBAAqB,CAAC,IAAY,EAAE,MAAc;IACzD,SAAS,WAAW,CAAC,IAAY;QAC/B,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE;YACxB,MAAM,SAAS,GAAG,4BAA4B,CAAC,IAAI,CAAC,CAAC;YACrD,OAAO,MAAM,CAAC,SAAS,CAAC,CAAC;SAC1B;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,gBAAgB,GAAG,IAAI;SAC1B,KAAK,CAAC,GAAG,CAAC;SACV,GAAG,CAAC,WAAW,CAAC;SAChB,MAAM,CAAC,eAAe,CAAC;SACvB,IAAI,CAAC,GAAG,CAAC,CAAC;IAEb,OAAO,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,gBAAgB,EAAE,CAAC,CAAC,CAAC,gBAAgB,CAAC;AAC1E,CAAC;AAED,SAAS,eAAe,CAAC,IAAS;IAChC,OAAO,CAAC,CAAC,IAAI,CAAC;AAChB,CAAC;AAED,SAAS,4BAA4B,CAAC,WAAmB;IACvD,IAAI,WAAW,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE;QAC7B,OAAO,WAAW,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;KACjC;IACD,OAAO,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC9B,CAAC"} \ No newline at end of file +{"version":3,"file":"linkHelpers.js","sourceRoot":"","sources":["../../../client/router/linkHelpers.ts"],"names":[],"mappings":"AAEA,cAAc;AACd,MAAM,UAAU,eAAe,CAC7B,IAAY,EACZ,MAAe,EACf,MAAe,EACf,IAAa;IAEb,MAAM,gBAAgB,GAAG,MAAM,CAAC,CAAC,CAAC,qBAAqB,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;IAC5E,MAAM,kBAAkB,GAAG,MAAM;QAC/B,CAAC,CAAC,IAAI,IAAI,eAAe,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,EAAE;QAC9C,CAAC,CAAC,EAAE,CAAA;IACN,MAAM,gBAAgB,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAA;IAC/C,OAAO,gBAAgB,GAAG,kBAAkB,GAAG,gBAAgB,CAAA;AACjE,CAAC;AAED,SAAS,qBAAqB,CAAC,IAAY,EAAE,MAAc;IACzD,SAAS,WAAW,CAAC,IAAY;QAC/B,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YACzB,MAAM,SAAS,GAAG,4BAA4B,CAAC,IAAI,CAAC,CAAC;YACrD,OAAO,MAAM,CAAC,SAAS,CAAC,CAAC;QAC3B,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,gBAAgB,GAAG,IAAI;SAC1B,KAAK,CAAC,GAAG,CAAC;SACV,GAAG,CAAC,WAAW,CAAC;SAChB,MAAM,CAAC,eAAe,CAAC;SACvB,IAAI,CAAC,GAAG,CAAC,CAAC;IAEb,OAAO,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,gBAAgB,EAAE,CAAC,CAAC,CAAC,gBAAgB,CAAC;AAC1E,CAAC;AAED,SAAS,eAAe,CAAC,IAAS;IAChC,OAAO,CAAC,CAAC,IAAI,CAAC;AAChB,CAAC;AAED,SAAS,4BAA4B,CAAC,WAAmB;IACvD,IAAI,WAAW,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QAC9B,OAAO,WAAW,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAClC,CAAC;IACD,OAAO,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC9B,CAAC"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/test/vitest/helpers.jsx.map b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/test/vitest/helpers.jsx.map index b7ab2a906f..375c4629a2 100644 --- a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/test/vitest/helpers.jsx.map +++ b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/test/vitest/helpers.jsx.map @@ -1 +1 @@ -{"version":3,"file":"helpers.jsx","sourceRoot":"","sources":["../../../../client/test/vitest/helpers.tsx"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"helpers.jsx","sourceRoot":"","sources":["../../../../client/test/vitest/helpers.tsx"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/core/storage.js.map b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/core/storage.js.map index b7cd5db441..73a6773d4f 100644 --- a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/core/storage.js.map +++ b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/core/storage.js.map @@ -1 +1 @@ -{"version":3,"file":"storage.js","sourceRoot":"","sources":["../../core/storage.ts"],"names":[],"mappings":"AAQA,SAAS,2BAA2B,CAAC,MAAc;IACjD,SAAS,cAAc,CAAC,GAAW;QACjC,OAAO,GAAG,MAAM,IAAI,GAAG,EAAE,CAAA;IAC3B,CAAC;IAED,OAAO;QACL,cAAc;QACd,GAAG,CAAC,GAAG,EAAE,KAAK;YACZ,6BAA6B,EAAE,CAAA;YAC/B,YAAY,CAAC,OAAO,CAAC,cAAc,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAA;QAClE,CAAC;QACD,GAAG,CAAC,GAAG;YACL,6BAA6B,EAAE,CAAA;YAC/B,MAAM,KAAK,GAAG,YAAY,CAAC,OAAO,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAA;YACvD,IAAI;gBACF,OAAO,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;aAC7C;YAAC,OAAO,CAAM,EAAE;gBACf,OAAO,SAAS,CAAA;aACjB;QACH,CAAC;QACD,MAAM,CAAC,GAAG;YACR,6BAA6B,EAAE,CAAA;YAC/B,YAAY,CAAC,UAAU,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAA;QAC9C,CAAC;QACD,KAAK;YACH,6BAA6B,EAAE,CAAA;YAC/B,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE;gBACxC,IAAI,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE;oBAC1B,YAAY,CAAC,UAAU,CAAC,GAAG,CAAC,CAAA;iBAC7B;YACH,CAAC,CAAC,CAAA;QACJ,CAAC;KACF,CAAA;AACH,CAAC;AAED,MAAM,CAAC,MAAM,OAAO,GAAG,2BAA2B,CAAC,MAAM,CAAC,CAAA;AAE1D,SAAS,6BAA6B;IACpC,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE;QACxB,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAA;KACnD;AACH,CAAC"} \ No newline at end of file +{"version":3,"file":"storage.js","sourceRoot":"","sources":["../../core/storage.ts"],"names":[],"mappings":"AAQA,SAAS,2BAA2B,CAAC,MAAc;IACjD,SAAS,cAAc,CAAC,GAAW;QACjC,OAAO,GAAG,MAAM,IAAI,GAAG,EAAE,CAAA;IAC3B,CAAC;IAED,OAAO;QACL,cAAc;QACd,GAAG,CAAC,GAAG,EAAE,KAAK;YACZ,6BAA6B,EAAE,CAAA;YAC/B,YAAY,CAAC,OAAO,CAAC,cAAc,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAA;QAClE,CAAC;QACD,GAAG,CAAC,GAAG;YACL,6BAA6B,EAAE,CAAA;YAC/B,MAAM,KAAK,GAAG,YAAY,CAAC,OAAO,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAA;YACvD,IAAI,CAAC;gBACH,OAAO,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;YAC9C,CAAC;YAAC,OAAO,CAAM,EAAE,CAAC;gBAChB,OAAO,SAAS,CAAA;YAClB,CAAC;QACH,CAAC;QACD,MAAM,CAAC,GAAG;YACR,6BAA6B,EAAE,CAAA;YAC/B,YAAY,CAAC,UAAU,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAA;QAC9C,CAAC;QACD,KAAK;YACH,6BAA6B,EAAE,CAAA;YAC/B,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE;gBACxC,IAAI,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;oBAC3B,YAAY,CAAC,UAAU,CAAC,GAAG,CAAC,CAAA;gBAC9B,CAAC;YACH,CAAC,CAAC,CAAA;QACJ,CAAC;KACF,CAAA;AACH,CAAC;AAED,MAAM,CAAC,MAAM,OAAO,GAAG,2BAA2B,CAAC,MAAM,CAAC,CAAA;AAE1D,SAAS,6BAA6B;IACpC,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAA;IACpD,CAAC;AACH,CAAC"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/server/HttpError.js.map b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/server/HttpError.js.map index 34064e924c..3cc7095281 100644 --- a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/server/HttpError.js.map +++ b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/server/HttpError.js.map @@ -1 +1 @@ -{"version":3,"file":"HttpError.js","sourceRoot":"","sources":["../../server/HttpError.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,SAAU,SAAQ,KAAK;IAIlC,YAAa,UAAkB,EAAE,OAAgB,EAAE,IAA8B,EAAE,GAAG,MAAiB;QACrG,KAAK,CAAC,OAAO,EAAE,GAAG,MAAM,CAAC,CAAA;QAEzB,IAAI,KAAK,CAAC,iBAAiB,EAAE;YAC3B,KAAK,CAAC,iBAAiB,CAAC,IAAI,EAAE,SAAS,CAAC,CAAA;SACzC;QAED,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,CAAA;QAEjC,IAAI,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC,IAAI,UAAU,IAAI,GAAG,IAAI,UAAU,GAAG,GAAG,CAAC,EAAE;YAC5E,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAA;SACrE;QACD,IAAI,CAAC,UAAU,GAAG,UAAU,CAAA;QAE5B,IAAI,IAAI,EAAE;YACR,IAAI,CAAC,IAAI,GAAG,IAAI,CAAA;SACjB;IACH,CAAC;CACF"} \ No newline at end of file +{"version":3,"file":"HttpError.js","sourceRoot":"","sources":["../../server/HttpError.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,SAAU,SAAQ,KAAK;IAIlC,YAAa,UAAkB,EAAE,OAAgB,EAAE,IAA8B,EAAE,GAAG,MAAiB;QACrG,KAAK,CAAC,OAAO,EAAE,GAAG,MAAM,CAAC,CAAA;QAEzB,IAAI,KAAK,CAAC,iBAAiB,EAAE,CAAC;YAC5B,KAAK,CAAC,iBAAiB,CAAC,IAAI,EAAE,SAAS,CAAC,CAAA;QAC1C,CAAC;QAED,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,CAAA;QAEjC,IAAI,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC,IAAI,UAAU,IAAI,GAAG,IAAI,UAAU,GAAG,GAAG,CAAC,EAAE,CAAC;YAC7E,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAA;QACtE,CAAC;QACD,IAAI,CAAC,UAAU,GAAG,UAAU,CAAA;QAE5B,IAAI,IAAI,EAAE,CAAC;YACT,IAAI,CAAC,IAAI,GAAG,IAAI,CAAA;QAClB,CAAC;IACH,CAAC;CACF"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/server/jobs/core/pgBoss/pgBoss.js.map b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/server/jobs/core/pgBoss/pgBoss.js.map index 6db706ac2b..ebe3e7b855 100644 --- a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/server/jobs/core/pgBoss/pgBoss.js.map +++ b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/server/jobs/core/pgBoss/pgBoss.js.map @@ -1 +1 @@ -{"version":3,"file":"pgBoss.js","sourceRoot":"","sources":["../../../../../server/jobs/core/pgBoss/pgBoss.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,SAAS,CAAA;AAC5B,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAEpC,MAAM,IAAI,GAAG,YAAY,EAAE,CAAA;AAE3B,SAAS,YAAY;IACnB,IAAI,gBAAgB,GAAG;QACrB,gBAAgB,EAAE,MAAM,CAAC,WAAW;KACrC,CAAA;IAED,uFAAuF;IACvF,IAAI,OAAO,CAAC,GAAG,CAAC,mBAAmB,EAAE;QACnC,IAAI;YACF,gBAAgB,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAA;SAC/D;QAAC,WAAM;YACN,OAAO,CAAC,KAAK,CACX,4EAA4E,CAC7E,CAAA;SACF;KACF;IAED,OAAO,IAAI,MAAM,CAAC,gBAAgB,CAAC,CAAA;AACrC,CAAC;AAED,IAAI,oBAA4C,CAAA;AAChD,IAAI,mBAA2C,CAAA;AAC/C,cAAc;AACd,yEAAyE;AACzE,MAAM,CAAC,MAAM,aAAa,GAAG,IAAI,OAAO,CAAS,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;IACnE,oBAAoB,GAAG,OAAO,CAAA;IAC9B,mBAAmB,GAAG,MAAM,CAAA;AAC9B,CAAC,CAAC,CAAA;AAEF,IAAK,YAKJ;AALD,WAAK,YAAY;IACf,uCAAuB,CAAA;IACvB,qCAAqB,CAAA;IACrB,mCAAmB,CAAA;IACnB,+BAAe,CAAA;AACjB,CAAC,EALI,YAAY,KAAZ,YAAY,QAKhB;AAED,IAAI,YAAY,GAAiB,YAAY,CAAC,SAAS,CAAA;AAEvD,cAAc;AACd;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW;IAC/B,sEAAsE;IACtE,IAAI,YAAY,KAAK,YAAY,CAAC,SAAS,EAAE;QAC3C,OAAM;KACP;IACD,YAAY,GAAG,YAAY,CAAC,QAAQ,CAAA;IACpC,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAA;IAElC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAA;IACjD,IAAI;QACF,MAAM,IAAI,CAAC,KAAK,EAAE,CAAA;KACnB;IAAC,OAAO,KAAK,EAAE;QACd,OAAO,CAAC,KAAK,CAAC,0BAA0B,CAAC,CAAA;QACzC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;QACpB,YAAY,GAAG,YAAY,CAAC,KAAK,CAAA;QACjC,mBAAmB,CAAC,IAAI,CAAC,CAAA;QACzB,OAAM;KACP;IAED,oBAAoB,CAAC,IAAI,CAAC,CAAA;IAE1B,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAA;IAC/B,YAAY,GAAG,YAAY,CAAC,OAAO,CAAA;AACrC,CAAC"} \ No newline at end of file +{"version":3,"file":"pgBoss.js","sourceRoot":"","sources":["../../../../../server/jobs/core/pgBoss/pgBoss.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,SAAS,CAAA;AAC5B,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAEpC,MAAM,IAAI,GAAG,YAAY,EAAE,CAAA;AAE3B,SAAS,YAAY;IACnB,IAAI,gBAAgB,GAAG;QACrB,gBAAgB,EAAE,MAAM,CAAC,WAAW;KACrC,CAAA;IAED,uFAAuF;IACvF,IAAI,OAAO,CAAC,GAAG,CAAC,mBAAmB,EAAE,CAAC;QACpC,IAAI,CAAC;YACH,gBAAgB,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAA;QAChE,CAAC;QAAC,WAAM,CAAC;YACP,OAAO,CAAC,KAAK,CACX,4EAA4E,CAC7E,CAAA;QACH,CAAC;IACH,CAAC;IAED,OAAO,IAAI,MAAM,CAAC,gBAAgB,CAAC,CAAA;AACrC,CAAC;AAED,IAAI,oBAA4C,CAAA;AAChD,IAAI,mBAA2C,CAAA;AAC/C,cAAc;AACd,yEAAyE;AACzE,MAAM,CAAC,MAAM,aAAa,GAAG,IAAI,OAAO,CAAS,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;IACnE,oBAAoB,GAAG,OAAO,CAAA;IAC9B,mBAAmB,GAAG,MAAM,CAAA;AAC9B,CAAC,CAAC,CAAA;AAEF,IAAK,YAKJ;AALD,WAAK,YAAY;IACf,uCAAuB,CAAA;IACvB,qCAAqB,CAAA;IACrB,mCAAmB,CAAA;IACnB,+BAAe,CAAA;AACjB,CAAC,EALI,YAAY,KAAZ,YAAY,QAKhB;AAED,IAAI,YAAY,GAAiB,YAAY,CAAC,SAAS,CAAA;AAEvD,cAAc;AACd;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW;IAC/B,sEAAsE;IACtE,IAAI,YAAY,KAAK,YAAY,CAAC,SAAS,EAAE,CAAC;QAC5C,OAAM;IACR,CAAC;IACD,YAAY,GAAG,YAAY,CAAC,QAAQ,CAAA;IACpC,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAA;IAElC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAA;IACjD,IAAI,CAAC;QACH,MAAM,IAAI,CAAC,KAAK,EAAE,CAAA;IACpB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,0BAA0B,CAAC,CAAA;QACzC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;QACpB,YAAY,GAAG,YAAY,CAAC,KAAK,CAAA;QACjC,mBAAmB,CAAC,IAAI,CAAC,CAAA;QACzB,OAAM;IACR,CAAC;IAED,oBAAoB,CAAC,IAAI,CAAC,CAAA;IAE1B,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAA;IAC/B,YAAY,GAAG,YAAY,CAAC,OAAO,CAAA;AACrC,CAAC"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/server/jobs/core/pgBoss/pgBossJob.js.map b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/server/jobs/core/pgBoss/pgBossJob.js.map index 4b8eb79a28..7f0a871aaa 100644 --- a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/server/jobs/core/pgBoss/pgBossJob.js.map +++ b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/server/jobs/core/pgBoss/pgBossJob.js.map @@ -1 +1 @@ -{"version":3,"file":"pgBossJob.js","sourceRoot":"","sources":["../../../../../server/jobs/core/pgBoss/pgBossJob.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"pgBossJob.js","sourceRoot":"","sources":["../../../../../server/jobs/core/pgBoss/pgBossJob.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/server/jobs/mySpecialJob.d.ts b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/server/jobs/mySpecialJob.d.ts index 4f9f5b1763..929b907b4b 100644 --- a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/server/jobs/mySpecialJob.d.ts +++ b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/server/jobs/mySpecialJob.d.ts @@ -22,7 +22,7 @@ export declare const mySpecialJob: { state: "failed"; output: object; } | { - state: "retry" | "created" | "active" | "expired" | "cancelled"; + state: "retry" | "active" | "created" | "expired" | "cancelled"; output: null; } | { state: "completed"; diff --git a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/server/utils.js.map b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/server/utils.js.map index f3af561141..17121f586d 100644 --- a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/server/utils.js.map +++ b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/server/utils.js.map @@ -1 +1 @@ -{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../server/utils.ts"],"names":[],"mappings":"AAWA;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAC7B,UAIQ,EACR,EAAE,CACJ,KAAK,EAAE,GAA2B,EAAE,GAAa,EAAE,IAAkB,EAAE,EAAE;IACvE,IAAI;QACF,MAAM,UAAU,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,CAAA;KACjC;IAAC,OAAO,KAAK,EAAE;QACd,IAAI,CAAC,KAAK,CAAC,CAAA;KACZ;AACH,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,EAAU,EAAoB,EAAE,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAA"} \ No newline at end of file +{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../server/utils.ts"],"names":[],"mappings":"AAWA;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAC7B,UAIQ,EACR,EAAE,CACJ,KAAK,EAAE,GAA2B,EAAE,GAAa,EAAE,IAAkB,EAAE,EAAE;IACvE,IAAI,CAAC;QACH,MAAM,UAAU,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,CAAA;IAClC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,CAAC,KAAK,CAAC,CAAA;IACb,CAAC;AACH,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,EAAU,EAAoB,EAAE,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAA"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/universal/validators.js.map b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/universal/validators.js.map index 313c98cef4..f020413e43 100644 --- a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/universal/validators.js.map +++ b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/universal/validators.js.map @@ -1 +1 @@ -{"version":3,"file":"validators.js","sourceRoot":"","sources":["../../universal/validators.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,kBAAkB,CAAC,MAAc;IAC7C,IAAI;QACA,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC;QAC5B;;;;;;UAME;QACF,OAAO,GAAG,CAAC,QAAQ,KAAK,OAAO,IAAI,GAAG,CAAC,QAAQ,KAAK,QAAQ,CAAC;KAChE;IAAC,OAAO,CAAC,EAAE;QACR,OAAO,KAAK,CAAC;KAChB;AACL,CAAC;AAED,MAAM,UAAU,0BAA0B,CAAC,KAAyB,EAAE,IAAY;IAC9E,IAAI,KAAK,IAAI,CAAC,kBAAkB,CAAC,KAAK,CAAC,EAAE;QACrC,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,+BAA+B,CAAC,CAAC;KAC3D;AACL,CAAC"} \ No newline at end of file +{"version":3,"file":"validators.js","sourceRoot":"","sources":["../../universal/validators.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,kBAAkB,CAAC,MAAc;IAC7C,IAAI,CAAC;QACD,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC;QAC5B;;;;;;UAME;QACF,OAAO,GAAG,CAAC,QAAQ,KAAK,OAAO,IAAI,GAAG,CAAC,QAAQ,KAAK,QAAQ,CAAC;IACjE,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACT,OAAO,KAAK,CAAC;IACjB,CAAC;AACL,CAAC;AAED,MAAM,UAAU,0BAA0B,CAAC,KAAyB,EAAE,IAAY;IAC9E,IAAI,KAAK,IAAI,CAAC,kBAAkB,CAAC,KAAK,CAAC,EAAE,CAAC;QACtC,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,+BAA+B,CAAC,CAAC;IAC5D,CAAC;AACL,CAAC"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/package.json b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/package.json index e8c735e8e8..ea215ce5d8 100644 --- a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/package.json +++ b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/package.json @@ -10,7 +10,6 @@ "axios": "^1.4.0", "express": "~4.18.1", "jsdom": "^21.1.1", - "jsonwebtoken": "^8.5.1", "lodash.merge": "^4.6.2", "mitt": "3.0.0", "msw": "^1.1.0", diff --git a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/server/package.json b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/server/package.json index 009928aa42..af6031d33e 100644 --- a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/server/package.json +++ b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/server/package.json @@ -6,7 +6,6 @@ "dotenv": "16.0.2", "express": "~4.18.1", "helmet": "^6.0.0", - "jsonwebtoken": "^8.5.1", "morgan": "~1.10.0", "rate-limiter-flexible": "^2.4.1", "superjson": "^1.12.2" diff --git a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/.waspchecksums b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/.waspchecksums index 9cc3698e59..7d035b56e8 100644 --- a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/.waspchecksums +++ b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/.waspchecksums @@ -207,7 +207,7 @@ "file", "../out/sdk/wasp/package.json" ], - "c955fa158905668984f65806b587b8455abc60ef82807bfd7137a3e7dc839902" + "d0db918bf9df0766992ba13933d847853b330e3b601e5f367c3ad25eaecddc87" ], [ [ @@ -417,7 +417,7 @@ "file", "server/package.json" ], - "5ac54ac0cfcfc05435a68b009c88c1e38220787699871411e0c533a76dbe701b" + "204a25f8a86edd2b492f841d2314c510a8f450205620427bb52de7d3ebb1ea1c" ], [ [ diff --git a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/installedNpmDepsLog.json b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/installedNpmDepsLog.json index 4b37fb6e15..7880e96505 100644 --- a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/installedNpmDepsLog.json +++ b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/installedNpmDepsLog.json @@ -1 +1 @@ -{"_waspSdkNpmDeps":{"dependencies":[{"name":"@prisma/client","version":"4.16.2"},{"name":"prisma","version":"4.16.2"},{"name":"@tanstack/react-query","version":"^4.29.0"},{"name":"axios","version":"^1.4.0"},{"name":"express","version":"~4.18.1"},{"name":"jsonwebtoken","version":"^8.5.1"},{"name":"mitt","version":"3.0.0"},{"name":"react","version":"^18.2.0"},{"name":"lodash.merge","version":"^4.6.2"},{"name":"react-router-dom","version":"^5.3.3"},{"name":"react-hook-form","version":"^7.45.4"},{"name":"superjson","version":"^1.12.2"},{"name":"@types/express-serve-static-core","version":"^4.17.13"},{"name":"@types/react-router-dom","version":"^5.3.3"},{"name":"uuid","version":"^9.0.0"},{"name":"vitest","version":"^1.2.1"},{"name":"@vitest/ui","version":"^1.2.1"},{"name":"jsdom","version":"^21.1.1"},{"name":"@testing-library/react","version":"^14.1.2"},{"name":"@testing-library/jest-dom","version":"^6.3.0"},{"name":"msw","version":"^1.1.0"}],"devDependencies":[{"name":"@tsconfig/node18","version":"latest"}]},"_userNpmDeps":{"userDependencies":[{"name":"react","version":"^18.2.0"},{"name":"wasp","version":"file:.wasp/out/sdk/wasp"}],"userDevDependencies":[{"name":"@types/react","version":"^18.0.37"},{"name":"prisma","version":"4.16.2"},{"name":"typescript","version":"^5.1.0"},{"name":"vite","version":"^4.3.9"}]},"_waspFrameworkNpmDeps":{"npmDepsForWebApp":{"dependencies":[{"name":"@tanstack/react-query","version":"^4.29.0"},{"name":"axios","version":"^1.4.0"},{"name":"mitt","version":"3.0.0"},{"name":"react-dom","version":"^18.2.0"},{"name":"react-hook-form","version":"^7.45.4"},{"name":"react-router-dom","version":"^5.3.3"},{"name":"superjson","version":"^1.12.2"}],"devDependencies":[{"name":"@tsconfig/vite-react","version":"^2.0.0"},{"name":"@types/react-dom","version":"^18.0.11"},{"name":"@types/react-router-dom","version":"^5.3.3"},{"name":"@vitejs/plugin-react","version":"^4.2.1"},{"name":"dotenv","version":"^16.0.3"}]},"npmDepsForServer":{"dependencies":[{"name":"cookie-parser","version":"~1.4.6"},{"name":"cors","version":"^2.8.5"},{"name":"dotenv","version":"16.0.2"},{"name":"express","version":"~4.18.1"},{"name":"helmet","version":"^6.0.0"},{"name":"jsonwebtoken","version":"^8.5.1"},{"name":"morgan","version":"~1.10.0"},{"name":"rate-limiter-flexible","version":"^2.4.1"},{"name":"superjson","version":"^1.12.2"}],"devDependencies":[{"name":"@tsconfig/node18","version":"latest"},{"name":"@types/cors","version":"^2.8.5"},{"name":"@types/express","version":"^4.17.13"},{"name":"@types/express-serve-static-core","version":"^4.17.13"},{"name":"@types/node","version":"^18.0.0"},{"name":"nodemon","version":"^2.0.19"},{"name":"rollup","version":"^4.9.6"},{"name":"rollup-plugin-esbuild","version":"^6.1.1"},{"name":"standard","version":"^17.0.0"}]}}} \ No newline at end of file +{"_waspSdkNpmDeps":{"dependencies":[{"name":"@prisma/client","version":"4.16.2"},{"name":"prisma","version":"4.16.2"},{"name":"@tanstack/react-query","version":"^4.29.0"},{"name":"axios","version":"^1.4.0"},{"name":"express","version":"~4.18.1"},{"name":"mitt","version":"3.0.0"},{"name":"react","version":"^18.2.0"},{"name":"lodash.merge","version":"^4.6.2"},{"name":"react-router-dom","version":"^5.3.3"},{"name":"react-hook-form","version":"^7.45.4"},{"name":"superjson","version":"^1.12.2"},{"name":"@types/express-serve-static-core","version":"^4.17.13"},{"name":"@types/react-router-dom","version":"^5.3.3"},{"name":"uuid","version":"^9.0.0"},{"name":"vitest","version":"^1.2.1"},{"name":"@vitest/ui","version":"^1.2.1"},{"name":"jsdom","version":"^21.1.1"},{"name":"@testing-library/react","version":"^14.1.2"},{"name":"@testing-library/jest-dom","version":"^6.3.0"},{"name":"msw","version":"^1.1.0"}],"devDependencies":[{"name":"@tsconfig/node18","version":"latest"}]},"_userNpmDeps":{"userDependencies":[{"name":"react","version":"^18.2.0"},{"name":"wasp","version":"file:.wasp/out/sdk/wasp"}],"userDevDependencies":[{"name":"@types/react","version":"^18.0.37"},{"name":"prisma","version":"4.16.2"},{"name":"typescript","version":"^5.1.0"},{"name":"vite","version":"^4.3.9"}]},"_waspFrameworkNpmDeps":{"npmDepsForWebApp":{"dependencies":[{"name":"@tanstack/react-query","version":"^4.29.0"},{"name":"axios","version":"^1.4.0"},{"name":"mitt","version":"3.0.0"},{"name":"react-dom","version":"^18.2.0"},{"name":"react-hook-form","version":"^7.45.4"},{"name":"react-router-dom","version":"^5.3.3"},{"name":"superjson","version":"^1.12.2"}],"devDependencies":[{"name":"@tsconfig/vite-react","version":"^2.0.0"},{"name":"@types/react-dom","version":"^18.0.11"},{"name":"@types/react-router-dom","version":"^5.3.3"},{"name":"@vitejs/plugin-react","version":"^4.2.1"},{"name":"dotenv","version":"^16.0.3"}]},"npmDepsForServer":{"dependencies":[{"name":"cookie-parser","version":"~1.4.6"},{"name":"cors","version":"^2.8.5"},{"name":"dotenv","version":"16.0.2"},{"name":"express","version":"~4.18.1"},{"name":"helmet","version":"^6.0.0"},{"name":"morgan","version":"~1.10.0"},{"name":"rate-limiter-flexible","version":"^2.4.1"},{"name":"superjson","version":"^1.12.2"}],"devDependencies":[{"name":"@tsconfig/node18","version":"latest"},{"name":"@types/cors","version":"^2.8.5"},{"name":"@types/express","version":"^4.17.13"},{"name":"@types/express-serve-static-core","version":"^4.17.13"},{"name":"@types/node","version":"^18.0.0"},{"name":"nodemon","version":"^2.0.19"},{"name":"rollup","version":"^4.9.6"},{"name":"rollup-plugin-esbuild","version":"^6.1.1"},{"name":"standard","version":"^17.0.0"}]}}} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/api/index.js.map b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/api/index.js.map index b4ae2eba65..fab323a0b2 100644 --- a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/api/index.js.map +++ b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/api/index.js.map @@ -1 +1 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["../../api/index.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"index.js","sourceRoot":"","sources":["../../api/index.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/actions/core.js.map b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/actions/core.js.map index 5834336f1d..b13c7d6712 100644 --- a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/actions/core.js.map +++ b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/actions/core.js.map @@ -1 +1 @@ -{"version":3,"file":"core.js","sourceRoot":"","sources":["../../../../client/operations/actions/core.js"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAA;AACxE,OAAO,EACL,wBAAwB,EACxB,kBAAkB,GACnB,MAAM,0BAA0B,CAAA;AAEjC,cAAc;AACd,MAAM,UAAU,YAAY,CAAC,mBAAmB,EAAE,YAAY;IAC5D,MAAM,WAAW,GAAG,kBAAkB,CAAC,mBAAmB,CAAC,CAAA;IAE3D,KAAK,UAAU,cAAc,CAAC,IAAI,EAAE,mCAAmC;QACrE,wBAAwB,CAAC,mCAAmC,CAAC,CAAA;QAC7D,IAAI;YACF,yEAAyE;YACzE,wEAAwE;YACxE,kCAAkC;YAClC,OAAO,MAAM,aAAa,CAAC,WAAW,EAAE,IAAI,CAAC,CAAA;SAC9C;gBAAS;YACR,MAAM,kBAAkB,CAAC,YAAY,EAAE,mCAAmC,CAAC,CAAA;SAC5E;IACH,CAAC;IAED,0EAA0E;IAC1E,yEAAyE;IACzE,6EAA6E;IAC7E,yEAAyE;IACzE,gBAAgB;IAChB,EAAE;IACF,0EAA0E;IAC1E,8EAA8E;IAC9E,wCAAwC;IACxC,MAAM,MAAM,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC,cAAc,CAAC,IAAI,EAAE,EAAE,CAAC,CAAA;IACjD,MAAM,CAAC,QAAQ,GAAG,cAAc,CAAA;IAEhC,OAAO,MAAM,CAAA;AACf,CAAC"} \ No newline at end of file +{"version":3,"file":"core.js","sourceRoot":"","sources":["../../../../client/operations/actions/core.js"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAA;AACxE,OAAO,EACL,wBAAwB,EACxB,kBAAkB,GACnB,MAAM,0BAA0B,CAAA;AAEjC,cAAc;AACd,MAAM,UAAU,YAAY,CAAC,mBAAmB,EAAE,YAAY;IAC5D,MAAM,WAAW,GAAG,kBAAkB,CAAC,mBAAmB,CAAC,CAAA;IAE3D,KAAK,UAAU,cAAc,CAAC,IAAI,EAAE,mCAAmC;QACrE,wBAAwB,CAAC,mCAAmC,CAAC,CAAA;QAC7D,IAAI,CAAC;YACH,yEAAyE;YACzE,wEAAwE;YACxE,kCAAkC;YAClC,OAAO,MAAM,aAAa,CAAC,WAAW,EAAE,IAAI,CAAC,CAAA;QAC/C,CAAC;gBAAS,CAAC;YACT,MAAM,kBAAkB,CAAC,YAAY,EAAE,mCAAmC,CAAC,CAAA;QAC7E,CAAC;IACH,CAAC;IAED,0EAA0E;IAC1E,yEAAyE;IACzE,6EAA6E;IAC7E,yEAAyE;IACzE,gBAAgB;IAChB,EAAE;IACF,0EAA0E;IAC1E,8EAA8E;IAC9E,wCAAwC;IACxC,MAAM,MAAM,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC,cAAc,CAAC,IAAI,EAAE,EAAE,CAAC,CAAA;IACjD,MAAM,CAAC,QAAQ,GAAG,cAAc,CAAA;IAEhC,OAAO,MAAM,CAAA;AACf,CAAC"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/core.js.map b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/core.js.map index 68ea114aa9..20d72dc15e 100644 --- a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/core.js.map +++ b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/core.js.map @@ -1 +1 @@ -{"version":3,"file":"core.js","sourceRoot":"","sources":["../../../client/operations/core.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"core.js","sourceRoot":"","sources":["../../../client/operations/core.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/internal/index.js.map b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/internal/index.js.map index a4097ef8cb..a7cf9e445b 100644 --- a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/internal/index.js.map +++ b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/internal/index.js.map @@ -1 +1 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../client/operations/internal/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AACxC,OAAO,EACL,SAAS,IAAI,kBAAkB,EAC/B,WAAW,IAAI,oBAAoB,GACnC,MAAM,WAAW,CAAA;AAKnB,cAAc;AACd,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,cAA4D,EAAE,IAAS;IACzG,IAAI;QACF,MAAM,aAAa,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAA;QAC9C,MAAM,QAAQ,GAAG,MAAM,GAAG,CAAC,IAAI,CAAC,cAAc,CAAC,IAAI,EAAE,aAAa,CAAC,CAAA;QACnE,OAAO,oBAAoB,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAA;KAC3C;IAAC,OAAO,KAAK,EAAE;QACd,cAAc,CAAC,KAAK,CAAC,CAAA;KACtB;AACH,CAAC;AAED,cAAc;AACd,MAAM,UAAU,kBAAkB,CAAC,sBAA8B;IAC/D,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,sBAAsB,EAAE,EAAE,CAAA;AACxE,CAAC"} \ No newline at end of file +{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../client/operations/internal/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AACxC,OAAO,EACL,SAAS,IAAI,kBAAkB,EAC/B,WAAW,IAAI,oBAAoB,GACnC,MAAM,WAAW,CAAA;AAKnB,cAAc;AACd,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,cAA4D,EAAE,IAAS;IACzG,IAAI,CAAC;QACH,MAAM,aAAa,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAA;QAC9C,MAAM,QAAQ,GAAG,MAAM,GAAG,CAAC,IAAI,CAAC,cAAc,CAAC,IAAI,EAAE,aAAa,CAAC,CAAA;QACnE,OAAO,oBAAoB,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAA;IAC5C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,cAAc,CAAC,KAAK,CAAC,CAAA;IACvB,CAAC;AACH,CAAC;AAED,cAAc;AACd,MAAM,UAAU,kBAAkB,CAAC,sBAA8B;IAC/D,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,sBAAsB,EAAE,EAAE,CAAA;AACxE,CAAC"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/internal/resources.js.map b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/internal/resources.js.map index c91fecd3c7..61f8241c3e 100644 --- a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/internal/resources.js.map +++ b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/internal/resources.js.map @@ -1 +1 @@ -{"version":3,"file":"resources.js","sourceRoot":"","sources":["../../../../client/operations/internal/resources.js"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAA;AAC1D,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAA;AAC3D,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAA;AAEpD,kDAAkD;AAClD,mDAAmD;AACnD,iBAAiB;AACjB,MAAM,wBAAwB,GAAG,IAAI,GAAG,EAAE,CAAA;AAE1C,MAAM,cAAc,GAAG,qBAAqB,CAAC,YAAY,CAAC,CAAA;AAE1D,cAAc;AACd;;;;;GAKG;AACH,MAAM,UAAU,uBAAuB,CAAC,aAAa,EAAE,SAAS;IAC9D,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE;QAChC,IAAI,SAAS,GAAG,wBAAwB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;QACtD,IAAI,CAAC,SAAS,EAAE;YACd,SAAS,GAAG,IAAI,GAAG,EAAE,CAAA;YACrB,wBAAwB,CAAC,GAAG,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAA;SAClD;QACD,SAAS,CAAC,GAAG,CAAC,aAAa,CAAC,CAAA;KAC7B;AACH,CAAC;AAED,MAAM,UAAU,wBAAwB,CAAC,sBAAsB;IAC7D,sBAAsB,CAAC,OAAO,CAC5B,CAAC,EAAE,QAAQ,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC,cAAc,CAAC,GAAG,CAAC,QAAQ,EAAE,WAAW,CAAC,CACzE,CAAA;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,SAAS,EAAE,sBAAsB;IACxE,sBAAsB,CAAC,OAAO,CAAC,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,cAAc,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAA;IACjF,MAAM,sBAAsB,CAAC,SAAS,CAAC,CAAA;AACzC,CAAC;AAED,MAAM,UAAU,0BAA0B,CAAC,QAAQ;IACjD,OAAO,cAAc,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAA;AACnD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,0BAA0B;IAC9C,MAAM,WAAW,GAAG,MAAM,sBAAsB,CAAA;IAChD,wEAAwE;IACxE,8EAA8E;IAC9E,eAAe;IACf,iFAAiF;IACjF,6EAA6E;IAC7E,wFAAwF;IACxF,kFAAkF;IAClF,WAAW,CAAC,YAAY,EAAE,CAAA;IAC1B,6EAA6E;IAC7E,2DAA2D;IAC3D,WAAW,CAAC,aAAa,EAAE,CAAA;AAC7B,CAAC;AAED;;;GAGG;AACH,KAAK,UAAU,sBAAsB,CAAC,SAAS;IAC7C,MAAM,WAAW,GAAG,MAAM,sBAAsB,CAAA;IAEhD,MAAM,0BAA0B,GAAG,wBAAwB,CAAC,SAAS,CAAC,CAAA;IACtE,0BAA0B,CAAC,OAAO,CAChC,aAAa,CAAC,EAAE,CAAC,WAAW,CAAC,iBAAiB,CAAC,aAAa,CAAC,CAC9D,CAAA;AACH,CAAC;AAED;;;GAGG;AACH,SAAS,uBAAuB,CAAC,QAAQ;IACvC,OAAO,KAAK,CAAC,IAAI,CAAC,wBAAwB,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAA;AACjE,CAAC;AAED,SAAS,wBAAwB,CAAC,SAAS;IACzC,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,uBAAuB,CAAC,CAAC,CAAC,CAAA;AACxE,CAAC"} \ No newline at end of file +{"version":3,"file":"resources.js","sourceRoot":"","sources":["../../../../client/operations/internal/resources.js"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAA;AAC1D,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAA;AAC3D,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAA;AAEpD,kDAAkD;AAClD,mDAAmD;AACnD,iBAAiB;AACjB,MAAM,wBAAwB,GAAG,IAAI,GAAG,EAAE,CAAA;AAE1C,MAAM,cAAc,GAAG,qBAAqB,CAAC,YAAY,CAAC,CAAA;AAE1D,cAAc;AACd;;;;;GAKG;AACH,MAAM,UAAU,uBAAuB,CAAC,aAAa,EAAE,SAAS;IAC9D,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;QACjC,IAAI,SAAS,GAAG,wBAAwB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;QACtD,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,SAAS,GAAG,IAAI,GAAG,EAAE,CAAA;YACrB,wBAAwB,CAAC,GAAG,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAA;QACnD,CAAC;QACD,SAAS,CAAC,GAAG,CAAC,aAAa,CAAC,CAAA;IAC9B,CAAC;AACH,CAAC;AAED,MAAM,UAAU,wBAAwB,CAAC,sBAAsB;IAC7D,sBAAsB,CAAC,OAAO,CAC5B,CAAC,EAAE,QAAQ,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC,cAAc,CAAC,GAAG,CAAC,QAAQ,EAAE,WAAW,CAAC,CACzE,CAAA;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,SAAS,EAAE,sBAAsB;IACxE,sBAAsB,CAAC,OAAO,CAAC,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,cAAc,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAA;IACjF,MAAM,sBAAsB,CAAC,SAAS,CAAC,CAAA;AACzC,CAAC;AAED,MAAM,UAAU,0BAA0B,CAAC,QAAQ;IACjD,OAAO,cAAc,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAA;AACnD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,0BAA0B;IAC9C,MAAM,WAAW,GAAG,MAAM,sBAAsB,CAAA;IAChD,wEAAwE;IACxE,8EAA8E;IAC9E,eAAe;IACf,iFAAiF;IACjF,6EAA6E;IAC7E,wFAAwF;IACxF,kFAAkF;IAClF,WAAW,CAAC,YAAY,EAAE,CAAA;IAC1B,6EAA6E;IAC7E,2DAA2D;IAC3D,WAAW,CAAC,aAAa,EAAE,CAAA;AAC7B,CAAC;AAED;;;GAGG;AACH,KAAK,UAAU,sBAAsB,CAAC,SAAS;IAC7C,MAAM,WAAW,GAAG,MAAM,sBAAsB,CAAA;IAEhD,MAAM,0BAA0B,GAAG,wBAAwB,CAAC,SAAS,CAAC,CAAA;IACtE,0BAA0B,CAAC,OAAO,CAChC,aAAa,CAAC,EAAE,CAAC,WAAW,CAAC,iBAAiB,CAAC,aAAa,CAAC,CAC9D,CAAA;AACH,CAAC;AAED;;;GAGG;AACH,SAAS,uBAAuB,CAAC,QAAQ;IACvC,OAAO,KAAK,CAAC,IAAI,CAAC,wBAAwB,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAA;AACjE,CAAC;AAED,SAAS,wBAAwB,CAAC,SAAS;IACzC,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,uBAAuB,CAAC,CAAC,CAAC,CAAA;AACxE,CAAC"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/internal/updateHandlersMap.js.map b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/internal/updateHandlersMap.js.map index 7940fcd972..950c377452 100644 --- a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/internal/updateHandlersMap.js.map +++ b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/internal/updateHandlersMap.js.map @@ -1 +1 @@ -{"version":3,"file":"updateHandlersMap.js","sourceRoot":"","sources":["../../../../client/operations/internal/updateHandlersMap.js"],"names":[],"mappings":"AAAA,MAAM,UAAU,qBAAqB,CAAC,aAAa;IACjD,MAAM,cAAc,GAAG,IAAI,GAAG,EAAE,CAAA;IAEhC,SAAS,gBAAgB,CAAC,YAAY;QACpC,OAAO,cAAc,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC;IAChD,CAAC;IAED,SAAS,GAAG,CAAC,QAAQ,EAAE,WAAW;QAChC,MAAM,YAAY,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAA;QAC5C,MAAM,QAAQ,GAAG,gBAAgB,CAAC,YAAY,CAAC,CAAC;QAChD,cAAc,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC,GAAG,QAAQ,EAAE,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC,CAAC,CAAA;IAC5E,CAAC;IAED,SAAS,iBAAiB,CAAC,QAAQ;QACjC,MAAM,YAAY,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAA;QAC5C,OAAO,gBAAgB,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC,WAAW,CAAC,CAAA;IAC7E,CAAC;IAED,SAAS,MAAM,CAAC,gBAAgB;QAC9B,MAAM,YAAY,GAAG,aAAa,CAAC,gBAAgB,CAAC,CAAA;QACpD,MAAM,gBAAgB,GAAG,gBAAgB,CAAC,YAAY,CAAC,CAAC,MAAM,CAC5D,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,QAAQ,KAAK,gBAAgB,CAChD,CAAA;QAED,IAAI,gBAAgB,CAAC,MAAM,GAAG,CAAC,EAAE;YAC/B,cAAc,CAAC,GAAG,CAAC,YAAY,EAAE,gBAAgB,CAAC,CAAA;SACnD;aAAM;YACL,cAAc,CAAC,MAAM,CAAC,YAAY,CAAC,CAAA;SACpC;IACH,CAAC;IAED,OAAO;QACL,GAAG;QACH,MAAM;QACN,iBAAiB;KAClB,CAAA;AACH,CAAC"} \ No newline at end of file +{"version":3,"file":"updateHandlersMap.js","sourceRoot":"","sources":["../../../../client/operations/internal/updateHandlersMap.js"],"names":[],"mappings":"AAAA,MAAM,UAAU,qBAAqB,CAAC,aAAa;IACjD,MAAM,cAAc,GAAG,IAAI,GAAG,EAAE,CAAA;IAEhC,SAAS,gBAAgB,CAAC,YAAY;QACpC,OAAO,cAAc,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC;IAChD,CAAC;IAED,SAAS,GAAG,CAAC,QAAQ,EAAE,WAAW;QAChC,MAAM,YAAY,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAA;QAC5C,MAAM,QAAQ,GAAG,gBAAgB,CAAC,YAAY,CAAC,CAAC;QAChD,cAAc,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC,GAAG,QAAQ,EAAE,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC,CAAC,CAAA;IAC5E,CAAC;IAED,SAAS,iBAAiB,CAAC,QAAQ;QACjC,MAAM,YAAY,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAA;QAC5C,OAAO,gBAAgB,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC,WAAW,CAAC,CAAA;IAC7E,CAAC;IAED,SAAS,MAAM,CAAC,gBAAgB;QAC9B,MAAM,YAAY,GAAG,aAAa,CAAC,gBAAgB,CAAC,CAAA;QACpD,MAAM,gBAAgB,GAAG,gBAAgB,CAAC,YAAY,CAAC,CAAC,MAAM,CAC5D,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,QAAQ,KAAK,gBAAgB,CAChD,CAAA;QAED,IAAI,gBAAgB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAChC,cAAc,CAAC,GAAG,CAAC,YAAY,EAAE,gBAAgB,CAAC,CAAA;QACpD,CAAC;aAAM,CAAC;YACN,cAAc,CAAC,MAAM,CAAC,YAAY,CAAC,CAAA;QACrC,CAAC;IACH,CAAC;IAED,OAAO;QACL,GAAG;QACH,MAAM;QACN,iBAAiB;KAClB,CAAA;AACH,CAAC"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/queryClient.js.map b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/queryClient.js.map index 82e2b19139..15d3f12588 100644 --- a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/queryClient.js.map +++ b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/queryClient.js.map @@ -1 +1 @@ -{"version":3,"file":"queryClient.js","sourceRoot":"","sources":["../../../client/operations/queryClient.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAqB,MAAM,uBAAuB,CAAA;AAEtE,MAAM,wBAAwB,GAAG,EAAE,CAAC;AAEpC,IAAI,iBAAoC,EACtC,6BAAsD,EACtD,wBAAiC,CAAC;AAEpC,+BAA+B;AAC/B,MAAM,CAAC,MAAM,sBAAsB,GAAyB,IAAI,OAAO,CACrE,CAAC,OAAO,EAAE,EAAE;IACV,6BAA6B,GAAG,OAAO,CAAC;AAC1C,CAAC,CACF,CAAC;AAEF,aAAa;AACb,MAAM,UAAU,oBAAoB,CAAC,MAAyB;IAC5D,IAAI,wBAAwB,EAAE;QAC5B,MAAM,IAAI,KAAK,CACb,6DAA6D,CAC9D,CAAC;KACH;IAED,iBAAiB,GAAG,MAAM,CAAC;AAC7B,CAAC;AAED,+BAA+B;AAC/B,MAAM,UAAU,qBAAqB;IACnC,MAAM,WAAW,GAAG,IAAI,WAAW,CACjC,iBAAiB,aAAjB,iBAAiB,cAAjB,iBAAiB,GAAI,wBAAwB,CAC9C,CAAC;IACF,wBAAwB,GAAG,IAAI,CAAC;IAChC,6BAA6B,CAAC,WAAW,CAAC,CAAC;AAC7C,CAAC"} \ No newline at end of file +{"version":3,"file":"queryClient.js","sourceRoot":"","sources":["../../../client/operations/queryClient.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAqB,MAAM,uBAAuB,CAAA;AAEtE,MAAM,wBAAwB,GAAG,EAAE,CAAC;AAEpC,IAAI,iBAAoC,EACtC,6BAAsD,EACtD,wBAAiC,CAAC;AAEpC,+BAA+B;AAC/B,MAAM,CAAC,MAAM,sBAAsB,GAAyB,IAAI,OAAO,CACrE,CAAC,OAAO,EAAE,EAAE;IACV,6BAA6B,GAAG,OAAO,CAAC;AAC1C,CAAC,CACF,CAAC;AAEF,aAAa;AACb,MAAM,UAAU,oBAAoB,CAAC,MAAyB;IAC5D,IAAI,wBAAwB,EAAE,CAAC;QAC7B,MAAM,IAAI,KAAK,CACb,6DAA6D,CAC9D,CAAC;IACJ,CAAC;IAED,iBAAiB,GAAG,MAAM,CAAC;AAC7B,CAAC;AAED,+BAA+B;AAC/B,MAAM,UAAU,qBAAqB;IACnC,MAAM,WAAW,GAAG,IAAI,WAAW,CACjC,iBAAiB,aAAjB,iBAAiB,cAAjB,iBAAiB,GAAI,wBAAwB,CAC9C,CAAC;IACF,wBAAwB,GAAG,IAAI,CAAC;IAChC,6BAA6B,CAAC,WAAW,CAAC,CAAC;AAC7C,CAAC"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/router/linkHelpers.js.map b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/router/linkHelpers.js.map index 064bcce597..c532d39f5e 100644 --- a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/router/linkHelpers.js.map +++ b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/router/linkHelpers.js.map @@ -1 +1 @@ -{"version":3,"file":"linkHelpers.js","sourceRoot":"","sources":["../../../client/router/linkHelpers.ts"],"names":[],"mappings":"AAEA,cAAc;AACd,MAAM,UAAU,eAAe,CAC7B,IAAY,EACZ,MAAe,EACf,MAAe,EACf,IAAa;IAEb,MAAM,gBAAgB,GAAG,MAAM,CAAC,CAAC,CAAC,qBAAqB,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;IAC5E,MAAM,kBAAkB,GAAG,MAAM;QAC/B,CAAC,CAAC,IAAI,IAAI,eAAe,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,EAAE;QAC9C,CAAC,CAAC,EAAE,CAAA;IACN,MAAM,gBAAgB,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAA;IAC/C,OAAO,gBAAgB,GAAG,kBAAkB,GAAG,gBAAgB,CAAA;AACjE,CAAC;AAED,SAAS,qBAAqB,CAAC,IAAY,EAAE,MAAc;IACzD,SAAS,WAAW,CAAC,IAAY;QAC/B,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE;YACxB,MAAM,SAAS,GAAG,4BAA4B,CAAC,IAAI,CAAC,CAAC;YACrD,OAAO,MAAM,CAAC,SAAS,CAAC,CAAC;SAC1B;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,gBAAgB,GAAG,IAAI;SAC1B,KAAK,CAAC,GAAG,CAAC;SACV,GAAG,CAAC,WAAW,CAAC;SAChB,MAAM,CAAC,eAAe,CAAC;SACvB,IAAI,CAAC,GAAG,CAAC,CAAC;IAEb,OAAO,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,gBAAgB,EAAE,CAAC,CAAC,CAAC,gBAAgB,CAAC;AAC1E,CAAC;AAED,SAAS,eAAe,CAAC,IAAS;IAChC,OAAO,CAAC,CAAC,IAAI,CAAC;AAChB,CAAC;AAED,SAAS,4BAA4B,CAAC,WAAmB;IACvD,IAAI,WAAW,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE;QAC7B,OAAO,WAAW,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;KACjC;IACD,OAAO,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC9B,CAAC"} \ No newline at end of file +{"version":3,"file":"linkHelpers.js","sourceRoot":"","sources":["../../../client/router/linkHelpers.ts"],"names":[],"mappings":"AAEA,cAAc;AACd,MAAM,UAAU,eAAe,CAC7B,IAAY,EACZ,MAAe,EACf,MAAe,EACf,IAAa;IAEb,MAAM,gBAAgB,GAAG,MAAM,CAAC,CAAC,CAAC,qBAAqB,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;IAC5E,MAAM,kBAAkB,GAAG,MAAM;QAC/B,CAAC,CAAC,IAAI,IAAI,eAAe,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,EAAE;QAC9C,CAAC,CAAC,EAAE,CAAA;IACN,MAAM,gBAAgB,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAA;IAC/C,OAAO,gBAAgB,GAAG,kBAAkB,GAAG,gBAAgB,CAAA;AACjE,CAAC;AAED,SAAS,qBAAqB,CAAC,IAAY,EAAE,MAAc;IACzD,SAAS,WAAW,CAAC,IAAY;QAC/B,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YACzB,MAAM,SAAS,GAAG,4BAA4B,CAAC,IAAI,CAAC,CAAC;YACrD,OAAO,MAAM,CAAC,SAAS,CAAC,CAAC;QAC3B,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,gBAAgB,GAAG,IAAI;SAC1B,KAAK,CAAC,GAAG,CAAC;SACV,GAAG,CAAC,WAAW,CAAC;SAChB,MAAM,CAAC,eAAe,CAAC;SACvB,IAAI,CAAC,GAAG,CAAC,CAAC;IAEb,OAAO,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,gBAAgB,EAAE,CAAC,CAAC,CAAC,gBAAgB,CAAC;AAC1E,CAAC;AAED,SAAS,eAAe,CAAC,IAAS;IAChC,OAAO,CAAC,CAAC,IAAI,CAAC;AAChB,CAAC;AAED,SAAS,4BAA4B,CAAC,WAAmB;IACvD,IAAI,WAAW,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QAC9B,OAAO,WAAW,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAClC,CAAC;IACD,OAAO,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC9B,CAAC"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/test/vitest/helpers.jsx.map b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/test/vitest/helpers.jsx.map index b7ab2a906f..375c4629a2 100644 --- a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/test/vitest/helpers.jsx.map +++ b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/test/vitest/helpers.jsx.map @@ -1 +1 @@ -{"version":3,"file":"helpers.jsx","sourceRoot":"","sources":["../../../../client/test/vitest/helpers.tsx"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"helpers.jsx","sourceRoot":"","sources":["../../../../client/test/vitest/helpers.tsx"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/core/storage.js.map b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/core/storage.js.map index b7cd5db441..73a6773d4f 100644 --- a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/core/storage.js.map +++ b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/core/storage.js.map @@ -1 +1 @@ -{"version":3,"file":"storage.js","sourceRoot":"","sources":["../../core/storage.ts"],"names":[],"mappings":"AAQA,SAAS,2BAA2B,CAAC,MAAc;IACjD,SAAS,cAAc,CAAC,GAAW;QACjC,OAAO,GAAG,MAAM,IAAI,GAAG,EAAE,CAAA;IAC3B,CAAC;IAED,OAAO;QACL,cAAc;QACd,GAAG,CAAC,GAAG,EAAE,KAAK;YACZ,6BAA6B,EAAE,CAAA;YAC/B,YAAY,CAAC,OAAO,CAAC,cAAc,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAA;QAClE,CAAC;QACD,GAAG,CAAC,GAAG;YACL,6BAA6B,EAAE,CAAA;YAC/B,MAAM,KAAK,GAAG,YAAY,CAAC,OAAO,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAA;YACvD,IAAI;gBACF,OAAO,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;aAC7C;YAAC,OAAO,CAAM,EAAE;gBACf,OAAO,SAAS,CAAA;aACjB;QACH,CAAC;QACD,MAAM,CAAC,GAAG;YACR,6BAA6B,EAAE,CAAA;YAC/B,YAAY,CAAC,UAAU,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAA;QAC9C,CAAC;QACD,KAAK;YACH,6BAA6B,EAAE,CAAA;YAC/B,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE;gBACxC,IAAI,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE;oBAC1B,YAAY,CAAC,UAAU,CAAC,GAAG,CAAC,CAAA;iBAC7B;YACH,CAAC,CAAC,CAAA;QACJ,CAAC;KACF,CAAA;AACH,CAAC;AAED,MAAM,CAAC,MAAM,OAAO,GAAG,2BAA2B,CAAC,MAAM,CAAC,CAAA;AAE1D,SAAS,6BAA6B;IACpC,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE;QACxB,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAA;KACnD;AACH,CAAC"} \ No newline at end of file +{"version":3,"file":"storage.js","sourceRoot":"","sources":["../../core/storage.ts"],"names":[],"mappings":"AAQA,SAAS,2BAA2B,CAAC,MAAc;IACjD,SAAS,cAAc,CAAC,GAAW;QACjC,OAAO,GAAG,MAAM,IAAI,GAAG,EAAE,CAAA;IAC3B,CAAC;IAED,OAAO;QACL,cAAc;QACd,GAAG,CAAC,GAAG,EAAE,KAAK;YACZ,6BAA6B,EAAE,CAAA;YAC/B,YAAY,CAAC,OAAO,CAAC,cAAc,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAA;QAClE,CAAC;QACD,GAAG,CAAC,GAAG;YACL,6BAA6B,EAAE,CAAA;YAC/B,MAAM,KAAK,GAAG,YAAY,CAAC,OAAO,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAA;YACvD,IAAI,CAAC;gBACH,OAAO,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;YAC9C,CAAC;YAAC,OAAO,CAAM,EAAE,CAAC;gBAChB,OAAO,SAAS,CAAA;YAClB,CAAC;QACH,CAAC;QACD,MAAM,CAAC,GAAG;YACR,6BAA6B,EAAE,CAAA;YAC/B,YAAY,CAAC,UAAU,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAA;QAC9C,CAAC;QACD,KAAK;YACH,6BAA6B,EAAE,CAAA;YAC/B,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE;gBACxC,IAAI,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;oBAC3B,YAAY,CAAC,UAAU,CAAC,GAAG,CAAC,CAAA;gBAC9B,CAAC;YACH,CAAC,CAAC,CAAA;QACJ,CAAC;KACF,CAAA;AACH,CAAC;AAED,MAAM,CAAC,MAAM,OAAO,GAAG,2BAA2B,CAAC,MAAM,CAAC,CAAA;AAE1D,SAAS,6BAA6B;IACpC,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAA;IACpD,CAAC;AACH,CAAC"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/server/HttpError.js.map b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/server/HttpError.js.map index 34064e924c..3cc7095281 100644 --- a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/server/HttpError.js.map +++ b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/server/HttpError.js.map @@ -1 +1 @@ -{"version":3,"file":"HttpError.js","sourceRoot":"","sources":["../../server/HttpError.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,SAAU,SAAQ,KAAK;IAIlC,YAAa,UAAkB,EAAE,OAAgB,EAAE,IAA8B,EAAE,GAAG,MAAiB;QACrG,KAAK,CAAC,OAAO,EAAE,GAAG,MAAM,CAAC,CAAA;QAEzB,IAAI,KAAK,CAAC,iBAAiB,EAAE;YAC3B,KAAK,CAAC,iBAAiB,CAAC,IAAI,EAAE,SAAS,CAAC,CAAA;SACzC;QAED,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,CAAA;QAEjC,IAAI,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC,IAAI,UAAU,IAAI,GAAG,IAAI,UAAU,GAAG,GAAG,CAAC,EAAE;YAC5E,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAA;SACrE;QACD,IAAI,CAAC,UAAU,GAAG,UAAU,CAAA;QAE5B,IAAI,IAAI,EAAE;YACR,IAAI,CAAC,IAAI,GAAG,IAAI,CAAA;SACjB;IACH,CAAC;CACF"} \ No newline at end of file +{"version":3,"file":"HttpError.js","sourceRoot":"","sources":["../../server/HttpError.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,SAAU,SAAQ,KAAK;IAIlC,YAAa,UAAkB,EAAE,OAAgB,EAAE,IAA8B,EAAE,GAAG,MAAiB;QACrG,KAAK,CAAC,OAAO,EAAE,GAAG,MAAM,CAAC,CAAA;QAEzB,IAAI,KAAK,CAAC,iBAAiB,EAAE,CAAC;YAC5B,KAAK,CAAC,iBAAiB,CAAC,IAAI,EAAE,SAAS,CAAC,CAAA;QAC1C,CAAC;QAED,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,CAAA;QAEjC,IAAI,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC,IAAI,UAAU,IAAI,GAAG,IAAI,UAAU,GAAG,GAAG,CAAC,EAAE,CAAC;YAC7E,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAA;QACtE,CAAC;QACD,IAAI,CAAC,UAAU,GAAG,UAAU,CAAA;QAE5B,IAAI,IAAI,EAAE,CAAC;YACT,IAAI,CAAC,IAAI,GAAG,IAAI,CAAA;QAClB,CAAC;IACH,CAAC;CACF"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/server/utils.js.map b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/server/utils.js.map index f3af561141..17121f586d 100644 --- a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/server/utils.js.map +++ b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/server/utils.js.map @@ -1 +1 @@ -{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../server/utils.ts"],"names":[],"mappings":"AAWA;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAC7B,UAIQ,EACR,EAAE,CACJ,KAAK,EAAE,GAA2B,EAAE,GAAa,EAAE,IAAkB,EAAE,EAAE;IACvE,IAAI;QACF,MAAM,UAAU,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,CAAA;KACjC;IAAC,OAAO,KAAK,EAAE;QACd,IAAI,CAAC,KAAK,CAAC,CAAA;KACZ;AACH,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,EAAU,EAAoB,EAAE,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAA"} \ No newline at end of file +{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../server/utils.ts"],"names":[],"mappings":"AAWA;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAC7B,UAIQ,EACR,EAAE,CACJ,KAAK,EAAE,GAA2B,EAAE,GAAa,EAAE,IAAkB,EAAE,EAAE;IACvE,IAAI,CAAC;QACH,MAAM,UAAU,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,CAAA;IAClC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,CAAC,KAAK,CAAC,CAAA;IACb,CAAC;AACH,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,EAAU,EAAoB,EAAE,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAA"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/universal/validators.js.map b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/universal/validators.js.map index 313c98cef4..f020413e43 100644 --- a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/universal/validators.js.map +++ b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/universal/validators.js.map @@ -1 +1 @@ -{"version":3,"file":"validators.js","sourceRoot":"","sources":["../../universal/validators.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,kBAAkB,CAAC,MAAc;IAC7C,IAAI;QACA,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC;QAC5B;;;;;;UAME;QACF,OAAO,GAAG,CAAC,QAAQ,KAAK,OAAO,IAAI,GAAG,CAAC,QAAQ,KAAK,QAAQ,CAAC;KAChE;IAAC,OAAO,CAAC,EAAE;QACR,OAAO,KAAK,CAAC;KAChB;AACL,CAAC;AAED,MAAM,UAAU,0BAA0B,CAAC,KAAyB,EAAE,IAAY;IAC9E,IAAI,KAAK,IAAI,CAAC,kBAAkB,CAAC,KAAK,CAAC,EAAE;QACrC,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,+BAA+B,CAAC,CAAC;KAC3D;AACL,CAAC"} \ No newline at end of file +{"version":3,"file":"validators.js","sourceRoot":"","sources":["../../universal/validators.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,kBAAkB,CAAC,MAAc;IAC7C,IAAI,CAAC;QACD,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC;QAC5B;;;;;;UAME;QACF,OAAO,GAAG,CAAC,QAAQ,KAAK,OAAO,IAAI,GAAG,CAAC,QAAQ,KAAK,QAAQ,CAAC;IACjE,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACT,OAAO,KAAK,CAAC;IACjB,CAAC;AACL,CAAC;AAED,MAAM,UAAU,0BAA0B,CAAC,KAAyB,EAAE,IAAY;IAC9E,IAAI,KAAK,IAAI,CAAC,kBAAkB,CAAC,KAAK,CAAC,EAAE,CAAC;QACtC,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,+BAA+B,CAAC,CAAC;IAC5D,CAAC;AACL,CAAC"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/package.json b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/package.json index 3f9c859316..e290f61ea9 100644 --- a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/package.json +++ b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/package.json @@ -10,7 +10,6 @@ "axios": "^1.4.0", "express": "~4.18.1", "jsdom": "^21.1.1", - "jsonwebtoken": "^8.5.1", "lodash.merge": "^4.6.2", "mitt": "3.0.0", "msw": "^1.1.0", diff --git a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/server/package.json b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/server/package.json index 78c986051e..3a4ce1d6b9 100644 --- a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/server/package.json +++ b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/server/package.json @@ -6,7 +6,6 @@ "dotenv": "16.0.2", "express": "~4.18.1", "helmet": "^6.0.0", - "jsonwebtoken": "^8.5.1", "morgan": "~1.10.0", "rate-limiter-flexible": "^2.4.1", "superjson": "^1.12.2" diff --git a/waspc/src/Wasp/Generator/SdkGenerator.hs b/waspc/src/Wasp/Generator/SdkGenerator.hs index 3e8d120231..0b6dc6e95d 100644 --- a/waspc/src/Wasp/Generator/SdkGenerator.hs +++ b/waspc/src/Wasp/Generator/SdkGenerator.hs @@ -205,7 +205,6 @@ npmDepsForSdk spec = ("@tanstack/react-query", "^4.29.0"), ("axios", "^1.4.0"), ("express", "~4.18.1"), - ("jsonwebtoken", "^8.5.1"), ("mitt", "3.0.0"), ("react", "^18.2.0"), ("lodash.merge", "^4.6.2"), diff --git a/waspc/src/Wasp/Generator/ServerGenerator.hs b/waspc/src/Wasp/Generator/ServerGenerator.hs index 449a0370ed..3aa2f783ed 100644 --- a/waspc/src/Wasp/Generator/ServerGenerator.hs +++ b/waspc/src/Wasp/Generator/ServerGenerator.hs @@ -148,7 +148,6 @@ npmDepsForWasp spec = ("cors", "^2.8.5"), ("express", "~4.18.1"), ("morgan", "~1.10.0"), - ("jsonwebtoken", "^8.5.1"), ("dotenv", "16.0.2"), ("helmet", "^6.0.0"), ("rate-limiter-flexible", "^2.4.1"), diff --git a/waspc/src/Wasp/Generator/ServerGenerator/Auth/EmailAuthG.hs b/waspc/src/Wasp/Generator/ServerGenerator/Auth/EmailAuthG.hs index 78769f2343..da078de103 100644 --- a/waspc/src/Wasp/Generator/ServerGenerator/Auth/EmailAuthG.hs +++ b/waspc/src/Wasp/Generator/ServerGenerator/Auth/EmailAuthG.hs @@ -35,8 +35,7 @@ genEmailAuth :: AS.AppSpec -> AS.Auth.Auth -> Generator [FileDraft] genEmailAuth spec auth = case emailAuth of Just emailAuthConfig -> sequence - [ genEmailAuthConfig spec emailAuthConfig, - genTypes emailAuthConfig + [ genEmailAuthConfig spec emailAuthConfig ] <++> genRoutes Nothing -> return [] @@ -100,9 +99,3 @@ genRoutes = ] where genFileCopy = return . C.mkSrcTmplFd - -genTypes :: AS.Auth.EmailAuthConfig -> Generator FileDraft -genTypes _emailAuthConfig = return $ C.mkTmplFdWithData tmplFile (Just tmplData) - where - tmplFile = C.srcDirInServerTemplatesDir [relfile|auth/providers/email/types.ts|] - tmplData = object [] From 7329465974e922f3404e2563a908e4a648c4e025 Mon Sep 17 00:00:00 2001 From: Mihovil Ilakovac Date: Mon, 18 Mar 2024 12:56:46 +0100 Subject: [PATCH 03/20] Define the `WASP_SERVER_URL` env var (#1856) --- waspc/ChangeLog.md | 182 +++++++++--------- .../templates/sdk/wasp/client/config.ts | 5 +- .../templates/sdk/wasp/server/config.ts | 7 +- .../templates/server/scripts/validate-env.mjs | 1 + .../waspBuild/.wasp/build/.waspchecksums | 4 +- .../build/sdk/wasp/dist/server/config.d.ts | 1 + .../build/sdk/wasp/dist/server/config.js | 4 + .../build/sdk/wasp/dist/server/config.js.map | 2 +- .../.wasp/build/sdk/wasp/server/config.ts | 5 + .../build/server/scripts/validate-env.mjs | 1 + .../out/sdk/wasp/dist/server/config.d.ts | 1 + .../.wasp/out/sdk/wasp/dist/server/config.js | 4 + .../out/sdk/wasp/dist/server/config.js.map | 2 +- .../.wasp/out/sdk/wasp/server/config.ts | 5 + .../waspCompile/.wasp/out/.waspchecksums | 4 +- .../out/sdk/wasp/dist/server/config.d.ts | 1 + .../.wasp/out/sdk/wasp/dist/server/config.js | 4 + .../out/sdk/wasp/dist/server/config.js.map | 2 +- .../.wasp/out/sdk/wasp/server/config.ts | 5 + .../.wasp/out/server/scripts/validate-env.mjs | 1 + .../waspComplexTest/.wasp/out/.waspchecksums | 4 +- .../out/sdk/wasp/dist/server/config.d.ts | 1 + .../.wasp/out/sdk/wasp/dist/server/config.js | 4 + .../out/sdk/wasp/dist/server/config.js.map | 2 +- .../.wasp/out/sdk/wasp/server/config.ts | 5 + .../.wasp/out/server/scripts/validate-env.mjs | 1 + .../waspJob/.wasp/out/.waspchecksums | 4 +- .../out/sdk/wasp/dist/server/config.d.ts | 1 + .../.wasp/out/sdk/wasp/dist/server/config.js | 4 + .../out/sdk/wasp/dist/server/config.js.map | 2 +- .../.wasp/out/sdk/wasp/server/config.ts | 5 + .../.wasp/out/server/scripts/validate-env.mjs | 1 + .../waspMigrate/.wasp/out/.waspchecksums | 4 +- .../.wasp/out/sdk/wasp/client/config.ts | 3 +- .../out/sdk/wasp/dist/server/config.d.ts | 1 + .../.wasp/out/sdk/wasp/dist/server/config.js | 4 + .../out/sdk/wasp/dist/server/config.js.map | 2 +- .../.wasp/out/sdk/wasp/server/config.ts | 5 + .../.wasp/out/server/scripts/validate-env.mjs | 1 + .../deploy/src/providers/fly/setup/setup.ts | 1 + waspc/src/Wasp/Generator/SdkGenerator.hs | 13 +- .../Wasp/Generator/ServerGenerator/Common.hs | 8 + .../Wasp/Generator/WebAppGenerator/Common.hs | 6 +- web/docs/advanced/deployment/manually.md | 20 +- 44 files changed, 224 insertions(+), 119 deletions(-) diff --git a/waspc/ChangeLog.md b/waspc/ChangeLog.md index 6fc4611666..b441199b37 100644 --- a/waspc/ChangeLog.md +++ b/waspc/ChangeLog.md @@ -1,6 +1,10 @@ # Changelog -## 0.12.4 (2024-03-12) +## 0.13.0 (2024-03-18) + +### 🎉 New features + +- Wasp now supports defining the `WASP_SERVER_URL` environment variable and exposes it as `serverUrl` in the server config which can be imported from `wasp/server`. ### 🐞 Bug fixes @@ -173,13 +177,13 @@ By adding a `vite.config.ts` or `vite.config.js` to your `client` directory, you not to open the browser automatically: ```ts -import { defineConfig } from 'vite' +import { defineConfig } from "vite"; export default defineConfig({ server: { open: false, }, -}) +}); ``` ⚠️ Be careful when changing the dev server port, you'll need to update the `WASP_WEB_CLIENT_URL` env var in your `.env.server` file. @@ -221,27 +225,27 @@ app crudTesting { Then, you need to define the `fields` object in your `auth.js` file: ```js -import { defineAdditionalSignupFields } from '@wasp/auth/index.js' +import { defineAdditionalSignupFields } from "@wasp/auth/index.js"; export const fields = defineAdditionalSignupFields({ address: (data) => { // Validate the address field - if (typeof data.address !== 'string') { - throw new Error('Address is required.') + if (typeof data.address !== "string") { + throw new Error("Address is required."); } if (data.address.length < 10) { - throw new Error('Address must be at least 10 characters long.') + throw new Error("Address must be at least 10 characters long."); } // Return the address field - return data.address + return data.address; }, -}) +}); ``` Finally, you can extend the `SignupForm` component on the client: ```jsx -import { SignupForm } from '@wasp/auth/forms/Signup' +import { SignupForm } from "@wasp/auth/forms/Signup"; export const SignupPage = () => { return ( @@ -251,19 +255,19 @@ export const SignupPage = () => { - ) -} + ); +}; ``` ### 🎉 [New Feature] Support for PostgreSQL Extensions @@ -305,8 +309,8 @@ job simplePrintJob { ``` ```typescript -import { SimplePrintJob } from '@wasp/jobs/simplePrintJob' -import { Task } from '@wasp/entities' +import { SimplePrintJob } from "@wasp/jobs/simplePrintJob"; +import { Task } from "@wasp/entities"; export const simplePrint: SimplePrintJob< { name: string }, @@ -314,11 +318,11 @@ export const simplePrint: SimplePrintJob< > = async (args, context) => { // 👆 args are typed e.g. { name: string } // 👆 context is typed e.g. { entitites: { Task: ... } } - const tasks = await context.entities.Task.findMany({}) + const tasks = await context.entities.Task.findMany({}); return { tasks, - } -} + }; +}; ``` When you use the job, you can pass the arguments and receive the result with the correct types: @@ -373,9 +377,9 @@ export const TaskList = () => { You can also get all the pages in your app with the `routes` object: ```jsx -import { routes } from '@wasp/router' +import { routes } from "@wasp/router"; -const linkToTask = routes.TaskRoute({ params: { id: 1 } }) +const linkToTask = routes.TaskRoute({ params: { id: 1 } }); ``` ### 🐞 Bug fixes @@ -499,67 +503,67 @@ app todoApp { Then implement it on the server with optional types: ```typescript -import type { WebSocketDefinition } from '@wasp/webSocket' +import type { WebSocketDefinition } from "@wasp/webSocket"; export const webSocketFn: WebSocketFn = (io, context) => { - io.on('connection', (socket) => { + io.on("connection", (socket) => { // ... - }) -} + }); +}; type WebSocketFn = WebSocketDefinition< ClientToServerEvents, ServerToClientEvents -> +>; interface ServerToClientEvents { - chatMessage: (msg: { id: string; username: string; text: string }) => void + chatMessage: (msg: { id: string; username: string; text: string }) => void; } interface ClientToServerEvents { - chatMessage: (msg: string) => void + chatMessage: (msg: string) => void; } ``` And use it on the client with automatic type inference: ```typescript -import React, { useState } from 'react' +import React, { useState } from "react"; import { useSocket, useSocketListener, ServerToClientPayload, -} from '@wasp/webSocket' +} from "@wasp/webSocket"; export const ChatPage = () => { const [messageText, setMessageText] = useState< // We are using a helper type to get the payload type for the "chatMessage" event. - ClientToServerPayload<'chatMessage'> - >('') + ClientToServerPayload<"chatMessage"> + >(""); const [messages, setMessages] = useState< - ServerToClientPayload<'chatMessage'>[] - >([]) + ServerToClientPayload<"chatMessage">[] + >([]); // The "socket" instance is typed with the types you defined on the server. - const { socket, isConnected } = useSocket() + const { socket, isConnected } = useSocket(); // This is a type-safe event handler: "chatMessage" event and its payload type // are defined on the server. - useSocketListener('chatMessage', logMessage) + useSocketListener("chatMessage", logMessage); - function logMessage(msg: ServerToClientPayload<'chatMessage'>) { - setMessages((priorMessages) => [msg, ...priorMessages]) + function logMessage(msg: ServerToClientPayload<"chatMessage">) { + setMessages((priorMessages) => [msg, ...priorMessages]); } function handleSubmit(e: React.FormEvent) { - e.preventDefault() + e.preventDefault(); // This is a type-safe event emitter: "chatMessage" event and its payload type // are defined on the server. - socket.emit('chatMessage', messageText) + socket.emit("chatMessage", messageText); // ... } // ... -} +}; ``` ### 🎉 [New feature] Automatic CRUD backend generation @@ -588,21 +592,21 @@ crud Tasks { This gives us the following operations: `getAll`, `get`, `create`, `update` and `delete`, which we can use in our client like this: ```typescript -import { Tasks } from '@wasp/crud/Tasks' -import { useState } from 'react' +import { Tasks } from "@wasp/crud/Tasks"; +import { useState } from "react"; export const MainPage = () => { - const { data: tasks, isLoading, error } = Tasks.getAll.useQuery() - const createTask = Tasks.create.useAction() + const { data: tasks, isLoading, error } = Tasks.getAll.useQuery(); + const createTask = Tasks.create.useAction(); // ... function handleCreateTask() { - createTask({ description: taskDescription, isDone: false }) - setTaskDescription('') + createTask({ description: taskDescription, isDone: false }); + setTaskDescription(""); } // ... -} +}; ``` ### 🎉 [New feature] IDE tooling improvements @@ -723,20 +727,20 @@ Frontend code can now infer correct payload/response types for Queries and Actio Define a Query on the server: ```typescript -export const getTask: GetTaskInfo, Task> = async ( +export const getTask: GetTaskInfo, Task> = async ( { id }, context ) => { // ... -} +}; ``` Get properly typed functions and data on the frontend: ```typescript -import { useQuery } from '@wasp/queries' +import { useQuery } from "@wasp/queries"; // Wasp knows the type of `getTask` thanks to your backend definition. -import getTask from '@wasp/queries/getTask' +import getTask from "@wasp/queries/getTask"; export const TaskInfo = () => { const { @@ -749,10 +753,12 @@ export const TaskInfo = () => { error, // TypeScript knows the second argument must be a `Pick` thanks // to the backend definition. - } = useQuery(getTask, { id: 1 }) + } = useQuery(getTask, { id: 1 }); if (isError) { - return
Error during fetching tasks: {error.message || 'unknown'}
+ return ( +
Error during fetching tasks: {error.message || "unknown"}
+ ); } // TypeScript forces you to perform this check. @@ -760,8 +766,8 @@ export const TaskInfo = () => {
Waiting for info...
) : (
{taskInfo}
- ) -} + ); +}; ``` The same feature is available for Actions. @@ -773,25 +779,25 @@ Client and the server can now communicate with richer payloads. Return a Superjson-compatible object from your Operation: ```typescript -type FooInfo = { foos: Foo[]; message: string; queriedAt: Date } +type FooInfo = { foos: Foo[]; message: string; queriedAt: Date }; const getFoos: GetFoo = (_args, context) => { - const foos = context.entities.Foo.findMany() + const foos = context.entities.Foo.findMany(); return { foos, - message: 'Here are some foos!', + message: "Here are some foos!", queriedAt: new Date(), - } -} + }; +}; ``` And seamlessly use it on the frontend: ```typescript -import getfoos from '@wasp/queries/getTask' +import getfoos from "@wasp/queries/getTask"; -const { data } = useQuery(getfoos) -const { foos, message, queriedAt } = data +const { data } = useQuery(getfoos); +const { foos, message, queriedAt } = data; // foos: Foo[] // message: string // queriedAt: Date @@ -834,11 +840,11 @@ Wasp now provides a set of UI components for authentication. You can use them to We provide `LoginForm`, `SignupForm`, `ForgotPassworForm`, `ResetPasswordForm` and`VerifyEmailForm` components. You can import them from `@wasp/auth/forms` like: ```js -import { LoginForm } from '@wasp/auth/forms/Login' -import { SignupForm } from '@wasp/auth/forms/Signup' -import { ForgotPasswordForm } from '@wasp/auth/forms/ForgotPassword' -import { ResetPasswordForm } from '@wasp/auth/forms/ResetPassword' -import { VerifyEmailForm } from '@wasp/auth/forms/VerifyEmail' +import { LoginForm } from "@wasp/auth/forms/Login"; +import { SignupForm } from "@wasp/auth/forms/Signup"; +import { ForgotPasswordForm } from "@wasp/auth/forms/ForgotPassword"; +import { ResetPasswordForm } from "@wasp/auth/forms/ResetPassword"; +import { VerifyEmailForm } from "@wasp/auth/forms/VerifyEmail"; ``` ### Database seeding @@ -858,18 +864,18 @@ app MyApp { ``` ```js -import { createTask } from './actions.js' +import { createTask } from "./actions.js"; export const devSeedSimple = async (prismaClient) => { const { password, ...newUser } = await prismaClient.user.create({ - username: 'RiuTheDog', - password: 'bark1234', - }) + username: "RiuTheDog", + password: "bark1234", + }); await createTask( - { description: 'Chase the cat' }, + { description: "Chase the cat" }, { user: newUser, entities: { Task: prismaClient.task } } - ) -} + ); +}; //... ``` @@ -1011,17 +1017,17 @@ And here's how you can to the same in a frontend file: ```typescript // ... -import { useQuery } from '@wasp/queries' -import getTasks from '@wasp/queries/getTasks.js' -import { Task } from '@wasp/entities' +import { useQuery } from "@wasp/queries"; +import getTasks from "@wasp/queries/getTasks.js"; +import { Task } from "@wasp/entities"; -type TaskPayload = Pick +type TaskPayload = Pick; const Todo = (props: any) => { // The variable 'task' will now have the type Task. - const { data: task } = useQuery(getTask, { id: taskId }) + const { data: task } = useQuery(getTask, { id: taskId }); // ... -} +}; ``` ### Automatically generated types for Queries and Actions @@ -1041,10 +1047,10 @@ query getTasks { You'll get the following feature: ```typescript -import { Task } from '@wasp/entities' -import { GetTasks } from '@wasp/queries' +import { Task } from "@wasp/entities"; +import { GetTasks } from "@wasp/queries"; -type Payload = Pick +type Payload = Pick; // Use the type parameters to specify the Query's argument and return types. const getTasks: GetTasks = (args, context) => { @@ -1056,7 +1062,7 @@ const getTasks: GetTasks = (args, context) => { // // Thanks to the second type argument in `GetTasks`, the compiler knows the // function must return a value of type `Task[]`. -} +}; ``` ### Uninstall command diff --git a/waspc/data/Generator/templates/sdk/wasp/client/config.ts b/waspc/data/Generator/templates/sdk/wasp/client/config.ts index e9234e6f2a..77367f7bf3 100644 --- a/waspc/data/Generator/templates/sdk/wasp/client/config.ts +++ b/waspc/data/Generator/templates/sdk/wasp/client/config.ts @@ -1,9 +1,10 @@ +{{={= =}=}} import { stripTrailingSlash } from 'wasp/universal/url' -const apiUrl = stripTrailingSlash(import.meta.env.REACT_APP_API_URL) || 'http://localhost:3001'; +const apiUrl = stripTrailingSlash(import.meta.env.REACT_APP_API_URL) || '{= defaultServerUrl =}'; const config = { apiUrl, } -export default config +export default config \ No newline at end of file diff --git a/waspc/data/Generator/templates/sdk/wasp/server/config.ts b/waspc/data/Generator/templates/sdk/wasp/server/config.ts index fcdc0b6667..a247438a64 100644 --- a/waspc/data/Generator/templates/sdk/wasp/server/config.ts +++ b/waspc/data/Generator/templates/sdk/wasp/server/config.ts @@ -28,6 +28,7 @@ type CommonConfig = BaseConfig & { type EnvConfig = BaseConfig & { frontendUrl: string; + serverUrl: string; } type Config = CommonConfig & EnvConfig @@ -40,7 +41,7 @@ const config: { all: { env, isDevelopment: env === 'development', - port: parseInt(process.env.PORT) || 3001, + port: parseInt(process.env.PORT) || {= defaultServerPort =}, databaseUrl: process.env.{= databaseUrlEnvVarName =}, allowedCORSOrigins: [], {=# isAuthEnabled =} @@ -59,8 +60,10 @@ export default resolvedConfig function getDevelopmentConfig(): EnvConfig { const frontendUrl = stripTrailingSlash(process.env.WASP_WEB_CLIENT_URL || '{= defaultClientUrl =}'); + const serverUrl = stripTrailingSlash(process.env.WASP_SERVER_URL || '{= defaultServerUrl =}'); return { frontendUrl, + serverUrl, allowedCORSOrigins: '*', {=# isAuthEnabled =} auth: { @@ -72,8 +75,10 @@ function getDevelopmentConfig(): EnvConfig { function getProductionConfig(): EnvConfig { const frontendUrl = stripTrailingSlash(process.env.WASP_WEB_CLIENT_URL); + const serverUrl = stripTrailingSlash(process.env.WASP_SERVER_URL); return { frontendUrl, + serverUrl, allowedCORSOrigins: [frontendUrl], {=# isAuthEnabled =} auth: { diff --git a/waspc/data/Generator/templates/server/scripts/validate-env.mjs b/waspc/data/Generator/templates/server/scripts/validate-env.mjs index ac264b7961..f6e50aceca 100644 --- a/waspc/data/Generator/templates/server/scripts/validate-env.mjs +++ b/waspc/data/Generator/templates/server/scripts/validate-env.mjs @@ -2,3 +2,4 @@ import { throwIfNotValidAbsoluteURL } from 'wasp/universal/validators'; console.info("🔍 Validating environment variables..."); throwIfNotValidAbsoluteURL(process.env.WASP_WEB_CLIENT_URL, 'Environment variable WASP_WEB_CLIENT_URL'); +throwIfNotValidAbsoluteURL(process.env.WASP_SERVER_URL, 'Environment variable WASP_SERVER_URL'); diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/.waspchecksums b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/.waspchecksums index cccecec5ff..e6a57ddfcb 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/.waspchecksums +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/.waspchecksums @@ -242,7 +242,7 @@ "file", "../out/sdk/wasp/server/config.ts" ], - "4976e545d8fcf019508e95f472305e9ef27dfb3423c71e428a5414e35cdd52be" + "e5388a9259a22671ee2d2ef46d2c09fdd46c3b3ec24248c7a0b471c0fbf7aa54" ], [ [ @@ -424,7 +424,7 @@ "file", "server/scripts/validate-env.mjs" ], - "65168a764fc6cbe785ee40a8e8533b4694ef9019fc5a73f60f7252152330d0a2" + "100177b4326ccab7362eff378315d532ad1cc17cd28d1ed5978cb167fd627746" ], [ [ diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/server/config.d.ts b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/server/config.d.ts index 223bb1b22c..68bb448c56 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/server/config.d.ts +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/server/config.d.ts @@ -9,6 +9,7 @@ type CommonConfig = BaseConfig & { }; type EnvConfig = BaseConfig & { frontendUrl: string; + serverUrl: string; }; type Config = CommonConfig & EnvConfig; declare const resolvedConfig: Config; diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/server/config.js b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/server/config.js index 6de1c8d25f..dabd38b4b0 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/server/config.js +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/server/config.js @@ -17,15 +17,19 @@ const resolvedConfig = merge(config.all, config[env]); export default resolvedConfig; function getDevelopmentConfig() { const frontendUrl = stripTrailingSlash(process.env.WASP_WEB_CLIENT_URL || 'http://localhost:3000/'); + const serverUrl = stripTrailingSlash(process.env.WASP_SERVER_URL || 'http://localhost:3001'); return { frontendUrl, + serverUrl, allowedCORSOrigins: '*', }; } function getProductionConfig() { const frontendUrl = stripTrailingSlash(process.env.WASP_WEB_CLIENT_URL); + const serverUrl = stripTrailingSlash(process.env.WASP_SERVER_URL); return { frontendUrl, + serverUrl, allowedCORSOrigins: [frontendUrl], }; } diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/server/config.js.map b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/server/config.js.map index 4b121ba37d..f4ad188c93 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/server/config.js.map +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/server/config.js.map @@ -1 +1 @@ -{"version":3,"file":"config.js","sourceRoot":"","sources":["../../server/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,cAAc,CAAA;AAEhC,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAExD,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,aAAa,CAAA;AAwBjD,MAAM,MAAM,GAIR;IACF,GAAG,EAAE;QACH,GAAG;QACH,aAAa,EAAE,GAAG,KAAK,aAAa;QACpC,IAAI,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,IAAI;QACxC,WAAW,EAAE,OAAO,CAAC,GAAG,CAAC,YAAY;QACrC,kBAAkB,EAAE,EAAE;KACvB;IACD,WAAW,EAAE,oBAAoB,EAAE;IACnC,UAAU,EAAE,mBAAmB,EAAE;CAClC,CAAA;AAED,MAAM,cAAc,GAAW,KAAK,CAAC,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAA;AAC7D,aAAa;AACb,eAAe,cAAc,CAAA;AAE7B,SAAS,oBAAoB;IAC3B,MAAM,WAAW,GAAG,kBAAkB,CAAC,OAAO,CAAC,GAAG,CAAC,mBAAmB,IAAI,wBAAwB,CAAC,CAAC;IACpG,OAAO;QACL,WAAW;QACX,kBAAkB,EAAE,GAAG;KACxB,CAAA;AACH,CAAC;AAED,SAAS,mBAAmB;IAC1B,MAAM,WAAW,GAAG,kBAAkB,CAAC,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;IACxE,OAAO;QACL,WAAW;QACX,kBAAkB,EAAE,CAAC,WAAW,CAAC;KAClC,CAAA;AACH,CAAC"} \ No newline at end of file +{"version":3,"file":"config.js","sourceRoot":"","sources":["../../server/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,cAAc,CAAA;AAEhC,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAExD,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,aAAa,CAAA;AAyBjD,MAAM,MAAM,GAIR;IACF,GAAG,EAAE;QACH,GAAG;QACH,aAAa,EAAE,GAAG,KAAK,aAAa;QACpC,IAAI,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,IAAI;QACxC,WAAW,EAAE,OAAO,CAAC,GAAG,CAAC,YAAY;QACrC,kBAAkB,EAAE,EAAE;KACvB;IACD,WAAW,EAAE,oBAAoB,EAAE;IACnC,UAAU,EAAE,mBAAmB,EAAE;CAClC,CAAA;AAED,MAAM,cAAc,GAAW,KAAK,CAAC,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAA;AAC7D,aAAa;AACb,eAAe,cAAc,CAAA;AAE7B,SAAS,oBAAoB;IAC3B,MAAM,WAAW,GAAG,kBAAkB,CAAC,OAAO,CAAC,GAAG,CAAC,mBAAmB,IAAI,wBAAwB,CAAC,CAAC;IACpG,MAAM,SAAS,GAAG,kBAAkB,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,uBAAuB,CAAC,CAAC;IAC7F,OAAO;QACL,WAAW;QACX,SAAS;QACT,kBAAkB,EAAE,GAAG;KACxB,CAAA;AACH,CAAC;AAED,SAAS,mBAAmB;IAC1B,MAAM,WAAW,GAAG,kBAAkB,CAAC,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;IACxE,MAAM,SAAS,GAAG,kBAAkB,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;IAClE,OAAO;QACL,WAAW;QACX,SAAS;QACT,kBAAkB,EAAE,CAAC,WAAW,CAAC;KAClC,CAAA;AACH,CAAC"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/server/config.ts b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/server/config.ts index 07c90ee26b..52699d800c 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/server/config.ts +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/server/config.ts @@ -22,6 +22,7 @@ type CommonConfig = BaseConfig & { type EnvConfig = BaseConfig & { frontendUrl: string; + serverUrl: string; } type Config = CommonConfig & EnvConfig @@ -48,16 +49,20 @@ export default resolvedConfig function getDevelopmentConfig(): EnvConfig { const frontendUrl = stripTrailingSlash(process.env.WASP_WEB_CLIENT_URL || 'http://localhost:3000/'); + const serverUrl = stripTrailingSlash(process.env.WASP_SERVER_URL || 'http://localhost:3001'); return { frontendUrl, + serverUrl, allowedCORSOrigins: '*', } } function getProductionConfig(): EnvConfig { const frontendUrl = stripTrailingSlash(process.env.WASP_WEB_CLIENT_URL); + const serverUrl = stripTrailingSlash(process.env.WASP_SERVER_URL); return { frontendUrl, + serverUrl, allowedCORSOrigins: [frontendUrl], } } diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/server/scripts/validate-env.mjs b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/server/scripts/validate-env.mjs index ac264b7961..f6e50aceca 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/server/scripts/validate-env.mjs +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/server/scripts/validate-env.mjs @@ -2,3 +2,4 @@ import { throwIfNotValidAbsoluteURL } from 'wasp/universal/validators'; console.info("🔍 Validating environment variables..."); throwIfNotValidAbsoluteURL(process.env.WASP_WEB_CLIENT_URL, 'Environment variable WASP_WEB_CLIENT_URL'); +throwIfNotValidAbsoluteURL(process.env.WASP_SERVER_URL, 'Environment variable WASP_SERVER_URL'); diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/server/config.d.ts b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/server/config.d.ts index 223bb1b22c..68bb448c56 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/server/config.d.ts +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/server/config.d.ts @@ -9,6 +9,7 @@ type CommonConfig = BaseConfig & { }; type EnvConfig = BaseConfig & { frontendUrl: string; + serverUrl: string; }; type Config = CommonConfig & EnvConfig; declare const resolvedConfig: Config; diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/server/config.js b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/server/config.js index 6de1c8d25f..dabd38b4b0 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/server/config.js +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/server/config.js @@ -17,15 +17,19 @@ const resolvedConfig = merge(config.all, config[env]); export default resolvedConfig; function getDevelopmentConfig() { const frontendUrl = stripTrailingSlash(process.env.WASP_WEB_CLIENT_URL || 'http://localhost:3000/'); + const serverUrl = stripTrailingSlash(process.env.WASP_SERVER_URL || 'http://localhost:3001'); return { frontendUrl, + serverUrl, allowedCORSOrigins: '*', }; } function getProductionConfig() { const frontendUrl = stripTrailingSlash(process.env.WASP_WEB_CLIENT_URL); + const serverUrl = stripTrailingSlash(process.env.WASP_SERVER_URL); return { frontendUrl, + serverUrl, allowedCORSOrigins: [frontendUrl], }; } diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/server/config.js.map b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/server/config.js.map index 4b121ba37d..f4ad188c93 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/server/config.js.map +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/server/config.js.map @@ -1 +1 @@ -{"version":3,"file":"config.js","sourceRoot":"","sources":["../../server/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,cAAc,CAAA;AAEhC,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAExD,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,aAAa,CAAA;AAwBjD,MAAM,MAAM,GAIR;IACF,GAAG,EAAE;QACH,GAAG;QACH,aAAa,EAAE,GAAG,KAAK,aAAa;QACpC,IAAI,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,IAAI;QACxC,WAAW,EAAE,OAAO,CAAC,GAAG,CAAC,YAAY;QACrC,kBAAkB,EAAE,EAAE;KACvB;IACD,WAAW,EAAE,oBAAoB,EAAE;IACnC,UAAU,EAAE,mBAAmB,EAAE;CAClC,CAAA;AAED,MAAM,cAAc,GAAW,KAAK,CAAC,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAA;AAC7D,aAAa;AACb,eAAe,cAAc,CAAA;AAE7B,SAAS,oBAAoB;IAC3B,MAAM,WAAW,GAAG,kBAAkB,CAAC,OAAO,CAAC,GAAG,CAAC,mBAAmB,IAAI,wBAAwB,CAAC,CAAC;IACpG,OAAO;QACL,WAAW;QACX,kBAAkB,EAAE,GAAG;KACxB,CAAA;AACH,CAAC;AAED,SAAS,mBAAmB;IAC1B,MAAM,WAAW,GAAG,kBAAkB,CAAC,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;IACxE,OAAO;QACL,WAAW;QACX,kBAAkB,EAAE,CAAC,WAAW,CAAC;KAClC,CAAA;AACH,CAAC"} \ No newline at end of file +{"version":3,"file":"config.js","sourceRoot":"","sources":["../../server/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,cAAc,CAAA;AAEhC,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAExD,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,aAAa,CAAA;AAyBjD,MAAM,MAAM,GAIR;IACF,GAAG,EAAE;QACH,GAAG;QACH,aAAa,EAAE,GAAG,KAAK,aAAa;QACpC,IAAI,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,IAAI;QACxC,WAAW,EAAE,OAAO,CAAC,GAAG,CAAC,YAAY;QACrC,kBAAkB,EAAE,EAAE;KACvB;IACD,WAAW,EAAE,oBAAoB,EAAE;IACnC,UAAU,EAAE,mBAAmB,EAAE;CAClC,CAAA;AAED,MAAM,cAAc,GAAW,KAAK,CAAC,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAA;AAC7D,aAAa;AACb,eAAe,cAAc,CAAA;AAE7B,SAAS,oBAAoB;IAC3B,MAAM,WAAW,GAAG,kBAAkB,CAAC,OAAO,CAAC,GAAG,CAAC,mBAAmB,IAAI,wBAAwB,CAAC,CAAC;IACpG,MAAM,SAAS,GAAG,kBAAkB,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,uBAAuB,CAAC,CAAC;IAC7F,OAAO;QACL,WAAW;QACX,SAAS;QACT,kBAAkB,EAAE,GAAG;KACxB,CAAA;AACH,CAAC;AAED,SAAS,mBAAmB;IAC1B,MAAM,WAAW,GAAG,kBAAkB,CAAC,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;IACxE,MAAM,SAAS,GAAG,kBAAkB,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;IAClE,OAAO;QACL,WAAW;QACX,SAAS;QACT,kBAAkB,EAAE,CAAC,WAAW,CAAC;KAClC,CAAA;AACH,CAAC"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/server/config.ts b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/server/config.ts index 07c90ee26b..52699d800c 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/server/config.ts +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/server/config.ts @@ -22,6 +22,7 @@ type CommonConfig = BaseConfig & { type EnvConfig = BaseConfig & { frontendUrl: string; + serverUrl: string; } type Config = CommonConfig & EnvConfig @@ -48,16 +49,20 @@ export default resolvedConfig function getDevelopmentConfig(): EnvConfig { const frontendUrl = stripTrailingSlash(process.env.WASP_WEB_CLIENT_URL || 'http://localhost:3000/'); + const serverUrl = stripTrailingSlash(process.env.WASP_SERVER_URL || 'http://localhost:3001'); return { frontendUrl, + serverUrl, allowedCORSOrigins: '*', } } function getProductionConfig(): EnvConfig { const frontendUrl = stripTrailingSlash(process.env.WASP_WEB_CLIENT_URL); + const serverUrl = stripTrailingSlash(process.env.WASP_SERVER_URL); return { frontendUrl, + serverUrl, allowedCORSOrigins: [frontendUrl], } } diff --git a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/.waspchecksums b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/.waspchecksums index 49b42b1ff9..4332d9cec4 100644 --- a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/.waspchecksums +++ b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/.waspchecksums @@ -242,7 +242,7 @@ "file", "../out/sdk/wasp/server/config.ts" ], - "4976e545d8fcf019508e95f472305e9ef27dfb3423c71e428a5414e35cdd52be" + "e5388a9259a22671ee2d2ef46d2c09fdd46c3b3ec24248c7a0b471c0fbf7aa54" ], [ [ @@ -431,7 +431,7 @@ "file", "server/scripts/validate-env.mjs" ], - "65168a764fc6cbe785ee40a8e8533b4694ef9019fc5a73f60f7252152330d0a2" + "100177b4326ccab7362eff378315d532ad1cc17cd28d1ed5978cb167fd627746" ], [ [ diff --git a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/server/config.d.ts b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/server/config.d.ts index 223bb1b22c..68bb448c56 100644 --- a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/server/config.d.ts +++ b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/server/config.d.ts @@ -9,6 +9,7 @@ type CommonConfig = BaseConfig & { }; type EnvConfig = BaseConfig & { frontendUrl: string; + serverUrl: string; }; type Config = CommonConfig & EnvConfig; declare const resolvedConfig: Config; diff --git a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/server/config.js b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/server/config.js index 6de1c8d25f..dabd38b4b0 100644 --- a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/server/config.js +++ b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/server/config.js @@ -17,15 +17,19 @@ const resolvedConfig = merge(config.all, config[env]); export default resolvedConfig; function getDevelopmentConfig() { const frontendUrl = stripTrailingSlash(process.env.WASP_WEB_CLIENT_URL || 'http://localhost:3000/'); + const serverUrl = stripTrailingSlash(process.env.WASP_SERVER_URL || 'http://localhost:3001'); return { frontendUrl, + serverUrl, allowedCORSOrigins: '*', }; } function getProductionConfig() { const frontendUrl = stripTrailingSlash(process.env.WASP_WEB_CLIENT_URL); + const serverUrl = stripTrailingSlash(process.env.WASP_SERVER_URL); return { frontendUrl, + serverUrl, allowedCORSOrigins: [frontendUrl], }; } diff --git a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/server/config.js.map b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/server/config.js.map index 4b121ba37d..f4ad188c93 100644 --- a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/server/config.js.map +++ b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/server/config.js.map @@ -1 +1 @@ -{"version":3,"file":"config.js","sourceRoot":"","sources":["../../server/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,cAAc,CAAA;AAEhC,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAExD,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,aAAa,CAAA;AAwBjD,MAAM,MAAM,GAIR;IACF,GAAG,EAAE;QACH,GAAG;QACH,aAAa,EAAE,GAAG,KAAK,aAAa;QACpC,IAAI,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,IAAI;QACxC,WAAW,EAAE,OAAO,CAAC,GAAG,CAAC,YAAY;QACrC,kBAAkB,EAAE,EAAE;KACvB;IACD,WAAW,EAAE,oBAAoB,EAAE;IACnC,UAAU,EAAE,mBAAmB,EAAE;CAClC,CAAA;AAED,MAAM,cAAc,GAAW,KAAK,CAAC,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAA;AAC7D,aAAa;AACb,eAAe,cAAc,CAAA;AAE7B,SAAS,oBAAoB;IAC3B,MAAM,WAAW,GAAG,kBAAkB,CAAC,OAAO,CAAC,GAAG,CAAC,mBAAmB,IAAI,wBAAwB,CAAC,CAAC;IACpG,OAAO;QACL,WAAW;QACX,kBAAkB,EAAE,GAAG;KACxB,CAAA;AACH,CAAC;AAED,SAAS,mBAAmB;IAC1B,MAAM,WAAW,GAAG,kBAAkB,CAAC,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;IACxE,OAAO;QACL,WAAW;QACX,kBAAkB,EAAE,CAAC,WAAW,CAAC;KAClC,CAAA;AACH,CAAC"} \ No newline at end of file +{"version":3,"file":"config.js","sourceRoot":"","sources":["../../server/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,cAAc,CAAA;AAEhC,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAExD,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,aAAa,CAAA;AAyBjD,MAAM,MAAM,GAIR;IACF,GAAG,EAAE;QACH,GAAG;QACH,aAAa,EAAE,GAAG,KAAK,aAAa;QACpC,IAAI,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,IAAI;QACxC,WAAW,EAAE,OAAO,CAAC,GAAG,CAAC,YAAY;QACrC,kBAAkB,EAAE,EAAE;KACvB;IACD,WAAW,EAAE,oBAAoB,EAAE;IACnC,UAAU,EAAE,mBAAmB,EAAE;CAClC,CAAA;AAED,MAAM,cAAc,GAAW,KAAK,CAAC,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAA;AAC7D,aAAa;AACb,eAAe,cAAc,CAAA;AAE7B,SAAS,oBAAoB;IAC3B,MAAM,WAAW,GAAG,kBAAkB,CAAC,OAAO,CAAC,GAAG,CAAC,mBAAmB,IAAI,wBAAwB,CAAC,CAAC;IACpG,MAAM,SAAS,GAAG,kBAAkB,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,uBAAuB,CAAC,CAAC;IAC7F,OAAO;QACL,WAAW;QACX,SAAS;QACT,kBAAkB,EAAE,GAAG;KACxB,CAAA;AACH,CAAC;AAED,SAAS,mBAAmB;IAC1B,MAAM,WAAW,GAAG,kBAAkB,CAAC,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;IACxE,MAAM,SAAS,GAAG,kBAAkB,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;IAClE,OAAO;QACL,WAAW;QACX,SAAS;QACT,kBAAkB,EAAE,CAAC,WAAW,CAAC;KAClC,CAAA;AACH,CAAC"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/server/config.ts b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/server/config.ts index 07c90ee26b..52699d800c 100644 --- a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/server/config.ts +++ b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/server/config.ts @@ -22,6 +22,7 @@ type CommonConfig = BaseConfig & { type EnvConfig = BaseConfig & { frontendUrl: string; + serverUrl: string; } type Config = CommonConfig & EnvConfig @@ -48,16 +49,20 @@ export default resolvedConfig function getDevelopmentConfig(): EnvConfig { const frontendUrl = stripTrailingSlash(process.env.WASP_WEB_CLIENT_URL || 'http://localhost:3000/'); + const serverUrl = stripTrailingSlash(process.env.WASP_SERVER_URL || 'http://localhost:3001'); return { frontendUrl, + serverUrl, allowedCORSOrigins: '*', } } function getProductionConfig(): EnvConfig { const frontendUrl = stripTrailingSlash(process.env.WASP_WEB_CLIENT_URL); + const serverUrl = stripTrailingSlash(process.env.WASP_SERVER_URL); return { frontendUrl, + serverUrl, allowedCORSOrigins: [frontendUrl], } } diff --git a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/server/scripts/validate-env.mjs b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/server/scripts/validate-env.mjs index ac264b7961..f6e50aceca 100644 --- a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/server/scripts/validate-env.mjs +++ b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/server/scripts/validate-env.mjs @@ -2,3 +2,4 @@ import { throwIfNotValidAbsoluteURL } from 'wasp/universal/validators'; console.info("🔍 Validating environment variables..."); throwIfNotValidAbsoluteURL(process.env.WASP_WEB_CLIENT_URL, 'Environment variable WASP_WEB_CLIENT_URL'); +throwIfNotValidAbsoluteURL(process.env.WASP_SERVER_URL, 'Environment variable WASP_SERVER_URL'); diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/.waspchecksums b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/.waspchecksums index 882a3b1180..52bcba6311 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/.waspchecksums +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/.waspchecksums @@ -529,7 +529,7 @@ "file", "../out/sdk/wasp/server/config.ts" ], - "5d933eb55d44f4c3c42df7e8387dbd4b8b02f47191e59ee50d59c08a1f86634e" + "0cb590d15087323479f4a0e3622c464b6f172979e01a35c71521d31f6457a46f" ], [ [ @@ -823,7 +823,7 @@ "file", "server/scripts/validate-env.mjs" ], - "65168a764fc6cbe785ee40a8e8533b4694ef9019fc5a73f60f7252152330d0a2" + "100177b4326ccab7362eff378315d532ad1cc17cd28d1ed5978cb167fd627746" ], [ [ diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/server/config.d.ts b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/server/config.d.ts index 623a32bd91..56da48e819 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/server/config.d.ts +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/server/config.d.ts @@ -12,6 +12,7 @@ type CommonConfig = BaseConfig & { }; type EnvConfig = BaseConfig & { frontendUrl: string; + serverUrl: string; }; type Config = CommonConfig & EnvConfig; declare const resolvedConfig: Config; diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/server/config.js b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/server/config.js index 1a38557c02..7fd7f5e7e9 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/server/config.js +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/server/config.js @@ -20,8 +20,10 @@ const resolvedConfig = merge(config.all, config[env]); export default resolvedConfig; function getDevelopmentConfig() { const frontendUrl = stripTrailingSlash(process.env.WASP_WEB_CLIENT_URL || 'http://localhost:3000/'); + const serverUrl = stripTrailingSlash(process.env.WASP_SERVER_URL || 'http://localhost:3001'); return { frontendUrl, + serverUrl, allowedCORSOrigins: '*', auth: { jwtSecret: 'DEVJWTSECRET' @@ -30,8 +32,10 @@ function getDevelopmentConfig() { } function getProductionConfig() { const frontendUrl = stripTrailingSlash(process.env.WASP_WEB_CLIENT_URL); + const serverUrl = stripTrailingSlash(process.env.WASP_SERVER_URL); return { frontendUrl, + serverUrl, allowedCORSOrigins: [frontendUrl], auth: { jwtSecret: process.env.JWT_SECRET diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/server/config.js.map b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/server/config.js.map index 9f40b26c5b..d2f0e1bb1c 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/server/config.js.map +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/server/config.js.map @@ -1 +1 @@ -{"version":3,"file":"config.js","sourceRoot":"","sources":["../../server/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,cAAc,CAAA;AAEhC,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAExD,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,aAAa,CAAA;AA2BjD,MAAM,MAAM,GAIR;IACF,GAAG,EAAE;QACH,GAAG;QACH,aAAa,EAAE,GAAG,KAAK,aAAa;QACpC,IAAI,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,IAAI;QACxC,WAAW,EAAE,OAAO,CAAC,GAAG,CAAC,YAAY;QACrC,kBAAkB,EAAE,EAAE;QACtB,IAAI,EAAE;YACJ,SAAS,EAAE,SAAS;SACrB;KACF;IACD,WAAW,EAAE,oBAAoB,EAAE;IACnC,UAAU,EAAE,mBAAmB,EAAE;CAClC,CAAA;AAED,MAAM,cAAc,GAAW,KAAK,CAAC,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAA;AAC7D,aAAa;AACb,eAAe,cAAc,CAAA;AAE7B,SAAS,oBAAoB;IAC3B,MAAM,WAAW,GAAG,kBAAkB,CAAC,OAAO,CAAC,GAAG,CAAC,mBAAmB,IAAI,wBAAwB,CAAC,CAAC;IACpG,OAAO;QACL,WAAW;QACX,kBAAkB,EAAE,GAAG;QACvB,IAAI,EAAE;YACJ,SAAS,EAAE,cAAc;SAC1B;KACF,CAAA;AACH,CAAC;AAED,SAAS,mBAAmB;IAC1B,MAAM,WAAW,GAAG,kBAAkB,CAAC,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;IACxE,OAAO;QACL,WAAW;QACX,kBAAkB,EAAE,CAAC,WAAW,CAAC;QACjC,IAAI,EAAE;YACJ,SAAS,EAAE,OAAO,CAAC,GAAG,CAAC,UAAU;SAClC;KACF,CAAA;AACH,CAAC"} \ No newline at end of file +{"version":3,"file":"config.js","sourceRoot":"","sources":["../../server/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,cAAc,CAAA;AAEhC,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAExD,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,aAAa,CAAA;AA4BjD,MAAM,MAAM,GAIR;IACF,GAAG,EAAE;QACH,GAAG;QACH,aAAa,EAAE,GAAG,KAAK,aAAa;QACpC,IAAI,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,IAAI;QACxC,WAAW,EAAE,OAAO,CAAC,GAAG,CAAC,YAAY;QACrC,kBAAkB,EAAE,EAAE;QACtB,IAAI,EAAE;YACJ,SAAS,EAAE,SAAS;SACrB;KACF;IACD,WAAW,EAAE,oBAAoB,EAAE;IACnC,UAAU,EAAE,mBAAmB,EAAE;CAClC,CAAA;AAED,MAAM,cAAc,GAAW,KAAK,CAAC,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAA;AAC7D,aAAa;AACb,eAAe,cAAc,CAAA;AAE7B,SAAS,oBAAoB;IAC3B,MAAM,WAAW,GAAG,kBAAkB,CAAC,OAAO,CAAC,GAAG,CAAC,mBAAmB,IAAI,wBAAwB,CAAC,CAAC;IACpG,MAAM,SAAS,GAAG,kBAAkB,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,uBAAuB,CAAC,CAAC;IAC7F,OAAO;QACL,WAAW;QACX,SAAS;QACT,kBAAkB,EAAE,GAAG;QACvB,IAAI,EAAE;YACJ,SAAS,EAAE,cAAc;SAC1B;KACF,CAAA;AACH,CAAC;AAED,SAAS,mBAAmB;IAC1B,MAAM,WAAW,GAAG,kBAAkB,CAAC,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;IACxE,MAAM,SAAS,GAAG,kBAAkB,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;IAClE,OAAO;QACL,WAAW;QACX,SAAS;QACT,kBAAkB,EAAE,CAAC,WAAW,CAAC;QACjC,IAAI,EAAE;YACJ,SAAS,EAAE,OAAO,CAAC,GAAG,CAAC,UAAU;SAClC;KACF,CAAA;AACH,CAAC"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/server/config.ts b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/server/config.ts index 5c22ee596d..90bc82125a 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/server/config.ts +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/server/config.ts @@ -25,6 +25,7 @@ type CommonConfig = BaseConfig & { type EnvConfig = BaseConfig & { frontendUrl: string; + serverUrl: string; } type Config = CommonConfig & EnvConfig @@ -54,8 +55,10 @@ export default resolvedConfig function getDevelopmentConfig(): EnvConfig { const frontendUrl = stripTrailingSlash(process.env.WASP_WEB_CLIENT_URL || 'http://localhost:3000/'); + const serverUrl = stripTrailingSlash(process.env.WASP_SERVER_URL || 'http://localhost:3001'); return { frontendUrl, + serverUrl, allowedCORSOrigins: '*', auth: { jwtSecret: 'DEVJWTSECRET' @@ -65,8 +68,10 @@ function getDevelopmentConfig(): EnvConfig { function getProductionConfig(): EnvConfig { const frontendUrl = stripTrailingSlash(process.env.WASP_WEB_CLIENT_URL); + const serverUrl = stripTrailingSlash(process.env.WASP_SERVER_URL); return { frontendUrl, + serverUrl, allowedCORSOrigins: [frontendUrl], auth: { jwtSecret: process.env.JWT_SECRET diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/server/scripts/validate-env.mjs b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/server/scripts/validate-env.mjs index ac264b7961..f6e50aceca 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/server/scripts/validate-env.mjs +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/server/scripts/validate-env.mjs @@ -2,3 +2,4 @@ import { throwIfNotValidAbsoluteURL } from 'wasp/universal/validators'; console.info("🔍 Validating environment variables..."); throwIfNotValidAbsoluteURL(process.env.WASP_WEB_CLIENT_URL, 'Environment variable WASP_WEB_CLIENT_URL'); +throwIfNotValidAbsoluteURL(process.env.WASP_SERVER_URL, 'Environment variable WASP_SERVER_URL'); diff --git a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/.waspchecksums b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/.waspchecksums index 351b1c914f..12348ec0e4 100644 --- a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/.waspchecksums +++ b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/.waspchecksums @@ -249,7 +249,7 @@ "file", "../out/sdk/wasp/server/config.ts" ], - "4976e545d8fcf019508e95f472305e9ef27dfb3423c71e428a5414e35cdd52be" + "e5388a9259a22671ee2d2ef46d2c09fdd46c3b3ec24248c7a0b471c0fbf7aa54" ], [ [ @@ -487,7 +487,7 @@ "file", "server/scripts/validate-env.mjs" ], - "65168a764fc6cbe785ee40a8e8533b4694ef9019fc5a73f60f7252152330d0a2" + "100177b4326ccab7362eff378315d532ad1cc17cd28d1ed5978cb167fd627746" ], [ [ diff --git a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/server/config.d.ts b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/server/config.d.ts index 223bb1b22c..68bb448c56 100644 --- a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/server/config.d.ts +++ b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/server/config.d.ts @@ -9,6 +9,7 @@ type CommonConfig = BaseConfig & { }; type EnvConfig = BaseConfig & { frontendUrl: string; + serverUrl: string; }; type Config = CommonConfig & EnvConfig; declare const resolvedConfig: Config; diff --git a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/server/config.js b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/server/config.js index 6de1c8d25f..dabd38b4b0 100644 --- a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/server/config.js +++ b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/server/config.js @@ -17,15 +17,19 @@ const resolvedConfig = merge(config.all, config[env]); export default resolvedConfig; function getDevelopmentConfig() { const frontendUrl = stripTrailingSlash(process.env.WASP_WEB_CLIENT_URL || 'http://localhost:3000/'); + const serverUrl = stripTrailingSlash(process.env.WASP_SERVER_URL || 'http://localhost:3001'); return { frontendUrl, + serverUrl, allowedCORSOrigins: '*', }; } function getProductionConfig() { const frontendUrl = stripTrailingSlash(process.env.WASP_WEB_CLIENT_URL); + const serverUrl = stripTrailingSlash(process.env.WASP_SERVER_URL); return { frontendUrl, + serverUrl, allowedCORSOrigins: [frontendUrl], }; } diff --git a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/server/config.js.map b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/server/config.js.map index 4b121ba37d..f4ad188c93 100644 --- a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/server/config.js.map +++ b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/server/config.js.map @@ -1 +1 @@ -{"version":3,"file":"config.js","sourceRoot":"","sources":["../../server/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,cAAc,CAAA;AAEhC,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAExD,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,aAAa,CAAA;AAwBjD,MAAM,MAAM,GAIR;IACF,GAAG,EAAE;QACH,GAAG;QACH,aAAa,EAAE,GAAG,KAAK,aAAa;QACpC,IAAI,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,IAAI;QACxC,WAAW,EAAE,OAAO,CAAC,GAAG,CAAC,YAAY;QACrC,kBAAkB,EAAE,EAAE;KACvB;IACD,WAAW,EAAE,oBAAoB,EAAE;IACnC,UAAU,EAAE,mBAAmB,EAAE;CAClC,CAAA;AAED,MAAM,cAAc,GAAW,KAAK,CAAC,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAA;AAC7D,aAAa;AACb,eAAe,cAAc,CAAA;AAE7B,SAAS,oBAAoB;IAC3B,MAAM,WAAW,GAAG,kBAAkB,CAAC,OAAO,CAAC,GAAG,CAAC,mBAAmB,IAAI,wBAAwB,CAAC,CAAC;IACpG,OAAO;QACL,WAAW;QACX,kBAAkB,EAAE,GAAG;KACxB,CAAA;AACH,CAAC;AAED,SAAS,mBAAmB;IAC1B,MAAM,WAAW,GAAG,kBAAkB,CAAC,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;IACxE,OAAO;QACL,WAAW;QACX,kBAAkB,EAAE,CAAC,WAAW,CAAC;KAClC,CAAA;AACH,CAAC"} \ No newline at end of file +{"version":3,"file":"config.js","sourceRoot":"","sources":["../../server/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,cAAc,CAAA;AAEhC,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAExD,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,aAAa,CAAA;AAyBjD,MAAM,MAAM,GAIR;IACF,GAAG,EAAE;QACH,GAAG;QACH,aAAa,EAAE,GAAG,KAAK,aAAa;QACpC,IAAI,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,IAAI;QACxC,WAAW,EAAE,OAAO,CAAC,GAAG,CAAC,YAAY;QACrC,kBAAkB,EAAE,EAAE;KACvB;IACD,WAAW,EAAE,oBAAoB,EAAE;IACnC,UAAU,EAAE,mBAAmB,EAAE;CAClC,CAAA;AAED,MAAM,cAAc,GAAW,KAAK,CAAC,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAA;AAC7D,aAAa;AACb,eAAe,cAAc,CAAA;AAE7B,SAAS,oBAAoB;IAC3B,MAAM,WAAW,GAAG,kBAAkB,CAAC,OAAO,CAAC,GAAG,CAAC,mBAAmB,IAAI,wBAAwB,CAAC,CAAC;IACpG,MAAM,SAAS,GAAG,kBAAkB,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,uBAAuB,CAAC,CAAC;IAC7F,OAAO;QACL,WAAW;QACX,SAAS;QACT,kBAAkB,EAAE,GAAG;KACxB,CAAA;AACH,CAAC;AAED,SAAS,mBAAmB;IAC1B,MAAM,WAAW,GAAG,kBAAkB,CAAC,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;IACxE,MAAM,SAAS,GAAG,kBAAkB,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;IAClE,OAAO;QACL,WAAW;QACX,SAAS;QACT,kBAAkB,EAAE,CAAC,WAAW,CAAC;KAClC,CAAA;AACH,CAAC"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/server/config.ts b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/server/config.ts index 07c90ee26b..52699d800c 100644 --- a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/server/config.ts +++ b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/server/config.ts @@ -22,6 +22,7 @@ type CommonConfig = BaseConfig & { type EnvConfig = BaseConfig & { frontendUrl: string; + serverUrl: string; } type Config = CommonConfig & EnvConfig @@ -48,16 +49,20 @@ export default resolvedConfig function getDevelopmentConfig(): EnvConfig { const frontendUrl = stripTrailingSlash(process.env.WASP_WEB_CLIENT_URL || 'http://localhost:3000/'); + const serverUrl = stripTrailingSlash(process.env.WASP_SERVER_URL || 'http://localhost:3001'); return { frontendUrl, + serverUrl, allowedCORSOrigins: '*', } } function getProductionConfig(): EnvConfig { const frontendUrl = stripTrailingSlash(process.env.WASP_WEB_CLIENT_URL); + const serverUrl = stripTrailingSlash(process.env.WASP_SERVER_URL); return { frontendUrl, + serverUrl, allowedCORSOrigins: [frontendUrl], } } diff --git a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/server/scripts/validate-env.mjs b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/server/scripts/validate-env.mjs index ac264b7961..f6e50aceca 100644 --- a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/server/scripts/validate-env.mjs +++ b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/server/scripts/validate-env.mjs @@ -2,3 +2,4 @@ import { throwIfNotValidAbsoluteURL } from 'wasp/universal/validators'; console.info("🔍 Validating environment variables..."); throwIfNotValidAbsoluteURL(process.env.WASP_WEB_CLIENT_URL, 'Environment variable WASP_WEB_CLIENT_URL'); +throwIfNotValidAbsoluteURL(process.env.WASP_SERVER_URL, 'Environment variable WASP_SERVER_URL'); diff --git a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/.waspchecksums b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/.waspchecksums index 7d035b56e8..0eb61fa0c9 100644 --- a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/.waspchecksums +++ b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/.waspchecksums @@ -242,7 +242,7 @@ "file", "../out/sdk/wasp/server/config.ts" ], - "4976e545d8fcf019508e95f472305e9ef27dfb3423c71e428a5414e35cdd52be" + "e5388a9259a22671ee2d2ef46d2c09fdd46c3b3ec24248c7a0b471c0fbf7aa54" ], [ [ @@ -431,7 +431,7 @@ "file", "server/scripts/validate-env.mjs" ], - "65168a764fc6cbe785ee40a8e8533b4694ef9019fc5a73f60f7252152330d0a2" + "100177b4326ccab7362eff378315d532ad1cc17cd28d1ed5978cb167fd627746" ], [ [ diff --git a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/client/config.ts b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/client/config.ts index e9234e6f2a..b87c9515df 100644 --- a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/client/config.ts +++ b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/client/config.ts @@ -1,6 +1,7 @@ +{{={= =}=}} import { stripTrailingSlash } from 'wasp/universal/url' -const apiUrl = stripTrailingSlash(import.meta.env.REACT_APP_API_URL) || 'http://localhost:3001'; +const apiUrl = stripTrailingSlash(import.meta.env.REACT_APP_API_URL) || '{= defaultServerUrl =}'; const config = { apiUrl, diff --git a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/server/config.d.ts b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/server/config.d.ts index 223bb1b22c..68bb448c56 100644 --- a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/server/config.d.ts +++ b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/server/config.d.ts @@ -9,6 +9,7 @@ type CommonConfig = BaseConfig & { }; type EnvConfig = BaseConfig & { frontendUrl: string; + serverUrl: string; }; type Config = CommonConfig & EnvConfig; declare const resolvedConfig: Config; diff --git a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/server/config.js b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/server/config.js index 6de1c8d25f..dabd38b4b0 100644 --- a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/server/config.js +++ b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/server/config.js @@ -17,15 +17,19 @@ const resolvedConfig = merge(config.all, config[env]); export default resolvedConfig; function getDevelopmentConfig() { const frontendUrl = stripTrailingSlash(process.env.WASP_WEB_CLIENT_URL || 'http://localhost:3000/'); + const serverUrl = stripTrailingSlash(process.env.WASP_SERVER_URL || 'http://localhost:3001'); return { frontendUrl, + serverUrl, allowedCORSOrigins: '*', }; } function getProductionConfig() { const frontendUrl = stripTrailingSlash(process.env.WASP_WEB_CLIENT_URL); + const serverUrl = stripTrailingSlash(process.env.WASP_SERVER_URL); return { frontendUrl, + serverUrl, allowedCORSOrigins: [frontendUrl], }; } diff --git a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/server/config.js.map b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/server/config.js.map index 4b121ba37d..f4ad188c93 100644 --- a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/server/config.js.map +++ b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/server/config.js.map @@ -1 +1 @@ -{"version":3,"file":"config.js","sourceRoot":"","sources":["../../server/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,cAAc,CAAA;AAEhC,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAExD,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,aAAa,CAAA;AAwBjD,MAAM,MAAM,GAIR;IACF,GAAG,EAAE;QACH,GAAG;QACH,aAAa,EAAE,GAAG,KAAK,aAAa;QACpC,IAAI,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,IAAI;QACxC,WAAW,EAAE,OAAO,CAAC,GAAG,CAAC,YAAY;QACrC,kBAAkB,EAAE,EAAE;KACvB;IACD,WAAW,EAAE,oBAAoB,EAAE;IACnC,UAAU,EAAE,mBAAmB,EAAE;CAClC,CAAA;AAED,MAAM,cAAc,GAAW,KAAK,CAAC,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAA;AAC7D,aAAa;AACb,eAAe,cAAc,CAAA;AAE7B,SAAS,oBAAoB;IAC3B,MAAM,WAAW,GAAG,kBAAkB,CAAC,OAAO,CAAC,GAAG,CAAC,mBAAmB,IAAI,wBAAwB,CAAC,CAAC;IACpG,OAAO;QACL,WAAW;QACX,kBAAkB,EAAE,GAAG;KACxB,CAAA;AACH,CAAC;AAED,SAAS,mBAAmB;IAC1B,MAAM,WAAW,GAAG,kBAAkB,CAAC,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;IACxE,OAAO;QACL,WAAW;QACX,kBAAkB,EAAE,CAAC,WAAW,CAAC;KAClC,CAAA;AACH,CAAC"} \ No newline at end of file +{"version":3,"file":"config.js","sourceRoot":"","sources":["../../server/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,cAAc,CAAA;AAEhC,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAExD,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,aAAa,CAAA;AAyBjD,MAAM,MAAM,GAIR;IACF,GAAG,EAAE;QACH,GAAG;QACH,aAAa,EAAE,GAAG,KAAK,aAAa;QACpC,IAAI,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,IAAI;QACxC,WAAW,EAAE,OAAO,CAAC,GAAG,CAAC,YAAY;QACrC,kBAAkB,EAAE,EAAE;KACvB;IACD,WAAW,EAAE,oBAAoB,EAAE;IACnC,UAAU,EAAE,mBAAmB,EAAE;CAClC,CAAA;AAED,MAAM,cAAc,GAAW,KAAK,CAAC,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAA;AAC7D,aAAa;AACb,eAAe,cAAc,CAAA;AAE7B,SAAS,oBAAoB;IAC3B,MAAM,WAAW,GAAG,kBAAkB,CAAC,OAAO,CAAC,GAAG,CAAC,mBAAmB,IAAI,wBAAwB,CAAC,CAAC;IACpG,MAAM,SAAS,GAAG,kBAAkB,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,uBAAuB,CAAC,CAAC;IAC7F,OAAO;QACL,WAAW;QACX,SAAS;QACT,kBAAkB,EAAE,GAAG;KACxB,CAAA;AACH,CAAC;AAED,SAAS,mBAAmB;IAC1B,MAAM,WAAW,GAAG,kBAAkB,CAAC,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;IACxE,MAAM,SAAS,GAAG,kBAAkB,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;IAClE,OAAO;QACL,WAAW;QACX,SAAS;QACT,kBAAkB,EAAE,CAAC,WAAW,CAAC;KAClC,CAAA;AACH,CAAC"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/server/config.ts b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/server/config.ts index 07c90ee26b..52699d800c 100644 --- a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/server/config.ts +++ b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/server/config.ts @@ -22,6 +22,7 @@ type CommonConfig = BaseConfig & { type EnvConfig = BaseConfig & { frontendUrl: string; + serverUrl: string; } type Config = CommonConfig & EnvConfig @@ -48,16 +49,20 @@ export default resolvedConfig function getDevelopmentConfig(): EnvConfig { const frontendUrl = stripTrailingSlash(process.env.WASP_WEB_CLIENT_URL || 'http://localhost:3000/'); + const serverUrl = stripTrailingSlash(process.env.WASP_SERVER_URL || 'http://localhost:3001'); return { frontendUrl, + serverUrl, allowedCORSOrigins: '*', } } function getProductionConfig(): EnvConfig { const frontendUrl = stripTrailingSlash(process.env.WASP_WEB_CLIENT_URL); + const serverUrl = stripTrailingSlash(process.env.WASP_SERVER_URL); return { frontendUrl, + serverUrl, allowedCORSOrigins: [frontendUrl], } } diff --git a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/server/scripts/validate-env.mjs b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/server/scripts/validate-env.mjs index ac264b7961..f6e50aceca 100644 --- a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/server/scripts/validate-env.mjs +++ b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/server/scripts/validate-env.mjs @@ -2,3 +2,4 @@ import { throwIfNotValidAbsoluteURL } from 'wasp/universal/validators'; console.info("🔍 Validating environment variables..."); throwIfNotValidAbsoluteURL(process.env.WASP_WEB_CLIENT_URL, 'Environment variable WASP_WEB_CLIENT_URL'); +throwIfNotValidAbsoluteURL(process.env.WASP_SERVER_URL, 'Environment variable WASP_SERVER_URL'); diff --git a/waspc/packages/deploy/src/providers/fly/setup/setup.ts b/waspc/packages/deploy/src/providers/fly/setup/setup.ts index d229cf2d45..9509e344de 100644 --- a/waspc/packages/deploy/src/providers/fly/setup/setup.ts +++ b/waspc/packages/deploy/src/providers/fly/setup/setup.ts @@ -119,6 +119,7 @@ Press any key to continue or Ctrl+C to cancel.`); // doesn't provide a way to set envars that persist to fly.toml. 'PORT=8080', `WASP_WEB_CLIENT_URL=${deploymentInfo.clientUrl}`, + `WASP_SERVER_URL=${deploymentInfo.serverUrl}`, ]; if (deploymentInfo.options.serverSecret.length > 0) { diff --git a/waspc/src/Wasp/Generator/SdkGenerator.hs b/waspc/src/Wasp/Generator/SdkGenerator.hs index 0b6dc6e95d..b72d391520 100644 --- a/waspc/src/Wasp/Generator/SdkGenerator.hs +++ b/waspc/src/Wasp/Generator/SdkGenerator.hs @@ -53,6 +53,7 @@ import qualified Wasp.Generator.SdkGenerator.Server.OperationsGenerator as Serve import Wasp.Generator.SdkGenerator.ServerApiG (genServerApi) import Wasp.Generator.SdkGenerator.WebSocketGenerator (depsRequiredByWebSockets, genWebSockets) import qualified Wasp.Generator.ServerGenerator.AuthG as ServerAuthG +import qualified Wasp.Generator.ServerGenerator.Common as Server import qualified Wasp.Generator.WebAppGenerator.Common as WebApp import qualified Wasp.Node.Version as NodeVersion import Wasp.Project.Common (WaspProjectDir) @@ -82,7 +83,6 @@ genSdkReal spec = [ genFileCopy [relfile|vite-env.d.ts|], genFileCopy [relfile|api/index.ts|], genFileCopy [relfile|api/events.ts|], - genFileCopy [relfile|client/config.ts|], genFileCopy [relfile|core/storage.ts|], genFileCopy [relfile|server/index.ts|], genFileCopy [relfile|server/HttpError.ts|], @@ -90,6 +90,7 @@ genSdkReal spec = genFileCopy [relfile|client/test/index.ts|], genFileCopy [relfile|client/index.ts|], genFileCopy [relfile|dev/index.ts|], + genClientConfigFile, genServerConfigFile spec, genTsConfigJson, genServerUtils spec, @@ -259,9 +260,17 @@ genServerConfigFile spec = return $ C.mkTmplFdWithData relConfigFilePath tmplDat object [ "isAuthEnabled" .= isAuthEnabled spec, "databaseUrlEnvVarName" .= Db.databaseUrlEnvVarName, - "defaultClientUrl" .= WebApp.getDefaultClientUrl spec + "defaultClientUrl" .= WebApp.getDefaultDevClientUrl spec, + "defaultServerUrl" .= Server.defaultDevServerUrl, + "defaultServerPort" .= Server.defaultServerPort ] +genClientConfigFile :: Generator FileDraft +genClientConfigFile = return $ C.mkTmplFdWithData relConfigFilePath tmplData + where + relConfigFilePath = [relfile|client/config.ts|] + tmplData = object ["defaultServerUrl" .= Server.defaultDevServerUrl] + -- todo(filip): remove this duplication, we have almost the same thing in the -- ServerGenerator. genTsConfigJson :: Generator FileDraft diff --git a/waspc/src/Wasp/Generator/ServerGenerator/Common.hs b/waspc/src/Wasp/Generator/ServerGenerator/Common.hs index 3319bb4bde..cd85159bee 100644 --- a/waspc/src/Wasp/Generator/ServerGenerator/Common.hs +++ b/waspc/src/Wasp/Generator/ServerGenerator/Common.hs @@ -17,6 +17,8 @@ module Wasp.Generator.ServerGenerator.Common ServerSrcDir, ServerTemplatesDir, ServerTemplatesSrcDir, + defaultDevServerUrl, + defaultServerPort, ) where @@ -124,3 +126,9 @@ toESModulesImportPath :: FilePath -> FilePath toESModulesImportPath = changeExtensionTo "js" where changeExtensionTo ext = (++ '.' : ext) . fst . splitExtension + +defaultServerPort :: Int +defaultServerPort = 3001 + +defaultDevServerUrl :: String +defaultDevServerUrl = "http://localhost:" ++ show defaultServerPort diff --git a/waspc/src/Wasp/Generator/WebAppGenerator/Common.hs b/waspc/src/Wasp/Generator/WebAppGenerator/Common.hs index 96420b860b..3e3c6d623b 100644 --- a/waspc/src/Wasp/Generator/WebAppGenerator/Common.hs +++ b/waspc/src/Wasp/Generator/WebAppGenerator/Common.hs @@ -22,7 +22,7 @@ module Wasp.Generator.WebAppGenerator.Common staticAssetsDirInWebAppDir, WebAppStaticAssetsDir, getBaseDir, - getDefaultClientUrl, + getDefaultDevClientUrl, defaultClientPort, ) where @@ -148,5 +148,5 @@ getBaseDir spec = fromMaybe [absdirP|/|] maybeBaseDir defaultClientPort :: Int defaultClientPort = 3000 -getDefaultClientUrl :: AppSpec -> String -getDefaultClientUrl spec = "http://localhost:" ++ show defaultClientPort ++ SP.fromAbsDirP (getBaseDir spec) +getDefaultDevClientUrl :: AppSpec -> String +getDefaultDevClientUrl spec = "http://localhost:" ++ show defaultClientPort ++ SP.fromAbsDirP (getBaseDir spec) diff --git a/web/docs/advanced/deployment/manually.md b/web/docs/advanced/deployment/manually.md index d394ab745f..95fdd3f9dd 100644 --- a/web/docs/advanced/deployment/manually.md +++ b/web/docs/advanced/deployment/manually.md @@ -71,6 +71,11 @@ Here are the environment variables your server will be looking for: The URL where you plan to deploy your frontend app is running (e.g., `https://.netlify.app`). The server needs to know about it to properly configure Same-Origin Policy (CORS) headers. +- `WASP_SERVER_URL` + + The URL where the server is running (e.g., `https://.fly.dev`). + The server needs it to properly redirect users when logging in with OAuth providers like Google or GitHub. + - `JWT_SECRET` ( if using Wasp Auth) You only need this environment variable if you're using Wasp's `auth` features. @@ -178,11 +183,12 @@ Next, let's add a few more environment variables: ```bash flyctl secrets set PORT=8080 flyctl secrets set JWT_SECRET= -flyctl secrets set WASP_WEB_CLIENT_URL= +flyctl secrets set WASP_WEB_CLIENT_URL= +flyctl secrets set WASP_SERVER_URL= ``` :::note -If you do not know what your frontend URL is yet, don't worry. You can set `WASP_WEB_CLIENT_URL` after you deploy your frontend. +If you do not know what your client URL is yet, don't worry. You can set `WASP_WEB_CLIENT_URL` after you deploy your client. ::: @@ -199,7 +205,7 @@ flyctl deploy --remote-only --config ../../fly.toml This will build and deploy the backend of your Wasp app on Fly.io to `https://.fly.dev` 🤘🎸 -Now, if you haven't, you can deploy your frontend and add the client url by running `flyctl secrets set WASP_WEB_CLIENT_URL=`. We suggest using [Netlify](#netlify) for your frontend, but you can use any static hosting provider. +Now, if you haven't, you can deploy your client and add the client URL by running `flyctl secrets set WASP_WEB_CLIENT_URL=`. We suggest using [Netlify](#netlify) for your client, but you can use any static hosting provider. Additionally, some useful `flyctl` commands: @@ -325,6 +331,7 @@ Let's deploy our server first: - click **Variable reference** and select `DATABASE_URL` (it will populate it with the correct value) - add `WASP_WEB_CLIENT_URL` - enter the the `client` domain (e.g. `https://client-production-XXXX.up.railway.app`) + - add `WASP_SERVER_URL` - enter the the `server` domain (e.g. `https://server-production-XXXX.up.railway.app`) - add `JWT_SECRET` - enter a random string at least 32 characters long (use an [online generator](https://djecrety.ir/)) @@ -502,15 +509,16 @@ Heroku does not offer a free plan anymore and `mini` is their cheapest database Heroku will also set `DATABASE_URL` env var for us at this point. If you are using an external database, you will have to set it up yourself. -The `PORT` env var will also be provided by Heroku, so the only two left to set are the `JWT_SECRET` and `WASP_WEB_CLIENT_URL` env vars: +The `PORT` env var will also be provided by Heroku, so the ones left to set are the `JWT_SECRET`, `WASP_WEB_CLIENT_URL` and `WASP_SERVER_URL` env vars: ``` heroku config:set --app JWT_SECRET= -heroku config:set --app WASP_WEB_CLIENT_URL= +heroku config:set --app WASP_WEB_CLIENT_URL= +heroku config:set --app WASP_SERVER_URL= ``` :::note -If you do not know what your frontend URL is yet, don't worry. You can set `WASP_WEB_CLIENT_URL` after you deploy your frontend. +If you do not know what your client URL is yet, don't worry. You can set `WASP_WEB_CLIENT_URL` after you deploy your client. ::: ### Deploy to a Heroku App From 3d5ed1a5d38577a3da9042464971c02c1a40476b Mon Sep 17 00:00:00 2001 From: Mihovil Ilakovac Date: Mon, 18 Mar 2024 13:06:59 +0100 Subject: [PATCH 04/20] Replaces Passport with Arctic for OAuth (#1851) --- waspc/ChangeLog.md | 14 ++ .../src/auth/pages/OAuthCallback.tsx | 132 ++++++++++++++++++ .../src/auth/pages/OAuthCodeExchange.jsx | 70 ---------- .../templates/react-app/src/router.tsx | 10 +- .../sdk/wasp/auth/providers/types.ts | 10 +- .../templates/sdk/wasp/server/utils.ts | 12 +- .../src/auth/providers/config/_oauth.ts | 42 ------ .../src/auth/providers/config/github.ts | 91 ++++++++++++ .../src/auth/providers/config/google.ts | 80 +++++++++++ .../server/src/auth/providers/index.ts | 14 +- .../server/src/auth/providers/oauth/config.ts | 19 +++ .../src/auth/providers/oauth/cookies.ts | 35 +++++ .../src/auth/providers/oauth/createRouter.ts | 112 --------------- .../server/src/auth/providers/oauth/env.ts | 16 +++ .../src/auth/providers/oauth/handler.ts | 108 ++++++++++++++ .../server/src/auth/providers/oauth/init.ts | 76 ---------- .../src/auth/providers/oauth/oneTimeCode.ts | 89 ++++++++++++ .../src/auth/providers/oauth/redirect.ts | 19 +++ .../server/src/auth/providers/oauth/state.ts | 70 ++++++++++ .../server/src/auth/providers/oauth/types.ts | 7 - .../server/src/auth/providers/oauth/user.ts | 86 ++++++++++++ .../waspBuild/.wasp/build/.waspchecksums | 4 +- .../.wasp/build/sdk/wasp/client/config.ts | 2 +- .../build/sdk/wasp/dist/server/utils.d.ts | 1 + .../.wasp/build/sdk/wasp/dist/server/utils.js | 6 + .../build/sdk/wasp/dist/server/utils.js.map | 2 +- .../.wasp/build/sdk/wasp/server/utils.ts | 12 +- .../.wasp/out/sdk/wasp/client/config.ts | 2 +- .../.wasp/out/sdk/wasp/dist/server/utils.d.ts | 1 + .../.wasp/out/sdk/wasp/dist/server/utils.js | 6 + .../out/sdk/wasp/dist/server/utils.js.map | 2 +- .../.wasp/out/sdk/wasp/server/utils.ts | 12 +- .../waspCompile/.wasp/out/.waspchecksums | 4 +- .../.wasp/out/sdk/wasp/client/config.ts | 2 +- .../.wasp/out/sdk/wasp/dist/server/utils.d.ts | 1 + .../.wasp/out/sdk/wasp/dist/server/utils.js | 6 + .../out/sdk/wasp/dist/server/utils.js.map | 2 +- .../.wasp/out/sdk/wasp/server/utils.ts | 12 +- .../waspComplexTest-golden/files.manifest | 12 +- .../waspComplexTest/.wasp/out/.waspchecksums | 70 ++++++++-- .../.wasp/out/installedNpmDepsLog.json | 2 +- .../out/sdk/wasp/auth/providers/types.ts | 10 +- .../.wasp/out/sdk/wasp/client/config.ts | 2 +- .../sdk/wasp/dist/auth/providers/types.d.ts | 6 +- .../.wasp/out/sdk/wasp/dist/server/utils.d.ts | 1 + .../.wasp/out/sdk/wasp/dist/server/utils.js | 6 + .../out/sdk/wasp/dist/server/utils.js.map | 2 +- .../.wasp/out/sdk/wasp/server/utils.ts | 12 +- .../.wasp/out/server/package.json | 3 +- .../src/auth/providers/config/google.ts | 72 +++++++--- .../out/server/src/auth/providers/index.ts | 14 +- .../server/src/auth/providers/oauth/config.ts | 19 +++ .../src/auth/providers/oauth/cookies.ts | 35 +++++ .../src/auth/providers/oauth/createRouter.ts | 111 --------------- .../server/src/auth/providers/oauth/env.ts | 16 +++ .../src/auth/providers/oauth/handler.ts | 108 ++++++++++++++ .../server/src/auth/providers/oauth/init.ts | 76 ---------- .../src/auth/providers/oauth/oneTimeCode.ts | 89 ++++++++++++ .../src/auth/providers/oauth/redirect.ts | 18 +++ .../server/src/auth/providers/oauth/state.ts | 70 ++++++++++ .../server/src/auth/providers/oauth/types.ts | 7 - .../server/src/auth/providers/oauth/user.ts | 85 +++++++++++ .../web-app/src/auth/pages/OAuthCallback.tsx | 131 +++++++++++++++++ .../src/auth/pages/OAuthCodeExchange.jsx | 69 --------- .../.wasp/out/web-app/src/router.tsx | 6 +- .../waspJob/.wasp/out/.waspchecksums | 4 +- .../.wasp/out/sdk/wasp/client/config.ts | 2 +- .../.wasp/out/sdk/wasp/dist/server/utils.d.ts | 1 + .../.wasp/out/sdk/wasp/dist/server/utils.js | 6 + .../out/sdk/wasp/dist/server/utils.js.map | 2 +- .../.wasp/out/sdk/wasp/server/utils.ts | 12 +- .../waspMigrate/.wasp/out/.waspchecksums | 4 +- .../.wasp/out/sdk/wasp/client/config.ts | 5 +- .../.wasp/out/sdk/wasp/dist/server/utils.d.ts | 1 + .../.wasp/out/sdk/wasp/dist/server/utils.js | 6 + .../out/sdk/wasp/dist/server/utils.js.map | 2 +- .../.wasp/out/sdk/wasp/server/utils.ts | 12 +- waspc/examples/todoApp/main.wasp | 8 +- waspc/examples/todoApp/package-lock.json | 122 ++++------------ waspc/examples/todoApp/src/auth/github.js | 4 +- waspc/examples/todoApp/src/auth/google.js | 4 +- waspc/examples/todoApp/src/user.ts | 11 +- waspc/src/Wasp/Generator/AuthProviders.hs | 7 +- .../src/Wasp/Generator/AuthProviders/OAuth.hs | 44 +++--- waspc/src/Wasp/Generator/ServerGenerator.hs | 4 +- .../ServerGenerator/Auth/OAuthAuthG.hs | 83 ++++++----- .../Wasp/Generator/WebAppGenerator/AuthG.hs | 6 +- .../WebAppGenerator/RouterGenerator.hs | 41 +----- 88 files changed, 1699 insertions(+), 933 deletions(-) create mode 100644 waspc/data/Generator/templates/react-app/src/auth/pages/OAuthCallback.tsx delete mode 100644 waspc/data/Generator/templates/react-app/src/auth/pages/OAuthCodeExchange.jsx delete mode 100644 waspc/data/Generator/templates/server/src/auth/providers/config/_oauth.ts create mode 100644 waspc/data/Generator/templates/server/src/auth/providers/config/github.ts create mode 100644 waspc/data/Generator/templates/server/src/auth/providers/config/google.ts create mode 100644 waspc/data/Generator/templates/server/src/auth/providers/oauth/config.ts create mode 100644 waspc/data/Generator/templates/server/src/auth/providers/oauth/cookies.ts delete mode 100644 waspc/data/Generator/templates/server/src/auth/providers/oauth/createRouter.ts create mode 100644 waspc/data/Generator/templates/server/src/auth/providers/oauth/env.ts create mode 100644 waspc/data/Generator/templates/server/src/auth/providers/oauth/handler.ts delete mode 100644 waspc/data/Generator/templates/server/src/auth/providers/oauth/init.ts create mode 100644 waspc/data/Generator/templates/server/src/auth/providers/oauth/oneTimeCode.ts create mode 100644 waspc/data/Generator/templates/server/src/auth/providers/oauth/redirect.ts create mode 100644 waspc/data/Generator/templates/server/src/auth/providers/oauth/state.ts create mode 100644 waspc/data/Generator/templates/server/src/auth/providers/oauth/user.ts create mode 100644 waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/server/src/auth/providers/oauth/config.ts create mode 100644 waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/server/src/auth/providers/oauth/cookies.ts delete mode 100644 waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/server/src/auth/providers/oauth/createRouter.ts create mode 100644 waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/server/src/auth/providers/oauth/env.ts create mode 100644 waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/server/src/auth/providers/oauth/handler.ts delete mode 100644 waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/server/src/auth/providers/oauth/init.ts create mode 100644 waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/server/src/auth/providers/oauth/oneTimeCode.ts create mode 100644 waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/server/src/auth/providers/oauth/redirect.ts create mode 100644 waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/server/src/auth/providers/oauth/state.ts create mode 100644 waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/server/src/auth/providers/oauth/user.ts create mode 100644 waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/web-app/src/auth/pages/OAuthCallback.tsx delete mode 100644 waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/web-app/src/auth/pages/OAuthCodeExchange.jsx diff --git a/waspc/ChangeLog.md b/waspc/ChangeLog.md index b441199b37..af747cfc35 100644 --- a/waspc/ChangeLog.md +++ b/waspc/ChangeLog.md @@ -2,13 +2,27 @@ ## 0.13.0 (2024-03-18) +### ⚠️ Breaking changes + +Wasp 0.13.0 switches away from using Passport for our OAuth providers in favor of [Arctic](https://arctic.js.org/) from the [Lucia](https://lucia-auth.com/) ecosystem. This change simplifies the codebase and makes it easier to add new OAuth providers in the future. + +This however, means that there are breaking changes in the way you define OAuth providers in your Wasp project. + +Read the migration guide at https://wasp-lang.dev/docs/migrate-from-0-12-to-0-13 for more details. + ### 🎉 New features +- Wasp adds support for Keycloak as an OAuth provider. - Wasp now supports defining the `WASP_SERVER_URL` environment variable and exposes it as `serverUrl` in the server config which can be imported from `wasp/server`. ### 🐞 Bug fixes - Projects that import `wasp/auth/types` no longer fail when building the web app. +- Wasp now displays OAuth related errors in the browser instead of redirecting to the login page. + +### 🔧 Small improvements + +- Wasp uses Oslo for handling JWTs. ## 0.12.3 (2024-03-01) diff --git a/waspc/data/Generator/templates/react-app/src/auth/pages/OAuthCallback.tsx b/waspc/data/Generator/templates/react-app/src/auth/pages/OAuthCallback.tsx new file mode 100644 index 0000000000..47d6ad3008 --- /dev/null +++ b/waspc/data/Generator/templates/react-app/src/auth/pages/OAuthCallback.tsx @@ -0,0 +1,132 @@ +{{={= =}=}} +import { useEffect, useRef, useState } from "react"; +import { type AxiosResponse } from "axios"; +import { Redirect, useLocation } from 'react-router-dom' +import { useAuth } from 'wasp/client/auth' +import { api } from 'wasp/client/api' +import { initSession } from 'wasp/auth/helpers/user' + +const wrapperStyles = { + display: "flex", + alignItems: "center", + justifyContent: "center", + padding: "4rem", +}; + +const commonMessageStyles = { + display: 'flex', + alignItems: 'center', + gap: '.5rem', + borderRadius: '.5rem', + padding: '1rem', +}; + +const errorMessageStyles = { + ...commonMessageStyles, + borderColor: 'rgb(240 82 82)', + backgroundColor: 'rgb(253 232 232)', + color: 'rgb(200 30 30)', +}; + +const loadingMessageStyles = { + ...commonMessageStyles, + borderColor: 'rgb(107 114 128)', + backgroundColor: 'rgb(243 244 246)', + color: 'rgb(55 65 81)', +}; + +export function OAuthCallbackPage() { + const { isLoading, error, user } = useOAuthCallbackHandler(); + + if (user !== undefined && user !== null) { + return ; + } + + return ( +
+ {error &&
{error}
} + {isLoading &&
Please wait a moment while we log you in.
} +
+ ); +} + +function useOAuthCallbackHandler() { + const { data: user } = useAuth(); + const [isLoading, setIsLoading] = useState(true); + const [error, setError] = useState(null); + const location = useLocation(); + + async function handleCallback() { + try { + setIsLoading(true); + const query = new URLSearchParams(location.search); + + // If we got redirect with an error, display it to the user + // and don't continue with the login process. + const errorFromRedirect = query.get('error'); + if (errorFromRedirect !== null) { + setError(errorFromRedirect); + return; + } + + const code = location.hash.slice(1); + const response = await exchangeOAuthCodeForToken({ code }); + if (!isResponseWithSessionId(response)) { + setError("Unable to login with the OAuth provider."); + return; + } + await initSession(response.data.sessionId); + } catch (e: unknown) { + console.error(e); + setError("Unable to login with the OAuth provider."); + } finally { + setIsLoading(false); + } + } + + const isFirstRender = useRef(true); + useEffect(() => { + if (isFirstRender.current) { + isFirstRender.current = false; + handleCallback(); + } + }, []); + + return { + user, + error, + isLoading, + }; +} + +const MessageIcon = () => ( + +) + +async function exchangeOAuthCodeForToken(data: { + code: string +}): Promise> { + return api.post('/auth/exchange-code', data) +} + +function isResponseWithSessionId( + response: AxiosResponse +): response is AxiosResponse<{ sessionId: string }> { + return response.data && typeof (response.data as any).sessionId === 'string' +} diff --git a/waspc/data/Generator/templates/react-app/src/auth/pages/OAuthCodeExchange.jsx b/waspc/data/Generator/templates/react-app/src/auth/pages/OAuthCodeExchange.jsx deleted file mode 100644 index 364ba4c65b..0000000000 --- a/waspc/data/Generator/templates/react-app/src/auth/pages/OAuthCodeExchange.jsx +++ /dev/null @@ -1,70 +0,0 @@ -{{={= =}=}} -import React, { useEffect, useRef } from 'react' -import { useHistory } from 'react-router-dom' - -import { config } from 'wasp/client' -import { api } from 'wasp/client/api' -import { initSession } from 'wasp/auth/helpers/user' - -// After a user authenticates via an Oauth 2.0 provider, this is the page that -// the provider should redirect them to, while providing query string parameters -// that contain information needed for the API server to authenticate with the provider. -// This page forwards that information to the API server and in response get a JWT, -// which it stores on the client, therefore completing the OAuth authentication process. -export default function OAuthCodeExchange({ pathToApiServerRouteHandlingOauthRedirect }) { - const history = useHistory() - - // We are using a ref to prevent sending the OAuth token twice in development. - // Since React 18 and using their StrictMode, useEffect is called twice in development. - - // Fixing it this way is not recommended by the docs, but they don't offer any alternatives - // for this particular use case (oauth redirect page): - // https://react.dev/learn/synchronizing-with-effects#how-to-handle-the-effect-firing-twice-in-development - const firstRender = useRef(true) - useEffect(() => { - if (!firstRender.current) { - return - } - // NOTE: Different auth methods will have different Wasp API server validation paths. - // This helps us reuse one component for various methods (e.g., Google, Facebook, etc.). - const apiServerUrlHandlingOauthRedirect = constructOauthRedirectApiServerUrl(pathToApiServerRouteHandlingOauthRedirect) - - exchangeCodeForSessionIdAndRedirect(history, apiServerUrlHandlingOauthRedirect) - return () => { - firstRender.current = false - } - }, [history, pathToApiServerRouteHandlingOauthRedirect]) - - return ( -

Completing login process...

- ) -} - -function constructOauthRedirectApiServerUrl(pathToApiServerRouteHandlingOauthRedirect) { - // Take the redirect query params supplied by the external OAuth provider and - // send them as-is to our backend, so Passport can finish the process. - const queryParams = window.location.search - return `${config.apiUrl}${pathToApiServerRouteHandlingOauthRedirect}${queryParams}` -} - -async function exchangeCodeForSessionIdAndRedirect(history, apiServerUrlHandlingOauthRedirect) { - const sessionId = await exchangeCodeForSessionId(apiServerUrlHandlingOauthRedirect) - - if (sessionId !== null) { - await initSession(sessionId) - history.push('{= onAuthSucceededRedirectTo =}') - } else { - console.error('Error obtaining session ID') - history.push('{= onAuthFailedRedirectTo =}') - } -} - -async function exchangeCodeForSessionId(url) { - try { - const response = await api.get(url) - return response?.data?.sessionId || null - } catch (e) { - console.error(e) - return null - } -} diff --git a/waspc/data/Generator/templates/react-app/src/router.tsx b/waspc/data/Generator/templates/react-app/src/router.tsx index 1113b1e6f1..5234bbd786 100644 --- a/waspc/data/Generator/templates/react-app/src/router.tsx +++ b/waspc/data/Generator/templates/react-app/src/router.tsx @@ -14,7 +14,7 @@ import createAuthRequiredPage from "./auth/pages/createAuthRequiredPage" {=/ pagesToImport =} {=# isExternalAuthEnabled =} -import OAuthCodeExchange from "./auth/pages/OAuthCodeExchange" +import { OAuthCallbackPage } from "./auth/pages/OAuthCallback" {=/ isExternalAuthEnabled =} import { routes } from 'wasp/client/router' @@ -40,13 +40,9 @@ const router = ( /> ))} {=# isExternalAuthEnabled =} - {=# externalAuthProviders =} - {=# authProviderEnabled =} - - + + - {=/ authProviderEnabled =} - {=/ externalAuthProviders =} {=/ isExternalAuthEnabled =} {=# rootComponent.isDefined =} diff --git a/waspc/data/Generator/templates/sdk/wasp/auth/providers/types.ts b/waspc/data/Generator/templates/sdk/wasp/auth/providers/types.ts index 7e1ca77667..71e82c6792 100644 --- a/waspc/data/Generator/templates/sdk/wasp/auth/providers/types.ts +++ b/waspc/data/Generator/templates/sdk/wasp/auth/providers/types.ts @@ -16,19 +16,11 @@ export type ProviderConfig = { // Unique provider identifier, used as part of URL paths id: ProviderName; displayName: string; - // Each provider config can have an init method which is ran on setup time - // e.g. for oAuth providers this is the time when the Passport strategy is registered. - init?(provider: ProviderConfig): Promise; // Every provider must have a setupRouter method which returns the Express router. // In this function we are flexibile to do what ever is necessary to make the provider work. - createRouter(provider: ProviderConfig, initData: InitData): Router; + createRouter(provider: ProviderConfig): Router; }; -// PRIVATE API -export type InitData = { - [key: string]: any; -} - // PRIVATE API export type RequestWithWasp = Request & { wasp?: { [key: string]: any } } diff --git a/waspc/data/Generator/templates/sdk/wasp/server/utils.ts b/waspc/data/Generator/templates/sdk/wasp/server/utils.ts index 35807dd6bb..a71e73fdc6 100644 --- a/waspc/data/Generator/templates/sdk/wasp/server/utils.ts +++ b/waspc/data/Generator/templates/sdk/wasp/server/utils.ts @@ -1,11 +1,6 @@ {{={= =}=}} -import crypto from 'crypto' import { Request, Response, NextFunction } from 'express' -import { readdir } from 'fs' -import { dirname } from 'path' -import { fileURLToPath } from 'url' - {=# isAuthEnabled =} import { type AuthUser } from 'wasp/auth' {=/ isAuthEnabled =} @@ -40,3 +35,10 @@ async (req: RequestWithExtraFields, res: Response, next: NextFunction) => { } export const sleep = (ms: number): Promise => new Promise((r) => setTimeout(r, ms)) + +export function redirect(res: Response, redirectUri: string) { + return res + .status(302) + .setHeader("Location", redirectUri) + .end(); +} diff --git a/waspc/data/Generator/templates/server/src/auth/providers/config/_oauth.ts b/waspc/data/Generator/templates/server/src/auth/providers/config/_oauth.ts deleted file mode 100644 index 6a88b5500f..0000000000 --- a/waspc/data/Generator/templates/server/src/auth/providers/config/_oauth.ts +++ /dev/null @@ -1,42 +0,0 @@ -{{={= =}=}} - -import { createRouter } from "../oauth/createRouter.js"; -import { makeOAuthInit } from "../oauth/init.js"; - -import type { ProviderConfig } from "wasp/auth/providers/types"; -import type { OAuthConfig } from "../oauth/types.js"; - -{=# userSignupFields.isDefined =} -{=& userSignupFields.importStatement =} -const _waspUserSignupFields = {= userSignupFields.importIdentifier =} -{=/ userSignupFields.isDefined =} -{=^ userSignupFields.isDefined =} -const _waspUserSignupFields = undefined -{=/ userSignupFields.isDefined =} -{=# configFn.isDefined =} -{=& configFn.importStatement =} -const _waspUserDefinedConfigFn = {= configFn.importIdentifier =} -{=/ configFn.isDefined =} -{=^ configFn.isDefined =} -const _waspUserDefinedConfigFn = undefined -{=/ configFn.isDefined =} - -const _waspOAuthConfig: OAuthConfig = { - {=# oAuthConfigProps =} - {= key =}: {=& value =}, - {=/ oAuthConfigProps =} -}; - -const _waspConfig: ProviderConfig = { - id: "{= providerId =}", - displayName: "{= displayName =}", - init: makeOAuthInit({ - npmPackage: '{= npmPackage =}', - userSignupFields: _waspUserSignupFields, - userDefinedConfigFn: _waspUserDefinedConfigFn, - oAuthConfig: _waspOAuthConfig, - }), - createRouter, -} - -export default _waspConfig; diff --git a/waspc/data/Generator/templates/server/src/auth/providers/config/github.ts b/waspc/data/Generator/templates/server/src/auth/providers/config/github.ts new file mode 100644 index 0000000000..3bfbd63877 --- /dev/null +++ b/waspc/data/Generator/templates/server/src/auth/providers/config/github.ts @@ -0,0 +1,91 @@ +{{={= =}=}} +import { GitHub } from "arctic"; + +import type { ProviderConfig } from "wasp/auth/providers/types"; +import { ensureEnvVarsForProvider } from "../oauth/env.js"; +import { mergeDefaultAndUserConfig } from "../oauth/config.js"; +import { createOAuthProviderRouter } from "../oauth/handler.js"; + +{=# userSignupFields.isDefined =} +{=& userSignupFields.importStatement =} +const _waspUserSignupFields = {= userSignupFields.importIdentifier =} +{=/ userSignupFields.isDefined =} +{=^ userSignupFields.isDefined =} +const _waspUserSignupFields = undefined +{=/ userSignupFields.isDefined =} +{=# configFn.isDefined =} +{=& configFn.importStatement =} +const _waspUserDefinedConfigFn = {= configFn.importIdentifier =} +{=/ configFn.isDefined =} +{=^ configFn.isDefined =} +const _waspUserDefinedConfigFn = undefined +{=/ configFn.isDefined =} + +const _waspConfig: ProviderConfig = { + id: "{= providerId =}", + displayName: "{= displayName =}", + createRouter(provider) { + const env = ensureEnvVarsForProvider( + ["GITHUB_CLIENT_ID", "GITHUB_CLIENT_SECRET"], + provider + ); + + const github = new GitHub( + env.GITHUB_CLIENT_ID, + env.GITHUB_CLIENT_SECRET, + ); + + const config = mergeDefaultAndUserConfig({ + scopes: {=& requiredScopes =}, + }, _waspUserDefinedConfigFn); + + async function getGithubProfile(accessToken: string): Promise<{ + providerProfile: unknown; + providerUserId: string; + }> { + const response = await fetch("https://api.github.com/user", { + headers: { + Authorization: `Bearer ${accessToken}`, + }, + }); + const providerProfile = (await response.json()) as { + id?: string; + emails?: unknown[]; + }; + + if (!providerProfile.id) { + throw new Error("Invalid profile"); + } + + const scopes = config.scopes as string[]; + // Using the logic from https://github.com/cfsghost/passport-github/blob/master/lib/strategy.js#L118C24-L120C10 + const isEmailAccessAllowed = scopes.some((scope) => { + return scope === 'user' || scope === 'user:email'; + }); + if (isEmailAccessAllowed) { + const emailsResponse = await fetch("https://api.github.com/user/emails", { + headers: { + Authorization: `Bearer ${accessToken}`, + }, + }); + const emails = (await emailsResponse.json()) as unknown[]; + providerProfile.emails = emails; + } + + return { providerProfile, providerUserId: `${providerProfile.id}` }; + } + + return createOAuthProviderRouter({ + provider, + stateTypes: ['state'], + userSignupFields: _waspUserSignupFields, + getAuthorizationUrl: ({ state }) => github.createAuthorizationURL(state, config), + getProviderInfo: async ({ code }) => { + const { accessToken } = await github.validateAuthorizationCode(code); + return getGithubProfile(accessToken); + }, + }); + }, +} + +export default _waspConfig; diff --git a/waspc/data/Generator/templates/server/src/auth/providers/config/google.ts b/waspc/data/Generator/templates/server/src/auth/providers/config/google.ts new file mode 100644 index 0000000000..caf38a87ab --- /dev/null +++ b/waspc/data/Generator/templates/server/src/auth/providers/config/google.ts @@ -0,0 +1,80 @@ +{{={= =}=}} +import { Google } from "arctic"; + +import type { ProviderConfig } from "wasp/auth/providers/types"; +import { getRedirectUriForCallback } from "../oauth/redirect.js"; +import { ensureEnvVarsForProvider } from "../oauth/env.js"; +import { mergeDefaultAndUserConfig } from "../oauth/config.js"; +import { createOAuthProviderRouter } from "../oauth/handler.js"; + +{=# userSignupFields.isDefined =} +{=& userSignupFields.importStatement =} +const _waspUserSignupFields = {= userSignupFields.importIdentifier =} +{=/ userSignupFields.isDefined =} +{=^ userSignupFields.isDefined =} +const _waspUserSignupFields = undefined +{=/ userSignupFields.isDefined =} +{=# configFn.isDefined =} +{=& configFn.importStatement =} +const _waspUserDefinedConfigFn = {= configFn.importIdentifier =} +{=/ configFn.isDefined =} +{=^ configFn.isDefined =} +const _waspUserDefinedConfigFn = undefined +{=/ configFn.isDefined =} + +const _waspConfig: ProviderConfig = { + id: "{= providerId =}", + displayName: "{= displayName =}", + createRouter(provider) { + const env = ensureEnvVarsForProvider( + ["GOOGLE_CLIENT_ID", "GOOGLE_CLIENT_SECRET"], + provider + ); + + const google = new Google( + env.GOOGLE_CLIENT_ID, + env.GOOGLE_CLIENT_SECRET, + getRedirectUriForCallback(provider.id).toString(), + ); + + const config = mergeDefaultAndUserConfig({ + scopes: {=& requiredScopes =}, + }, _waspUserDefinedConfigFn); + + async function getGoogleProfile(accessToken: string): Promise<{ + providerProfile: unknown; + providerUserId: string; + }> { + const response = await fetch( + "https://openidconnect.googleapis.com/v1/userinfo", + { + headers: { + Authorization: `Bearer ${accessToken}`, + }, + } + ); + const providerProfile = (await response.json()) as { + sub?: string; + }; + + if (!providerProfile.sub) { + throw new Error("Invalid profile"); + } + + return { providerProfile, providerUserId: providerProfile.sub }; + } + + return createOAuthProviderRouter({ + provider, + stateTypes: ['state', 'codeVerifier'], + userSignupFields: _waspUserSignupFields, + getAuthorizationUrl: ({ state, codeVerifier }) => google.createAuthorizationURL(state, codeVerifier, config), + getProviderInfo: async ({ code, codeVerifier }) => { + const { accessToken } = await google.validateAuthorizationCode(code, codeVerifier); + return getGoogleProfile(accessToken); + }, + }); + }, +} + +export default _waspConfig; diff --git a/waspc/data/Generator/templates/server/src/auth/providers/index.ts b/waspc/data/Generator/templates/server/src/auth/providers/index.ts index d389667a64..0883aa2eab 100644 --- a/waspc/data/Generator/templates/server/src/auth/providers/index.ts +++ b/waspc/data/Generator/templates/server/src/auth/providers/index.ts @@ -1,5 +1,6 @@ {{={= =}=}} import { Router } from "express"; +import { setupOneTimeCodeRoute } from "./oauth/oneTimeCode"; {=# providers =} {=& importStatement =} @@ -13,14 +14,15 @@ const providers = [ const router = Router(); +// Setting up a common route for all OAuth providers to exchange +// one-time code for a session. +setupOneTimeCodeRoute(router); + for (const provider of providers) { - const { init, createRouter } = provider; - const initData = init - ? await init(provider) - : undefined; - const providerRouter = createRouter(provider, initData); + const { createRouter } = provider; + const providerRouter = createRouter(provider); router.use(`/${provider.id}`, providerRouter); - console.log(`🚀 "${provider.displayName}" auth initialized`) + console.log(`🚀 "${provider.displayName}" auth initialized`); } export default router; diff --git a/waspc/data/Generator/templates/server/src/auth/providers/oauth/config.ts b/waspc/data/Generator/templates/server/src/auth/providers/oauth/config.ts new file mode 100644 index 0000000000..3de0d7e686 --- /dev/null +++ b/waspc/data/Generator/templates/server/src/auth/providers/oauth/config.ts @@ -0,0 +1,19 @@ +export function mergeDefaultAndUserConfig( + defaultConfig: DefaultConfig, + userConfigFn: () => UserConfig, +): DefaultConfig & UserConfig; +export function mergeDefaultAndUserConfig( + defaultConfig: DefaultConfig +): DefaultConfig; +export function mergeDefaultAndUserConfig( + defaultConfig: DefaultConfig, + userConfigFn?: () => UserConfig, +): DefaultConfig { + if (!userConfigFn) { + return defaultConfig; + } + return { + ...defaultConfig, + ...userConfigFn(), + } +} diff --git a/waspc/data/Generator/templates/server/src/auth/providers/oauth/cookies.ts b/waspc/data/Generator/templates/server/src/auth/providers/oauth/cookies.ts new file mode 100644 index 0000000000..88d092f70e --- /dev/null +++ b/waspc/data/Generator/templates/server/src/auth/providers/oauth/cookies.ts @@ -0,0 +1,35 @@ +import { + Request as ExpressRequest, + Response as ExpressResponse, +} from "express"; +import { parseCookies } from "oslo/cookie"; + +import { type ProviderConfig } from "wasp/auth/providers/types"; + +import { type StateType } from './state'; + +export function setOAuthCookieValue( + provider: ProviderConfig, + res: ExpressResponse, + stateType: StateType, + value: string, +) { + const cookieName = `${provider.id}_${stateType}`; + res.cookie(cookieName, value, { + httpOnly: true, + // TODO: use server config to determine if secure + secure: process.env.NODE_ENV === "production", + path: "/", + maxAge: 60 * 60 * 1000, // 1 hour + }); +} + +export function getOAuthCookieValue( + provider: ProviderConfig, + req: ExpressRequest, + stateType: StateType, +) { + const cookieName = `${provider.id}_${stateType}`; + const cookies = parseCookies(req.headers.cookie ?? ""); + return cookies.get(cookieName); +} diff --git a/waspc/data/Generator/templates/server/src/auth/providers/oauth/createRouter.ts b/waspc/data/Generator/templates/server/src/auth/providers/oauth/createRouter.ts deleted file mode 100644 index 38a783304a..0000000000 --- a/waspc/data/Generator/templates/server/src/auth/providers/oauth/createRouter.ts +++ /dev/null @@ -1,112 +0,0 @@ -{{={= =}=}} - -import { Router } from "express" -import passport from "passport" - -import { prisma, config as waspServerConfig } from 'wasp/server' -import { - type ProviderName, - type ProviderId, - createProviderId, - authConfig, - contextWithUserEntity, - createUser, - rethrowPossibleAuthError, - sanitizeAndSerializeProviderData, - validateAndGetUserFields, -} from 'wasp/auth/utils' -import { createSession } from "wasp/auth/session" -import { type {= authEntityUpper =} } from "wasp/entities" -import type { ProviderConfig, RequestWithWasp, UserSignupFields } from "wasp/auth/providers/types" -import { handleRejection } from "wasp/server/utils" - -// For oauth providers, we have an endpoint /login to get the auth URL, -// and the /callback endpoint which is used to get the actual access_token and the user info. -export function createRouter(provider: ProviderConfig, initData: { - passportStrategyName: string, - userSignupFields?: UserSignupFields, -}) { - const { passportStrategyName, userSignupFields } = initData; - - const router = Router(); - - // Constructs a provider OAuth URL and redirects browser to start sign in flow. - router.get('/login', passport.authenticate(passportStrategyName, { session: false })); - - // Validates the OAuth code from the frontend, via server-to-server communication - // with provider. If valid, provides frontend a response containing the JWT. - // NOTE: `addProviderProfileToRequest` is invoked as part of the `passport.authenticate` - // call, before the final route handler callback. This is how we gain access to `req.wasp.providerProfile`. - router.get('/callback', - passport.authenticate(passportStrategyName, { - session: false, - failureRedirect: waspServerConfig.frontendUrl + authConfig.failureRedirectPath - }), - handleRejection(async function (req: RequestWithWasp, res) { - const providerProfile = req?.wasp?.providerProfile; - - if (!providerProfile) { - throw new Error(`Missing ${provider.displayName} provider profile on request. This should not happen! Please contact Wasp.`); - } else if (!providerProfile.id) { - throw new Error(`${provider.displayName} provider profile was missing required id property. This should not happen! Please contact Wasp.`); - } - - const providerId = createProviderId(provider.id, providerProfile.id); - - try { - const authId = await getAuthIdFromProviderDetails(providerId, providerProfile, userSignupFields) - const session = await createSession(authId) - return res.json({ - sessionId: session.id, - }) - } catch (e) { - rethrowPossibleAuthError(e) - } - }) - ) - - return router; -} - -// We need a user id to create the auth token, so we either find an existing user -// or create a new one if none exists for this provider. -async function getAuthIdFromProviderDetails( - providerId: ProviderId, - providerProfile: any, - userSignupFields?: UserSignupFields, -): Promise<{= authEntityUpper =}['id']> { - const existingAuthIdentity = await prisma.{= authIdentityEntityLower =}.findUnique({ - where: { - providerName_providerUserId: providerId, - }, - include: { - {= authFieldOnAuthIdentityEntityName =}: { - include: { - {= userFieldOnAuthEntityName =}: true - } - } - } - }) - - if (existingAuthIdentity) { - return existingAuthIdentity.{= authFieldOnAuthIdentityEntityName =}.id - } else { - const userFields = await validateAndGetUserFields( - { profile: providerProfile }, - userSignupFields, - ); - - // For now, we don't have any extra data for the oauth providers, so we just pass an empty object. - const providerData = await sanitizeAndSerializeProviderData({}) - - const user = await createUser( - providerId, - providerData, - // Using any here because we want to avoid TypeScript errors and - // rely on Prisma to validate the data. - userFields as any, - ) - - return user.auth.id - } -} diff --git a/waspc/data/Generator/templates/server/src/auth/providers/oauth/env.ts b/waspc/data/Generator/templates/server/src/auth/providers/oauth/env.ts new file mode 100644 index 0000000000..24776c6dd3 --- /dev/null +++ b/waspc/data/Generator/templates/server/src/auth/providers/oauth/env.ts @@ -0,0 +1,16 @@ +import { type ProviderConfig } from "wasp/auth/providers/types"; + +export function ensureEnvVarsForProvider( + envVarNames: EnvVarName[], + provider: ProviderConfig, +): Record { + const result: Record = {}; + for (const envVarName of envVarNames) { + const value = process.env[envVarName]; + if (!value) { + throw new Error(`${envVarName} env variable is required when using the ${provider.displayName} auth provider.`); + } + result[envVarName] = value; + } + return result as Record; +} diff --git a/waspc/data/Generator/templates/server/src/auth/providers/oauth/handler.ts b/waspc/data/Generator/templates/server/src/auth/providers/oauth/handler.ts new file mode 100644 index 0000000000..9fdc36c3b9 --- /dev/null +++ b/waspc/data/Generator/templates/server/src/auth/providers/oauth/handler.ts @@ -0,0 +1,108 @@ +import { Router } from "express"; + +import { handleRejection, redirect } from "wasp/server/utils"; +import { rethrowPossibleAuthError } from "wasp/auth/utils"; +import { type UserSignupFields, type ProviderConfig } from "wasp/auth/providers/types"; + +import { + type StateType, + generateAndStoreOAuthState, + validateAndGetOAuthState, +} from "../oauth/state.js"; +import { + finishOAuthFlowAndGetRedirectUri, + handleOAuthErrorAndGetRedirectUri, +} from "../oauth/user.js"; +import { callbackPath, loginPath } from "./redirect.js"; + +export function createOAuthProviderRouter({ + provider, + stateTypes, + userSignupFields, + getAuthorizationUrl, + getProviderInfo, +}: { + provider: ProviderConfig, + /* + - State is used to validate the callback to ensure the user + that requested the login is the same that is completing it. + - It can include just the "state" or an extra "codeVerifier" for PKCE. + - The state types used depend on the provider. + */ + stateTypes: ST[], + userSignupFields: UserSignupFields | undefined, + /* + The function that returns the URL to redirect the user to the + provider's login page. + */ + getAuthorizationUrl: Parameters>[2], + /* + The function that returns the user's profile and ID from the + provider's callback. + */ + getProviderInfo: Parameters>[3], +}): Router { + const router = Router(); + + router.get( + `/${loginPath}`, + createOAuthLoginHandler(provider, stateTypes, getAuthorizationUrl) + ) + + router.get( + `/${callbackPath}`, + createOAuthCallbackHandler( + provider, + stateTypes, + userSignupFields, + getProviderInfo + ) + ) + + return router; +} + +function createOAuthLoginHandler( + provider: ProviderConfig, + stateTypes: ST[], + getAuthorizationUrl: (oAuthState: ReturnType>) => Promise, +) { + return handleRejection(async (_req, res) => { + const oAuthState = generateAndStoreOAuthState(stateTypes, provider, res); + const url = await getAuthorizationUrl(oAuthState); + return redirect(res, url.toString()); + }) +} + +function createOAuthCallbackHandler( + provider: ProviderConfig, + stateTypes: ST[], + userSignupFields: UserSignupFields | undefined, + getProviderInfo: (oAuthState: ReturnType>) => Promise<{ + providerUserId: string, + providerProfile: unknown, + }>, +) { + return handleRejection(async (req, res) => { + try { + const oAuthState = validateAndGetOAuthState(stateTypes, provider, req); + const { providerProfile, providerUserId } = await getProviderInfo(oAuthState); + try { + const redirectUri = await finishOAuthFlowAndGetRedirectUri( + provider, + providerProfile, + providerUserId, + userSignupFields, + ); + // Redirect to the client with the one time code + return redirect(res, redirectUri.toString()); + } catch (e) { + rethrowPossibleAuthError(e); + } + } catch (e) { + const redirectUri = handleOAuthErrorAndGetRedirectUri(e); + // Redirect to the client with the error + return redirect(res, redirectUri.toString()); + } + }) +} diff --git a/waspc/data/Generator/templates/server/src/auth/providers/oauth/init.ts b/waspc/data/Generator/templates/server/src/auth/providers/oauth/init.ts deleted file mode 100644 index 15cb5631fc..0000000000 --- a/waspc/data/Generator/templates/server/src/auth/providers/oauth/init.ts +++ /dev/null @@ -1,76 +0,0 @@ -import passport from "passport"; - -import { config as waspServerConfig } from 'wasp/server'; - -import type { InitData, ProviderConfig, RequestWithWasp, UserSignupFields } from "wasp/auth/providers/types"; -import type { OAuthConfig, UserDefinedConfigFn } from "./types.js"; - -export function makeOAuthInit({ userDefinedConfigFn, userSignupFields, npmPackage, oAuthConfig }: OAuthImports) { - return async function init(provider: ProviderConfig): Promise { - const userDefinedConfig = userDefinedConfigFn - ? userDefinedConfigFn() - : {}; - const ProviderStrategy = await import(npmPackage); - - const passportStrategyName = `wasp${provider.id}LoginStrategy`; - const requiredConfig = { - clientID: oAuthConfig.clientID, - clientSecret: oAuthConfig.clientSecret, - scope: oAuthConfig.scope, - callbackURL: `${waspServerConfig.frontendUrl}/auth/login/${provider.id}`, - passReqToCallback: true - }; - - const config = { - ...requiredConfig, - ...userDefinedConfig, - }; - ensureValidConfig(provider, config); - - const passportStrategy = new ProviderStrategy.default( - config, - addProviderProfileToRequest - ); - passport.use(passportStrategyName, passportStrategy); - - return { - passportStrategyName, - userSignupFields, - }; - } -} - -// This function is invoked after we successfully exchange the one-time-use OAuth code for a real provider API token. -// This token was used to get the provider profile information supplied as a parameter. -// We add the provider profile to the request for downstream use. -async function addProviderProfileToRequest( - req: RequestWithWasp, - _accessToken: string, - _refreshToken: string, - providerProfile: { [key: string]: any }, - done: any, -) { - req.wasp = { ...req.wasp, providerProfile }; - done(null, {}); -} - -function ensureValidConfig(provider: ProviderConfig, config: OAuthConfig): void { - if (!config.clientID) { - throw new Error(`The ${provider.displayName} auth provider requires clientID provided via env variables.`) - } - - if (!config.clientSecret) { - throw new Error(`The ${provider.displayName} auth provider requires clientSecret provided via env variables.`) - } - - if (!config.scope || !Array.isArray(config.scope)) { - throw new Error(`The ${provider.displayName} auth provider requires scope.`) - } -} - -export type OAuthImports = { - npmPackage: string; - userDefinedConfigFn?: UserDefinedConfigFn; - oAuthConfig: OAuthConfig; - userSignupFields?: UserSignupFields; -}; diff --git a/waspc/data/Generator/templates/server/src/auth/providers/oauth/oneTimeCode.ts b/waspc/data/Generator/templates/server/src/auth/providers/oauth/oneTimeCode.ts new file mode 100644 index 0000000000..0b98a1d879 --- /dev/null +++ b/waspc/data/Generator/templates/server/src/auth/providers/oauth/oneTimeCode.ts @@ -0,0 +1,89 @@ +import { Router } from "express"; + +import { HttpError } from 'wasp/server'; +import { handleRejection } from 'wasp/server/utils' +import { createJWT, validateJWT, TimeSpan } from 'wasp/auth/jwt' +import { findAuthWithUserBy } from 'wasp/auth/utils' +import { createSession } from 'wasp/auth/session' +import { exchangeCodeForTokenPath } from "./redirect.js"; + +export const tokenStore = createTokenStore(); + +export function setupOneTimeCodeRoute(router: Router) { + router.post( + `/${exchangeCodeForTokenPath}`, + handleRejection(async (req, res) => { + const { code } = req.body; + + if (code === undefined) { + throw new HttpError(400, "Unable to login with the OAuth provider. The code is missing."); + } + + if (tokenStore.isUsed(code)) { + throw new HttpError(400, "Unable to login with the OAuth provider. The code has already been used."); + } + + const { id: authId } = await tokenStore.verifyToken(code); + const auth = await findAuthWithUserBy({ id: authId }) + + if (auth === null) { + throw new HttpError(400, "Unable to login with the OAuth provider. The code is invalid."); + } + + const session = await createSession(auth.id); + + tokenStore.markUsed(code); + + return res.json({ + sessionId: session.id, + }); + }) + ); +} + +function createTokenStore() { + const usedTokens = new Map(); + + const validFor = new TimeSpan(1, 'm') // 1 minute + const cleanupAfter = 1000 * 60 * 60; // 1 hour + + function createToken(userId: string): Promise { + return createJWT( + { + id: userId, + }, + { + expiresIn: validFor, + } + ); + } + + function verifyToken(token: string): Promise<{ id: string }> { + return validateJWT(token); + } + + function isUsed(token: string): boolean { + return usedTokens.has(token); + } + + function markUsed(token: string): void { + usedTokens.set(token, Date.now()); + cleanUp(); + } + + function cleanUp(): void { + const now = Date.now(); + for (const [token, timestamp] of usedTokens.entries()) { + if (now - timestamp > cleanupAfter) { + usedTokens.delete(token); + } + } + } + + return { + createToken, + verifyToken, + isUsed, + markUsed, + }; +} diff --git a/waspc/data/Generator/templates/server/src/auth/providers/oauth/redirect.ts b/waspc/data/Generator/templates/server/src/auth/providers/oauth/redirect.ts new file mode 100644 index 0000000000..d3a97b9db9 --- /dev/null +++ b/waspc/data/Generator/templates/server/src/auth/providers/oauth/redirect.ts @@ -0,0 +1,19 @@ +{{={= =}=}} +import { config } from 'wasp/server' + +export const loginPath = '{= serverOAuthLoginHandlerPath =}' +export const callbackPath = '{= serverOAuthCallbackHandlerPath =}' +export const exchangeCodeForTokenPath = '{= serverExchangeCodeForTokenHandlerPath =}' +const clientOAuthCallbackPath = '{= clientOAuthCallbackPath =}' + +export function getRedirectUriForCallback(providerName: string): URL { + return new URL(`${config.serverUrl}/auth/${providerName}/${callbackPath}`); +} + +export function getRedirectUriForOneTimeCode(oneTimeCode: string): URL { + return new URL(`${config.frontendUrl}${clientOAuthCallbackPath}#${oneTimeCode}`); +} + +export function getRedirectUriForError(error: string): URL { + return new URL(`${config.frontendUrl}${clientOAuthCallbackPath}?error=${error}`); +} diff --git a/waspc/data/Generator/templates/server/src/auth/providers/oauth/state.ts b/waspc/data/Generator/templates/server/src/auth/providers/oauth/state.ts new file mode 100644 index 0000000000..ab1b0f8aaa --- /dev/null +++ b/waspc/data/Generator/templates/server/src/auth/providers/oauth/state.ts @@ -0,0 +1,70 @@ +import { + Response as ExpressResponse, + Request as ExpressRequest, +} from "express"; +import { generateCodeVerifier, generateState } from "arctic"; + +import type { ProviderConfig } from "wasp/auth/providers/types"; + +import { setOAuthCookieValue, getOAuthCookieValue } from "./cookies.js"; + +export type StateType = 'state' | 'codeVerifier'; + +export function generateAndStoreOAuthState( + stateTypes: ST[], + provider: ProviderConfig, + res: ExpressResponse, +): { [name in ST]: string } { + const result = {} as { [name in StateType]: string } + + if (stateTypes.includes('state' as ST)) { + const state = generateState(); + setOAuthCookieValue(provider, res, 'state', state); + result.state = state; + } + + if (stateTypes.includes('codeVerifier' as ST)) { + const codeVerifier = generateCodeVerifier(); + setOAuthCookieValue(provider, res, 'codeVerifier', codeVerifier); + result.codeVerifier = codeVerifier; + } + + return result; +} + +export function validateAndGetOAuthState( + stateTypes: ST[], + provider: ProviderConfig, + req: ExpressRequest, +): { [name in ST]: string } & { code: string } { + const result = {} as { [name in StateType]: string } & { code: string }; + + if (stateTypes.includes('state' as ST)) { + const state = req.query.state; + const storedState = getOAuthCookieValue(provider, req, 'state'); + if ( + !state || + !storedState || + storedState !== state + ) { + throw new Error("Invalid state"); + } + result.state = storedState; + } + + if (stateTypes.includes('codeVerifier' as ST)) { + const storedCodeVerifier = getOAuthCookieValue(provider, req, 'codeVerifier'); + if (!storedCodeVerifier) { + throw new Error("Invalid code verifier"); + } + result.codeVerifier = storedCodeVerifier; + } + + const code = req.query.code; + if (typeof code !== "string") { + throw new Error("Invalid code"); + } + result.code = code; + + return result; +} diff --git a/waspc/data/Generator/templates/server/src/auth/providers/oauth/types.ts b/waspc/data/Generator/templates/server/src/auth/providers/oauth/types.ts index c60f3d3c80..6b6908d61f 100644 --- a/waspc/data/Generator/templates/server/src/auth/providers/oauth/types.ts +++ b/waspc/data/Generator/templates/server/src/auth/providers/oauth/types.ts @@ -1,13 +1,6 @@ {{={= =}=}} import type { Prisma } from "@prisma/client" -import { contextWithUserEntity } from 'wasp/auth/utils' - -export type OAuthConfig = { - clientID?: string; - clientSecret?: string; - scope?: string[]; -} export type UserFieldsFromOAuthSignup = Prisma.{= userEntityName =}CreateInput diff --git a/waspc/data/Generator/templates/server/src/auth/providers/oauth/user.ts b/waspc/data/Generator/templates/server/src/auth/providers/oauth/user.ts new file mode 100644 index 0000000000..d9c1d92a56 --- /dev/null +++ b/waspc/data/Generator/templates/server/src/auth/providers/oauth/user.ts @@ -0,0 +1,86 @@ +{{={= =}=}} +import { HttpError } from 'wasp/server' +import { + type ProviderId, + createUser, + sanitizeAndSerializeProviderData, + validateAndGetUserFields, + createProviderId, +} from 'wasp/auth/utils' +import { type {= authEntityUpper =} } from 'wasp/entities' +import { prisma } from 'wasp/server' +import { type UserSignupFields, type ProviderConfig } from 'wasp/auth/providers/types' +import { getRedirectUriForOneTimeCode, getRedirectUriForError } from './redirect' +import { tokenStore } from './oneTimeCode' + +export async function finishOAuthFlowAndGetRedirectUri( + provider: ProviderConfig, + providerProfile: unknown, + providerUserId: string, + userSignupFields: UserSignupFields | undefined, +): Promise { + const providerId = createProviderId(provider.id, providerUserId); + + const authId = await getAuthIdFromProviderDetails(providerId, providerProfile, userSignupFields); + + const oneTimeCode = await tokenStore.createToken(authId); + + return getRedirectUriForOneTimeCode(oneTimeCode); +} + +export function handleOAuthErrorAndGetRedirectUri(error: unknown): URL { + if (error instanceof HttpError) { + const errorMessage = isHttpErrorWithExtraMessage(error) + ? `${error.message}: ${error.data.message}` + : error.message; + return getRedirectUriForError(errorMessage) + } + return getRedirectUriForError("An unknown error occurred while trying to log in with the OAuth provider."); +} + +function isHttpErrorWithExtraMessage(error: HttpError): error is HttpError & { data: { message: string } } { + return error.data && typeof (error.data as any).message === 'string'; +} + +// We need a user id to create the auth token, so we either find an existing user +// or create a new one if none exists for this provider. +async function getAuthIdFromProviderDetails( + providerId: ProviderId, + providerProfile: any, + userSignupFields: UserSignupFields | undefined, +): Promise<{= authEntityUpper =}['id']> { + const existingAuthIdentity = await prisma.{= authIdentityEntityLower =}.findUnique({ + where: { + providerName_providerUserId: providerId, + }, + include: { + {= authFieldOnAuthIdentityEntityName =}: { + include: { + {= userFieldOnAuthEntityName =}: true + } + } + } + }) + + if (existingAuthIdentity) { + return existingAuthIdentity.{= authFieldOnAuthIdentityEntityName =}.id + } else { + const userFields = await validateAndGetUserFields( + { profile: providerProfile }, + userSignupFields, + ); + + // For now, we don't have any extra data for the oauth providers, so we just pass an empty object. + const providerData = await sanitizeAndSerializeProviderData({}) + + const user = await createUser( + providerId, + providerData, + // Using any here because we want to avoid TypeScript errors and + // rely on Prisma to validate the data. + userFields as any, + ) + + return user.auth.id + } +} diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/.waspchecksums b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/.waspchecksums index e6a57ddfcb..4c59d0820d 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/.waspchecksums +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/.waspchecksums @@ -18,7 +18,7 @@ "file", "../out/sdk/wasp/client/config.ts" ], - "12a7dffb1c3fe762cec8d9d928af353cb169ff199d3934b1f3c27ce0e3a2f987" + "68141be8527e8ae3d15838663769737278a71d3853b1dbdc48696e92d4e42548" ], [ [ @@ -319,7 +319,7 @@ "file", "../out/sdk/wasp/server/utils.ts" ], - "a4178a3e2527d47d141340b99abf675125859fa9cb5a0535e3efa7b34a3bcabb" + "688fdd57d6a9e9ead90141c6f0ebea9d39713d5bd7a630d43f2c2cb5a7984108" ], [ [ diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/client/config.ts b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/client/config.ts index e9234e6f2a..a9cb2de2d3 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/client/config.ts +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/client/config.ts @@ -6,4 +6,4 @@ const config = { apiUrl, } -export default config +export default config \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/server/utils.d.ts b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/server/utils.d.ts index 266b9c6fbb..0e3653e5cd 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/server/utils.d.ts +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/server/utils.d.ts @@ -9,4 +9,5 @@ type RequestWithExtraFields = Request & {}; */ export declare const handleRejection: (middleware: (req: RequestWithExtraFields, res: Response, next: NextFunction) => any) => (req: RequestWithExtraFields, res: Response, next: NextFunction) => Promise; export declare const sleep: (ms: number) => Promise; +export declare function redirect(res: Response, redirectUri: string): any; export {}; diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/server/utils.js b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/server/utils.js index 9b2034006b..07e1731907 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/server/utils.js +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/server/utils.js @@ -14,4 +14,10 @@ export const handleRejection = (middleware) => async (req, res, next) => { } }; export const sleep = (ms) => new Promise((r) => setTimeout(r, ms)); +export function redirect(res, redirectUri) { + return res + .status(302) + .setHeader("Location", redirectUri) + .end(); +} //# sourceMappingURL=utils.js.map \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/server/utils.js.map b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/server/utils.js.map index 17121f586d..9ca16bf322 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/server/utils.js.map +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/server/utils.js.map @@ -1 +1 @@ -{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../server/utils.ts"],"names":[],"mappings":"AAWA;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAC7B,UAIQ,EACR,EAAE,CACJ,KAAK,EAAE,GAA2B,EAAE,GAAa,EAAE,IAAkB,EAAE,EAAE;IACvE,IAAI,CAAC;QACH,MAAM,UAAU,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,CAAA;IAClC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,CAAC,KAAK,CAAC,CAAA;IACb,CAAC;AACH,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,EAAU,EAAoB,EAAE,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAA"} \ No newline at end of file +{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../server/utils.ts"],"names":[],"mappings":"AAMA;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAC7B,UAIQ,EACR,EAAE,CACJ,KAAK,EAAE,GAA2B,EAAE,GAAa,EAAE,IAAkB,EAAE,EAAE;IACvE,IAAI,CAAC;QACH,MAAM,UAAU,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,CAAA;IAClC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,CAAC,KAAK,CAAC,CAAA;IACb,CAAC;AACH,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,EAAU,EAAoB,EAAE,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAA;AAE5F,MAAM,UAAU,QAAQ,CAAC,GAAa,EAAE,WAAmB;IACzD,OAAO,GAAG;SACP,MAAM,CAAC,GAAG,CAAC;SACX,SAAS,CAAC,UAAU,EAAE,WAAW,CAAC;SAClC,GAAG,EAAE,CAAC;AACX,CAAC"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/server/utils.ts b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/server/utils.ts index c8cc823348..85ba9a4d8d 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/server/utils.ts +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/server/utils.ts @@ -1,10 +1,5 @@ -import crypto from 'crypto' import { Request, Response, NextFunction } from 'express' -import { readdir } from 'fs' -import { dirname } from 'path' -import { fileURLToPath } from 'url' - type RequestWithExtraFields = Request & { } @@ -32,3 +27,10 @@ async (req: RequestWithExtraFields, res: Response, next: NextFunction) => { } export const sleep = (ms: number): Promise => new Promise((r) => setTimeout(r, ms)) + +export function redirect(res: Response, redirectUri: string) { + return res + .status(302) + .setHeader("Location", redirectUri) + .end(); +} diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/client/config.ts b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/client/config.ts index e9234e6f2a..a9cb2de2d3 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/client/config.ts +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/client/config.ts @@ -6,4 +6,4 @@ const config = { apiUrl, } -export default config +export default config \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/server/utils.d.ts b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/server/utils.d.ts index 266b9c6fbb..0e3653e5cd 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/server/utils.d.ts +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/server/utils.d.ts @@ -9,4 +9,5 @@ type RequestWithExtraFields = Request & {}; */ export declare const handleRejection: (middleware: (req: RequestWithExtraFields, res: Response, next: NextFunction) => any) => (req: RequestWithExtraFields, res: Response, next: NextFunction) => Promise; export declare const sleep: (ms: number) => Promise; +export declare function redirect(res: Response, redirectUri: string): any; export {}; diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/server/utils.js b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/server/utils.js index 9b2034006b..07e1731907 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/server/utils.js +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/server/utils.js @@ -14,4 +14,10 @@ export const handleRejection = (middleware) => async (req, res, next) => { } }; export const sleep = (ms) => new Promise((r) => setTimeout(r, ms)); +export function redirect(res, redirectUri) { + return res + .status(302) + .setHeader("Location", redirectUri) + .end(); +} //# sourceMappingURL=utils.js.map \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/server/utils.js.map b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/server/utils.js.map index 17121f586d..9ca16bf322 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/server/utils.js.map +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/server/utils.js.map @@ -1 +1 @@ -{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../server/utils.ts"],"names":[],"mappings":"AAWA;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAC7B,UAIQ,EACR,EAAE,CACJ,KAAK,EAAE,GAA2B,EAAE,GAAa,EAAE,IAAkB,EAAE,EAAE;IACvE,IAAI,CAAC;QACH,MAAM,UAAU,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,CAAA;IAClC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,CAAC,KAAK,CAAC,CAAA;IACb,CAAC;AACH,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,EAAU,EAAoB,EAAE,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAA"} \ No newline at end of file +{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../server/utils.ts"],"names":[],"mappings":"AAMA;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAC7B,UAIQ,EACR,EAAE,CACJ,KAAK,EAAE,GAA2B,EAAE,GAAa,EAAE,IAAkB,EAAE,EAAE;IACvE,IAAI,CAAC;QACH,MAAM,UAAU,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,CAAA;IAClC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,CAAC,KAAK,CAAC,CAAA;IACb,CAAC;AACH,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,EAAU,EAAoB,EAAE,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAA;AAE5F,MAAM,UAAU,QAAQ,CAAC,GAAa,EAAE,WAAmB;IACzD,OAAO,GAAG;SACP,MAAM,CAAC,GAAG,CAAC;SACX,SAAS,CAAC,UAAU,EAAE,WAAW,CAAC;SAClC,GAAG,EAAE,CAAC;AACX,CAAC"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/server/utils.ts b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/server/utils.ts index c8cc823348..85ba9a4d8d 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/server/utils.ts +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/server/utils.ts @@ -1,10 +1,5 @@ -import crypto from 'crypto' import { Request, Response, NextFunction } from 'express' -import { readdir } from 'fs' -import { dirname } from 'path' -import { fileURLToPath } from 'url' - type RequestWithExtraFields = Request & { } @@ -32,3 +27,10 @@ async (req: RequestWithExtraFields, res: Response, next: NextFunction) => { } export const sleep = (ms: number): Promise => new Promise((r) => setTimeout(r, ms)) + +export function redirect(res: Response, redirectUri: string) { + return res + .status(302) + .setHeader("Location", redirectUri) + .end(); +} diff --git a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/.waspchecksums b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/.waspchecksums index 4332d9cec4..34e243bcca 100644 --- a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/.waspchecksums +++ b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/.waspchecksums @@ -18,7 +18,7 @@ "file", "../out/sdk/wasp/client/config.ts" ], - "12a7dffb1c3fe762cec8d9d928af353cb169ff199d3934b1f3c27ce0e3a2f987" + "68141be8527e8ae3d15838663769737278a71d3853b1dbdc48696e92d4e42548" ], [ [ @@ -319,7 +319,7 @@ "file", "../out/sdk/wasp/server/utils.ts" ], - "a4178a3e2527d47d141340b99abf675125859fa9cb5a0535e3efa7b34a3bcabb" + "688fdd57d6a9e9ead90141c6f0ebea9d39713d5bd7a630d43f2c2cb5a7984108" ], [ [ diff --git a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/client/config.ts b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/client/config.ts index e9234e6f2a..a9cb2de2d3 100644 --- a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/client/config.ts +++ b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/client/config.ts @@ -6,4 +6,4 @@ const config = { apiUrl, } -export default config +export default config \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/server/utils.d.ts b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/server/utils.d.ts index 266b9c6fbb..0e3653e5cd 100644 --- a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/server/utils.d.ts +++ b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/server/utils.d.ts @@ -9,4 +9,5 @@ type RequestWithExtraFields = Request & {}; */ export declare const handleRejection: (middleware: (req: RequestWithExtraFields, res: Response, next: NextFunction) => any) => (req: RequestWithExtraFields, res: Response, next: NextFunction) => Promise; export declare const sleep: (ms: number) => Promise; +export declare function redirect(res: Response, redirectUri: string): any; export {}; diff --git a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/server/utils.js b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/server/utils.js index 9b2034006b..07e1731907 100644 --- a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/server/utils.js +++ b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/server/utils.js @@ -14,4 +14,10 @@ export const handleRejection = (middleware) => async (req, res, next) => { } }; export const sleep = (ms) => new Promise((r) => setTimeout(r, ms)); +export function redirect(res, redirectUri) { + return res + .status(302) + .setHeader("Location", redirectUri) + .end(); +} //# sourceMappingURL=utils.js.map \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/server/utils.js.map b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/server/utils.js.map index 17121f586d..9ca16bf322 100644 --- a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/server/utils.js.map +++ b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/server/utils.js.map @@ -1 +1 @@ -{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../server/utils.ts"],"names":[],"mappings":"AAWA;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAC7B,UAIQ,EACR,EAAE,CACJ,KAAK,EAAE,GAA2B,EAAE,GAAa,EAAE,IAAkB,EAAE,EAAE;IACvE,IAAI,CAAC;QACH,MAAM,UAAU,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,CAAA;IAClC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,CAAC,KAAK,CAAC,CAAA;IACb,CAAC;AACH,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,EAAU,EAAoB,EAAE,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAA"} \ No newline at end of file +{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../server/utils.ts"],"names":[],"mappings":"AAMA;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAC7B,UAIQ,EACR,EAAE,CACJ,KAAK,EAAE,GAA2B,EAAE,GAAa,EAAE,IAAkB,EAAE,EAAE;IACvE,IAAI,CAAC;QACH,MAAM,UAAU,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,CAAA;IAClC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,CAAC,KAAK,CAAC,CAAA;IACb,CAAC;AACH,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,EAAU,EAAoB,EAAE,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAA;AAE5F,MAAM,UAAU,QAAQ,CAAC,GAAa,EAAE,WAAmB;IACzD,OAAO,GAAG;SACP,MAAM,CAAC,GAAG,CAAC;SACX,SAAS,CAAC,UAAU,EAAE,WAAW,CAAC;SAClC,GAAG,EAAE,CAAC;AACX,CAAC"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/server/utils.ts b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/server/utils.ts index c8cc823348..85ba9a4d8d 100644 --- a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/server/utils.ts +++ b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/server/utils.ts @@ -1,10 +1,5 @@ -import crypto from 'crypto' import { Request, Response, NextFunction } from 'express' -import { readdir } from 'fs' -import { dirname } from 'path' -import { fileURLToPath } from 'url' - type RequestWithExtraFields = Request & { } @@ -32,3 +27,10 @@ async (req: RequestWithExtraFields, res: Response, next: NextFunction) => { } export const sleep = (ms: number): Promise => new Promise((r) => setTimeout(r, ms)) + +export function redirect(res: Response, redirectUri: string) { + return res + .status(302) + .setHeader("Location", redirectUri) + .end(); +} diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/files.manifest b/waspc/e2e-test/test-outputs/waspComplexTest-golden/files.manifest index 67f768d580..11c8382531 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/files.manifest +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/files.manifest @@ -421,9 +421,15 @@ waspComplexTest/.wasp/out/server/src/actions/types.ts waspComplexTest/.wasp/out/server/src/app.js waspComplexTest/.wasp/out/server/src/auth/providers/config/google.ts waspComplexTest/.wasp/out/server/src/auth/providers/index.ts -waspComplexTest/.wasp/out/server/src/auth/providers/oauth/createRouter.ts -waspComplexTest/.wasp/out/server/src/auth/providers/oauth/init.ts +waspComplexTest/.wasp/out/server/src/auth/providers/oauth/config.ts +waspComplexTest/.wasp/out/server/src/auth/providers/oauth/cookies.ts +waspComplexTest/.wasp/out/server/src/auth/providers/oauth/env.ts +waspComplexTest/.wasp/out/server/src/auth/providers/oauth/handler.ts +waspComplexTest/.wasp/out/server/src/auth/providers/oauth/oneTimeCode.ts +waspComplexTest/.wasp/out/server/src/auth/providers/oauth/redirect.ts +waspComplexTest/.wasp/out/server/src/auth/providers/oauth/state.ts waspComplexTest/.wasp/out/server/src/auth/providers/oauth/types.ts +waspComplexTest/.wasp/out/server/src/auth/providers/oauth/user.ts waspComplexTest/.wasp/out/server/src/crud/tasks.ts waspComplexTest/.wasp/out/server/src/jobs/core/allJobs.ts waspComplexTest/.wasp/out/server/src/jobs/mySpecialJob.ts @@ -456,7 +462,7 @@ waspComplexTest/.wasp/out/web-app/public/.gitkeep waspComplexTest/.wasp/out/web-app/public/favicon.ico waspComplexTest/.wasp/out/web-app/public/manifest.json waspComplexTest/.wasp/out/web-app/scripts/validate-env.mjs -waspComplexTest/.wasp/out/web-app/src/auth/pages/OAuthCodeExchange.jsx +waspComplexTest/.wasp/out/web-app/src/auth/pages/OAuthCallback.tsx waspComplexTest/.wasp/out/web-app/src/auth/pages/createAuthRequiredPage.jsx waspComplexTest/.wasp/out/web-app/src/entities/index.ts waspComplexTest/.wasp/out/web-app/src/index.tsx diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/.waspchecksums b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/.waspchecksums index 52bcba6311..cb850389c0 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/.waspchecksums +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/.waspchecksums @@ -130,7 +130,7 @@ "file", "../out/sdk/wasp/auth/providers/types.ts" ], - "645ad70b2f5d91f6e14042547ba94b782644a4f12d62cbd9df1ed2e2081127c1" + "0ede63791b4c7f3bdd21c7d07e815f5d9e49c31a9d7cd41d482c32e73e3d73ad" ], [ [ @@ -200,7 +200,7 @@ "file", "../out/sdk/wasp/client/config.ts" ], - "12a7dffb1c3fe762cec8d9d928af353cb169ff199d3934b1f3c27ce0e3a2f987" + "68141be8527e8ae3d15838663769737278a71d3853b1dbdc48696e92d4e42548" ], [ [ @@ -711,7 +711,7 @@ "file", "../out/sdk/wasp/server/utils.ts" ], - "fb02a9482c7bfe388b6140bd6be95d6ab97f69ec5458c59055ab3d7b91893309" + "630dd952c1f4e0c388eb8b73d4f2e9db0cc9015cfc4cb6d6d6dacec6fcd4559c" ], [ [ @@ -809,7 +809,7 @@ "file", "server/package.json" ], - "c5a9447608033195282d5d9625fe84525d58e986d11b03f56f3d8570d8381347" + "23fbe60e2f89a7fb12a11bd11aef43e3ed713ffd49697ab40c1cbbf0b3c4c84d" ], [ [ @@ -851,35 +851,77 @@ "file", "server/src/auth/providers/config/google.ts" ], - "6b82ea1a7779db285649a0f80e5199acb93617025de04492b2bb0357cc5b5e69" + "d5546bace955d33579dc25fd9b88689435e8d572b1190d18ffc0276521e2db86" ], [ [ "file", "server/src/auth/providers/index.ts" ], - "2965a704a128cdde97428d59b4839244087c56c63ff63dfc5cd4b130c3f4e4c7" + "cb175fdf18744f3f5cc08a1c1d82aed869d2b7c0bdac6e51e28eb52e046b61fc" ], [ [ "file", - "server/src/auth/providers/oauth/createRouter.ts" + "server/src/auth/providers/oauth/config.ts" ], - "a117a9b61d0e647707d4dc2cd4f8746784d6d5d005ca0cc4fc2502fcf0aa416b" + "b5901b3c8067b9d5f83ba4e67dc3360e102bd246f57d502227051b66df1b5915" ], [ [ "file", - "server/src/auth/providers/oauth/init.ts" + "server/src/auth/providers/oauth/cookies.ts" ], - "a7c95d63cea8842f5e2bc541080f38d5b19aacbc79f9dadb787376cba276108d" + "3887cc320c8084201db087ab5d8ede9c72816f99803e66b4178960ca22091bbc" + ], + [ + [ + "file", + "server/src/auth/providers/oauth/env.ts" + ], + "65c5ce3b4ead10faad600435654d2614a862281ce5177996599bc159c39bb551" + ], + [ + [ + "file", + "server/src/auth/providers/oauth/handler.ts" + ], + "d243cf5465c41a2409f2ae6d032e3678dbad7507376ba41c8f300be6bc104b2b" + ], + [ + [ + "file", + "server/src/auth/providers/oauth/oneTimeCode.ts" + ], + "6a23d30c2d98e14f6e293ebf3bb9392d25a3eeb7f1ec98078440a11af0aa0c78" + ], + [ + [ + "file", + "server/src/auth/providers/oauth/redirect.ts" + ], + "1aabb58c599dae1e8a47d139c80464331ab87cfefa5a712df4ef594b7876a2a5" + ], + [ + [ + "file", + "server/src/auth/providers/oauth/state.ts" + ], + "b50a6b92cb4bb30a62587b26b0b8ef9fda0f1ad656b74640771e7e232757b677" ], [ [ "file", "server/src/auth/providers/oauth/types.ts" ], - "26cd322bd83ee8d6569fac1e3db47b2d07292f40ff3a8a501a363a3338d243b3" + "eb54019f51a0ba1e7c4c15734e6a36dea1631727b0816bea7b0c2855aeb5f0c0" + ], + [ + [ + "file", + "server/src/auth/providers/oauth/user.ts" + ], + "0803aedea9bb4806e2c1e2adc2707bbcfa0f8aa66bcaa50ff65fe984470365d0" ], [ [ @@ -1115,9 +1157,9 @@ [ [ "file", - "web-app/src/auth/pages/OAuthCodeExchange.jsx" + "web-app/src/auth/pages/OAuthCallback.tsx" ], - "714f11069cf0d238e50cef6ed485843a007dfc6c1d023cf5e090689a53a10690" + "cae2fb9d5e096386387ef5caa75f3d2730c1fcd86d91ba8a6efbe023cb66b529" ], [ [ @@ -1159,7 +1201,7 @@ "file", "web-app/src/router.tsx" ], - "bd4451ae7df15adb5fcebb5ad99bd0831edb3481d1a7a46abc894a5d50c14ed1" + "938782afaf3fbe32d850a983e55fe7e31bb261cf8f79e84c7e800b7847544f15" ], [ [ diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/installedNpmDepsLog.json b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/installedNpmDepsLog.json index 8442e36fd1..444ad7cc73 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/installedNpmDepsLog.json +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/installedNpmDepsLog.json @@ -1 +1 @@ -{"_waspSdkNpmDeps":{"dependencies":[{"name":"@prisma/client","version":"4.16.2"},{"name":"prisma","version":"4.16.2"},{"name":"@tanstack/react-query","version":"^4.29.0"},{"name":"axios","version":"^1.4.0"},{"name":"express","version":"~4.18.1"},{"name":"mitt","version":"3.0.0"},{"name":"react","version":"^18.2.0"},{"name":"lodash.merge","version":"^4.6.2"},{"name":"react-router-dom","version":"^5.3.3"},{"name":"react-hook-form","version":"^7.45.4"},{"name":"superjson","version":"^1.12.2"},{"name":"@types/express-serve-static-core","version":"^4.17.13"},{"name":"@types/react-router-dom","version":"^5.3.3"},{"name":"@stitches/react","version":"^1.2.8"},{"name":"lucia","version":"^3.0.1"},{"name":"@lucia-auth/adapter-prisma","version":"^4.0.0"},{"name":"oslo","version":"^1.1.2"},{"name":"@sendgrid/mail","version":"^7.7.0"},{"name":"uuid","version":"^9.0.0"},{"name":"vitest","version":"^1.2.1"},{"name":"@vitest/ui","version":"^1.2.1"},{"name":"jsdom","version":"^21.1.1"},{"name":"@testing-library/react","version":"^14.1.2"},{"name":"@testing-library/jest-dom","version":"^6.3.0"},{"name":"msw","version":"^1.1.0"},{"name":"pg-boss","version":"^8.4.2"}],"devDependencies":[{"name":"@tsconfig/node18","version":"latest"}]},"_userNpmDeps":{"userDependencies":[{"name":"react","version":"^18.2.0"},{"name":"wasp","version":"file:.wasp/out/sdk/wasp"}],"userDevDependencies":[{"name":"@types/react","version":"^18.0.37"},{"name":"prisma","version":"4.16.2"},{"name":"typescript","version":"^5.1.0"},{"name":"vite","version":"^4.3.9"}]},"_waspFrameworkNpmDeps":{"npmDepsForWebApp":{"dependencies":[{"name":"@tanstack/react-query","version":"^4.29.0"},{"name":"axios","version":"^1.4.0"},{"name":"mitt","version":"3.0.0"},{"name":"react-dom","version":"^18.2.0"},{"name":"react-hook-form","version":"^7.45.4"},{"name":"react-router-dom","version":"^5.3.3"},{"name":"superjson","version":"^1.12.2"}],"devDependencies":[{"name":"@tsconfig/vite-react","version":"^2.0.0"},{"name":"@types/react-dom","version":"^18.0.11"},{"name":"@types/react-router-dom","version":"^5.3.3"},{"name":"@vitejs/plugin-react","version":"^4.2.1"},{"name":"dotenv","version":"^16.0.3"}]},"npmDepsForServer":{"dependencies":[{"name":"cookie-parser","version":"~1.4.6"},{"name":"cors","version":"^2.8.5"},{"name":"dotenv","version":"16.0.2"},{"name":"express","version":"~4.18.1"},{"name":"helmet","version":"^6.0.0"},{"name":"morgan","version":"~1.10.0"},{"name":"passport","version":"0.6.0"},{"name":"passport-google-oauth20","version":"2.0.0"},{"name":"rate-limiter-flexible","version":"^2.4.1"},{"name":"superjson","version":"^1.12.2"}],"devDependencies":[{"name":"@tsconfig/node18","version":"latest"},{"name":"@types/cors","version":"^2.8.5"},{"name":"@types/express","version":"^4.17.13"},{"name":"@types/express-serve-static-core","version":"^4.17.13"},{"name":"@types/node","version":"^18.0.0"},{"name":"nodemon","version":"^2.0.19"},{"name":"rollup","version":"^4.9.6"},{"name":"rollup-plugin-esbuild","version":"^6.1.1"},{"name":"standard","version":"^17.0.0"}]}}} \ No newline at end of file +{"_waspSdkNpmDeps":{"dependencies":[{"name":"@prisma/client","version":"4.16.2"},{"name":"prisma","version":"4.16.2"},{"name":"@tanstack/react-query","version":"^4.29.0"},{"name":"axios","version":"^1.4.0"},{"name":"express","version":"~4.18.1"},{"name":"mitt","version":"3.0.0"},{"name":"react","version":"^18.2.0"},{"name":"lodash.merge","version":"^4.6.2"},{"name":"react-router-dom","version":"^5.3.3"},{"name":"react-hook-form","version":"^7.45.4"},{"name":"superjson","version":"^1.12.2"},{"name":"@types/express-serve-static-core","version":"^4.17.13"},{"name":"@types/react-router-dom","version":"^5.3.3"},{"name":"@stitches/react","version":"^1.2.8"},{"name":"lucia","version":"^3.0.1"},{"name":"@lucia-auth/adapter-prisma","version":"^4.0.0"},{"name":"oslo","version":"^1.1.2"},{"name":"@sendgrid/mail","version":"^7.7.0"},{"name":"uuid","version":"^9.0.0"},{"name":"vitest","version":"^1.2.1"},{"name":"@vitest/ui","version":"^1.2.1"},{"name":"jsdom","version":"^21.1.1"},{"name":"@testing-library/react","version":"^14.1.2"},{"name":"@testing-library/jest-dom","version":"^6.3.0"},{"name":"msw","version":"^1.1.0"},{"name":"pg-boss","version":"^8.4.2"}],"devDependencies":[{"name":"@tsconfig/node18","version":"latest"}]},"_userNpmDeps":{"userDependencies":[{"name":"react","version":"^18.2.0"},{"name":"wasp","version":"file:.wasp/out/sdk/wasp"}],"userDevDependencies":[{"name":"@types/react","version":"^18.0.37"},{"name":"prisma","version":"4.16.2"},{"name":"typescript","version":"^5.1.0"},{"name":"vite","version":"^4.3.9"}]},"_waspFrameworkNpmDeps":{"npmDepsForWebApp":{"dependencies":[{"name":"@tanstack/react-query","version":"^4.29.0"},{"name":"axios","version":"^1.4.0"},{"name":"mitt","version":"3.0.0"},{"name":"react-dom","version":"^18.2.0"},{"name":"react-hook-form","version":"^7.45.4"},{"name":"react-router-dom","version":"^5.3.3"},{"name":"superjson","version":"^1.12.2"}],"devDependencies":[{"name":"@tsconfig/vite-react","version":"^2.0.0"},{"name":"@types/react-dom","version":"^18.0.11"},{"name":"@types/react-router-dom","version":"^5.3.3"},{"name":"@vitejs/plugin-react","version":"^4.2.1"},{"name":"dotenv","version":"^16.0.3"}]},"npmDepsForServer":{"dependencies":[{"name":"arctic","version":"^1.2.1"},{"name":"cookie-parser","version":"~1.4.6"},{"name":"cors","version":"^2.8.5"},{"name":"dotenv","version":"16.0.2"},{"name":"express","version":"~4.18.1"},{"name":"helmet","version":"^6.0.0"},{"name":"morgan","version":"~1.10.0"},{"name":"rate-limiter-flexible","version":"^2.4.1"},{"name":"superjson","version":"^1.12.2"}],"devDependencies":[{"name":"@tsconfig/node18","version":"latest"},{"name":"@types/cors","version":"^2.8.5"},{"name":"@types/express","version":"^4.17.13"},{"name":"@types/express-serve-static-core","version":"^4.17.13"},{"name":"@types/node","version":"^18.0.0"},{"name":"nodemon","version":"^2.0.19"},{"name":"rollup","version":"^4.9.6"},{"name":"rollup-plugin-esbuild","version":"^6.1.1"},{"name":"standard","version":"^17.0.0"}]}}} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/auth/providers/types.ts b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/auth/providers/types.ts index 8cd06b8afc..ad4aa7cd33 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/auth/providers/types.ts +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/auth/providers/types.ts @@ -15,19 +15,11 @@ export type ProviderConfig = { // Unique provider identifier, used as part of URL paths id: ProviderName; displayName: string; - // Each provider config can have an init method which is ran on setup time - // e.g. for oAuth providers this is the time when the Passport strategy is registered. - init?(provider: ProviderConfig): Promise; // Every provider must have a setupRouter method which returns the Express router. // In this function we are flexibile to do what ever is necessary to make the provider work. - createRouter(provider: ProviderConfig, initData: InitData): Router; + createRouter(provider: ProviderConfig): Router; }; -// PRIVATE API -export type InitData = { - [key: string]: any; -} - // PRIVATE API export type RequestWithWasp = Request & { wasp?: { [key: string]: any } } diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/client/config.ts b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/client/config.ts index e9234e6f2a..a9cb2de2d3 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/client/config.ts +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/client/config.ts @@ -6,4 +6,4 @@ const config = { apiUrl, } -export default config +export default config \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/auth/providers/types.d.ts b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/auth/providers/types.d.ts index 8ac8c45ae2..ce42036a38 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/auth/providers/types.d.ts +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/auth/providers/types.d.ts @@ -7,11 +7,7 @@ type UserEntityCreateInput = Prisma.UserCreateInput; export type ProviderConfig = { id: ProviderName; displayName: string; - init?(provider: ProviderConfig): Promise; - createRouter(provider: ProviderConfig, initData: InitData): Router; -}; -export type InitData = { - [key: string]: any; + createRouter(provider: ProviderConfig): Router; }; export type RequestWithWasp = Request & { wasp?: { diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/server/utils.d.ts b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/server/utils.d.ts index 1fde6136f1..529ce619a9 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/server/utils.d.ts +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/server/utils.d.ts @@ -13,4 +13,5 @@ type RequestWithExtraFields = Request & { */ export declare const handleRejection: (middleware: (req: RequestWithExtraFields, res: Response, next: NextFunction) => any) => (req: RequestWithExtraFields, res: Response, next: NextFunction) => Promise; export declare const sleep: (ms: number) => Promise; +export declare function redirect(res: Response, redirectUri: string): any; export {}; diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/server/utils.js b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/server/utils.js index 9b2034006b..07e1731907 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/server/utils.js +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/server/utils.js @@ -14,4 +14,10 @@ export const handleRejection = (middleware) => async (req, res, next) => { } }; export const sleep = (ms) => new Promise((r) => setTimeout(r, ms)); +export function redirect(res, redirectUri) { + return res + .status(302) + .setHeader("Location", redirectUri) + .end(); +} //# sourceMappingURL=utils.js.map \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/server/utils.js.map b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/server/utils.js.map index 0bc5cd9384..1b58c5ee90 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/server/utils.js.map +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/server/utils.js.map @@ -1 +1 @@ -{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../server/utils.ts"],"names":[],"mappings":"AAcA;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAC7B,UAIQ,EACR,EAAE,CACJ,KAAK,EAAE,GAA2B,EAAE,GAAa,EAAE,IAAkB,EAAE,EAAE;IACvE,IAAI,CAAC;QACH,MAAM,UAAU,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,CAAA;IAClC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,CAAC,KAAK,CAAC,CAAA;IACb,CAAC;AACH,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,EAAU,EAAoB,EAAE,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAA"} \ No newline at end of file +{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../server/utils.ts"],"names":[],"mappings":"AASA;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAC7B,UAIQ,EACR,EAAE,CACJ,KAAK,EAAE,GAA2B,EAAE,GAAa,EAAE,IAAkB,EAAE,EAAE;IACvE,IAAI,CAAC;QACH,MAAM,UAAU,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,CAAA;IAClC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,CAAC,KAAK,CAAC,CAAA;IACb,CAAC;AACH,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,EAAU,EAAoB,EAAE,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAA;AAE5F,MAAM,UAAU,QAAQ,CAAC,GAAa,EAAE,WAAmB;IACzD,OAAO,GAAG;SACP,MAAM,CAAC,GAAG,CAAC;SACX,SAAS,CAAC,UAAU,EAAE,WAAW,CAAC;SAClC,GAAG,EAAE,CAAC;AACX,CAAC"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/server/utils.ts b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/server/utils.ts index a7c640cbff..3ac8ed86bd 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/server/utils.ts +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/server/utils.ts @@ -1,10 +1,5 @@ -import crypto from 'crypto' import { Request, Response, NextFunction } from 'express' -import { readdir } from 'fs' -import { dirname } from 'path' -import { fileURLToPath } from 'url' - import { type AuthUser } from 'wasp/auth' type RequestWithExtraFields = Request & { @@ -35,3 +30,10 @@ async (req: RequestWithExtraFields, res: Response, next: NextFunction) => { } export const sleep = (ms: number): Promise => new Promise((r) => setTimeout(r, ms)) + +export function redirect(res: Response, redirectUri: string) { + return res + .status(302) + .setHeader("Location", redirectUri) + .end(); +} diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/server/package.json b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/server/package.json index 3751cb8c6b..c857d727d6 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/server/package.json +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/server/package.json @@ -1,14 +1,13 @@ { "comment-filip": "The server.js location changed because we have now included client source files above .wasp/out/server/src.", "dependencies": { + "arctic": "^1.2.1", "cookie-parser": "~1.4.6", "cors": "^2.8.5", "dotenv": "16.0.2", "express": "~4.18.1", "helmet": "^6.0.0", "morgan": "~1.10.0", - "passport": "0.6.0", - "passport-google-oauth20": "2.0.0", "rate-limiter-flexible": "^2.4.1", "superjson": "^1.12.2" }, diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/server/src/auth/providers/config/google.ts b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/server/src/auth/providers/config/google.ts index 2d78f640b9..769b8bd690 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/server/src/auth/providers/config/google.ts +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/server/src/auth/providers/config/google.ts @@ -1,29 +1,67 @@ - -import { createRouter } from "../oauth/createRouter.js"; -import { makeOAuthInit } from "../oauth/init.js"; +import { Google } from "arctic"; import type { ProviderConfig } from "wasp/auth/providers/types"; -import type { OAuthConfig } from "../oauth/types.js"; +import { getRedirectUriForCallback } from "../oauth/redirect.js"; +import { ensureEnvVarsForProvider } from "../oauth/env.js"; +import { mergeDefaultAndUserConfig } from "../oauth/config.js"; +import { createOAuthProviderRouter } from "../oauth/handler.js"; const _waspUserSignupFields = undefined const _waspUserDefinedConfigFn = undefined -const _waspOAuthConfig: OAuthConfig = { - clientID: process.env.GOOGLE_CLIENT_ID, - clientSecret: process.env.GOOGLE_CLIENT_SECRET, - scope: ['profile'], -}; - const _waspConfig: ProviderConfig = { id: "google", displayName: "Google", - init: makeOAuthInit({ - npmPackage: 'passport-google-oauth20', - userSignupFields: _waspUserSignupFields, - userDefinedConfigFn: _waspUserDefinedConfigFn, - oAuthConfig: _waspOAuthConfig, - }), - createRouter, + createRouter(provider) { + const env = ensureEnvVarsForProvider( + ["GOOGLE_CLIENT_ID", "GOOGLE_CLIENT_SECRET"], + provider + ); + + const google = new Google( + env.GOOGLE_CLIENT_ID, + env.GOOGLE_CLIENT_SECRET, + getRedirectUriForCallback(provider.id).toString(), + ); + + const config = mergeDefaultAndUserConfig({ + scopes: ['profile'], + }, _waspUserDefinedConfigFn); + + async function getGoogleProfile(accessToken: string): Promise<{ + providerProfile: unknown; + providerUserId: string; + }> { + const response = await fetch( + "https://openidconnect.googleapis.com/v1/userinfo", + { + headers: { + Authorization: `Bearer ${accessToken}`, + }, + } + ); + const providerProfile = (await response.json()) as { + sub?: string; + }; + + if (!providerProfile.sub) { + throw new Error("Invalid profile"); + } + + return { providerProfile, providerUserId: providerProfile.sub }; + } + + return createOAuthProviderRouter({ + provider, + stateTypes: ['state', 'codeVerifier'], + userSignupFields: _waspUserSignupFields, + getAuthorizationUrl: ({ state, codeVerifier }) => google.createAuthorizationURL(state, codeVerifier, config), + getProviderInfo: async ({ code, codeVerifier }) => { + const { accessToken } = await google.validateAuthorizationCode(code, codeVerifier); + return getGoogleProfile(accessToken); + }, + }); + }, } export default _waspConfig; diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/server/src/auth/providers/index.ts b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/server/src/auth/providers/index.ts index bacf3cb737..6b2e3f9cda 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/server/src/auth/providers/index.ts +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/server/src/auth/providers/index.ts @@ -1,4 +1,5 @@ import { Router } from "express"; +import { setupOneTimeCodeRoute } from "./oauth/oneTimeCode"; import google from './config/google.js' @@ -8,14 +9,15 @@ const providers = [ const router = Router(); +// Setting up a common route for all OAuth providers to exchange +// one-time code for a session. +setupOneTimeCodeRoute(router); + for (const provider of providers) { - const { init, createRouter } = provider; - const initData = init - ? await init(provider) - : undefined; - const providerRouter = createRouter(provider, initData); + const { createRouter } = provider; + const providerRouter = createRouter(provider); router.use(`/${provider.id}`, providerRouter); - console.log(`🚀 "${provider.displayName}" auth initialized`) + console.log(`🚀 "${provider.displayName}" auth initialized`); } export default router; diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/server/src/auth/providers/oauth/config.ts b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/server/src/auth/providers/oauth/config.ts new file mode 100644 index 0000000000..3de0d7e686 --- /dev/null +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/server/src/auth/providers/oauth/config.ts @@ -0,0 +1,19 @@ +export function mergeDefaultAndUserConfig( + defaultConfig: DefaultConfig, + userConfigFn: () => UserConfig, +): DefaultConfig & UserConfig; +export function mergeDefaultAndUserConfig( + defaultConfig: DefaultConfig +): DefaultConfig; +export function mergeDefaultAndUserConfig( + defaultConfig: DefaultConfig, + userConfigFn?: () => UserConfig, +): DefaultConfig { + if (!userConfigFn) { + return defaultConfig; + } + return { + ...defaultConfig, + ...userConfigFn(), + } +} diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/server/src/auth/providers/oauth/cookies.ts b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/server/src/auth/providers/oauth/cookies.ts new file mode 100644 index 0000000000..88d092f70e --- /dev/null +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/server/src/auth/providers/oauth/cookies.ts @@ -0,0 +1,35 @@ +import { + Request as ExpressRequest, + Response as ExpressResponse, +} from "express"; +import { parseCookies } from "oslo/cookie"; + +import { type ProviderConfig } from "wasp/auth/providers/types"; + +import { type StateType } from './state'; + +export function setOAuthCookieValue( + provider: ProviderConfig, + res: ExpressResponse, + stateType: StateType, + value: string, +) { + const cookieName = `${provider.id}_${stateType}`; + res.cookie(cookieName, value, { + httpOnly: true, + // TODO: use server config to determine if secure + secure: process.env.NODE_ENV === "production", + path: "/", + maxAge: 60 * 60 * 1000, // 1 hour + }); +} + +export function getOAuthCookieValue( + provider: ProviderConfig, + req: ExpressRequest, + stateType: StateType, +) { + const cookieName = `${provider.id}_${stateType}`; + const cookies = parseCookies(req.headers.cookie ?? ""); + return cookies.get(cookieName); +} diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/server/src/auth/providers/oauth/createRouter.ts b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/server/src/auth/providers/oauth/createRouter.ts deleted file mode 100644 index 9f9557be39..0000000000 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/server/src/auth/providers/oauth/createRouter.ts +++ /dev/null @@ -1,111 +0,0 @@ - -import { Router } from "express" -import passport from "passport" - -import { prisma, config as waspServerConfig } from 'wasp/server' -import { - type ProviderName, - type ProviderId, - createProviderId, - authConfig, - contextWithUserEntity, - createUser, - rethrowPossibleAuthError, - sanitizeAndSerializeProviderData, - validateAndGetUserFields, -} from 'wasp/auth/utils' -import { createSession } from "wasp/auth/session" -import { type Auth } from "wasp/entities" -import type { ProviderConfig, RequestWithWasp, UserSignupFields } from "wasp/auth/providers/types" -import { handleRejection } from "wasp/server/utils" - -// For oauth providers, we have an endpoint /login to get the auth URL, -// and the /callback endpoint which is used to get the actual access_token and the user info. -export function createRouter(provider: ProviderConfig, initData: { - passportStrategyName: string, - userSignupFields?: UserSignupFields, -}) { - const { passportStrategyName, userSignupFields } = initData; - - const router = Router(); - - // Constructs a provider OAuth URL and redirects browser to start sign in flow. - router.get('/login', passport.authenticate(passportStrategyName, { session: false })); - - // Validates the OAuth code from the frontend, via server-to-server communication - // with provider. If valid, provides frontend a response containing the JWT. - // NOTE: `addProviderProfileToRequest` is invoked as part of the `passport.authenticate` - // call, before the final route handler callback. This is how we gain access to `req.wasp.providerProfile`. - router.get('/callback', - passport.authenticate(passportStrategyName, { - session: false, - failureRedirect: waspServerConfig.frontendUrl + authConfig.failureRedirectPath - }), - handleRejection(async function (req: RequestWithWasp, res) { - const providerProfile = req?.wasp?.providerProfile; - - if (!providerProfile) { - throw new Error(`Missing ${provider.displayName} provider profile on request. This should not happen! Please contact Wasp.`); - } else if (!providerProfile.id) { - throw new Error(`${provider.displayName} provider profile was missing required id property. This should not happen! Please contact Wasp.`); - } - - const providerId = createProviderId(provider.id, providerProfile.id); - - try { - const authId = await getAuthIdFromProviderDetails(providerId, providerProfile, userSignupFields) - const session = await createSession(authId) - return res.json({ - sessionId: session.id, - }) - } catch (e) { - rethrowPossibleAuthError(e) - } - }) - ) - - return router; -} - -// We need a user id to create the auth token, so we either find an existing user -// or create a new one if none exists for this provider. -async function getAuthIdFromProviderDetails( - providerId: ProviderId, - providerProfile: any, - userSignupFields?: UserSignupFields, -): Promise { - const existingAuthIdentity = await prisma.authIdentity.findUnique({ - where: { - providerName_providerUserId: providerId, - }, - include: { - auth: { - include: { - user: true - } - } - } - }) - - if (existingAuthIdentity) { - return existingAuthIdentity.auth.id - } else { - const userFields = await validateAndGetUserFields( - { profile: providerProfile }, - userSignupFields, - ); - - // For now, we don't have any extra data for the oauth providers, so we just pass an empty object. - const providerData = await sanitizeAndSerializeProviderData({}) - - const user = await createUser( - providerId, - providerData, - // Using any here because we want to avoid TypeScript errors and - // rely on Prisma to validate the data. - userFields as any, - ) - - return user.auth.id - } -} diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/server/src/auth/providers/oauth/env.ts b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/server/src/auth/providers/oauth/env.ts new file mode 100644 index 0000000000..24776c6dd3 --- /dev/null +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/server/src/auth/providers/oauth/env.ts @@ -0,0 +1,16 @@ +import { type ProviderConfig } from "wasp/auth/providers/types"; + +export function ensureEnvVarsForProvider( + envVarNames: EnvVarName[], + provider: ProviderConfig, +): Record { + const result: Record = {}; + for (const envVarName of envVarNames) { + const value = process.env[envVarName]; + if (!value) { + throw new Error(`${envVarName} env variable is required when using the ${provider.displayName} auth provider.`); + } + result[envVarName] = value; + } + return result as Record; +} diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/server/src/auth/providers/oauth/handler.ts b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/server/src/auth/providers/oauth/handler.ts new file mode 100644 index 0000000000..9fdc36c3b9 --- /dev/null +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/server/src/auth/providers/oauth/handler.ts @@ -0,0 +1,108 @@ +import { Router } from "express"; + +import { handleRejection, redirect } from "wasp/server/utils"; +import { rethrowPossibleAuthError } from "wasp/auth/utils"; +import { type UserSignupFields, type ProviderConfig } from "wasp/auth/providers/types"; + +import { + type StateType, + generateAndStoreOAuthState, + validateAndGetOAuthState, +} from "../oauth/state.js"; +import { + finishOAuthFlowAndGetRedirectUri, + handleOAuthErrorAndGetRedirectUri, +} from "../oauth/user.js"; +import { callbackPath, loginPath } from "./redirect.js"; + +export function createOAuthProviderRouter({ + provider, + stateTypes, + userSignupFields, + getAuthorizationUrl, + getProviderInfo, +}: { + provider: ProviderConfig, + /* + - State is used to validate the callback to ensure the user + that requested the login is the same that is completing it. + - It can include just the "state" or an extra "codeVerifier" for PKCE. + - The state types used depend on the provider. + */ + stateTypes: ST[], + userSignupFields: UserSignupFields | undefined, + /* + The function that returns the URL to redirect the user to the + provider's login page. + */ + getAuthorizationUrl: Parameters>[2], + /* + The function that returns the user's profile and ID from the + provider's callback. + */ + getProviderInfo: Parameters>[3], +}): Router { + const router = Router(); + + router.get( + `/${loginPath}`, + createOAuthLoginHandler(provider, stateTypes, getAuthorizationUrl) + ) + + router.get( + `/${callbackPath}`, + createOAuthCallbackHandler( + provider, + stateTypes, + userSignupFields, + getProviderInfo + ) + ) + + return router; +} + +function createOAuthLoginHandler( + provider: ProviderConfig, + stateTypes: ST[], + getAuthorizationUrl: (oAuthState: ReturnType>) => Promise, +) { + return handleRejection(async (_req, res) => { + const oAuthState = generateAndStoreOAuthState(stateTypes, provider, res); + const url = await getAuthorizationUrl(oAuthState); + return redirect(res, url.toString()); + }) +} + +function createOAuthCallbackHandler( + provider: ProviderConfig, + stateTypes: ST[], + userSignupFields: UserSignupFields | undefined, + getProviderInfo: (oAuthState: ReturnType>) => Promise<{ + providerUserId: string, + providerProfile: unknown, + }>, +) { + return handleRejection(async (req, res) => { + try { + const oAuthState = validateAndGetOAuthState(stateTypes, provider, req); + const { providerProfile, providerUserId } = await getProviderInfo(oAuthState); + try { + const redirectUri = await finishOAuthFlowAndGetRedirectUri( + provider, + providerProfile, + providerUserId, + userSignupFields, + ); + // Redirect to the client with the one time code + return redirect(res, redirectUri.toString()); + } catch (e) { + rethrowPossibleAuthError(e); + } + } catch (e) { + const redirectUri = handleOAuthErrorAndGetRedirectUri(e); + // Redirect to the client with the error + return redirect(res, redirectUri.toString()); + } + }) +} diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/server/src/auth/providers/oauth/init.ts b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/server/src/auth/providers/oauth/init.ts deleted file mode 100644 index 15cb5631fc..0000000000 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/server/src/auth/providers/oauth/init.ts +++ /dev/null @@ -1,76 +0,0 @@ -import passport from "passport"; - -import { config as waspServerConfig } from 'wasp/server'; - -import type { InitData, ProviderConfig, RequestWithWasp, UserSignupFields } from "wasp/auth/providers/types"; -import type { OAuthConfig, UserDefinedConfigFn } from "./types.js"; - -export function makeOAuthInit({ userDefinedConfigFn, userSignupFields, npmPackage, oAuthConfig }: OAuthImports) { - return async function init(provider: ProviderConfig): Promise { - const userDefinedConfig = userDefinedConfigFn - ? userDefinedConfigFn() - : {}; - const ProviderStrategy = await import(npmPackage); - - const passportStrategyName = `wasp${provider.id}LoginStrategy`; - const requiredConfig = { - clientID: oAuthConfig.clientID, - clientSecret: oAuthConfig.clientSecret, - scope: oAuthConfig.scope, - callbackURL: `${waspServerConfig.frontendUrl}/auth/login/${provider.id}`, - passReqToCallback: true - }; - - const config = { - ...requiredConfig, - ...userDefinedConfig, - }; - ensureValidConfig(provider, config); - - const passportStrategy = new ProviderStrategy.default( - config, - addProviderProfileToRequest - ); - passport.use(passportStrategyName, passportStrategy); - - return { - passportStrategyName, - userSignupFields, - }; - } -} - -// This function is invoked after we successfully exchange the one-time-use OAuth code for a real provider API token. -// This token was used to get the provider profile information supplied as a parameter. -// We add the provider profile to the request for downstream use. -async function addProviderProfileToRequest( - req: RequestWithWasp, - _accessToken: string, - _refreshToken: string, - providerProfile: { [key: string]: any }, - done: any, -) { - req.wasp = { ...req.wasp, providerProfile }; - done(null, {}); -} - -function ensureValidConfig(provider: ProviderConfig, config: OAuthConfig): void { - if (!config.clientID) { - throw new Error(`The ${provider.displayName} auth provider requires clientID provided via env variables.`) - } - - if (!config.clientSecret) { - throw new Error(`The ${provider.displayName} auth provider requires clientSecret provided via env variables.`) - } - - if (!config.scope || !Array.isArray(config.scope)) { - throw new Error(`The ${provider.displayName} auth provider requires scope.`) - } -} - -export type OAuthImports = { - npmPackage: string; - userDefinedConfigFn?: UserDefinedConfigFn; - oAuthConfig: OAuthConfig; - userSignupFields?: UserSignupFields; -}; diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/server/src/auth/providers/oauth/oneTimeCode.ts b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/server/src/auth/providers/oauth/oneTimeCode.ts new file mode 100644 index 0000000000..0b98a1d879 --- /dev/null +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/server/src/auth/providers/oauth/oneTimeCode.ts @@ -0,0 +1,89 @@ +import { Router } from "express"; + +import { HttpError } from 'wasp/server'; +import { handleRejection } from 'wasp/server/utils' +import { createJWT, validateJWT, TimeSpan } from 'wasp/auth/jwt' +import { findAuthWithUserBy } from 'wasp/auth/utils' +import { createSession } from 'wasp/auth/session' +import { exchangeCodeForTokenPath } from "./redirect.js"; + +export const tokenStore = createTokenStore(); + +export function setupOneTimeCodeRoute(router: Router) { + router.post( + `/${exchangeCodeForTokenPath}`, + handleRejection(async (req, res) => { + const { code } = req.body; + + if (code === undefined) { + throw new HttpError(400, "Unable to login with the OAuth provider. The code is missing."); + } + + if (tokenStore.isUsed(code)) { + throw new HttpError(400, "Unable to login with the OAuth provider. The code has already been used."); + } + + const { id: authId } = await tokenStore.verifyToken(code); + const auth = await findAuthWithUserBy({ id: authId }) + + if (auth === null) { + throw new HttpError(400, "Unable to login with the OAuth provider. The code is invalid."); + } + + const session = await createSession(auth.id); + + tokenStore.markUsed(code); + + return res.json({ + sessionId: session.id, + }); + }) + ); +} + +function createTokenStore() { + const usedTokens = new Map(); + + const validFor = new TimeSpan(1, 'm') // 1 minute + const cleanupAfter = 1000 * 60 * 60; // 1 hour + + function createToken(userId: string): Promise { + return createJWT( + { + id: userId, + }, + { + expiresIn: validFor, + } + ); + } + + function verifyToken(token: string): Promise<{ id: string }> { + return validateJWT(token); + } + + function isUsed(token: string): boolean { + return usedTokens.has(token); + } + + function markUsed(token: string): void { + usedTokens.set(token, Date.now()); + cleanUp(); + } + + function cleanUp(): void { + const now = Date.now(); + for (const [token, timestamp] of usedTokens.entries()) { + if (now - timestamp > cleanupAfter) { + usedTokens.delete(token); + } + } + } + + return { + createToken, + verifyToken, + isUsed, + markUsed, + }; +} diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/server/src/auth/providers/oauth/redirect.ts b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/server/src/auth/providers/oauth/redirect.ts new file mode 100644 index 0000000000..35c1cb4fd0 --- /dev/null +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/server/src/auth/providers/oauth/redirect.ts @@ -0,0 +1,18 @@ +import { config } from 'wasp/server' + +export const loginPath = 'login' +export const callbackPath = 'callback' +export const exchangeCodeForTokenPath = 'exchange-code' +const clientOAuthCallbackPath = '/oauth/callback' + +export function getRedirectUriForCallback(providerName: string): URL { + return new URL(`${config.serverUrl}/auth/${providerName}/${callbackPath}`); +} + +export function getRedirectUriForOneTimeCode(oneTimeCode: string): URL { + return new URL(`${config.frontendUrl}${clientOAuthCallbackPath}#${oneTimeCode}`); +} + +export function getRedirectUriForError(error: string): URL { + return new URL(`${config.frontendUrl}${clientOAuthCallbackPath}?error=${error}`); +} diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/server/src/auth/providers/oauth/state.ts b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/server/src/auth/providers/oauth/state.ts new file mode 100644 index 0000000000..ab1b0f8aaa --- /dev/null +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/server/src/auth/providers/oauth/state.ts @@ -0,0 +1,70 @@ +import { + Response as ExpressResponse, + Request as ExpressRequest, +} from "express"; +import { generateCodeVerifier, generateState } from "arctic"; + +import type { ProviderConfig } from "wasp/auth/providers/types"; + +import { setOAuthCookieValue, getOAuthCookieValue } from "./cookies.js"; + +export type StateType = 'state' | 'codeVerifier'; + +export function generateAndStoreOAuthState( + stateTypes: ST[], + provider: ProviderConfig, + res: ExpressResponse, +): { [name in ST]: string } { + const result = {} as { [name in StateType]: string } + + if (stateTypes.includes('state' as ST)) { + const state = generateState(); + setOAuthCookieValue(provider, res, 'state', state); + result.state = state; + } + + if (stateTypes.includes('codeVerifier' as ST)) { + const codeVerifier = generateCodeVerifier(); + setOAuthCookieValue(provider, res, 'codeVerifier', codeVerifier); + result.codeVerifier = codeVerifier; + } + + return result; +} + +export function validateAndGetOAuthState( + stateTypes: ST[], + provider: ProviderConfig, + req: ExpressRequest, +): { [name in ST]: string } & { code: string } { + const result = {} as { [name in StateType]: string } & { code: string }; + + if (stateTypes.includes('state' as ST)) { + const state = req.query.state; + const storedState = getOAuthCookieValue(provider, req, 'state'); + if ( + !state || + !storedState || + storedState !== state + ) { + throw new Error("Invalid state"); + } + result.state = storedState; + } + + if (stateTypes.includes('codeVerifier' as ST)) { + const storedCodeVerifier = getOAuthCookieValue(provider, req, 'codeVerifier'); + if (!storedCodeVerifier) { + throw new Error("Invalid code verifier"); + } + result.codeVerifier = storedCodeVerifier; + } + + const code = req.query.code; + if (typeof code !== "string") { + throw new Error("Invalid code"); + } + result.code = code; + + return result; +} diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/server/src/auth/providers/oauth/types.ts b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/server/src/auth/providers/oauth/types.ts index 7107a0d544..52753447b0 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/server/src/auth/providers/oauth/types.ts +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/server/src/auth/providers/oauth/types.ts @@ -1,12 +1,5 @@ import type { Prisma } from "@prisma/client" -import { contextWithUserEntity } from 'wasp/auth/utils' - -export type OAuthConfig = { - clientID?: string; - clientSecret?: string; - scope?: string[]; -} export type UserFieldsFromOAuthSignup = Prisma.UserCreateInput diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/server/src/auth/providers/oauth/user.ts b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/server/src/auth/providers/oauth/user.ts new file mode 100644 index 0000000000..67c9eedc7b --- /dev/null +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/server/src/auth/providers/oauth/user.ts @@ -0,0 +1,85 @@ +import { HttpError } from 'wasp/server' +import { + type ProviderId, + createUser, + sanitizeAndSerializeProviderData, + validateAndGetUserFields, + createProviderId, +} from 'wasp/auth/utils' +import { type Auth } from 'wasp/entities' +import { prisma } from 'wasp/server' +import { type UserSignupFields, type ProviderConfig } from 'wasp/auth/providers/types' +import { getRedirectUriForOneTimeCode, getRedirectUriForError } from './redirect' +import { tokenStore } from './oneTimeCode' + +export async function finishOAuthFlowAndGetRedirectUri( + provider: ProviderConfig, + providerProfile: unknown, + providerUserId: string, + userSignupFields: UserSignupFields | undefined, +): Promise { + const providerId = createProviderId(provider.id, providerUserId); + + const authId = await getAuthIdFromProviderDetails(providerId, providerProfile, userSignupFields); + + const oneTimeCode = await tokenStore.createToken(authId); + + return getRedirectUriForOneTimeCode(oneTimeCode); +} + +export function handleOAuthErrorAndGetRedirectUri(error: unknown): URL { + if (error instanceof HttpError) { + const errorMessage = isHttpErrorWithExtraMessage(error) + ? `${error.message}: ${error.data.message}` + : error.message; + return getRedirectUriForError(errorMessage) + } + return getRedirectUriForError("An unknown error occurred while trying to log in with the OAuth provider."); +} + +function isHttpErrorWithExtraMessage(error: HttpError): error is HttpError & { data: { message: string } } { + return error.data && typeof (error.data as any).message === 'string'; +} + +// We need a user id to create the auth token, so we either find an existing user +// or create a new one if none exists for this provider. +async function getAuthIdFromProviderDetails( + providerId: ProviderId, + providerProfile: any, + userSignupFields: UserSignupFields | undefined, +): Promise { + const existingAuthIdentity = await prisma.authIdentity.findUnique({ + where: { + providerName_providerUserId: providerId, + }, + include: { + auth: { + include: { + user: true + } + } + } + }) + + if (existingAuthIdentity) { + return existingAuthIdentity.auth.id + } else { + const userFields = await validateAndGetUserFields( + { profile: providerProfile }, + userSignupFields, + ); + + // For now, we don't have any extra data for the oauth providers, so we just pass an empty object. + const providerData = await sanitizeAndSerializeProviderData({}) + + const user = await createUser( + providerId, + providerData, + // Using any here because we want to avoid TypeScript errors and + // rely on Prisma to validate the data. + userFields as any, + ) + + return user.auth.id + } +} diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/web-app/src/auth/pages/OAuthCallback.tsx b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/web-app/src/auth/pages/OAuthCallback.tsx new file mode 100644 index 0000000000..71cc435a92 --- /dev/null +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/web-app/src/auth/pages/OAuthCallback.tsx @@ -0,0 +1,131 @@ +import { useEffect, useRef, useState } from "react"; +import { type AxiosResponse } from "axios"; +import { Redirect, useLocation } from 'react-router-dom' +import { useAuth } from 'wasp/client/auth' +import { api } from 'wasp/client/api' +import { initSession } from 'wasp/auth/helpers/user' + +const wrapperStyles = { + display: "flex", + alignItems: "center", + justifyContent: "center", + padding: "4rem", +}; + +const commonMessageStyles = { + display: 'flex', + alignItems: 'center', + gap: '.5rem', + borderRadius: '.5rem', + padding: '1rem', +}; + +const errorMessageStyles = { + ...commonMessageStyles, + borderColor: 'rgb(240 82 82)', + backgroundColor: 'rgb(253 232 232)', + color: 'rgb(200 30 30)', +}; + +const loadingMessageStyles = { + ...commonMessageStyles, + borderColor: 'rgb(107 114 128)', + backgroundColor: 'rgb(243 244 246)', + color: 'rgb(55 65 81)', +}; + +export function OAuthCallbackPage() { + const { isLoading, error, user } = useOAuthCallbackHandler(); + + if (user !== undefined && user !== null) { + return ; + } + + return ( +
+ {error &&
{error}
} + {isLoading &&
Please wait a moment while we log you in.
} +
+ ); +} + +function useOAuthCallbackHandler() { + const { data: user } = useAuth(); + const [isLoading, setIsLoading] = useState(true); + const [error, setError] = useState(null); + const location = useLocation(); + + async function handleCallback() { + try { + setIsLoading(true); + const query = new URLSearchParams(location.search); + + // If we got redirect with an error, display it to the user + // and don't continue with the login process. + const errorFromRedirect = query.get('error'); + if (errorFromRedirect !== null) { + setError(errorFromRedirect); + return; + } + + const code = location.hash.slice(1); + const response = await exchangeOAuthCodeForToken({ code }); + if (!isResponseWithSessionId(response)) { + setError("Unable to login with the OAuth provider."); + return; + } + await initSession(response.data.sessionId); + } catch (e: unknown) { + console.error(e); + setError("Unable to login with the OAuth provider."); + } finally { + setIsLoading(false); + } + } + + const isFirstRender = useRef(true); + useEffect(() => { + if (isFirstRender.current) { + isFirstRender.current = false; + handleCallback(); + } + }, []); + + return { + user, + error, + isLoading, + }; +} + +const MessageIcon = () => ( + +) + +async function exchangeOAuthCodeForToken(data: { + code: string +}): Promise> { + return api.post('/auth/exchange-code', data) +} + +function isResponseWithSessionId( + response: AxiosResponse +): response is AxiosResponse<{ sessionId: string }> { + return response.data && typeof (response.data as any).sessionId === 'string' +} diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/web-app/src/auth/pages/OAuthCodeExchange.jsx b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/web-app/src/auth/pages/OAuthCodeExchange.jsx deleted file mode 100644 index c24295408b..0000000000 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/web-app/src/auth/pages/OAuthCodeExchange.jsx +++ /dev/null @@ -1,69 +0,0 @@ -import React, { useEffect, useRef } from 'react' -import { useHistory } from 'react-router-dom' - -import { config } from 'wasp/client' -import { api } from 'wasp/client/api' -import { initSession } from 'wasp/auth/helpers/user' - -// After a user authenticates via an Oauth 2.0 provider, this is the page that -// the provider should redirect them to, while providing query string parameters -// that contain information needed for the API server to authenticate with the provider. -// This page forwards that information to the API server and in response get a JWT, -// which it stores on the client, therefore completing the OAuth authentication process. -export default function OAuthCodeExchange({ pathToApiServerRouteHandlingOauthRedirect }) { - const history = useHistory() - - // We are using a ref to prevent sending the OAuth token twice in development. - // Since React 18 and using their StrictMode, useEffect is called twice in development. - - // Fixing it this way is not recommended by the docs, but they don't offer any alternatives - // for this particular use case (oauth redirect page): - // https://react.dev/learn/synchronizing-with-effects#how-to-handle-the-effect-firing-twice-in-development - const firstRender = useRef(true) - useEffect(() => { - if (!firstRender.current) { - return - } - // NOTE: Different auth methods will have different Wasp API server validation paths. - // This helps us reuse one component for various methods (e.g., Google, Facebook, etc.). - const apiServerUrlHandlingOauthRedirect = constructOauthRedirectApiServerUrl(pathToApiServerRouteHandlingOauthRedirect) - - exchangeCodeForSessionIdAndRedirect(history, apiServerUrlHandlingOauthRedirect) - return () => { - firstRender.current = false - } - }, [history, pathToApiServerRouteHandlingOauthRedirect]) - - return ( -

Completing login process...

- ) -} - -function constructOauthRedirectApiServerUrl(pathToApiServerRouteHandlingOauthRedirect) { - // Take the redirect query params supplied by the external OAuth provider and - // send them as-is to our backend, so Passport can finish the process. - const queryParams = window.location.search - return `${config.apiUrl}${pathToApiServerRouteHandlingOauthRedirect}${queryParams}` -} - -async function exchangeCodeForSessionIdAndRedirect(history, apiServerUrlHandlingOauthRedirect) { - const sessionId = await exchangeCodeForSessionId(apiServerUrlHandlingOauthRedirect) - - if (sessionId !== null) { - await initSession(sessionId) - history.push('/') - } else { - console.error('Error obtaining session ID') - history.push('/login') - } -} - -async function exchangeCodeForSessionId(url) { - try { - const response = await api.get(url) - return response?.data?.sessionId || null - } catch (e) { - console.error(e) - return null - } -} diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/web-app/src/router.tsx b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/web-app/src/router.tsx index 2170647a5f..7ced466397 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/web-app/src/router.tsx +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/web-app/src/router.tsx @@ -6,7 +6,7 @@ import createAuthRequiredPage from "./auth/pages/createAuthRequiredPage" import { MainPage } from '../../../../src/MainPage' -import OAuthCodeExchange from "./auth/pages/OAuthCodeExchange" +import { OAuthCallbackPage } from "./auth/pages/OAuthCallback" import { routes } from 'wasp/client/router' @@ -26,8 +26,8 @@ const router = ( component={routeNameToRouteComponent[routeKey]} /> ))} - - + + diff --git a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/.waspchecksums b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/.waspchecksums index 12348ec0e4..7377fa6fb7 100644 --- a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/.waspchecksums +++ b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/.waspchecksums @@ -18,7 +18,7 @@ "file", "../out/sdk/wasp/client/config.ts" ], - "12a7dffb1c3fe762cec8d9d928af353cb169ff199d3934b1f3c27ce0e3a2f987" + "68141be8527e8ae3d15838663769737278a71d3853b1dbdc48696e92d4e42548" ], [ [ @@ -375,7 +375,7 @@ "file", "../out/sdk/wasp/server/utils.ts" ], - "a4178a3e2527d47d141340b99abf675125859fa9cb5a0535e3efa7b34a3bcabb" + "688fdd57d6a9e9ead90141c6f0ebea9d39713d5bd7a630d43f2c2cb5a7984108" ], [ [ diff --git a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/client/config.ts b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/client/config.ts index e9234e6f2a..a9cb2de2d3 100644 --- a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/client/config.ts +++ b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/client/config.ts @@ -6,4 +6,4 @@ const config = { apiUrl, } -export default config +export default config \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/server/utils.d.ts b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/server/utils.d.ts index 266b9c6fbb..0e3653e5cd 100644 --- a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/server/utils.d.ts +++ b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/server/utils.d.ts @@ -9,4 +9,5 @@ type RequestWithExtraFields = Request & {}; */ export declare const handleRejection: (middleware: (req: RequestWithExtraFields, res: Response, next: NextFunction) => any) => (req: RequestWithExtraFields, res: Response, next: NextFunction) => Promise; export declare const sleep: (ms: number) => Promise; +export declare function redirect(res: Response, redirectUri: string): any; export {}; diff --git a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/server/utils.js b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/server/utils.js index 9b2034006b..07e1731907 100644 --- a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/server/utils.js +++ b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/server/utils.js @@ -14,4 +14,10 @@ export const handleRejection = (middleware) => async (req, res, next) => { } }; export const sleep = (ms) => new Promise((r) => setTimeout(r, ms)); +export function redirect(res, redirectUri) { + return res + .status(302) + .setHeader("Location", redirectUri) + .end(); +} //# sourceMappingURL=utils.js.map \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/server/utils.js.map b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/server/utils.js.map index 17121f586d..9ca16bf322 100644 --- a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/server/utils.js.map +++ b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/server/utils.js.map @@ -1 +1 @@ -{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../server/utils.ts"],"names":[],"mappings":"AAWA;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAC7B,UAIQ,EACR,EAAE,CACJ,KAAK,EAAE,GAA2B,EAAE,GAAa,EAAE,IAAkB,EAAE,EAAE;IACvE,IAAI,CAAC;QACH,MAAM,UAAU,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,CAAA;IAClC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,CAAC,KAAK,CAAC,CAAA;IACb,CAAC;AACH,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,EAAU,EAAoB,EAAE,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAA"} \ No newline at end of file +{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../server/utils.ts"],"names":[],"mappings":"AAMA;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAC7B,UAIQ,EACR,EAAE,CACJ,KAAK,EAAE,GAA2B,EAAE,GAAa,EAAE,IAAkB,EAAE,EAAE;IACvE,IAAI,CAAC;QACH,MAAM,UAAU,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,CAAA;IAClC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,CAAC,KAAK,CAAC,CAAA;IACb,CAAC;AACH,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,EAAU,EAAoB,EAAE,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAA;AAE5F,MAAM,UAAU,QAAQ,CAAC,GAAa,EAAE,WAAmB;IACzD,OAAO,GAAG;SACP,MAAM,CAAC,GAAG,CAAC;SACX,SAAS,CAAC,UAAU,EAAE,WAAW,CAAC;SAClC,GAAG,EAAE,CAAC;AACX,CAAC"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/server/utils.ts b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/server/utils.ts index c8cc823348..85ba9a4d8d 100644 --- a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/server/utils.ts +++ b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/server/utils.ts @@ -1,10 +1,5 @@ -import crypto from 'crypto' import { Request, Response, NextFunction } from 'express' -import { readdir } from 'fs' -import { dirname } from 'path' -import { fileURLToPath } from 'url' - type RequestWithExtraFields = Request & { } @@ -32,3 +27,10 @@ async (req: RequestWithExtraFields, res: Response, next: NextFunction) => { } export const sleep = (ms: number): Promise => new Promise((r) => setTimeout(r, ms)) + +export function redirect(res: Response, redirectUri: string) { + return res + .status(302) + .setHeader("Location", redirectUri) + .end(); +} diff --git a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/.waspchecksums b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/.waspchecksums index 0eb61fa0c9..caa7abd1c0 100644 --- a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/.waspchecksums +++ b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/.waspchecksums @@ -18,7 +18,7 @@ "file", "../out/sdk/wasp/client/config.ts" ], - "12a7dffb1c3fe762cec8d9d928af353cb169ff199d3934b1f3c27ce0e3a2f987" + "68141be8527e8ae3d15838663769737278a71d3853b1dbdc48696e92d4e42548" ], [ [ @@ -319,7 +319,7 @@ "file", "../out/sdk/wasp/server/utils.ts" ], - "a4178a3e2527d47d141340b99abf675125859fa9cb5a0535e3efa7b34a3bcabb" + "688fdd57d6a9e9ead90141c6f0ebea9d39713d5bd7a630d43f2c2cb5a7984108" ], [ [ diff --git a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/client/config.ts b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/client/config.ts index b87c9515df..a9cb2de2d3 100644 --- a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/client/config.ts +++ b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/client/config.ts @@ -1,10 +1,9 @@ -{{={= =}=}} import { stripTrailingSlash } from 'wasp/universal/url' -const apiUrl = stripTrailingSlash(import.meta.env.REACT_APP_API_URL) || '{= defaultServerUrl =}'; +const apiUrl = stripTrailingSlash(import.meta.env.REACT_APP_API_URL) || 'http://localhost:3001'; const config = { apiUrl, } -export default config +export default config \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/server/utils.d.ts b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/server/utils.d.ts index 266b9c6fbb..0e3653e5cd 100644 --- a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/server/utils.d.ts +++ b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/server/utils.d.ts @@ -9,4 +9,5 @@ type RequestWithExtraFields = Request & {}; */ export declare const handleRejection: (middleware: (req: RequestWithExtraFields, res: Response, next: NextFunction) => any) => (req: RequestWithExtraFields, res: Response, next: NextFunction) => Promise; export declare const sleep: (ms: number) => Promise; +export declare function redirect(res: Response, redirectUri: string): any; export {}; diff --git a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/server/utils.js b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/server/utils.js index 9b2034006b..07e1731907 100644 --- a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/server/utils.js +++ b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/server/utils.js @@ -14,4 +14,10 @@ export const handleRejection = (middleware) => async (req, res, next) => { } }; export const sleep = (ms) => new Promise((r) => setTimeout(r, ms)); +export function redirect(res, redirectUri) { + return res + .status(302) + .setHeader("Location", redirectUri) + .end(); +} //# sourceMappingURL=utils.js.map \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/server/utils.js.map b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/server/utils.js.map index 17121f586d..9ca16bf322 100644 --- a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/server/utils.js.map +++ b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/server/utils.js.map @@ -1 +1 @@ -{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../server/utils.ts"],"names":[],"mappings":"AAWA;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAC7B,UAIQ,EACR,EAAE,CACJ,KAAK,EAAE,GAA2B,EAAE,GAAa,EAAE,IAAkB,EAAE,EAAE;IACvE,IAAI,CAAC;QACH,MAAM,UAAU,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,CAAA;IAClC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,CAAC,KAAK,CAAC,CAAA;IACb,CAAC;AACH,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,EAAU,EAAoB,EAAE,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAA"} \ No newline at end of file +{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../server/utils.ts"],"names":[],"mappings":"AAMA;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAC7B,UAIQ,EACR,EAAE,CACJ,KAAK,EAAE,GAA2B,EAAE,GAAa,EAAE,IAAkB,EAAE,EAAE;IACvE,IAAI,CAAC;QACH,MAAM,UAAU,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,CAAA;IAClC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,CAAC,KAAK,CAAC,CAAA;IACb,CAAC;AACH,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,EAAU,EAAoB,EAAE,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAA;AAE5F,MAAM,UAAU,QAAQ,CAAC,GAAa,EAAE,WAAmB;IACzD,OAAO,GAAG;SACP,MAAM,CAAC,GAAG,CAAC;SACX,SAAS,CAAC,UAAU,EAAE,WAAW,CAAC;SAClC,GAAG,EAAE,CAAC;AACX,CAAC"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/server/utils.ts b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/server/utils.ts index c8cc823348..85ba9a4d8d 100644 --- a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/server/utils.ts +++ b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/server/utils.ts @@ -1,10 +1,5 @@ -import crypto from 'crypto' import { Request, Response, NextFunction } from 'express' -import { readdir } from 'fs' -import { dirname } from 'path' -import { fileURLToPath } from 'url' - type RequestWithExtraFields = Request & { } @@ -32,3 +27,10 @@ async (req: RequestWithExtraFields, res: Response, next: NextFunction) => { } export const sleep = (ms: number): Promise => new Promise((r) => setTimeout(r, ms)) + +export function redirect(res: Response, redirectUri: string) { + return res + .status(302) + .setHeader("Location", redirectUri) + .end(); +} diff --git a/waspc/examples/todoApp/main.wasp b/waspc/examples/todoApp/main.wasp index 705cfe713e..bfaae98df2 100644 --- a/waspc/examples/todoApp/main.wasp +++ b/waspc/examples/todoApp/main.wasp @@ -18,10 +18,10 @@ app todoApp { configFn: import { config } from "@src/auth/google.js", userSignupFields: import { userSignupFields } from "@src/auth/google.js" }, - // gitHub: { - // // configFn: import { config } from "@src/auth/github.js", - // // userSignupFields: import { getUserFields } from "@src/auth/github.js" - // }, + gitHub: { + configFn: import { config } from "@src/auth/github.js", + userSignupFields: import { userSignupFields } from "@src/auth/github.js" + }, email: { userSignupFields: import { userSignupFields } from "@src/auth/email.js", fromField: { diff --git a/waspc/examples/todoApp/package-lock.json b/waspc/examples/todoApp/package-lock.json index 92352e97f8..1980c8fca7 100644 --- a/waspc/examples/todoApp/package-lock.json +++ b/waspc/examples/todoApp/package-lock.json @@ -31,12 +31,12 @@ "@testing-library/jest-dom": "^6.3.0", "@testing-library/react": "^14.1.2", "@types/express-serve-static-core": "^4.17.13", + "@types/react-router-dom": "^5.3.3", "@vitest/ui": "^1.2.1", "autoprefixer": "^10.4.13", "axios": "^1.4.0", "express": "~4.18.1", "jsdom": "^21.1.1", - "jsonwebtoken": "^8.5.1", "lodash.merge": "^4.6.2", "lucia": "^3.0.1", "mitt": "3.0.0", @@ -2292,6 +2292,11 @@ "@types/send": "*" } }, + "node_modules/@types/history": { + "version": "4.7.11", + "resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.11.tgz", + "integrity": "sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA==" + }, "node_modules/@types/http-errors": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", @@ -2354,6 +2359,25 @@ "@types/react": "*" } }, + "node_modules/@types/react-router": { + "version": "5.1.20", + "resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.20.tgz", + "integrity": "sha512-jGjmu/ZqS7FjSH6owMcD5qpq19+1RS9DeVRqfl1FeBMxTDQAGwlMWOcs52NDoXaNKyG3d1cYQFMs9rCrb88o9Q==", + "dependencies": { + "@types/history": "^4.7.11", + "@types/react": "*" + } + }, + "node_modules/@types/react-router-dom": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/@types/react-router-dom/-/react-router-dom-5.3.3.tgz", + "integrity": "sha512-kpqnYK4wcdm5UaWI3fLcELopqLrHgLqNsdpHauzlQktfkHL3npOSwtj1Uz9oKBAzs7lFtVkV8j83voAz2D8fhw==", + "dependencies": { + "@types/history": "^4.7.11", + "@types/react": "*", + "@types/react-router": "*" + } + }, "node_modules/@types/scheduler": { "version": "0.16.8", "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.8.tgz", @@ -3474,11 +3498,6 @@ "ieee754": "^1.1.13" } }, - "node_modules/buffer-equal-constant-time": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", - "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==" - }, "node_modules/buffer-writer": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-2.0.0.tgz", @@ -4122,14 +4141,6 @@ "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" }, - "node_modules/ecdsa-sig-formatter": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", - "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", - "dependencies": { - "safe-buffer": "^5.0.1" - } - }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -5680,51 +5691,6 @@ "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.1.tgz", "integrity": "sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA==" }, - "node_modules/jsonwebtoken": { - "version": "8.5.1", - "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", - "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==", - "dependencies": { - "jws": "^3.2.2", - "lodash.includes": "^4.3.0", - "lodash.isboolean": "^3.0.3", - "lodash.isinteger": "^4.0.4", - "lodash.isnumber": "^3.0.3", - "lodash.isplainobject": "^4.0.6", - "lodash.isstring": "^4.0.1", - "lodash.once": "^4.0.0", - "ms": "^2.1.1", - "semver": "^5.6.0" - }, - "engines": { - "node": ">=4", - "npm": ">=1.4.28" - } - }, - "node_modules/jsonwebtoken/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - }, - "node_modules/jwa": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", - "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", - "dependencies": { - "buffer-equal-constant-time": "1.0.1", - "ecdsa-sig-formatter": "1.0.11", - "safe-buffer": "^5.0.1" - } - }, - "node_modules/jws": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", - "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", - "dependencies": { - "jwa": "^1.4.1", - "safe-buffer": "^5.0.1" - } - }, "node_modules/lilconfig": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", @@ -5768,46 +5734,16 @@ "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" }, - "node_modules/lodash.includes": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", - "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==" - }, - "node_modules/lodash.isboolean": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", - "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==" - }, - "node_modules/lodash.isinteger": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", - "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==" - }, - "node_modules/lodash.isnumber": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", - "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==" - }, "node_modules/lodash.isplainobject": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==" }, - "node_modules/lodash.isstring": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", - "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==" - }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" }, - "node_modules/lodash.once": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", - "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==" - }, "node_modules/log-symbols": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", @@ -7399,14 +7335,6 @@ "loose-envify": "^1.1.0" } }, - "node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "bin": { - "semver": "bin/semver" - } - }, "node_modules/send": { "version": "0.18.0", "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", diff --git a/waspc/examples/todoApp/src/auth/github.js b/waspc/examples/todoApp/src/auth/github.js index 63f6dbb62f..685e74d9ee 100644 --- a/waspc/examples/todoApp/src/auth/github.js +++ b/waspc/examples/todoApp/src/auth/github.js @@ -1,9 +1,7 @@ export function config() { console.log('Inside user-supplied GitHub config') return { - clientID: process.env['GITHUB_CLIENT_ID'], - clientSecret: process.env['GITHUB_CLIENT_SECRET'], - scope: [], + scopes: ['user'], } } diff --git a/waspc/examples/todoApp/src/auth/google.js b/waspc/examples/todoApp/src/auth/google.js index 9071d973f6..b3498e6cd9 100644 --- a/waspc/examples/todoApp/src/auth/google.js +++ b/waspc/examples/todoApp/src/auth/google.js @@ -1,9 +1,7 @@ export function config() { console.log('Inside user-supplied Google config') return { - clientID: process.env['GOOGLE_CLIENT_ID'], - clientSecret: process.env['GOOGLE_CLIENT_SECRET'], - scope: ['profile', 'email'], + scopes: ['profile', 'email'], } } diff --git a/waspc/examples/todoApp/src/user.ts b/waspc/examples/todoApp/src/user.ts index 32d6d64d30..69e2fffaaf 100644 --- a/waspc/examples/todoApp/src/user.ts +++ b/waspc/examples/todoApp/src/user.ts @@ -1,4 +1,4 @@ -import { getEmail, findUserIdentity, type AuthUser as User } from "wasp/auth"; +import { getEmail, findUserIdentity, type AuthUser as User } from 'wasp/auth' export function getName(user?: User) { if (!user) { @@ -7,15 +7,20 @@ export function getName(user?: User) { // We use multiple auth methods, so we need to check which one is available. const emailIdentity = findUserIdentity(user, 'email') - if (emailIdentity) { + if (emailIdentity !== undefined) { return getEmail(user) } const googleIdentity = findUserIdentity(user, 'google') - if (googleIdentity) { + if (googleIdentity !== undefined) { return `Google user ${googleIdentity.providerUserId}` } + const githubIdentity = findUserIdentity(user, 'github') + if (githubIdentity !== undefined) { + return `GitHub user ${githubIdentity.providerUserId}` + } + // If we don't know how to get the name, return null. return null } diff --git a/waspc/src/Wasp/Generator/AuthProviders.hs b/waspc/src/Wasp/Generator/AuthProviders.hs index 6be0d2e65c..b940d0d9b2 100644 --- a/waspc/src/Wasp/Generator/AuthProviders.hs +++ b/waspc/src/Wasp/Generator/AuthProviders.hs @@ -1,7 +1,6 @@ module Wasp.Generator.AuthProviders where import Data.Maybe (fromJust) -import qualified Wasp.AppSpec.App.Dependency as App.Dependency import Wasp.Generator.AuthProviders.Common (makeProviderId) import qualified Wasp.Generator.AuthProviders.Email as E import qualified Wasp.Generator.AuthProviders.Local as L @@ -12,8 +11,7 @@ googleAuthProvider = OA.OAuthAuthProvider { OA._providerId = fromJust $ makeProviderId "google", OA._displayName = "Google", - OA._requiredScope = ["profile"], - OA._passportDependency = App.Dependency.make ("passport-google-oauth20", "2.0.0") + OA._requiredScope = ["profile"] } gitHubAuthProvider :: OA.OAuthAuthProvider @@ -21,8 +19,7 @@ gitHubAuthProvider = OA.OAuthAuthProvider { OA._providerId = fromJust $ makeProviderId "github", OA._displayName = "GitHub", - OA._requiredScope = [], - OA._passportDependency = App.Dependency.make ("passport-github2", "0.1.12") + OA._requiredScope = [] } localAuthProvider :: L.LocalAuthProvider diff --git a/waspc/src/Wasp/Generator/AuthProviders/OAuth.hs b/waspc/src/Wasp/Generator/AuthProviders/OAuth.hs index 95c7b7848b..a9c72be4c1 100644 --- a/waspc/src/Wasp/Generator/AuthProviders/OAuth.hs +++ b/waspc/src/Wasp/Generator/AuthProviders/OAuth.hs @@ -1,19 +1,17 @@ module Wasp.Generator.AuthProviders.OAuth - ( frontendLoginUrl, + ( clientOAuthCallbackPath, + serverOAuthLoginHandlerPath, + serverOAuthCallbackHandlerPath, serverLoginUrl, - serverOauthRedirectHandlerUrl, + serverExchangeCodeForTokenHandlerPath, + serverExchangeCodeForTokenUrl, providerId, displayName, - passportDependency, scopeStr, - clientIdEnvVarName, - clientSecretEnvVarName, OAuthAuthProvider (..), ) where -import Data.Char (toUpper) -import Wasp.AppSpec.App.Dependency (Dependency) import Wasp.Generator.AuthProviders.Common (ProviderId, fromProviderId) import Wasp.Generator.Common (makeJsArrayFromHaskellList) @@ -22,8 +20,7 @@ data OAuthAuthProvider = OAuthAuthProvider _providerId :: ProviderId, -- Used for pretty printing _displayName :: String, - _requiredScope :: OAuthScope, - _passportDependency :: Dependency + _requiredScope :: OAuthScope } type OAuthScope = [String] @@ -34,28 +31,25 @@ providerId = fromProviderId . _providerId displayName :: OAuthAuthProvider -> String displayName = _displayName -clientIdEnvVarName :: OAuthAuthProvider -> String -clientIdEnvVarName oai = upperCaseId oai ++ "_CLIENT_ID" - -clientSecretEnvVarName :: OAuthAuthProvider -> String -clientSecretEnvVarName oai = upperCaseId oai ++ "_CLIENT_SECRET" - -upperCaseId :: OAuthAuthProvider -> String -upperCaseId oai = map toUpper (providerId oai) - -- Generates the string used in JS e.g. ["profile"] list in Haskell becomes "[\"profile\"]" -- string which can be outputted in JS code verbatim. scopeStr :: OAuthAuthProvider -> String scopeStr oai = makeJsArrayFromHaskellList $ _requiredScope oai -passportDependency :: OAuthAuthProvider -> Dependency -passportDependency = _passportDependency +clientOAuthCallbackPath :: String +clientOAuthCallbackPath = "/oauth/callback" -frontendLoginUrl :: OAuthAuthProvider -> String -frontendLoginUrl oai = "/auth/login/" ++ providerId oai +serverOAuthLoginHandlerPath :: String +serverOAuthLoginHandlerPath = "login" serverLoginUrl :: OAuthAuthProvider -> String -serverLoginUrl oai = "/auth/" ++ providerId oai ++ "/login" +serverLoginUrl oai = "/auth/" ++ providerId oai ++ "/" ++ serverOAuthLoginHandlerPath + +serverOAuthCallbackHandlerPath :: String +serverOAuthCallbackHandlerPath = "callback" + +serverExchangeCodeForTokenHandlerPath :: String +serverExchangeCodeForTokenHandlerPath = "exchange-code" -serverOauthRedirectHandlerUrl :: OAuthAuthProvider -> String -serverOauthRedirectHandlerUrl oai = "/auth/" ++ providerId oai ++ "/callback" +serverExchangeCodeForTokenUrl :: String +serverExchangeCodeForTokenUrl = "/auth/" ++ serverExchangeCodeForTokenHandlerPath diff --git a/waspc/src/Wasp/Generator/ServerGenerator.hs b/waspc/src/Wasp/Generator/ServerGenerator.hs index 3aa2f783ed..9dc7b2216a 100644 --- a/waspc/src/Wasp/Generator/ServerGenerator.hs +++ b/waspc/src/Wasp/Generator/ServerGenerator.hs @@ -44,7 +44,7 @@ import Wasp.Generator.FileDraft (FileDraft, createTextFileDraft) import Wasp.Generator.Monad (Generator) import qualified Wasp.Generator.NpmDependencies as N import Wasp.Generator.ServerGenerator.ApiRoutesG (genApis) -import Wasp.Generator.ServerGenerator.Auth.OAuthAuthG (depsRequiredByPassport) +import Wasp.Generator.ServerGenerator.Auth.OAuthAuthG (depsRequiredByOAuth) import Wasp.Generator.ServerGenerator.AuthG (genAuth) import qualified Wasp.Generator.ServerGenerator.Common as C import Wasp.Generator.ServerGenerator.CrudG (genCrud) @@ -153,7 +153,7 @@ npmDepsForWasp spec = ("rate-limiter-flexible", "^2.4.1"), ("superjson", "^1.12.2") ] - ++ depsRequiredByPassport spec + ++ depsRequiredByOAuth spec ++ depsRequiredByWebSockets spec, N.waspDevDependencies = AS.Dependency.fromList diff --git a/waspc/src/Wasp/Generator/ServerGenerator/Auth/OAuthAuthG.hs b/waspc/src/Wasp/Generator/ServerGenerator/Auth/OAuthAuthG.hs index 6004c9c70a..5626a2c361 100644 --- a/waspc/src/Wasp/Generator/ServerGenerator/Auth/OAuthAuthG.hs +++ b/waspc/src/Wasp/Generator/ServerGenerator/Auth/OAuthAuthG.hs @@ -1,11 +1,10 @@ module Wasp.Generator.ServerGenerator.Auth.OAuthAuthG ( genOAuthAuth, - depsRequiredByPassport, + depsRequiredByOAuth, ) where import Data.Aeson (object, (.=)) -import qualified Data.Aeson as Aeson import Data.Maybe (fromJust, isJust) import StrongPath ( Dir, @@ -28,12 +27,18 @@ import qualified Wasp.AppSpec.App.Auth as AS.Auth import qualified Wasp.AppSpec.App.Dependency as App.Dependency import Wasp.AppSpec.Valid (getApp) import Wasp.Generator.AuthProviders (gitHubAuthProvider, googleAuthProvider) -import Wasp.Generator.AuthProviders.OAuth (OAuthAuthProvider) +import Wasp.Generator.AuthProviders.OAuth + ( OAuthAuthProvider, + clientOAuthCallbackPath, + serverExchangeCodeForTokenHandlerPath, + serverOAuthCallbackHandlerPath, + serverOAuthLoginHandlerPath, + ) import qualified Wasp.Generator.AuthProviders.OAuth as OAuth import qualified Wasp.Generator.DbGenerator.Auth as DbAuth import Wasp.Generator.FileDraft (FileDraft) import Wasp.Generator.Monad (Generator) -import Wasp.Generator.ServerGenerator.Common (ServerSrcDir) +import Wasp.Generator.ServerGenerator.Common (ServerTemplatesSrcDir) import qualified Wasp.Generator.ServerGenerator.Common as C import Wasp.Generator.ServerGenerator.JsImport (extImportToImportJson) import Wasp.Util ((<++>)) @@ -50,24 +55,40 @@ genOAuthAuth auth genOAuthHelpers :: AS.Auth.Auth -> Generator [FileDraft] genOAuthHelpers auth = sequence - [ genCreateRouter auth, - genTypes auth, - return $ C.mkSrcTmplFd [relfile|auth/providers/oauth/init.ts|] + [ genTypes auth, + genUser, + genRedirectHelpers, + return $ C.mkSrcTmplFd [relfile|auth/providers/oauth/handler.ts|], + return $ C.mkSrcTmplFd [relfile|auth/providers/oauth/state.ts|], + return $ C.mkSrcTmplFd [relfile|auth/providers/oauth/cookies.ts|], + return $ C.mkSrcTmplFd [relfile|auth/providers/oauth/env.ts|], + return $ C.mkSrcTmplFd [relfile|auth/providers/oauth/config.ts|], + return $ C.mkSrcTmplFd [relfile|auth/providers/oauth/oneTimeCode.ts|] ] -genCreateRouter :: AS.Auth.Auth -> Generator FileDraft -genCreateRouter auth = return $ C.mkTmplFdWithData [relfile|src/auth/providers/oauth/createRouter.ts|] (Just tmplData) +genUser :: Generator FileDraft +genUser = return $ C.mkTmplFdWithData tmplFile (Just tmplData) where + tmplFile = C.srcDirInServerTemplatesDir [relfile|auth/providers/oauth/user.ts|] tmplData = object - [ "userEntityUpper" .= userEntityName, - "authEntityUpper" .= (DbAuth.authEntityName :: String), + [ "authEntityUpper" .= (DbAuth.authEntityName :: String), "authIdentityEntityLower" .= (Util.toLowerFirst DbAuth.authIdentityEntityName :: String), - "identitiesFieldOnAuthEntityName" .= (DbAuth.identitiesFieldOnAuthEntityName :: String), "authFieldOnAuthIdentityEntityName" .= (DbAuth.authFieldOnAuthIdentityEntityName :: String), "userFieldOnAuthEntityName" .= (DbAuth.userFieldOnAuthEntityName :: String) ] - userEntityName = AS.refName . AS.Auth.userEntity $ auth + +genRedirectHelpers :: Generator FileDraft +genRedirectHelpers = return $ C.mkTmplFdWithData tmplFile (Just tmplData) + where + tmplFile = C.srcDirInServerTemplatesDir [relfile|auth/providers/oauth/redirect.ts|] + tmplData = + object + [ "clientOAuthCallbackPath" .= clientOAuthCallbackPath, + "serverOAuthLoginHandlerPath" .= serverOAuthLoginHandlerPath, + "serverOAuthCallbackHandlerPath" .= serverOAuthCallbackHandlerPath, + "serverExchangeCodeForTokenHandlerPath" .= serverExchangeCodeForTokenHandlerPath + ] genTypes :: AS.Auth.Auth -> Generator FileDraft genTypes auth = return $ C.mkTmplFdWithData tmplFile (Just tmplData) @@ -98,18 +119,16 @@ genOAuthProvider provider maybeUserConfig genOAuthConfig :: OAuthAuthProvider -> Maybe AS.Auth.ExternalAuthConfig -> - Path' (Rel ServerSrcDir) File' -> + Path' (Rel ServerTemplatesSrcDir) File' -> Generator FileDraft -genOAuthConfig provider maybeUserConfig pathToConfigDst = return $ C.mkTmplFdWithDstAndData tmplFile dstFile (Just tmplData) +genOAuthConfig provider maybeUserConfig pathToConfigTmpl = return $ C.mkTmplFdWithData tmplFile (Just tmplData) where - tmplFile = C.srcDirInServerTemplatesDir [relfile|auth/providers/config/_oauth.ts|] - dstFile = C.serverSrcDirInServerRootDir pathToConfigDst + tmplFile = C.srcDirInServerTemplatesDir pathToConfigTmpl tmplData = object [ "providerId" .= OAuth.providerId provider, "displayName" .= OAuth.displayName provider, - "npmPackage" .= App.Dependency.name (OAuth.passportDependency provider), - "oAuthConfigProps" .= getJsonForOAuthConfigProps provider, + "requiredScopes" .= OAuth.scopeStr provider, "configFn" .= extImportToImportJson relPathFromAuthConfigToServerSrcDir maybeConfigFn, "userSignupFields" .= extImportToImportJson relPathFromAuthConfigToServerSrcDir maybeUserSignupFields ] @@ -119,28 +138,8 @@ genOAuthConfig provider maybeUserConfig pathToConfigDst = return $ C.mkTmplFdWit relPathFromAuthConfigToServerSrcDir :: Path Posix (Rel importLocation) (Dir C.ServerSrcDir) relPathFromAuthConfigToServerSrcDir = [reldirP|../../../|] -getJsonForOAuthConfigProps :: OAuthAuthProvider -> [Aeson.Value] -getJsonForOAuthConfigProps provider = - [ object - [ "key" .= ("clientID" :: String), - "value" .= ("process.env." ++ OAuth.clientIdEnvVarName provider) - ], - object - [ "key" .= ("clientSecret" :: String), - "value" .= ("process.env." ++ OAuth.clientSecretEnvVarName provider) - ], - object - [ "key" .= ("scope" :: String), - "value" .= OAuth.scopeStr provider - ] - ] - -depsRequiredByPassport :: AppSpec -> [App.Dependency.Dependency] -depsRequiredByPassport spec = - concat - [ [App.Dependency.make ("passport", "0.6.0") | (AS.App.Auth.isExternalAuthEnabled <$> maybeAuth) == Just True], - [OAuth.passportDependency googleAuthProvider | (AS.App.Auth.isGoogleAuthEnabled <$> maybeAuth) == Just True], - [OAuth.passportDependency gitHubAuthProvider | (AS.App.Auth.isGitHubAuthEnabled <$> maybeAuth) == Just True] - ] +depsRequiredByOAuth :: AppSpec -> [App.Dependency.Dependency] +depsRequiredByOAuth spec = + [App.Dependency.make ("arctic", "^1.2.1") | (AS.App.Auth.isExternalAuthEnabled <$> maybeAuth) == Just True] where maybeAuth = AS.App.auth $ snd $ getApp spec diff --git a/waspc/src/Wasp/Generator/WebAppGenerator/AuthG.hs b/waspc/src/Wasp/Generator/WebAppGenerator/AuthG.hs index 62592fb881..916accbb42 100644 --- a/waspc/src/Wasp/Generator/WebAppGenerator/AuthG.hs +++ b/waspc/src/Wasp/Generator/WebAppGenerator/AuthG.hs @@ -9,6 +9,7 @@ import Wasp.AppSpec (AppSpec) import qualified Wasp.AppSpec.App as AS.App import qualified Wasp.AppSpec.App.Auth as AS.Auth import Wasp.AppSpec.Valid (getApp) +import Wasp.Generator.AuthProviders.OAuth (serverExchangeCodeForTokenUrl) import Wasp.Generator.FileDraft (FileDraft) import Wasp.Generator.Monad (Generator) import Wasp.Generator.WebAppGenerator.Auth.Common (getOnAuthSucceededRedirectToOrDefault) @@ -39,9 +40,10 @@ genOAuthCodeExchange :: AS.Auth.Auth -> Generator FileDraft genOAuthCodeExchange auth = return $ C.mkTmplFdWithData - [relfile|src/auth/pages/OAuthCodeExchange.jsx|] + [relfile|src/auth/pages/OAuthCallback.tsx|] ( object [ "onAuthSucceededRedirectTo" .= getOnAuthSucceededRedirectToOrDefault auth, - "onAuthFailedRedirectTo" .= AS.Auth.onAuthFailedRedirectTo auth + "onAuthFailedRedirectTo" .= AS.Auth.onAuthFailedRedirectTo auth, + "serverExchangeCodeForTokenUrl" .= serverExchangeCodeForTokenUrl ] ) diff --git a/waspc/src/Wasp/Generator/WebAppGenerator/RouterGenerator.hs b/waspc/src/Wasp/Generator/WebAppGenerator/RouterGenerator.hs index 2a06883d9c..4e8ebec6e1 100644 --- a/waspc/src/Wasp/Generator/WebAppGenerator/RouterGenerator.hs +++ b/waspc/src/Wasp/Generator/WebAppGenerator/RouterGenerator.hs @@ -21,8 +21,7 @@ import qualified Wasp.AppSpec.ExtImport as AS.ExtImport import qualified Wasp.AppSpec.Page as AS.Page import qualified Wasp.AppSpec.Route as AS.Route import Wasp.AppSpec.Valid (getApp, isAuthEnabled) -import Wasp.Generator.AuthProviders (gitHubAuthProvider, googleAuthProvider) -import Wasp.Generator.AuthProviders.OAuth (OAuthAuthProvider, frontendLoginUrl, serverOauthRedirectHandlerUrl) +import Wasp.Generator.AuthProviders.OAuth (clientOAuthCallbackPath) import Wasp.Generator.FileDraft (FileDraft) import Wasp.Generator.Monad (Generator) import Wasp.Generator.WebAppGenerator.Common (asTmplFile, asWebAppSrcFile) @@ -35,7 +34,6 @@ data RouterTemplateData = RouterTemplateData _pagesToImport :: ![PageTemplateData], _isAuthEnabled :: Bool, _isExternalAuthEnabled :: Bool, - _externalAuthProviders :: ![ExternalAuthProviderTemplateData], _rootComponent :: Aeson.Value, _baseDir :: String } @@ -47,9 +45,9 @@ instance ToJSON RouterTemplateData where "pagesToImport" .= _pagesToImport routerTD, "isAuthEnabled" .= _isAuthEnabled routerTD, "isExternalAuthEnabled" .= _isExternalAuthEnabled routerTD, - "externalAuthProviders" .= _externalAuthProviders routerTD, "rootComponent" .= _rootComponent routerTD, - "baseDir" .= _baseDir routerTD + "baseDir" .= _baseDir routerTD, + "oAuthCallbackPath" .= clientOAuthCallbackPath ] data RouteTemplateData = RouteTemplateData @@ -75,21 +73,6 @@ instance ToJSON PageTemplateData where [ "importStatement" .= _importStmt pageTD ] -data ExternalAuthProviderTemplateData = ExternalAuthProviderTemplateData - { _authFrontendUrl :: !String, - _authServerOauthRedirectUrl :: !String, - _authProviderEnabled :: Bool - } - deriving (Show, Eq) - -instance ToJSON ExternalAuthProviderTemplateData where - toJSON externalProviderTD = - object - [ "authFrontendUrl" .= _authFrontendUrl externalProviderTD, - "authServerOauthRedirectUrl" .= _authServerOauthRedirectUrl externalProviderTD, - "authProviderEnabled" .= _authProviderEnabled externalProviderTD - ] - genRouter :: AppSpec -> Generator [FileDraft] genRouter spec = sequence @@ -115,33 +98,15 @@ createRouterTemplateData spec = _pagesToImport = pages, _isAuthEnabled = isAuthEnabled spec, _isExternalAuthEnabled = (AS.App.Auth.isExternalAuthEnabled <$> maybeAuth) == Just True, - _externalAuthProviders = externalAuthProviders, _rootComponent = extImportToImportJson relPathToWebAppSrcDir maybeRootComponent, _baseDir = SP.fromAbsDirP $ C.getBaseDir spec } where routes = map (createRouteTemplateData spec) $ AS.getRoutes spec pages = map createPageTemplateData $ AS.getPages spec - externalAuthProviders = - map - (createExternalAuthProviderTemplateData maybeAuth) - [ (AS.App.Auth.isGoogleAuthEnabled, googleAuthProvider), - (AS.App.Auth.isGitHubAuthEnabled, gitHubAuthProvider) - ] maybeAuth = AS.App.auth $ snd $ getApp spec maybeRootComponent = AS.App.Client.rootComponent =<< AS.App.client (snd $ getApp spec) -createExternalAuthProviderTemplateData :: - Maybe AS.App.Auth.Auth -> - (AS.App.Auth.Auth -> Bool, OAuthAuthProvider) -> - ExternalAuthProviderTemplateData -createExternalAuthProviderTemplateData maybeAuth (method, provider) = - ExternalAuthProviderTemplateData - { _authFrontendUrl = frontendLoginUrl provider, - _authServerOauthRedirectUrl = serverOauthRedirectHandlerUrl provider, - _authProviderEnabled = (method <$> maybeAuth) == Just True - } - createRouteTemplateData :: AppSpec -> (String, AS.Route.Route) -> RouteTemplateData createRouteTemplateData spec namedRoute@(name, _) = RouteTemplateData From 0880556592fbc882d3b7252c4d72eb021e29d38d Mon Sep 17 00:00:00 2001 From: Mihovil Ilakovac Date: Mon, 18 Mar 2024 13:09:08 +0100 Subject: [PATCH 05/20] Adds Keycloak OAuth provider (#1876) --- waspc/cli/src/Wasp/Cli/Command/Studio.hs | 3 + .../forms/internal/common/LoginSignupForm.tsx | 7 + .../forms/internal/social/SocialIcons.tsx | 15 + .../templates/sdk/wasp/auth/utils.ts | 1 + .../templates/sdk/wasp/client/auth/index.ts | 3 + .../sdk/wasp/client/auth/keycloak.ts | 2 + .../src/auth/providers/config/keycloak.ts | 82 +++ .../templates/server/src/auth/utils.ts | 1 + .../waspComplexTest/.wasp/out/.waspchecksums | 6 +- .../forms/internal/common/LoginSignupForm.tsx | 1 + .../forms/internal/social/SocialIcons.tsx | 15 + .../.wasp/out/sdk/wasp/auth/utils.ts | 1 + .../forms/internal/common/LoginSignupForm.jsx | 1 + .../internal/common/LoginSignupForm.jsx.map | 2 +- .../forms/internal/social/SocialIcons.d.ts | 1 + .../forms/internal/social/SocialIcons.jsx | 5 + .../forms/internal/social/SocialIcons.jsx.map | 2 +- .../.wasp/out/sdk/wasp/dist/auth/utils.d.ts | 1 + .../.wasp/out/sdk/wasp/dist/auth/utils.js.map | 2 +- waspc/examples/todoApp/main.wasp | 1 + waspc/examples/todoApp/src/user.ts | 5 + waspc/src/Wasp/AppSpec/App/Auth.hs | 14 +- waspc/src/Wasp/Generator/AuthProviders.hs | 8 + .../Generator/SdkGenerator/Auth/AuthFormsG.hs | 9 +- .../Generator/SdkGenerator/Auth/OAuthAuthG.hs | 10 +- .../Generator/SdkGenerator/Client/AuthG.hs | 7 + .../ServerGenerator/Auth/OAuthAuthG.hs | 7 +- .../Wasp/Generator/ServerGenerator/AuthG.hs | 9 +- waspc/test/AnalyzerTest.hs | 2 +- waspc/test/AppSpec/ValidTest.hs | 9 +- web/docs/auth/Pills.css | 2 + web/docs/auth/Pills.jsx | 21 +- web/docs/auth/social-auth/SocialAuthGrid.tsx | 5 + web/docs/auth/social-auth/keycloak.md | 547 ++++++++++++++++++ web/docs/auth/ui.md | 6 +- web/sidebars.js | 1 + web/src/components/AuthMethodsGrid.tsx | 5 + web/static/img/auth/keycloak/1-keycloak.png | Bin 0 -> 57340 bytes web/static/img/auth/keycloak/2-keycloak.png | Bin 0 -> 35771 bytes web/static/img/auth/keycloak/3-keycloak.png | Bin 0 -> 41978 bytes web/static/img/auth/keycloak/4-keycloak.png | Bin 0 -> 43043 bytes web/static/img/auth/keycloak/5-keycloak.png | Bin 0 -> 36710 bytes 42 files changed, 792 insertions(+), 27 deletions(-) create mode 100644 waspc/data/Generator/templates/sdk/wasp/client/auth/keycloak.ts create mode 100644 waspc/data/Generator/templates/server/src/auth/providers/config/keycloak.ts create mode 100644 web/docs/auth/social-auth/keycloak.md create mode 100644 web/static/img/auth/keycloak/1-keycloak.png create mode 100644 web/static/img/auth/keycloak/2-keycloak.png create mode 100644 web/static/img/auth/keycloak/3-keycloak.png create mode 100644 web/static/img/auth/keycloak/4-keycloak.png create mode 100644 web/static/img/auth/keycloak/5-keycloak.png diff --git a/waspc/cli/src/Wasp/Cli/Command/Studio.hs b/waspc/cli/src/Wasp/Cli/Command/Studio.hs index f3929496bb..2e1680e3b3 100644 --- a/waspc/cli/src/Wasp/Cli/Command/Studio.hs +++ b/waspc/cli/src/Wasp/Cli/Command/Studio.hs @@ -182,6 +182,9 @@ studio = do [ "google" | isJust $ AS.App.Auth.google methods ], + [ "keycloak" + | isJust $ AS.App.Auth.keycloak methods + ], [ "gitHub" | isJust $ AS.App.Auth.gitHub methods ], diff --git a/waspc/data/Generator/templates/sdk/wasp/auth/forms/internal/common/LoginSignupForm.tsx b/waspc/data/Generator/templates/sdk/wasp/auth/forms/internal/common/LoginSignupForm.tsx index f87e2daada..ba9f336c52 100644 --- a/waspc/data/Generator/templates/sdk/wasp/auth/forms/internal/common/LoginSignupForm.tsx +++ b/waspc/data/Generator/templates/sdk/wasp/auth/forms/internal/common/LoginSignupForm.tsx @@ -108,6 +108,9 @@ const SocialAuthButtons = styled('div', { {=# isGoogleAuthEnabled =} const googleSignInUrl = `${config.apiUrl}{= googleSignInPath =}` {=/ isGoogleAuthEnabled =} +{=# isKeycloakAuthEnabled =} +const keycloakSignInUrl = `${config.apiUrl}{= keycloakSignInPath =}` +{=/ isKeycloakAuthEnabled =} {=# isGitHubAuthEnabled =} const gitHubSignInUrl = `${config.apiUrl}{= gitHubSignInPath =}` {=/ isGitHubAuthEnabled =} @@ -192,6 +195,10 @@ export const LoginSignupForm = ({ {=/ isGoogleAuthEnabled =} + {=# isKeycloakAuthEnabled =} + + {=/ isKeycloakAuthEnabled =} + {=# isGitHubAuthEnabled =} {=/ isGitHubAuthEnabled =} diff --git a/waspc/data/Generator/templates/sdk/wasp/auth/forms/internal/social/SocialIcons.tsx b/waspc/data/Generator/templates/sdk/wasp/auth/forms/internal/social/SocialIcons.tsx index 7192e457b1..5ffbb3e8ac 100644 --- a/waspc/data/Generator/templates/sdk/wasp/auth/forms/internal/social/SocialIcons.tsx +++ b/waspc/data/Generator/templates/sdk/wasp/auth/forms/internal/social/SocialIcons.tsx @@ -24,6 +24,21 @@ export const Google = () => ( ) +export const Keycloak = () => ( + +) + // PRIVATE API export const GitHub = () => ( { + const userInfoEndpoint = `${env.KEYCLOAK_REALM_URL}/protocol/openid-connect/userinfo`; + const response = await fetch( + userInfoEndpoint, + { + headers: { + Authorization: `Bearer ${accessToken}`, + }, + } + ); + const providerProfile = (await response.json()) as { + sub?: string; + }; + + if (!providerProfile.sub) { + throw new Error("Invalid profile"); + } + + return { providerProfile, providerUserId: providerProfile.sub }; + } + + return createOAuthProviderRouter({ + provider, + stateTypes: ['state', 'codeVerifier'], + userSignupFields: _waspUserSignupFields, + getAuthorizationUrl: ({ state, codeVerifier }) => keycloak.createAuthorizationURL(state, codeVerifier, config), + getProviderInfo: async ({ code, codeVerifier }) => { + const { accessToken } = await keycloak.validateAuthorizationCode(code, codeVerifier); + return getKeycloakProfile(accessToken); + }, + }); + }, +} + +export default _waspConfig; diff --git a/waspc/data/Generator/templates/server/src/auth/utils.ts b/waspc/data/Generator/templates/server/src/auth/utils.ts index 4d870a02d9..db4c7e9d8b 100644 --- a/waspc/data/Generator/templates/server/src/auth/utils.ts +++ b/waspc/data/Generator/templates/server/src/auth/utils.ts @@ -37,6 +37,7 @@ export type PossibleProviderData = { email: EmailProviderData; username: UsernameProviderData; google: OAuthProviderData; + keycloak: OAuthProviderData; github: OAuthProviderData; } diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/.waspchecksums b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/.waspchecksums index cb850389c0..1cb9733485 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/.waspchecksums +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/.waspchecksums @@ -53,7 +53,7 @@ "file", "../out/sdk/wasp/auth/forms/internal/common/LoginSignupForm.tsx" ], - "cba000c7dedb0e2f1c9730719e23215036a599bd58e7590adc5cdb176ac6b76b" + "c3299b01607b1206208e3e24a2830932607e8783a660b51e8f9168cbb067aab1" ], [ [ @@ -67,7 +67,7 @@ "file", "../out/sdk/wasp/auth/forms/internal/social/SocialIcons.tsx" ], - "bca4b3d9bc1cd57bdc83ad51be235ac5a5f220e8b63a91dcce6da296f32f51c6" + "eb12637809476e963828a91896d260f10552c7dd8d7f48f113ca0bfcee7f9ef0" ], [ [ @@ -165,7 +165,7 @@ "file", "../out/sdk/wasp/auth/utils.ts" ], - "014159c084202532b1da84bcd945f77960fe1f7acd383afc905e8fbea35b9d71" + "4001e5179622ab1c71646ad4225136a16cb9e7df9890c4bfd767c481e86c7619" ], [ [ diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/auth/forms/internal/common/LoginSignupForm.tsx b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/auth/forms/internal/common/LoginSignupForm.tsx index 72b4792854..d2d0fecbb2 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/auth/forms/internal/common/LoginSignupForm.tsx +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/auth/forms/internal/common/LoginSignupForm.tsx @@ -93,6 +93,7 @@ export const LoginSignupForm = ({ + ) diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/auth/forms/internal/social/SocialIcons.tsx b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/auth/forms/internal/social/SocialIcons.tsx index 7192e457b1..5ffbb3e8ac 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/auth/forms/internal/social/SocialIcons.tsx +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/auth/forms/internal/social/SocialIcons.tsx @@ -24,6 +24,21 @@ export const Google = () => ( ) +export const Keycloak = () => ( + +) + // PRIVATE API export const GitHub = () => ( + ); diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/auth/forms/internal/common/LoginSignupForm.jsx.map b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/auth/forms/internal/common/LoginSignupForm.jsx.map index c92ad8b4e7..b3bb264b89 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/auth/forms/internal/common/LoginSignupForm.jsx.map +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/auth/forms/internal/common/LoginSignupForm.jsx.map @@ -1 +1 @@ -{"version":3,"file":"LoginSignupForm.jsx","sourceRoot":"","sources":["../../../../../auth/forms/internal/common/LoginSignupForm.tsx"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"LoginSignupForm.jsx","sourceRoot":"","sources":["../../../../../auth/forms/internal/common/LoginSignupForm.tsx"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/auth/forms/internal/social/SocialIcons.d.ts b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/auth/forms/internal/social/SocialIcons.d.ts index 7c03773a16..2c2f2b4f07 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/auth/forms/internal/social/SocialIcons.d.ts +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/auth/forms/internal/social/SocialIcons.d.ts @@ -1,3 +1,4 @@ /// export declare const Google: () => import("react").JSX.Element; +export declare const Keycloak: () => import("react").JSX.Element; export declare const GitHub: () => import("react").JSX.Element; diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/auth/forms/internal/social/SocialIcons.jsx b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/auth/forms/internal/social/SocialIcons.jsx index df972a42bc..896d6c0666 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/auth/forms/internal/social/SocialIcons.jsx +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/auth/forms/internal/social/SocialIcons.jsx @@ -11,6 +11,11 @@ export const Google = () => (); +export const Keycloak = () => (); // PRIVATE API export const GitHub = () => (
+
+
+
{children}
+
+
+
+ ) +} +``` + + + + +```tsx title="src/pages/auth.tsx" +import { LoginForm } from 'wasp/client/auth' + +export function Login() { + return ( + + + + ) +} + +// A layout component to center the content +export function Layout({ children }: { children: React.ReactNode }) { + return ( +
+
+
+
{children}
+
+
+
+ ) +} +``` + +
+ + +:::info Auth UI +Our pages use an automatically generated Auth UI component. Read more about Auth UI components [here](../../auth/ui). +::: + +### Conclusion + +Yay, we've successfully set up Keycloak Auth! + +Running `wasp db migrate-dev` and `wasp start` should now give you a working app with authentication. +To see how to protect specific pages (i.e., hide them from non-authenticated users), read the docs on [using auth](../../auth/overview). + +## Default Behaviour + +Add `keycloak: {}` to the `auth.methods` dictionary to use it with default settings: + + + + +```wasp title=main.wasp +app myApp { + wasp: { + version: "^0.13.0" + }, + title: "My App", + auth: { + userEntity: User, + methods: { + // highlight-next-line + keycloak: {} + }, + onAuthFailedRedirectTo: "/login" + }, +} +``` + + + + +```wasp title=main.wasp +app myApp { + wasp: { + version: "^0.13.0" + }, + title: "My App", + auth: { + userEntity: User, + methods: { + // highlight-next-line + keycloak: {} + }, + onAuthFailedRedirectTo: "/login" + }, +} +``` + + + + + + +## Overrides + + + +### Data Received From Keycloak + +We are using Keycloak's API and its `/userinfo` endpoint to fetch the user's data. + +```ts title="Keycloak user data" +{ + sub: '5adba8fc-3ea6-445a-a379-13f0bb0b6969', + email_verified: true, + name: 'Test User', + preferred_username: 'test', + given_name: 'Test', + family_name: 'User', + email: 'test@example.com' +} +``` + +The fields you receive will depend on the scopes you requested. The default scope is set to `profile` only. If you want to get the user's email, you need to specify the `email` scope in the `configFn` function. + + + +For up-to-date info about the data received from Keycloak, please refer to the [Keycloak API documentation](https://www.keycloak.org/docs-api/23.0.7/javadocs/org/keycloak/representations/UserInfo.html). + + +### Using the Data Received From Keycloak + + + + + + +```wasp title="main.wasp" +app myApp { + wasp: { + version: "^0.13.0" + }, + title: "My App", + auth: { + userEntity: User, + methods: { + keycloak: { + // highlight-next-line + configFn: import { getConfig } from "@src/auth/keycloak.js", + // highlight-next-line + userSignupFields: import { userSignupFields } from "@src/auth/keycloak.js" + } + }, + onAuthFailedRedirectTo: "/login" + }, +} + +entity User {=psl + id Int @id @default(autoincrement()) + username String @unique + displayName String +psl=} + +// ... +``` + +```js title=src/auth/keycloak.js +export const userSignupFields = { + username: () => "hardcoded-username", + displayName: (data) => data.profile.name, +} + +export function getConfig() { + return { + scopes: ['profile', 'email'], + } +} +``` + + + + +```wasp title="main.wasp" +app myApp { + wasp: { + version: "^0.13.0" + }, + title: "My App", + auth: { + userEntity: User, + methods: { + keycloak: { + // highlight-next-line + configFn: import { getConfig } from "@src/auth/keycloak.js", + // highlight-next-line + userSignupFields: import { userSignupFields } from "@src/auth/keycloak.js" + } + }, + onAuthFailedRedirectTo: "/login" + }, +} + +entity User {=psl + id Int @id @default(autoincrement()) + username String @unique + displayName String +psl=} + +// ... +``` + +```ts title=src/auth/keycloak.ts +import { defineUserSignupFields } from 'wasp/server/auth' + +export const userSignupFields = defineUserSignupFields({ + username: () => "hardcoded-username", + displayName: (data: any) => data.profile.name, +}) + +export function getConfig() { + return { + scopes: ['profile', 'email'], + } +} +``` + + + + + + +## Using Auth + + + +## API Reference + + + + + + +```wasp title="main.wasp" +app myApp { + wasp: { + version: "^0.13.0" + }, + title: "My App", + auth: { + userEntity: User, + methods: { + keycloak: { + // highlight-next-line + configFn: import { getConfig } from "@src/auth/keycloak.js", + // highlight-next-line + userSignupFields: import { userSignupFields } from "@src/auth/keycloak.js" + } + }, + onAuthFailedRedirectTo: "/login" + }, +} +``` + + + + +```wasp title="main.wasp" +app myApp { + wasp: { + version: "^0.13.0" + }, + title: "My App", + auth: { + userEntity: User, + methods: { + keycloak: { + // highlight-next-line + configFn: import { getConfig } from "@src/auth/keycloak.js", + // highlight-next-line + userSignupFields: import { userSignupFields } from "@src/auth/keycloak.js" + } + }, + onAuthFailedRedirectTo: "/login" + }, +} +``` + + + + +The `keycloak` dict has the following properties: + +- #### `configFn: ExtImport` + + This function must return an object with the scopes for the OAuth provider. + + + + + ```js title=src/auth/keycloak.js + export function getConfig() { + return { + scopes: ['profile', 'email'], + } + } + ``` + + + + + ```ts title=src/auth/keycloak.ts + export function getConfig() { + return { + scopes: ['profile', 'email'], + } + } + ``` + + + + +- #### `userSignupFields: ExtImport` + + + + Read more about the `userSignupFields` function [here](../overview#1-defining-extra-fields). \ No newline at end of file diff --git a/web/docs/auth/ui.md b/web/docs/auth/ui.md index 696fd84003..68ddd91874 100644 --- a/web/docs/auth/ui.md +++ b/web/docs/auth/ui.md @@ -2,7 +2,7 @@ title: Auth UI --- -import { EmailPill, UsernameAndPasswordPill, GithubPill, GooglePill } from "./Pills"; +import { EmailPill, UsernameAndPasswordPill, GithubPill, GooglePill, KeycloakPill } from "./Pills"; To make using authentication in your app as easy as possible, Wasp generates the server-side code but also the client-side UI for you. It enables you to quickly get the login, signup, password reset and email verification flows in your app. @@ -110,7 +110,7 @@ The following components are available for you to use in your app: ### Login Form -Used with , , and authentication. +Used with , , , and authentication. ![Login form](/img/authui/login.png) @@ -165,7 +165,7 @@ It will automatically show the correct authentication providers based on your `m ### Signup Form -Used with , , and authentication. +Used with , , , and authentication. ![Signup form](/img/authui/signup.png) diff --git a/web/sidebars.js b/web/sidebars.js index f45d4c1a4f..0a4fe90c46 100644 --- a/web/sidebars.js +++ b/web/sidebars.js @@ -65,6 +65,7 @@ module.exports = { 'auth/social-auth/overview', 'auth/social-auth/github', 'auth/social-auth/google', + 'auth/social-auth/keycloak', ], }, 'auth/entities/entities', diff --git a/web/src/components/AuthMethodsGrid.tsx b/web/src/components/AuthMethodsGrid.tsx index 8cfad14eee..dca9c1ff3c 100644 --- a/web/src/components/AuthMethodsGrid.tsx +++ b/web/src/components/AuthMethodsGrid.tsx @@ -23,6 +23,11 @@ export function AuthMethodsGrid() { description: 'Users sign in with their Github account', linkToDocs: '/docs/auth/social-auth/github', }, + { + title: 'Keycloak', + description: 'Users sign in with their Keycloak account', + linkToDocs: '/docs/auth/social-auth/keycloak', + } ] return ( <> diff --git a/web/static/img/auth/keycloak/1-keycloak.png b/web/static/img/auth/keycloak/1-keycloak.png new file mode 100644 index 0000000000000000000000000000000000000000..5ec0cb97ba04c9e904bdf415585c3f2125fe3ec5 GIT binary patch literal 57340 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 literal 0 HcmV?d00001 diff --git a/web/static/img/auth/keycloak/2-keycloak.png b/web/static/img/auth/keycloak/2-keycloak.png new file mode 100644 index 0000000000000000000000000000000000000000..dde40bb6f7c265fa4a9822445e4c3936e054e360 GIT binary patch literal 35771 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 BS8M

F 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 literal 0 HcmV?d00001 diff --git a/web/static/img/auth/keycloak/5-keycloak.png b/web/static/img/auth/keycloak/5-keycloak.png new file mode 100644 index 0000000000000000000000000000000000000000..2c8f0912c1127fdef28e02db1001675bad0124fe GIT binary patch literal 36710 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 sY>rRbF|+{aB>D%Jlv)ibgrFK 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 literal 0 HcmV?d00001 From 8beec5928a8d58e1896789d1c7cbe9e6b2f5306a Mon Sep 17 00:00:00 2001 From: Mihovil Ilakovac Date: Mon, 18 Mar 2024 13:09:37 +0100 Subject: [PATCH 06/20] Adds migration docs to 0.13 (#1890) --- web/docs/auth/social-auth/github.md | 94 ++++++++++++------ web/docs/auth/social-auth/google.md | 77 +++++++++------ web/docs/auth/social-auth/overview.md | 8 +- web/docs/migrate-from-0-11-to-0-12.md | 8 ++ web/docs/migrate-from-0-12-to-0-13.md | 134 ++++++++++++++++++++++++++ web/package-lock.json | 2 +- web/package.json | 2 +- web/sidebars.js | 1 + web/src/remark/auto-import-tabs.js | 24 ++++- 9 files changed, 284 insertions(+), 66 deletions(-) create mode 100644 web/docs/migrate-from-0-12-to-0-13.md diff --git a/web/docs/auth/social-auth/github.md b/web/docs/auth/social-auth/github.md index d05f3e85be..f1359d0890 100644 --- a/web/docs/auth/social-auth/github.md +++ b/web/docs/auth/social-auth/github.md @@ -26,7 +26,7 @@ Enabling GitHub Authentication comes down to a series of steps: 1. Enabling GitHub authentication in the Wasp file. 1. Adding the `User` entity. 1. Creating a GitHub OAuth app. -1. Adding the neccessary Routes and Pages +1. Adding the necessary Routes and Pages 1. Using Auth UI components in our Pages. @@ -41,7 +41,7 @@ Let's start by properly configuring the Auth object: ```wasp title="main.wasp" app myApp { wasp: { - version: "^0.11.0" + version: "^0.13.0" }, title: "My App", auth: { @@ -66,7 +66,7 @@ app myApp { ```wasp title="main.wasp" app myApp { wasp: { - version: "^0.11.0" + version: "^0.13.0" }, title: "My App", auth: { @@ -135,8 +135,8 @@ width="400px" /> - For **Authorization callback URL**: - - For development, put: `http://localhost:3000/auth/login/github`. - - Once you know on which URL your app will be deployed, you can create a new app with that URL instead e.g. `https://someotherhost.com/auth/login/github`. + - For development, put: `http://localhost:3001/auth/github/callback`. + - Once you know on which URL your API server will be deployed, you can create a new app with that URL instead e.g. `https://your-server-url.com/auth/github/callback`. 4. Hit **Register application**. 5. Hit **Generate a new client secret** on the next page. @@ -255,7 +255,7 @@ export function Layout({ children }: { children: React.ReactNode }) { -We imported the generated Auth UI component and used them in our pages. Read more about the Auth UI components [here](../../auth/ui). +We imported the generated Auth UI components and used them in our pages. Read more about the Auth UI components [here](../../auth/ui). ### Conclusion @@ -276,7 +276,7 @@ Add `gitHub: {}` to the `auth.methods` dictionary to use it with default setting ```wasp title=main.wasp app myApp { wasp: { - version: "^0.11.0" + version: "^0.13.0" }, title: "My App", auth: { @@ -296,7 +296,7 @@ app myApp { ```wasp title=main.wasp app myApp { wasp: { - version: "^0.11.0" + version: "^0.13.0" }, title: "My App", auth: { @@ -319,7 +319,52 @@ app myApp { -### Using the User's Provider Account Details +### Data Received From GitHub + +We are using GitHub's API and its `/user` and `/user/emails` endpoints to get the user data. + +:::info We combine the data from the two endpoints + +You'll find the emails in the `emails` property in the object that you receive in `userSignupFields`. + +This is because we combine the data from the `/user` and `/user/emails` endpoints **if the `user` or `user:email` scope is requested.** + +::: + +The data we receive from GitHub on the `/user` endpoint looks something this: + +```json +{ + "login": "octocat", + "id": 1, + "name": "monalisa octocat", + "avatar_url": "https://github.com/images/error/octocat_happy.gif", + "gravatar_id": "", + // ... +} +``` + +And the data from the `/user/emails` endpoint looks something like this: + +```json +[ + { + "email": "octocat@github.com", + "verified": true, + "primary": true, + "visibility": "public" + } +] +``` + +The fields you receive will depend on the scopes you requested. By default we don't specify any scopes. If you want to get the emails, you need to specify the `user` or `user:email` scope in the `configFn` function. + + + +For an up to date info about the data received from GitHub, please refer to the [GitHub API documentation](https://docs.github.com/en/rest/users/users?apiVersion=2022-11-28#get-the-authenticated-user). + + +### Using the Data Received From GitHub @@ -329,7 +374,7 @@ app myApp { ```wasp title="main.wasp" app myApp { wasp: { - version: "^0.11.0" + version: "^0.13.0" }, title: "My App", auth: { @@ -358,14 +403,12 @@ psl=} ```js title=src/auth/github.js export const userSignupFields = { username: () => "hardcoded-username", - displayName: (data) => data.profile.displayName, + displayName: (data) => data.profile.name, }; export function getConfig() { return { - clientID // look up from env or elsewhere - clientSecret // look up from env or elsewhere - scope: [], + scopes: ['user'], }; } ``` @@ -376,7 +419,7 @@ export function getConfig() { ```wasp title="main.wasp" app myApp { wasp: { - version: "^0.11.0" + version: "^0.13.0" }, title: "My App", auth: { @@ -407,14 +450,12 @@ import { defineUserSignupFields } from 'wasp/server/auth' export const userSignupFields = defineUserSignupFields({ username: () => "hardcoded-username", - displayName: (data) => data.profile.displayName, + displayName: (data: any) => data.profile.name, }) export function getConfig() { return { - clientID, // look up from env or elsewhere - clientSecret, // look up from env or elsewhere - scope: [], + scopes: ['user'], } } ``` @@ -438,7 +479,7 @@ export function getConfig() { ```wasp title="main.wasp" app myApp { wasp: { - version: "^0.11.0" + version: "^0.13.0" }, title: "My App", auth: { @@ -462,7 +503,7 @@ app myApp { ```wasp title="main.wasp" app myApp { wasp: { - version: "^0.11.0" + version: "^0.13.0" }, title: "My App", auth: { @@ -487,7 +528,7 @@ The `gitHub` dict has the following properties: - #### `configFn: ExtImport` - This function should return an object with the Client ID, Client Secret, and scope for the OAuth provider. + This function should return an object with the scopes for the OAuth provider. @@ -495,9 +536,7 @@ The `gitHub` dict has the following properties: ```js title=src/auth/github.js export function getConfig() { return { - clientID, // look up from env or elsewhere - clientSecret, // look up from env or elsewhere - scope: [], + scopes: [], } } ``` @@ -508,9 +547,7 @@ The `gitHub` dict has the following properties: ```ts title=src/auth/github.ts export function getConfig() { return { - clientID, // look up from env or elsewhere - clientSecret, // look up from env or elsewhere - scope: [], + scopes: [], } } ``` @@ -521,4 +558,5 @@ The `gitHub` dict has the following properties: - #### `userSignupFields: ExtImport` + Read more about the `userSignupFields` function [here](../overview#1-defining-extra-fields). diff --git a/web/docs/auth/social-auth/google.md b/web/docs/auth/social-auth/google.md index 842909fb35..a9028eeb1c 100644 --- a/web/docs/auth/social-auth/google.md +++ b/web/docs/auth/social-auth/google.md @@ -26,7 +26,7 @@ Enabling Google Authentication comes down to a series of steps: 1. Enabling Google authentication in the Wasp file. 1. Adding the `User` entity. 1. Creating a Google OAuth app. -1. Adding the neccessary Routes and Pages +1. Adding the necessary Routes and Pages 1. Using Auth UI components in our Pages. @@ -41,7 +41,7 @@ Let's start by properly configuring the Auth object: ```wasp title="main.wasp" app myApp { wasp: { - version: "^0.11.0" + version: "^0.13.0" }, title: "My App", auth: { @@ -64,7 +64,7 @@ app myApp { ```wasp title="main.wasp" app myApp { wasp: { - version: "^0.11.0" + version: "^0.13.0" }, title: "My App", auth: { @@ -167,12 +167,12 @@ To use Google as an authentication method, you'll first need to create a Google ![Google Console Screenshot 12](/img/integrations-google-12.jpg) -- Under Authorized redirect URIs, put in: `http://localhost:3000/auth/login/google` +- Under Authorized redirect URIs, put in: `http://localhost:3001/auth/google/callback` ![Google Console Screenshot 13](/img/integrations-google-13.jpg) - Once you know on which URL(s) your API server will be deployed, also add those URL(s). - - For example: `https://someotherhost.com/auth/login/google` + - For example: `https://your-server-url.com/auth/google/callback` - When you save, you can click the Edit icon and your credentials will be shown. @@ -317,7 +317,7 @@ Add `google: {}` to the `auth.methods` dictionary to use it with default setting ```wasp title=main.wasp app myApp { wasp: { - version: "^0.11.0" + version: "^0.13.0" }, title: "My App", auth: { @@ -337,7 +337,7 @@ app myApp { ```wasp title=main.wasp app myApp { wasp: { - version: "^0.11.0" + version: "^0.13.0" }, title: "My App", auth: { @@ -360,7 +360,37 @@ app myApp { -### Using the User's Provider Account Details +### Data Received From Google + +We are using Google's API and its `/userinfo` endpoint to fetch the user's data. + +The data received from Google is an object which can contain the following fields: + +```json +[ + "name", + "given_name", + "family_name", + "email", + "email_verified", + "aud", + "exp", + "iat", + "iss", + "locale", + "picture", + "sub" +] +``` + +The fields you receive depend on the scopes you request. The default scope is set to `profile` only. If you want to get the user's email, you need to specify the `email` scope in the `configFn` function. + + + +For an up to date info about the data received from Google, please refer to the [Google API documentation](https://developers.google.com/identity/openid-connect/openid-connect#an-id-tokens-payload). + + +### Using the Data Received From Google @@ -370,7 +400,7 @@ app myApp { ```wasp title="main.wasp" app myApp { wasp: { - version: "^0.11.0" + version: "^0.13.0" }, title: "My App", auth: { @@ -399,14 +429,12 @@ psl=} ```js title=src/auth/google.js export const userSignupFields = { username: () => "hardcoded-username", - displayName: (data) => data.profile.displayName, + displayName: (data) => data.profile.name, } export function getConfig() { return { - clientID, // look up from env or elsewhere - clientSecret, // look up from env or elsewhere - scope: ['profile', 'email'], + scopes: ['profile', 'email'], } } ``` @@ -417,7 +445,7 @@ export function getConfig() { ```wasp title="main.wasp" app myApp { wasp: { - version: "^0.11.0" + version: "^0.13.0" }, title: "My App", auth: { @@ -448,14 +476,12 @@ import { defineUserSignupFields } from 'wasp/server/auth' export const userSignupFields = defineUserSignupFields({ username: () => "hardcoded-username", - displayName: (data) => data.profile.displayName, + displayName: (data: any) => data.profile.name, }) export function getConfig() { return { - clientID, // look up from env or elsewhere - clientSecret, // look up from env or elsewhere - scope: ['profile', 'email'], + scopes: ['profile', 'email'], } } ``` @@ -479,7 +505,7 @@ export function getConfig() { ```wasp title="main.wasp" app myApp { wasp: { - version: "^0.11.0" + version: "^0.13.0" }, title: "My App", auth: { @@ -503,7 +529,7 @@ app myApp { ```wasp title="main.wasp" app myApp { wasp: { - version: "^0.11.0" + version: "^0.13.0" }, title: "My App", auth: { @@ -528,7 +554,7 @@ The `google` dict has the following properties: - #### `configFn: ExtImport` - This function must return an object with the Client ID, the Client Secret, and the scope for the OAuth provider. + This function must return an object with the scopes for the OAuth provider. @@ -536,9 +562,7 @@ The `google` dict has the following properties: ```js title=src/auth/google.js export function getConfig() { return { - clientID, // look up from env or elsewhere - clientSecret, // look up from env or elsewhere - scope: ['profile', 'email'], + scopes: ['profile', 'email'], } } ``` @@ -549,9 +573,7 @@ The `google` dict has the following properties: ```ts title=src/auth/google.ts export function getConfig() { return { - clientID, // look up from env or elsewhere - clientSecret, // look up from env or elsewhere - scope: ['profile', 'email'], + scopes: ['profile', 'email'], } } ``` @@ -562,4 +584,5 @@ The `google` dict has the following properties: - #### `userSignupFields: ExtImport` + Read more about the `userSignupFields` function [here](../overview#1-defining-extra-fields). diff --git a/web/docs/auth/social-auth/overview.md b/web/docs/auth/social-auth/overview.md index 35d2cdb40f..c3c046e53d 100644 --- a/web/docs/auth/social-auth/overview.md +++ b/web/docs/auth/social-auth/overview.md @@ -36,7 +36,7 @@ Here's what the full setup looks like: ```wasp title=main.wasp app myApp { wasp: { - version: "^0.11.0" + version: "^0.13.0" }, title: "My App", auth: { @@ -62,7 +62,7 @@ psl=} ```wasp title=main.wasp app myApp { wasp: { - version: "^0.11.0" + version: "^0.13.0" }, title: "My App", auth: { @@ -152,7 +152,7 @@ Declare an import under `app.auth.methods.google.userSignupFields` (the example ```wasp title=main.wasp app myApp { wasp: { - version: "^0.11.0" + version: "^0.13.0" }, title: "My App", auth: { @@ -184,7 +184,7 @@ export const userSignupFields = { ```wasp title=main.wasp app myApp { wasp: { - version: "^0.11.0" + version: "^0.13.0" }, title: "My App", auth: { diff --git a/web/docs/migrate-from-0-11-to-0-12.md b/web/docs/migrate-from-0-11-to-0-12.md index 02bce5a293..f27d7a60c1 100644 --- a/web/docs/migrate-from-0-11-to-0-12.md +++ b/web/docs/migrate-from-0-11-to-0-12.md @@ -4,6 +4,14 @@ title: Migration from 0.11.X to 0.12.X import { EmailPill, UsernameAndPasswordPill, GithubPill, GooglePill } from "./auth/Pills"; +:::note The latest version of Wasp is 0.13.X + +To fully migrate from 0.11.X to the latest version of Wasp, you should first migrate to **0.12.X and then to 0.13.X**. + +Make sure to read the [migration guide from 0.12.X to 0.13.X](./migrate-from-0-12-to-0-13.md) after you finish this one. + +::: + ## What's new in Wasp 0.12.0? ### New project structure diff --git a/web/docs/migrate-from-0-12-to-0-13.md b/web/docs/migrate-from-0-12-to-0-13.md new file mode 100644 index 0000000000..fb7e5d8270 --- /dev/null +++ b/web/docs/migrate-from-0-12-to-0-13.md @@ -0,0 +1,134 @@ +--- +title: Migration from 0.12.X to 0.13.X +--- + +:::note Are you on 0.11.X or earlier? + +This guide only covers the migration from **0.12.X to 0.13.X**. If you are migrating from 0.11.X or earlier, please read the [migration guide from 0.11.X to 0.12.X](./migrate-from-0-11-to-0-12.md) first. + +::: + +## What's new in 0.13.0? + +### OAuth providers got an overhaul + +Wasp 0.13.0 switches away from using Passport for our OAuth providers in favor of [Arctic](https://arctic.js.org/) from the [Lucia](https://lucia-auth.com/) ecosystem. This change simplifies the codebase and makes it easier to add new OAuth providers in the future. + +### We added Keycloak as an OAuth provider + +Wasp now supports using [Keycloak](https://www.keycloak.org/) as an OAuth provider. + +## How to migrate? + +### Migrate your OAuth setup + +We had to make some breaking changes to upgrade the OAuth setup to the new Arctic lib. + +Follow the steps below to migrate: + +1. **Define the `WASP_SERVER_URL` server env variable** + + In 0.13.0 Wasp introduces a new server env variable `WASP_SERVER_URL` that you need to define. This is the URL of your Wasp server and it's used to generate the redirect URL for the OAuth providers. + + ```bash title="Server env variables" + WASP_SERVER_URL=https://your-wasp-server-url.com + ``` + + In development, Wasp sets the `WASP_SERVER_URL` to `http://localhost:3001` by default. + + :::info Migrating a deployed app + + If you are migrating a deployed app, you will need to define the `WASP_SERVER_URL` server env variable in your deployment environment. + + Read more about setting env variables in production [here](./project/env-vars#defining-env-vars-in-production). + ::: + +2. **Update the redirect URLs** for the OAuth providers + + The redirect URL for the OAuth providers has changed. You will need to update the redirect URL for the OAuth providers in the provider's dashboard. + + + + + ``` + {clientUrl}/auth/login/{provider} + ``` + + + + ``` + {serverUrl}/auth/{provider}/callback + ``` + + + + Check the new redirect URLs for [Google](./auth/social-auth/google.md#3-creating-a-google-oauth-app) and [GitHub](./auth/social-auth/github.md#3-creating-a-github-oauth-app) in Wasp's docs. + +3. **Update the `configFn`** for the OAuth providers + + If you didn't use the `configFn` option, you can skip this step. + + If you used the `configFn` to configure the `scope` for the OAuth providers, you will need to rename the `scope` property to `scopes`. + + Also, the object returned from `configFn` no longer needs to include the Client ID and the Client Secret. You can remove them from the object that `configFn` returns. + + + + + ```ts title="google.ts" + export function getConfig() { + return { + clientID: process.env.GOOGLE_CLIENT_ID, + clientSecret: process.env.GOOGLE_CLIENT_SECRET, + scope: ['profile', 'email'], + } + } + ``` + + + + + ```ts title="google.ts" + export function getConfig() { + return { + scopes: ['profile', 'email'], + } + } + ``` + + + +4. **Update the `userSignupFields` fields** to use the new `profile` format + + If you didn't use the `userSignupFields` option, you can skip this step. + + The data format for the `profile` that you receive from the OAuth providers has changed. You will need to update your code to reflect this change. + + + + + ```ts title="google.ts" + import { defineUserSignupFields } from 'wasp/server/auth' + + export const userSignupFields = defineUserSignupFields({ + displayName: (data: any) => data.profile.displayName, + }) + ``` + + + + ```ts title="google.ts" + import { defineUserSignupFields } from 'wasp/server/auth' + + export const userSignupFields = defineUserSignupFields({ + displayName: (data: any) => data.profile.name, + }) + ``` + + + + Wasp now directly forwards what it receives from the OAuth providers. You can check the data format for [Google](./auth/social-auth/google.md#data-received-from-google) and [GitHub](./auth/social-auth/github.md#data-received-from-github) in Wasp's docs. + +That's it! + +You should now be able to run your app with the new Wasp 0.13.0. \ No newline at end of file diff --git a/web/package-lock.json b/web/package-lock.json index 1d4d1687c9..c3110c2bc6 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -38,7 +38,7 @@ "remark-validate-links": "^12.1.1" }, "engines": { - "node": "^18.12.0" + "node": ">=18.12.0" } }, "node_modules/@algolia/autocomplete-core": { diff --git a/web/package.json b/web/package.json index c5e7e01b79..338a8846ec 100644 --- a/web/package.json +++ b/web/package.json @@ -48,7 +48,7 @@ "remark-validate-links": "^12.1.1" }, "engines": { - "node": "^18.12.0" + "node": ">=18.12.0" }, "browserslist": { "production": [ diff --git a/web/sidebars.js b/web/sidebars.js index 0a4fe90c46..795dcac20f 100644 --- a/web/sidebars.js +++ b/web/sidebars.js @@ -139,6 +139,7 @@ module.exports = { 'vision', 'contact', 'migrate-from-0-11-to-0-12', + 'migrate-from-0-12-to-0-13', ], }, ], diff --git a/web/src/remark/auto-import-tabs.js b/web/src/remark/auto-import-tabs.js index e2d9fc6901..ea1e67c15c 100644 --- a/web/src/remark/auto-import-tabs.js +++ b/web/src/remark/auto-import-tabs.js @@ -1,10 +1,24 @@ -// Copied from +// Copied from // https://github.com/redwoodjs/redwood/blob/bd903c5755925ea7174775a2fdaba371b700c910/docs/src/remark/auto-import-tabs.js +// and modified to work with nested tab usage. -const needImports = (tree) => - tree.children.some( - (child) => child.type === 'jsx' && /^ { + const checkChildren = (children) => { + for (const child of children) { + if (child.type === 'jsx' && /^ 0) { + if (checkChildren(child.children)) { + return true; + } + } + } + return false; + }; + + return checkChildren(tree.children); +}; const plugin = () => (tree, _file) => { if (needImports(tree)) { From 4c38ef8a45612c17286ec5ce525c90f8e7b64ec5 Mon Sep 17 00:00:00 2001 From: Mihovil Ilakovac Date: Mon, 18 Mar 2024 14:21:40 +0100 Subject: [PATCH 07/20] Bump version in Cabal file (#1898) --- .../e2e-test/test-outputs/waspBuild-golden/waspBuild/main.wasp | 2 +- .../test-outputs/waspCompile-golden/waspCompile/main.wasp | 2 +- .../waspComplexTest-golden/waspComplexTest/main.wasp | 2 +- waspc/e2e-test/test-outputs/waspJob-golden/waspJob/main.wasp | 2 +- .../test-outputs/waspMigrate-golden/waspMigrate/main.wasp | 2 +- waspc/e2e-test/test-outputs/waspNew-golden/waspNew/main.wasp | 2 +- waspc/waspc.cabal | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/main.wasp b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/main.wasp index 4d9679f9fd..2541d360b3 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/main.wasp +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/main.wasp @@ -1,7 +1,7 @@ app waspBuild { db: { system: PostgreSQL }, wasp: { - version: "^0.12.4" + version: "^0.13.0" }, title: "waspBuild" } diff --git a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/main.wasp b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/main.wasp index 4fcea6dc8a..f94d382ac5 100644 --- a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/main.wasp +++ b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/main.wasp @@ -1,6 +1,6 @@ app waspCompile { wasp: { - version: "^0.12.4" + version: "^0.13.0" }, title: "waspCompile" } diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/main.wasp b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/main.wasp index 2f051c2367..65a0a2532e 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/main.wasp +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/main.wasp @@ -1,7 +1,7 @@ app waspComplexTest { db: { system: PostgreSQL }, wasp: { - version: "^0.12.4" + version: "^0.13.0" }, auth: { userEntity: User, diff --git a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/main.wasp b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/main.wasp index 2cf14ace93..22c217ac79 100644 --- a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/main.wasp +++ b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/main.wasp @@ -1,7 +1,7 @@ app waspJob { db: { system: PostgreSQL }, wasp: { - version: "^0.12.4" + version: "^0.13.0" }, title: "waspJob" } diff --git a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/main.wasp b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/main.wasp index d99c64a2c3..25cd3ac6ab 100644 --- a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/main.wasp +++ b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/main.wasp @@ -1,6 +1,6 @@ app waspMigrate { wasp: { - version: "^0.12.4" + version: "^0.13.0" }, title: "waspMigrate" } diff --git a/waspc/e2e-test/test-outputs/waspNew-golden/waspNew/main.wasp b/waspc/e2e-test/test-outputs/waspNew-golden/waspNew/main.wasp index 4afdb038bd..2cd8dbc184 100644 --- a/waspc/e2e-test/test-outputs/waspNew-golden/waspNew/main.wasp +++ b/waspc/e2e-test/test-outputs/waspNew-golden/waspNew/main.wasp @@ -1,6 +1,6 @@ app waspNew { wasp: { - version: "^0.12.4" + version: "^0.13.0" }, title: "waspNew" } diff --git a/waspc/waspc.cabal b/waspc/waspc.cabal index a5f44515ef..004469c373 100644 --- a/waspc/waspc.cabal +++ b/waspc/waspc.cabal @@ -6,7 +6,7 @@ cabal-version: 2.4 -- Consider using hpack, or maybe even hpack-dhall. name: waspc -version: 0.12.4 +version: 0.13.0 description: Please see the README on GitHub at homepage: https://github.com/wasp-lang/wasp/waspc#readme bug-reports: https://github.com/wasp-lang/wasp/issues From 72ebdb8d8c55e4b9ea3681502c0d0ea1fdf52827 Mon Sep 17 00:00:00 2001 From: Mihovil Ilakovac Date: Mon, 18 Mar 2024 14:41:14 +0100 Subject: [PATCH 08/20] Fixes tests for 0.13.0 RC (#1899) --- waspc/examples/todoApp/main.wasp | 2 +- waspc/headless-test/examples/todoApp/todoApp.wasp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/waspc/examples/todoApp/main.wasp b/waspc/examples/todoApp/main.wasp index 8533e4a98e..8b76db4057 100644 --- a/waspc/examples/todoApp/main.wasp +++ b/waspc/examples/todoApp/main.wasp @@ -1,6 +1,6 @@ app todoApp { wasp: { - version: "^0.12.0" + version: "^0.13.0" }, title: "ToDo App", // head: [], diff --git a/waspc/headless-test/examples/todoApp/todoApp.wasp b/waspc/headless-test/examples/todoApp/todoApp.wasp index 05bcd410f7..efb2f6c3da 100644 --- a/waspc/headless-test/examples/todoApp/todoApp.wasp +++ b/waspc/headless-test/examples/todoApp/todoApp.wasp @@ -1,6 +1,6 @@ app todoApp { wasp: { - version: "^0.12.0" + version: "^0.13.0" }, title: "ToDo App", auth: { From ea247dc4fcf1c39688b7969377f1e899e30922c3 Mon Sep 17 00:00:00 2001 From: Mihovil Ilakovac Date: Mon, 18 Mar 2024 16:23:27 +0100 Subject: [PATCH 09/20] Fixes template issue with new OAuth impl (#1901) --- .../Generator/templates/server/src/auth/providers/index.ts | 4 ++++ waspc/src/Wasp/Generator/ServerGenerator/AuthG.hs | 6 +++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/waspc/data/Generator/templates/server/src/auth/providers/index.ts b/waspc/data/Generator/templates/server/src/auth/providers/index.ts index 0883aa2eab..36057ee769 100644 --- a/waspc/data/Generator/templates/server/src/auth/providers/index.ts +++ b/waspc/data/Generator/templates/server/src/auth/providers/index.ts @@ -1,6 +1,8 @@ {{={= =}=}} import { Router } from "express"; +{=# isExternalAuthEnabled =} import { setupOneTimeCodeRoute } from "./oauth/oneTimeCode"; +{=/ isExternalAuthEnabled =} {=# providers =} {=& importStatement =} @@ -14,9 +16,11 @@ const providers = [ const router = Router(); +{=# isExternalAuthEnabled =} // Setting up a common route for all OAuth providers to exchange // one-time code for a session. setupOneTimeCodeRoute(router); +{=/ isExternalAuthEnabled =} for (const provider of providers) { const { createRouter } = provider; diff --git a/waspc/src/Wasp/Generator/ServerGenerator/AuthG.hs b/waspc/src/Wasp/Generator/ServerGenerator/AuthG.hs index 93ec7fda32..2b1e686a72 100644 --- a/waspc/src/Wasp/Generator/ServerGenerator/AuthG.hs +++ b/waspc/src/Wasp/Generator/ServerGenerator/AuthG.hs @@ -71,7 +71,11 @@ genAuthRoutesIndex auth = return $ C.mkTmplFdWithDstAndData tmplFile dstFile (Ju genProvidersIndex :: AS.Auth.Auth -> Generator FileDraft genProvidersIndex auth = return $ C.mkTmplFdWithData [relfile|src/auth/providers/index.ts|] (Just tmplData) where - tmplData = object ["providers" .= providers] + tmplData = + object + [ "providers" .= providers, + "isExternalAuthEnabled" .= AS.Auth.isExternalAuthEnabled auth + ] providers = makeConfigImportJson From 329c324b51156cc68d7a6327c32554fe1ce742ee Mon Sep 17 00:00:00 2001 From: Mihovil Ilakovac Date: Mon, 18 Mar 2024 16:30:26 +0100 Subject: [PATCH 10/20] Updates tag for starters (#1903) --- .../src/Wasp/Cli/Command/CreateNewProject/StarterTemplates.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/waspc/cli/src/Wasp/Cli/Command/CreateNewProject/StarterTemplates.hs b/waspc/cli/src/Wasp/Cli/Command/CreateNewProject/StarterTemplates.hs index 2b78312236..dc61a878a6 100644 --- a/waspc/cli/src/Wasp/Cli/Command/CreateNewProject/StarterTemplates.hs +++ b/waspc/cli/src/Wasp/Cli/Command/CreateNewProject/StarterTemplates.hs @@ -226,7 +226,7 @@ waspGhOrgName = "wasp-lang" -- By tagging templates for each version of Wasp CLI, we ensure that each release of -- Wasp CLI uses correct version of templates, that work with it. waspVersionTemplateGitTag :: String -waspVersionTemplateGitTag = "wasp-v0.12-template" +waspVersionTemplateGitTag = "wasp-v0.13-template" findTemplateByString :: [StarterTemplate] -> String -> Maybe StarterTemplate findTemplateByString templates query = find ((== query) . show) templates From 5dbd3f0ec2334f66a23932918e0d1a07bb4e89ab Mon Sep 17 00:00:00 2001 From: Mihovil Ilakovac Date: Mon, 18 Mar 2024 17:47:32 +0100 Subject: [PATCH 11/20] Bumps Wasp version in docs and example apps (#1902) --- README.md | 2 +- examples/hackathon-submissions/main.wasp | 2 +- .../hackathon-submissions/package-lock.json | 102 -- examples/streaming/main.wasp | 2 +- examples/streaming/package-lock.json | 102 -- examples/thoughts/main.wasp | 2 +- examples/thoughts/package-lock.json | 122 +- examples/todo-typescript/main.wasp | 2 +- .../20240318142305_initial/migration.sql | 48 + .../migrations/migration_lock.toml | 3 + examples/todo-typescript/package-lock.json | 693 ++++++-- examples/tutorials/TodoApp/main.wasp | 2 +- examples/tutorials/TodoApp/package-lock.json | 102 -- examples/tutorials/TodoAppTs/main.wasp | 2 +- .../tutorials/TodoAppTs/package-lock.json | 102 -- examples/waspello/main.wasp | 2 +- examples/waspello/package-lock.json | 102 -- examples/waspleau/main.wasp | 2 +- examples/waspleau/package-lock.json | 102 -- examples/websockets-realtime-voting/main.wasp | 2 +- .../package-lock.json | 1544 ++++++++++++----- .../src/client/MainPage.tsx | 2 +- waspc/examples/crud-testing/main.wasp | 2 +- waspc/examples/pg-vector-example/main.wasp | 2 +- waspc/examples/todo-typescript/main.wasp | 2 +- web/docs/auth/email.md | 4 +- web/docs/auth/username-and-pass.md | 12 +- web/docs/data-model/crud.md | 2 +- web/docs/introduction/introduction.md | 2 +- web/docs/migrate-from-0-11-to-0-12.md | 4 +- web/docs/project/customizing-app.md | 8 +- web/docs/tutorial/02-project-structure.md | 4 +- web/docs/tutorial/03-pages.md | 4 +- web/docs/tutorial/07-auth.md | 2 +- 34 files changed, 1758 insertions(+), 1334 deletions(-) create mode 100644 examples/todo-typescript/migrations/20240318142305_initial/migration.sql create mode 100644 examples/todo-typescript/migrations/migration_lock.toml diff --git a/README.md b/README.md index 9f625258f4..f4983b7133 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ Simple Wasp config file in which you describe the high-level details of your web app todoApp { title: "ToDo App", // visible in the browser tab - wasp: { version: "^0.11.0" }, + wasp: { version: "^0.13.0" }, auth: { // full-stack auth out-of-the-box userEntity: User, methods: { email: {...} } } diff --git a/examples/hackathon-submissions/main.wasp b/examples/hackathon-submissions/main.wasp index d9c3052b3d..dd9c82219c 100644 --- a/examples/hackathon-submissions/main.wasp +++ b/examples/hackathon-submissions/main.wasp @@ -1,6 +1,6 @@ app hackathonBetaSubmissions { wasp: { - version: "^0.12.0" + version: "^0.13.0" }, db: { system: PostgreSQL diff --git a/examples/hackathon-submissions/package-lock.json b/examples/hackathon-submissions/package-lock.json index d763da3e85..440aa7a3a3 100644 --- a/examples/hackathon-submissions/package-lock.json +++ b/examples/hackathon-submissions/package-lock.json @@ -32,7 +32,6 @@ "axios": "^1.4.0", "express": "~4.18.1", "jsdom": "^21.1.1", - "jsonwebtoken": "^8.5.1", "lodash.merge": "^4.6.2", "mitt": "3.0.0", "msw": "^1.1.0", @@ -1868,11 +1867,6 @@ "ieee754": "^1.1.13" } }, - "node_modules/buffer-equal-constant-time": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", - "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==" - }, "node_modules/bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -2379,14 +2373,6 @@ "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" }, - "node_modules/ecdsa-sig-formatter": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", - "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", - "dependencies": { - "safe-buffer": "^5.0.1" - } - }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -3721,51 +3707,6 @@ "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.1.tgz", "integrity": "sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA==" }, - "node_modules/jsonwebtoken": { - "version": "8.5.1", - "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", - "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==", - "dependencies": { - "jws": "^3.2.2", - "lodash.includes": "^4.3.0", - "lodash.isboolean": "^3.0.3", - "lodash.isinteger": "^4.0.4", - "lodash.isnumber": "^3.0.3", - "lodash.isplainobject": "^4.0.6", - "lodash.isstring": "^4.0.1", - "lodash.once": "^4.0.0", - "ms": "^2.1.1", - "semver": "^5.6.0" - }, - "engines": { - "node": ">=4", - "npm": ">=1.4.28" - } - }, - "node_modules/jsonwebtoken/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - }, - "node_modules/jwa": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", - "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", - "dependencies": { - "buffer-equal-constant-time": "1.0.1", - "ecdsa-sig-formatter": "1.0.11", - "safe-buffer": "^5.0.1" - } - }, - "node_modules/jws": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", - "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", - "dependencies": { - "jwa": "^1.4.1", - "safe-buffer": "^5.0.1" - } - }, "node_modules/lilconfig": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", @@ -3799,46 +3740,11 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, - "node_modules/lodash.includes": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", - "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==" - }, - "node_modules/lodash.isboolean": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", - "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==" - }, - "node_modules/lodash.isinteger": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", - "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==" - }, - "node_modules/lodash.isnumber": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", - "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==" - }, - "node_modules/lodash.isplainobject": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==" - }, - "node_modules/lodash.isstring": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", - "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==" - }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" }, - "node_modules/lodash.once": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", - "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==" - }, "node_modules/log-symbols": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", @@ -5142,14 +5048,6 @@ "loose-envify": "^1.1.0" } }, - "node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "bin": { - "semver": "bin/semver" - } - }, "node_modules/send": { "version": "0.18.0", "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", diff --git a/examples/streaming/main.wasp b/examples/streaming/main.wasp index bd03e7e0b5..87a9770a04 100644 --- a/examples/streaming/main.wasp +++ b/examples/streaming/main.wasp @@ -1,6 +1,6 @@ app streaming { wasp: { - version: "^0.12.0" + version: "^0.13.0" }, title: "streaming" } diff --git a/examples/streaming/package-lock.json b/examples/streaming/package-lock.json index 605055a949..17fa247a86 100644 --- a/examples/streaming/package-lock.json +++ b/examples/streaming/package-lock.json @@ -30,7 +30,6 @@ "axios": "^1.4.0", "express": "~4.18.1", "jsdom": "^21.1.1", - "jsonwebtoken": "^8.5.1", "lodash.merge": "^4.6.2", "mitt": "3.0.0", "msw": "^1.1.0", @@ -1624,11 +1623,6 @@ "ieee754": "^1.1.13" } }, - "node_modules/buffer-equal-constant-time": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", - "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==" - }, "node_modules/bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -2071,14 +2065,6 @@ "node": ">=12" } }, - "node_modules/ecdsa-sig-formatter": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", - "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", - "dependencies": { - "safe-buffer": "^5.0.1" - } - }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -3304,51 +3290,6 @@ "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.1.tgz", "integrity": "sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA==" }, - "node_modules/jsonwebtoken": { - "version": "8.5.1", - "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", - "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==", - "dependencies": { - "jws": "^3.2.2", - "lodash.includes": "^4.3.0", - "lodash.isboolean": "^3.0.3", - "lodash.isinteger": "^4.0.4", - "lodash.isnumber": "^3.0.3", - "lodash.isplainobject": "^4.0.6", - "lodash.isstring": "^4.0.1", - "lodash.once": "^4.0.0", - "ms": "^2.1.1", - "semver": "^5.6.0" - }, - "engines": { - "node": ">=4", - "npm": ">=1.4.28" - } - }, - "node_modules/jsonwebtoken/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - }, - "node_modules/jwa": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", - "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", - "dependencies": { - "buffer-equal-constant-time": "1.0.1", - "ecdsa-sig-formatter": "1.0.11", - "safe-buffer": "^5.0.1" - } - }, - "node_modules/jws": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", - "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", - "dependencies": { - "jwa": "^1.4.1", - "safe-buffer": "^5.0.1" - } - }, "node_modules/local-pkg": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-0.5.0.tgz", @@ -3369,46 +3310,11 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, - "node_modules/lodash.includes": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", - "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==" - }, - "node_modules/lodash.isboolean": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", - "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==" - }, - "node_modules/lodash.isinteger": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", - "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==" - }, - "node_modules/lodash.isnumber": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", - "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==" - }, - "node_modules/lodash.isplainobject": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==" - }, - "node_modules/lodash.isstring": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", - "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==" - }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" }, - "node_modules/lodash.once": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", - "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==" - }, "node_modules/log-symbols": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", @@ -4462,14 +4368,6 @@ "loose-envify": "^1.1.0" } }, - "node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "bin": { - "semver": "bin/semver" - } - }, "node_modules/send": { "version": "0.18.0", "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", diff --git a/examples/thoughts/main.wasp b/examples/thoughts/main.wasp index bd08a36043..f18bb065e5 100644 --- a/examples/thoughts/main.wasp +++ b/examples/thoughts/main.wasp @@ -1,6 +1,6 @@ app Thoughts { wasp: { - version: "^0.12.0" + version: "^0.13.0" }, title: "Thoughts", db: { diff --git a/examples/thoughts/package-lock.json b/examples/thoughts/package-lock.json index de0bcc206c..1b0fb99ae5 100644 --- a/examples/thoughts/package-lock.json +++ b/examples/thoughts/package-lock.json @@ -29,11 +29,11 @@ "@testing-library/jest-dom": "^6.3.0", "@testing-library/react": "^14.1.2", "@types/express-serve-static-core": "^4.17.13", + "@types/react-router-dom": "^5.3.3", "@vitest/ui": "^1.2.1", "axios": "^1.4.0", "express": "~4.18.1", "jsdom": "^21.1.1", - "jsonwebtoken": "^8.5.1", "lodash.merge": "^4.6.2", "lucia": "^3.0.1", "mitt": "3.0.0", @@ -1632,6 +1632,11 @@ "@types/unist": "^2" } }, + "node_modules/@types/history": { + "version": "4.7.11", + "resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.11.tgz", + "integrity": "sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA==" + }, "node_modules/@types/js-levenshtein": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/@types/js-levenshtein/-/js-levenshtein-1.1.3.tgz", @@ -1696,6 +1701,25 @@ "@types/react": "*" } }, + "node_modules/@types/react-router": { + "version": "5.1.20", + "resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.20.tgz", + "integrity": "sha512-jGjmu/ZqS7FjSH6owMcD5qpq19+1RS9DeVRqfl1FeBMxTDQAGwlMWOcs52NDoXaNKyG3d1cYQFMs9rCrb88o9Q==", + "dependencies": { + "@types/history": "^4.7.11", + "@types/react": "*" + } + }, + "node_modules/@types/react-router-dom": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/@types/react-router-dom/-/react-router-dom-5.3.3.tgz", + "integrity": "sha512-kpqnYK4wcdm5UaWI3fLcELopqLrHgLqNsdpHauzlQktfkHL3npOSwtj1Uz9oKBAzs7lFtVkV8j83voAz2D8fhw==", + "dependencies": { + "@types/history": "^4.7.11", + "@types/react": "*", + "@types/react-router": "*" + } + }, "node_modules/@types/scheduler": { "version": "0.16.8", "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.8.tgz", @@ -2216,11 +2240,6 @@ "ieee754": "^1.1.13" } }, - "node_modules/buffer-equal-constant-time": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", - "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==" - }, "node_modules/bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -2726,14 +2745,6 @@ "url": "https://dotenvx.com" } }, - "node_modules/ecdsa-sig-formatter": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", - "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", - "dependencies": { - "safe-buffer": "^5.0.1" - } - }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -4063,46 +4074,6 @@ "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.1.tgz", "integrity": "sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA==" }, - "node_modules/jsonwebtoken": { - "version": "8.5.1", - "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", - "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==", - "dependencies": { - "jws": "^3.2.2", - "lodash.includes": "^4.3.0", - "lodash.isboolean": "^3.0.3", - "lodash.isinteger": "^4.0.4", - "lodash.isnumber": "^3.0.3", - "lodash.isplainobject": "^4.0.6", - "lodash.isstring": "^4.0.1", - "lodash.once": "^4.0.0", - "ms": "^2.1.1", - "semver": "^5.6.0" - }, - "engines": { - "node": ">=4", - "npm": ">=1.4.28" - } - }, - "node_modules/jwa": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", - "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", - "dependencies": { - "buffer-equal-constant-time": "1.0.1", - "ecdsa-sig-formatter": "1.0.11", - "safe-buffer": "^5.0.1" - } - }, - "node_modules/jws": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", - "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", - "dependencies": { - "jwa": "^1.4.1", - "safe-buffer": "^5.0.1" - } - }, "node_modules/local-pkg": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-0.5.0.tgz", @@ -4123,46 +4094,11 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, - "node_modules/lodash.includes": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", - "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==" - }, - "node_modules/lodash.isboolean": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", - "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==" - }, - "node_modules/lodash.isinteger": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", - "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==" - }, - "node_modules/lodash.isnumber": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", - "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==" - }, - "node_modules/lodash.isplainobject": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==" - }, - "node_modules/lodash.isstring": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", - "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==" - }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" }, - "node_modules/lodash.once": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", - "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==" - }, "node_modules/log-symbols": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", @@ -5905,14 +5841,6 @@ "loose-envify": "^1.1.0" } }, - "node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "bin": { - "semver": "bin/semver" - } - }, "node_modules/send": { "version": "0.18.0", "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", diff --git a/examples/todo-typescript/main.wasp b/examples/todo-typescript/main.wasp index 41e93470f7..677b00c582 100644 --- a/examples/todo-typescript/main.wasp +++ b/examples/todo-typescript/main.wasp @@ -1,6 +1,6 @@ app TodoTypescript { wasp: { - version: "^0.12.0" + version: "^0.13.0" }, title: "ToDo TypeScript", diff --git a/examples/todo-typescript/migrations/20240318142305_initial/migration.sql b/examples/todo-typescript/migrations/20240318142305_initial/migration.sql new file mode 100644 index 0000000000..919941fb15 --- /dev/null +++ b/examples/todo-typescript/migrations/20240318142305_initial/migration.sql @@ -0,0 +1,48 @@ +-- CreateTable +CREATE TABLE "User" ( + "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT +); + +-- CreateTable +CREATE TABLE "Task" ( + "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + "description" TEXT NOT NULL, + "isDone" BOOLEAN NOT NULL DEFAULT false, + "userId" INTEGER NOT NULL, + CONSTRAINT "Task_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User" ("id") ON DELETE RESTRICT ON UPDATE CASCADE +); + +-- CreateTable +CREATE TABLE "Auth" ( + "id" TEXT NOT NULL PRIMARY KEY, + "userId" INTEGER, + CONSTRAINT "Auth_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User" ("id") ON DELETE CASCADE ON UPDATE CASCADE +); + +-- CreateTable +CREATE TABLE "AuthIdentity" ( + "providerName" TEXT NOT NULL, + "providerUserId" TEXT NOT NULL, + "providerData" TEXT NOT NULL DEFAULT '{}', + "authId" TEXT NOT NULL, + + PRIMARY KEY ("providerName", "providerUserId"), + CONSTRAINT "AuthIdentity_authId_fkey" FOREIGN KEY ("authId") REFERENCES "Auth" ("id") ON DELETE CASCADE ON UPDATE CASCADE +); + +-- CreateTable +CREATE TABLE "Session" ( + "id" TEXT NOT NULL PRIMARY KEY, + "expiresAt" DATETIME NOT NULL, + "userId" TEXT NOT NULL, + CONSTRAINT "Session_userId_fkey" FOREIGN KEY ("userId") REFERENCES "Auth" ("id") ON DELETE CASCADE ON UPDATE CASCADE +); + +-- CreateIndex +CREATE UNIQUE INDEX "Auth_userId_key" ON "Auth"("userId"); + +-- CreateIndex +CREATE UNIQUE INDEX "Session_id_key" ON "Session"("id"); + +-- CreateIndex +CREATE INDEX "Session_userId_idx" ON "Session"("userId"); diff --git a/examples/todo-typescript/migrations/migration_lock.toml b/examples/todo-typescript/migrations/migration_lock.toml new file mode 100644 index 0000000000..e5e5c4705a --- /dev/null +++ b/examples/todo-typescript/migrations/migration_lock.toml @@ -0,0 +1,3 @@ +# Please do not edit this file manually +# It should be added in your version-control system (i.e. Git) +provider = "sqlite" \ No newline at end of file diff --git a/examples/todo-typescript/package-lock.json b/examples/todo-typescript/package-lock.json index f6a293f7ae..7385425352 100644 --- a/examples/todo-typescript/package-lock.json +++ b/examples/todo-typescript/package-lock.json @@ -20,34 +20,522 @@ "version": "1.0.0", "license": "ISC", "dependencies": { - "@lucia-auth/adapter-prisma": "^4.0.0-beta.9", + "@lucia-auth/adapter-prisma": "^4.0.0", "@prisma/client": "4.16.2", "@stitches/react": "^1.2.8", "@tanstack/react-query": "^4.29.0", "@testing-library/jest-dom": "^6.3.0", "@testing-library/react": "^14.1.2", "@types/express-serve-static-core": "^4.17.13", + "@types/react-router-dom": "^5.3.3", "@vitest/ui": "^1.2.1", "axios": "^1.4.0", "express": "~4.18.1", "jsdom": "^21.1.1", - "jsonwebtoken": "^8.5.1", "lodash.merge": "^4.6.2", - "lucia": "^3.0.0-beta.14", + "lucia": "^3.0.1", "mitt": "3.0.0", "msw": "^1.1.0", + "oslo": "^1.1.2", "prisma": "4.16.2", "react": "^18.2.0", "react-hook-form": "^7.45.4", "react-router-dom": "^5.3.3", - "secure-password": "^4.0.0", "superjson": "^1.12.2", + "uuid": "^9.0.0", "vitest": "^1.2.1" }, "devDependencies": { "@tsconfig/node18": "latest" } }, + ".wasp/out/sdk/wasp/node_modules/@node-rs/argon2": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@node-rs/argon2/-/argon2-1.7.0.tgz", + "integrity": "sha512-zfULc+/tmcWcxn+nHkbyY8vP3+MpEqKORbszt4UkpqZgBgDAAIYvuDN/zukfTgdmo6tmJKKVfzigZOPk4LlIog==", + "engines": { + "node": ">= 10" + }, + "optionalDependencies": { + "@node-rs/argon2-android-arm-eabi": "1.7.0", + "@node-rs/argon2-android-arm64": "1.7.0", + "@node-rs/argon2-darwin-arm64": "1.7.0", + "@node-rs/argon2-darwin-x64": "1.7.0", + "@node-rs/argon2-freebsd-x64": "1.7.0", + "@node-rs/argon2-linux-arm-gnueabihf": "1.7.0", + "@node-rs/argon2-linux-arm64-gnu": "1.7.0", + "@node-rs/argon2-linux-arm64-musl": "1.7.0", + "@node-rs/argon2-linux-x64-gnu": "1.7.0", + "@node-rs/argon2-linux-x64-musl": "1.7.0", + "@node-rs/argon2-wasm32-wasi": "1.7.0", + "@node-rs/argon2-win32-arm64-msvc": "1.7.0", + "@node-rs/argon2-win32-ia32-msvc": "1.7.0", + "@node-rs/argon2-win32-x64-msvc": "1.7.0" + } + }, + ".wasp/out/sdk/wasp/node_modules/@node-rs/argon2-android-arm-eabi": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@node-rs/argon2-android-arm-eabi/-/argon2-android-arm-eabi-1.7.0.tgz", + "integrity": "sha512-udDqkr5P9E+wYX1SZwAVPdyfYvaF4ry9Tm+R9LkfSHbzWH0uhU6zjIwNRp7m+n4gx691rk+lqqDAIP8RLKwbhg==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + ".wasp/out/sdk/wasp/node_modules/@node-rs/argon2-android-arm64": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@node-rs/argon2-android-arm64/-/argon2-android-arm64-1.7.0.tgz", + "integrity": "sha512-s9j/G30xKUx8WU50WIhF0fIl1EdhBGq0RQ06lEhZ0Gi0ap8lhqbE2Bn5h3/G2D1k0Dx+yjeVVNmt/xOQIRG38A==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + ".wasp/out/sdk/wasp/node_modules/@node-rs/argon2-darwin-arm64": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@node-rs/argon2-darwin-arm64/-/argon2-darwin-arm64-1.7.0.tgz", + "integrity": "sha512-ZIz4L6HGOB9U1kW23g+m7anGNuTZ0RuTw0vNp3o+2DWpb8u8rODq6A8tH4JRL79S+Co/Nq608m9uackN2pe0Rw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + ".wasp/out/sdk/wasp/node_modules/@node-rs/argon2-darwin-x64": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@node-rs/argon2-darwin-x64/-/argon2-darwin-x64-1.7.0.tgz", + "integrity": "sha512-5oi/pxqVhODW/pj1+3zElMTn/YukQeywPHHYDbcAW3KsojFjKySfhcJMd1DjKTc+CHQI+4lOxZzSUzK7mI14Hw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + ".wasp/out/sdk/wasp/node_modules/@node-rs/argon2-freebsd-x64": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@node-rs/argon2-freebsd-x64/-/argon2-freebsd-x64-1.7.0.tgz", + "integrity": "sha512-Ify08683hA4QVXYoIm5SUWOY5DPIT/CMB0CQT+IdxQAg/F+qp342+lUkeAtD5bvStQuCx/dFO3bnnzoe2clMhA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10" + } + }, + ".wasp/out/sdk/wasp/node_modules/@node-rs/argon2-linux-arm-gnueabihf": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@node-rs/argon2-linux-arm-gnueabihf/-/argon2-linux-arm-gnueabihf-1.7.0.tgz", + "integrity": "sha512-7DjDZ1h5AUHAtRNjD19RnQatbhL+uuxBASuuXIBu4/w6Dx8n7YPxwTP4MXfsvuRgKuMWiOb/Ub/HJ3kXVCXRkg==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + ".wasp/out/sdk/wasp/node_modules/@node-rs/argon2-linux-arm64-gnu": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@node-rs/argon2-linux-arm64-gnu/-/argon2-linux-arm64-gnu-1.7.0.tgz", + "integrity": "sha512-nJDoMP4Y3YcqGswE4DvP080w6O24RmnFEDnL0emdI8Nou17kNYBzP2546Nasx9GCyLzRcYQwZOUjrtUuQ+od2g==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + ".wasp/out/sdk/wasp/node_modules/@node-rs/argon2-linux-arm64-musl": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@node-rs/argon2-linux-arm64-musl/-/argon2-linux-arm64-musl-1.7.0.tgz", + "integrity": "sha512-BKWS8iVconhE3jrb9mj6t1J9vwUqQPpzCbUKxfTGJfc+kNL58F1SXHBoe2cDYGnHrFEHTY0YochzXoAfm4Dm/A==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + ".wasp/out/sdk/wasp/node_modules/@node-rs/argon2-linux-x64-gnu": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@node-rs/argon2-linux-x64-gnu/-/argon2-linux-x64-gnu-1.7.0.tgz", + "integrity": "sha512-EmgqZOlf4Jurk/szW1iTsVISx25bKksVC5uttJDUloTgsAgIGReCpUUO1R24pBhu9ESJa47iv8NSf3yAfGv6jQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + ".wasp/out/sdk/wasp/node_modules/@node-rs/argon2-linux-x64-musl": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@node-rs/argon2-linux-x64-musl/-/argon2-linux-x64-musl-1.7.0.tgz", + "integrity": "sha512-/o1efYCYIxjfuoRYyBTi2Iy+1iFfhqHCvvVsnjNSgO1xWiWrX0Rrt/xXW5Zsl7vS2Y+yu8PL8KFWRzZhaVxfKA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + ".wasp/out/sdk/wasp/node_modules/@node-rs/argon2-wasm32-wasi": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@node-rs/argon2-wasm32-wasi/-/argon2-wasm32-wasi-1.7.0.tgz", + "integrity": "sha512-Evmk9VcxqnuwQftfAfYEr6YZYSPLzmKUsbFIMep5nTt9PT4XYRFAERj7wNYp+rOcBenF3X4xoB+LhwcOMTNE5w==", + "cpu": [ + "wasm32" + ], + "optional": true, + "dependencies": { + "@emnapi/core": "^0.45.0", + "@emnapi/runtime": "^0.45.0", + "@tybys/wasm-util": "^0.8.1", + "memfs-browser": "^3.4.13000" + }, + "engines": { + "node": ">=14.0.0" + } + }, + ".wasp/out/sdk/wasp/node_modules/@node-rs/argon2-win32-arm64-msvc": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@node-rs/argon2-win32-arm64-msvc/-/argon2-win32-arm64-msvc-1.7.0.tgz", + "integrity": "sha512-qgsU7T004COWWpSA0tppDqDxbPLgg8FaU09krIJ7FBl71Sz8SFO40h7fDIjfbTT5w7u6mcaINMQ5bSHu75PCaA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + ".wasp/out/sdk/wasp/node_modules/@node-rs/argon2-win32-ia32-msvc": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@node-rs/argon2-win32-ia32-msvc/-/argon2-win32-ia32-msvc-1.7.0.tgz", + "integrity": "sha512-JGafwWYQ/HpZ3XSwP4adQ6W41pRvhcdXvpzIWtKvX+17+xEXAe2nmGWM6s27pVkg1iV2ZtoYLRDkOUoGqZkCcg==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + ".wasp/out/sdk/wasp/node_modules/@node-rs/argon2-win32-x64-msvc": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@node-rs/argon2-win32-x64-msvc/-/argon2-win32-x64-msvc-1.7.0.tgz", + "integrity": "sha512-9oq4ShyFakw8AG3mRls0AoCpxBFcimYx7+jvXeAf2OqKNO+mSA6eZ9z7KQeVCi0+SOEUYxMGf5UiGiDb9R6+9Q==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + ".wasp/out/sdk/wasp/node_modules/@node-rs/bcrypt": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@node-rs/bcrypt/-/bcrypt-1.9.0.tgz", + "integrity": "sha512-u2OlIxW264bFUfvbFqDz9HZKFjwe8FHFtn7T/U8mYjPZ7DWYpbUB+/dkW/QgYfMSfR0ejkyuWaBBe0coW7/7ig==", + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "optionalDependencies": { + "@node-rs/bcrypt-android-arm-eabi": "1.9.0", + "@node-rs/bcrypt-android-arm64": "1.9.0", + "@node-rs/bcrypt-darwin-arm64": "1.9.0", + "@node-rs/bcrypt-darwin-x64": "1.9.0", + "@node-rs/bcrypt-freebsd-x64": "1.9.0", + "@node-rs/bcrypt-linux-arm-gnueabihf": "1.9.0", + "@node-rs/bcrypt-linux-arm64-gnu": "1.9.0", + "@node-rs/bcrypt-linux-arm64-musl": "1.9.0", + "@node-rs/bcrypt-linux-x64-gnu": "1.9.0", + "@node-rs/bcrypt-linux-x64-musl": "1.9.0", + "@node-rs/bcrypt-wasm32-wasi": "1.9.0", + "@node-rs/bcrypt-win32-arm64-msvc": "1.9.0", + "@node-rs/bcrypt-win32-ia32-msvc": "1.9.0", + "@node-rs/bcrypt-win32-x64-msvc": "1.9.0" + } + }, + ".wasp/out/sdk/wasp/node_modules/@node-rs/bcrypt-android-arm-eabi": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-android-arm-eabi/-/bcrypt-android-arm-eabi-1.9.0.tgz", + "integrity": "sha512-nOCFISGtnodGHNiLrG0WYLWr81qQzZKYfmwHc7muUeq+KY0sQXyHOwZk9OuNQAWv/lnntmtbwkwT0QNEmOyLvA==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + ".wasp/out/sdk/wasp/node_modules/@node-rs/bcrypt-android-arm64": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-android-arm64/-/bcrypt-android-arm64-1.9.0.tgz", + "integrity": "sha512-+ZrIAtigVmjYkqZQTThHVlz0+TG6D+GDHWhVKvR2DifjtqJ0i+mb9gjo++hN+fWEQdWNGxKCiBBjwgT4EcXd6A==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + ".wasp/out/sdk/wasp/node_modules/@node-rs/bcrypt-darwin-arm64": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-darwin-arm64/-/bcrypt-darwin-arm64-1.9.0.tgz", + "integrity": "sha512-CQiS+F9Pa0XozvkXR1g7uXE9QvBOPOplDg0iCCPRYTN9PqA5qYxhwe48G3o+v2UeQceNRrbnEtWuANm7JRqIhw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + ".wasp/out/sdk/wasp/node_modules/@node-rs/bcrypt-darwin-x64": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-darwin-x64/-/bcrypt-darwin-x64-1.9.0.tgz", + "integrity": "sha512-4pTKGawYd7sNEjdJ7R/R67uwQH1VvwPZ0SSUMmeNHbxD5QlwAPXdDH11q22uzVXsvNFZ6nGQBg8No5OUGpx6Ug==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + ".wasp/out/sdk/wasp/node_modules/@node-rs/bcrypt-freebsd-x64": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-freebsd-x64/-/bcrypt-freebsd-x64-1.9.0.tgz", + "integrity": "sha512-UmWzySX4BJhT/B8xmTru6iFif3h0Rpx3TqxRLCcbgmH43r7k5/9QuhpiyzpvKGpKHJCFNm4F3rC2wghvw5FCIg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10" + } + }, + ".wasp/out/sdk/wasp/node_modules/@node-rs/bcrypt-linux-arm-gnueabihf": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-linux-arm-gnueabihf/-/bcrypt-linux-arm-gnueabihf-1.9.0.tgz", + "integrity": "sha512-8qoX4PgBND2cVwsbajoAWo3NwdfJPEXgpCsZQZURz42oMjbGyhhSYbovBCskGU3EBLoC8RA2B1jFWooeYVn5BA==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + ".wasp/out/sdk/wasp/node_modules/@node-rs/bcrypt-linux-arm64-gnu": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-linux-arm64-gnu/-/bcrypt-linux-arm64-gnu-1.9.0.tgz", + "integrity": "sha512-TuAC6kx0SbcIA4mSEWPi+OCcDjTQUMl213v5gMNlttF+D4ieIZx6pPDGTaMO6M2PDHTeCG0CBzZl0Lu+9b0c7Q==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + ".wasp/out/sdk/wasp/node_modules/@node-rs/bcrypt-linux-arm64-musl": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-linux-arm64-musl/-/bcrypt-linux-arm64-musl-1.9.0.tgz", + "integrity": "sha512-/sIvKDABOI8QOEnLD7hIj02BVaNOuCIWBKvxcJOt8+TuwJ6zmY1UI5kSv9d99WbiHjTp97wtAUbZQwauU4b9ew==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + ".wasp/out/sdk/wasp/node_modules/@node-rs/bcrypt-linux-x64-gnu": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-linux-x64-gnu/-/bcrypt-linux-x64-gnu-1.9.0.tgz", + "integrity": "sha512-DyyhDHDsLBsCKz1tZ1hLvUZSc1DK0FU0v52jK6IBQxrj24WscSU9zZe7ie/V9kdmA4Ep57BfpWX8Dsa2JxGdgQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + ".wasp/out/sdk/wasp/node_modules/@node-rs/bcrypt-linux-x64-musl": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-linux-x64-musl/-/bcrypt-linux-x64-musl-1.9.0.tgz", + "integrity": "sha512-duIiuqQ+Lew8ASSAYm6ZRqcmfBGWwsi81XLUwz86a2HR7Qv6V4yc3ZAUQovAikhjCsIqe8C11JlAZSK6+PlXYg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + ".wasp/out/sdk/wasp/node_modules/@node-rs/bcrypt-wasm32-wasi": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-wasm32-wasi/-/bcrypt-wasm32-wasi-1.9.0.tgz", + "integrity": "sha512-ylaGmn9Wjwv/D5lxtawttx3H6Uu2WTTR7lWlRHGT6Ga/MB1Vj4OjSGUW8G8zIVnKuXpGbZ92pgHlt4HUpSLctw==", + "cpu": [ + "wasm32" + ], + "optional": true, + "dependencies": { + "@emnapi/core": "^0.45.0", + "@emnapi/runtime": "^0.45.0", + "@tybys/wasm-util": "^0.8.1", + "memfs-browser": "^3.4.13000" + }, + "engines": { + "node": ">=14.0.0" + } + }, + ".wasp/out/sdk/wasp/node_modules/@node-rs/bcrypt-win32-arm64-msvc": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-win32-arm64-msvc/-/bcrypt-win32-arm64-msvc-1.9.0.tgz", + "integrity": "sha512-2h86gF7QFyEzODuDFml/Dp1MSJoZjxJ4yyT2Erf4NkwsiA5MqowUhUsorRwZhX6+2CtlGa7orbwi13AKMsYndw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + ".wasp/out/sdk/wasp/node_modules/@node-rs/bcrypt-win32-ia32-msvc": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-win32-ia32-msvc/-/bcrypt-win32-ia32-msvc-1.9.0.tgz", + "integrity": "sha512-kqxalCvhs4FkN0+gWWfa4Bdy2NQAkfiqq/CEf6mNXC13RSV673Ev9V8sRlQyNpCHCNkeXfOT9pgoBdJmMs9muA==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + ".wasp/out/sdk/wasp/node_modules/@node-rs/bcrypt-win32-x64-msvc": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-win32-x64-msvc/-/bcrypt-win32-x64-msvc-1.9.0.tgz", + "integrity": "sha512-2y0Tuo6ZAT2Cz8V7DHulSlv1Bip3zbzeXyeur+uR25IRNYXKvI/P99Zl85Fbuu/zzYAZRLLlGTRe6/9IHofe/w==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + ".wasp/out/sdk/wasp/node_modules/oslo": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/oslo/-/oslo-1.1.3.tgz", + "integrity": "sha512-hCz528UlNTiegplcyBg6AvG0HLNrnq06EJMp88Ze308GX1hszkb8u3puhNC4aqLMbYQ0hXpl+wQGnwxMtt5+5w==", + "dependencies": { + "@node-rs/argon2": "1.7.0", + "@node-rs/bcrypt": "1.9.0" + } + }, "node_modules/@adobe/css-tools": { "version": "4.3.3", "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.3.3.tgz", @@ -1602,6 +2090,11 @@ "@types/send": "*" } }, + "node_modules/@types/history": { + "version": "4.7.11", + "resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.11.tgz", + "integrity": "sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA==" + }, "node_modules/@types/js-levenshtein": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/@types/js-levenshtein/-/js-levenshtein-1.1.3.tgz", @@ -1658,6 +2151,25 @@ "@types/react": "*" } }, + "node_modules/@types/react-router": { + "version": "5.1.20", + "resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.20.tgz", + "integrity": "sha512-jGjmu/ZqS7FjSH6owMcD5qpq19+1RS9DeVRqfl1FeBMxTDQAGwlMWOcs52NDoXaNKyG3d1cYQFMs9rCrb88o9Q==", + "dependencies": { + "@types/history": "^4.7.11", + "@types/react": "*" + } + }, + "node_modules/@types/react-router-dom": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/@types/react-router-dom/-/react-router-dom-5.3.3.tgz", + "integrity": "sha512-kpqnYK4wcdm5UaWI3fLcELopqLrHgLqNsdpHauzlQktfkHL3npOSwtj1Uz9oKBAzs7lFtVkV8j83voAz2D8fhw==", + "dependencies": { + "@types/history": "^4.7.11", + "@types/react": "*", + "@types/react-router": "*" + } + }, "node_modules/@types/scheduler": { "version": "0.16.8", "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.8.tgz", @@ -2129,11 +2641,6 @@ "ieee754": "^1.1.13" } }, - "node_modules/buffer-equal-constant-time": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", - "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==" - }, "node_modules/bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -2576,14 +3083,6 @@ "node": ">=12" } }, - "node_modules/ecdsa-sig-formatter": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", - "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", - "dependencies": { - "safe-buffer": "^5.0.1" - } - }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -3013,6 +3512,12 @@ "node": ">= 0.6" } }, + "node_modules/fs-monkey": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.5.tgz", + "integrity": "sha512-8uMbBjrhzW76TYgEV27Y5E//W2f/lTFmx78P2w19FZSxarhI/798APGQyuGCwmkNxgwGRhrLfvWyLBvNtuOmew==", + "optional": true + }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -3809,51 +4314,6 @@ "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.1.tgz", "integrity": "sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA==" }, - "node_modules/jsonwebtoken": { - "version": "8.5.1", - "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", - "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==", - "dependencies": { - "jws": "^3.2.2", - "lodash.includes": "^4.3.0", - "lodash.isboolean": "^3.0.3", - "lodash.isinteger": "^4.0.4", - "lodash.isnumber": "^3.0.3", - "lodash.isplainobject": "^4.0.6", - "lodash.isstring": "^4.0.1", - "lodash.once": "^4.0.0", - "ms": "^2.1.1", - "semver": "^5.6.0" - }, - "engines": { - "node": ">=4", - "npm": ">=1.4.28" - } - }, - "node_modules/jsonwebtoken/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - }, - "node_modules/jwa": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", - "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", - "dependencies": { - "buffer-equal-constant-time": "1.0.1", - "ecdsa-sig-formatter": "1.0.11", - "safe-buffer": "^5.0.1" - } - }, - "node_modules/jws": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", - "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", - "dependencies": { - "jwa": "^1.4.1", - "safe-buffer": "^5.0.1" - } - }, "node_modules/local-pkg": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-0.5.0.tgz", @@ -3874,46 +4334,11 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, - "node_modules/lodash.includes": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", - "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==" - }, - "node_modules/lodash.isboolean": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", - "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==" - }, - "node_modules/lodash.isinteger": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", - "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==" - }, - "node_modules/lodash.isnumber": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", - "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==" - }, - "node_modules/lodash.isplainobject": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==" - }, - "node_modules/lodash.isstring": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", - "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==" - }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" }, - "node_modules/lodash.once": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", - "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==" - }, "node_modules/log-symbols": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", @@ -3998,6 +4423,27 @@ "node": ">= 0.6" } }, + "node_modules/memfs": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz", + "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==", + "optional": true, + "dependencies": { + "fs-monkey": "^1.0.4" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/memfs-browser": { + "version": "3.5.10302", + "resolved": "https://registry.npmjs.org/memfs-browser/-/memfs-browser-3.5.10302.tgz", + "integrity": "sha512-JJTc/nh3ig05O0gBBGZjTCPOyydaTxNF0uHYBrcc1gHNnO+KIHIvo0Y1FKCJsaei6FCl8C6xfQomXqu+cuzkIw==", + "optional": true, + "dependencies": { + "memfs": "3.5.3" + } + }, "node_modules/merge-descriptors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", @@ -4189,11 +4635,6 @@ "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==" }, - "node_modules/nanoassert": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/nanoassert/-/nanoassert-1.1.0.tgz", - "integrity": "sha512-C40jQ3NzfkP53NsO8kEOFd79p4b9kDXQMwgiY1z8ZwrDZgUyom0AHwGegF4Dm99L+YoYhuaB0ceerUcXmqr1rQ==" - }, "node_modules/nanoid": { "version": "3.3.7", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", @@ -4257,16 +4698,6 @@ "webidl-conversions": "^3.0.0" } }, - "node_modules/node-gyp-build": { - "version": "4.8.0", - "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.0.tgz", - "integrity": "sha512-u6fs2AEUljNho3EYTJNBfImO5QTo/J/1Etd+NVdCj7qWKUSN/bSLkZwhDv7I+w/MSC6qJ4cknepkAYykDdK8og==", - "bin": { - "node-gyp-build": "bin.js", - "node-gyp-build-optional": "optional.js", - "node-gyp-build-test": "build-test.js" - } - }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", @@ -4999,23 +5430,6 @@ "loose-envify": "^1.1.0" } }, - "node_modules/secure-password": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/secure-password/-/secure-password-4.0.0.tgz", - "integrity": "sha512-B268T/tx+hq7q85KH6gonEqK/lhrLhNtzYzqojuMtBPVFBtwiIwxqF+4yr9POsJu5cIxbJyM66eYfXZiPZUXRA==", - "dependencies": { - "nanoassert": "^1.0.0", - "sodium-native": "^3.1.1" - } - }, - "node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "bin": { - "semver": "bin/semver" - } - }, "node_modules/send": { "version": "0.18.0", "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", @@ -5156,15 +5570,6 @@ "node": ">= 10" } }, - "node_modules/sodium-native": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/sodium-native/-/sodium-native-3.4.1.tgz", - "integrity": "sha512-PaNN/roiFWzVVTL6OqjzYct38NSXewdl2wz8SRB51Br/MLIJPrbM3XexhVWkq7D3UWMysfrhKVf1v1phZq6MeQ==", - "hasInstallScript": true, - "dependencies": { - "node-gyp-build": "^4.3.0" - } - }, "node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -5524,6 +5929,18 @@ "node": ">= 0.4.0" } }, + "node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/value-equal": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/value-equal/-/value-equal-1.0.1.tgz", diff --git a/examples/tutorials/TodoApp/main.wasp b/examples/tutorials/TodoApp/main.wasp index 7a55234891..73ba54d28f 100644 --- a/examples/tutorials/TodoApp/main.wasp +++ b/examples/tutorials/TodoApp/main.wasp @@ -1,6 +1,6 @@ app TodoApp { wasp: { - version: "^0.12.0" // Pins the version of Wasp to use. + version: "^0.13.0" // Pins the version of Wasp to use. }, title: "TodoApp", // Used as the browser tab title. Note that all strings in Wasp are double quoted! auth: { diff --git a/examples/tutorials/TodoApp/package-lock.json b/examples/tutorials/TodoApp/package-lock.json index 5619077483..37fe388aee 100644 --- a/examples/tutorials/TodoApp/package-lock.json +++ b/examples/tutorials/TodoApp/package-lock.json @@ -32,7 +32,6 @@ "axios": "^1.4.0", "express": "~4.18.1", "jsdom": "^21.1.1", - "jsonwebtoken": "^8.5.1", "lodash.merge": "^4.6.2", "lucia": "^3.0.1", "mitt": "3.0.0", @@ -2238,11 +2237,6 @@ "ieee754": "^1.1.13" } }, - "node_modules/buffer-equal-constant-time": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", - "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==" - }, "node_modules/bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -2699,14 +2693,6 @@ "url": "https://dotenvx.com" } }, - "node_modules/ecdsa-sig-formatter": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", - "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", - "dependencies": { - "safe-buffer": "^5.0.1" - } - }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -3972,51 +3958,6 @@ "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.1.tgz", "integrity": "sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA==" }, - "node_modules/jsonwebtoken": { - "version": "8.5.1", - "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", - "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==", - "dependencies": { - "jws": "^3.2.2", - "lodash.includes": "^4.3.0", - "lodash.isboolean": "^3.0.3", - "lodash.isinteger": "^4.0.4", - "lodash.isnumber": "^3.0.3", - "lodash.isplainobject": "^4.0.6", - "lodash.isstring": "^4.0.1", - "lodash.once": "^4.0.0", - "ms": "^2.1.1", - "semver": "^5.6.0" - }, - "engines": { - "node": ">=4", - "npm": ">=1.4.28" - } - }, - "node_modules/jsonwebtoken/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - }, - "node_modules/jwa": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", - "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", - "dependencies": { - "buffer-equal-constant-time": "1.0.1", - "ecdsa-sig-formatter": "1.0.11", - "safe-buffer": "^5.0.1" - } - }, - "node_modules/jws": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", - "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", - "dependencies": { - "jwa": "^1.4.1", - "safe-buffer": "^5.0.1" - } - }, "node_modules/local-pkg": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-0.5.0.tgz", @@ -4037,46 +3978,11 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, - "node_modules/lodash.includes": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", - "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==" - }, - "node_modules/lodash.isboolean": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", - "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==" - }, - "node_modules/lodash.isinteger": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", - "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==" - }, - "node_modules/lodash.isnumber": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", - "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==" - }, - "node_modules/lodash.isplainobject": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==" - }, - "node_modules/lodash.isstring": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", - "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==" - }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" }, - "node_modules/lodash.once": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", - "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==" - }, "node_modules/log-symbols": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", @@ -5659,14 +5565,6 @@ "loose-envify": "^1.1.0" } }, - "node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "bin": { - "semver": "bin/semver" - } - }, "node_modules/send": { "version": "0.18.0", "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", diff --git a/examples/tutorials/TodoAppTs/main.wasp b/examples/tutorials/TodoAppTs/main.wasp index 74c3ad4886..6652417f4e 100644 --- a/examples/tutorials/TodoAppTs/main.wasp +++ b/examples/tutorials/TodoAppTs/main.wasp @@ -1,6 +1,6 @@ app TodoApp { wasp: { - version: "^0.12.0" // Pins the version of Wasp to use. + version: "^0.13.0" // Pins the version of Wasp to use. }, title: "TodoApp", // Used as the browser tab title. Note that all strings in Wasp are double quoted! auth: { diff --git a/examples/tutorials/TodoAppTs/package-lock.json b/examples/tutorials/TodoAppTs/package-lock.json index f2f57851ed..b837fc14aa 100644 --- a/examples/tutorials/TodoAppTs/package-lock.json +++ b/examples/tutorials/TodoAppTs/package-lock.json @@ -32,7 +32,6 @@ "axios": "^1.4.0", "express": "~4.18.1", "jsdom": "^21.1.1", - "jsonwebtoken": "^8.5.1", "lodash.merge": "^4.6.2", "lucia": "^3.0.1", "mitt": "3.0.0", @@ -2238,11 +2237,6 @@ "ieee754": "^1.1.13" } }, - "node_modules/buffer-equal-constant-time": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", - "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==" - }, "node_modules/bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -2699,14 +2693,6 @@ "url": "https://dotenvx.com" } }, - "node_modules/ecdsa-sig-formatter": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", - "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", - "dependencies": { - "safe-buffer": "^5.0.1" - } - }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -3972,51 +3958,6 @@ "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.1.tgz", "integrity": "sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA==" }, - "node_modules/jsonwebtoken": { - "version": "8.5.1", - "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", - "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==", - "dependencies": { - "jws": "^3.2.2", - "lodash.includes": "^4.3.0", - "lodash.isboolean": "^3.0.3", - "lodash.isinteger": "^4.0.4", - "lodash.isnumber": "^3.0.3", - "lodash.isplainobject": "^4.0.6", - "lodash.isstring": "^4.0.1", - "lodash.once": "^4.0.0", - "ms": "^2.1.1", - "semver": "^5.6.0" - }, - "engines": { - "node": ">=4", - "npm": ">=1.4.28" - } - }, - "node_modules/jsonwebtoken/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - }, - "node_modules/jwa": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", - "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", - "dependencies": { - "buffer-equal-constant-time": "1.0.1", - "ecdsa-sig-formatter": "1.0.11", - "safe-buffer": "^5.0.1" - } - }, - "node_modules/jws": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", - "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", - "dependencies": { - "jwa": "^1.4.1", - "safe-buffer": "^5.0.1" - } - }, "node_modules/local-pkg": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-0.5.0.tgz", @@ -4037,46 +3978,11 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, - "node_modules/lodash.includes": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", - "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==" - }, - "node_modules/lodash.isboolean": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", - "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==" - }, - "node_modules/lodash.isinteger": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", - "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==" - }, - "node_modules/lodash.isnumber": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", - "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==" - }, - "node_modules/lodash.isplainobject": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==" - }, - "node_modules/lodash.isstring": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", - "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==" - }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" }, - "node_modules/lodash.once": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", - "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==" - }, "node_modules/log-symbols": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", @@ -5659,14 +5565,6 @@ "loose-envify": "^1.1.0" } }, - "node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "bin": { - "semver": "bin/semver" - } - }, "node_modules/send": { "version": "0.18.0", "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", diff --git a/examples/waspello/main.wasp b/examples/waspello/main.wasp index ae1db13b79..2a2c1b45ee 100644 --- a/examples/waspello/main.wasp +++ b/examples/waspello/main.wasp @@ -1,6 +1,6 @@ app waspello { wasp: { - version: "^0.12.0" + version: "^0.13.0" }, title: "Waspello", diff --git a/examples/waspello/package-lock.json b/examples/waspello/package-lock.json index 96fafe4bc7..9c0c368837 100644 --- a/examples/waspello/package-lock.json +++ b/examples/waspello/package-lock.json @@ -37,7 +37,6 @@ "axios": "^1.4.0", "express": "~4.18.1", "jsdom": "^21.1.1", - "jsonwebtoken": "^8.5.1", "lodash.merge": "^4.6.2", "lucia": "^3.0.1", "mitt": "3.0.0", @@ -2428,11 +2427,6 @@ "ieee754": "^1.1.13" } }, - "node_modules/buffer-equal-constant-time": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", - "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==" - }, "node_modules/bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -2952,14 +2946,6 @@ "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" }, - "node_modules/ecdsa-sig-formatter": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", - "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", - "dependencies": { - "safe-buffer": "^5.0.1" - } - }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -4300,51 +4286,6 @@ "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.1.tgz", "integrity": "sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA==" }, - "node_modules/jsonwebtoken": { - "version": "8.5.1", - "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", - "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==", - "dependencies": { - "jws": "^3.2.2", - "lodash.includes": "^4.3.0", - "lodash.isboolean": "^3.0.3", - "lodash.isinteger": "^4.0.4", - "lodash.isnumber": "^3.0.3", - "lodash.isplainobject": "^4.0.6", - "lodash.isstring": "^4.0.1", - "lodash.once": "^4.0.0", - "ms": "^2.1.1", - "semver": "^5.6.0" - }, - "engines": { - "node": ">=4", - "npm": ">=1.4.28" - } - }, - "node_modules/jsonwebtoken/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - }, - "node_modules/jwa": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", - "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", - "dependencies": { - "buffer-equal-constant-time": "1.0.1", - "ecdsa-sig-formatter": "1.0.11", - "safe-buffer": "^5.0.1" - } - }, - "node_modules/jws": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", - "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", - "dependencies": { - "jwa": "^1.4.1", - "safe-buffer": "^5.0.1" - } - }, "node_modules/lilconfig": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", @@ -4378,46 +4319,11 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, - "node_modules/lodash.includes": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", - "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==" - }, - "node_modules/lodash.isboolean": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", - "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==" - }, - "node_modules/lodash.isinteger": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", - "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==" - }, - "node_modules/lodash.isnumber": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", - "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==" - }, - "node_modules/lodash.isplainobject": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==" - }, - "node_modules/lodash.isstring": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", - "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==" - }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" }, - "node_modules/lodash.once": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", - "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==" - }, "node_modules/log-symbols": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", @@ -6314,14 +6220,6 @@ "loose-envify": "^1.1.0" } }, - "node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "bin": { - "semver": "bin/semver" - } - }, "node_modules/send": { "version": "0.18.0", "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", diff --git a/examples/waspleau/main.wasp b/examples/waspleau/main.wasp index 2f0d14a226..d26caaaf03 100644 --- a/examples/waspleau/main.wasp +++ b/examples/waspleau/main.wasp @@ -1,6 +1,6 @@ app waspleau { wasp: { - version: "^0.12.0" + version: "^0.13.0" }, title: "Waspleau", diff --git a/examples/waspleau/package-lock.json b/examples/waspleau/package-lock.json index 9303c65971..8a4c78b811 100644 --- a/examples/waspleau/package-lock.json +++ b/examples/waspleau/package-lock.json @@ -31,7 +31,6 @@ "axios": "^1.4.0", "express": "~4.18.1", "jsdom": "^21.1.1", - "jsonwebtoken": "^8.5.1", "lodash.merge": "^4.6.2", "mitt": "3.0.0", "msw": "^1.1.0", @@ -1641,11 +1640,6 @@ "ieee754": "^1.1.13" } }, - "node_modules/buffer-equal-constant-time": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", - "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==" - }, "node_modules/buffer-writer": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-2.0.0.tgz", @@ -2129,14 +2123,6 @@ "node": ">=12" } }, - "node_modules/ecdsa-sig-formatter": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", - "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", - "dependencies": { - "safe-buffer": "^5.0.1" - } - }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -3376,51 +3362,6 @@ "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.1.tgz", "integrity": "sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA==" }, - "node_modules/jsonwebtoken": { - "version": "8.5.1", - "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", - "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==", - "dependencies": { - "jws": "^3.2.2", - "lodash.includes": "^4.3.0", - "lodash.isboolean": "^3.0.3", - "lodash.isinteger": "^4.0.4", - "lodash.isnumber": "^3.0.3", - "lodash.isplainobject": "^4.0.6", - "lodash.isstring": "^4.0.1", - "lodash.once": "^4.0.0", - "ms": "^2.1.1", - "semver": "^5.6.0" - }, - "engines": { - "node": ">=4", - "npm": ">=1.4.28" - } - }, - "node_modules/jsonwebtoken/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - }, - "node_modules/jwa": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", - "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", - "dependencies": { - "buffer-equal-constant-time": "1.0.1", - "ecdsa-sig-formatter": "1.0.11", - "safe-buffer": "^5.0.1" - } - }, - "node_modules/jws": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", - "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", - "dependencies": { - "jwa": "^1.4.1", - "safe-buffer": "^5.0.1" - } - }, "node_modules/local-pkg": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-0.5.0.tgz", @@ -3446,46 +3387,11 @@ "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" }, - "node_modules/lodash.includes": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", - "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==" - }, - "node_modules/lodash.isboolean": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", - "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==" - }, - "node_modules/lodash.isinteger": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", - "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==" - }, - "node_modules/lodash.isnumber": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", - "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==" - }, - "node_modules/lodash.isplainobject": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==" - }, - "node_modules/lodash.isstring": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", - "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==" - }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" }, - "node_modules/lodash.once": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", - "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==" - }, "node_modules/log-symbols": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", @@ -4710,14 +4616,6 @@ "loose-envify": "^1.1.0" } }, - "node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "bin": { - "semver": "bin/semver" - } - }, "node_modules/send": { "version": "0.18.0", "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", diff --git a/examples/websockets-realtime-voting/main.wasp b/examples/websockets-realtime-voting/main.wasp index 8f44f2b994..7e0e10b095 100644 --- a/examples/websockets-realtime-voting/main.wasp +++ b/examples/websockets-realtime-voting/main.wasp @@ -1,6 +1,6 @@ app whereDoWeEat { wasp: { - version: "^0.12.0" + version: "^0.13.0" }, title: "where-do-we-eat", client: { diff --git a/examples/websockets-realtime-voting/package-lock.json b/examples/websockets-realtime-voting/package-lock.json index 15270c7735..11ee99567c 100644 --- a/examples/websockets-realtime-voting/package-lock.json +++ b/examples/websockets-realtime-voting/package-lock.json @@ -19,35 +19,528 @@ } }, ".wasp/out/sdk/wasp": { - "version": "0.0.1", + "version": "1.0.0", + "license": "ISC", "dependencies": { - "@lucia-auth/adapter-prisma": "^4.0.0-beta.9", + "@lucia-auth/adapter-prisma": "^4.0.0", "@prisma/client": "4.16.2", "@socket.io/component-emitter": "^4.0.0", "@stitches/react": "^1.2.8", "@tanstack/react-query": "^4.29.0", "@testing-library/jest-dom": "^6.3.0", "@testing-library/react": "^14.1.2", - "@tsconfig/node18": "*", "@types/express-serve-static-core": "^4.17.13", + "@types/react-router-dom": "^5.3.3", "@vitest/ui": "^1.2.1", + "autoprefixer": "^10.4.13", "axios": "^1.4.0", "express": "~4.18.1", "jsdom": "^21.1.1", - "jsonwebtoken": "^8.5.1", "lodash.merge": "^4.6.2", - "lucia": "^3.0.0-beta.14", + "lucia": "^3.0.1", "mitt": "3.0.0", "msw": "^1.1.0", + "oslo": "^1.1.2", + "postcss": "^8.4.21", "prisma": "4.16.2", "react": "^18.2.0", "react-hook-form": "^7.45.4", "react-router-dom": "^5.3.3", - "secure-password": "^4.0.0", "socket.io": "^4.6.1", "socket.io-client": "^4.6.1", "superjson": "^1.12.2", + "tailwindcss": "^3.2.7", "vitest": "^1.2.1" + }, + "devDependencies": { + "@tsconfig/node18": "latest" + } + }, + ".wasp/out/sdk/wasp/node_modules/@node-rs/argon2": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@node-rs/argon2/-/argon2-1.7.0.tgz", + "integrity": "sha512-zfULc+/tmcWcxn+nHkbyY8vP3+MpEqKORbszt4UkpqZgBgDAAIYvuDN/zukfTgdmo6tmJKKVfzigZOPk4LlIog==", + "engines": { + "node": ">= 10" + }, + "optionalDependencies": { + "@node-rs/argon2-android-arm-eabi": "1.7.0", + "@node-rs/argon2-android-arm64": "1.7.0", + "@node-rs/argon2-darwin-arm64": "1.7.0", + "@node-rs/argon2-darwin-x64": "1.7.0", + "@node-rs/argon2-freebsd-x64": "1.7.0", + "@node-rs/argon2-linux-arm-gnueabihf": "1.7.0", + "@node-rs/argon2-linux-arm64-gnu": "1.7.0", + "@node-rs/argon2-linux-arm64-musl": "1.7.0", + "@node-rs/argon2-linux-x64-gnu": "1.7.0", + "@node-rs/argon2-linux-x64-musl": "1.7.0", + "@node-rs/argon2-wasm32-wasi": "1.7.0", + "@node-rs/argon2-win32-arm64-msvc": "1.7.0", + "@node-rs/argon2-win32-ia32-msvc": "1.7.0", + "@node-rs/argon2-win32-x64-msvc": "1.7.0" + } + }, + ".wasp/out/sdk/wasp/node_modules/@node-rs/argon2-android-arm-eabi": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@node-rs/argon2-android-arm-eabi/-/argon2-android-arm-eabi-1.7.0.tgz", + "integrity": "sha512-udDqkr5P9E+wYX1SZwAVPdyfYvaF4ry9Tm+R9LkfSHbzWH0uhU6zjIwNRp7m+n4gx691rk+lqqDAIP8RLKwbhg==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + ".wasp/out/sdk/wasp/node_modules/@node-rs/argon2-android-arm64": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@node-rs/argon2-android-arm64/-/argon2-android-arm64-1.7.0.tgz", + "integrity": "sha512-s9j/G30xKUx8WU50WIhF0fIl1EdhBGq0RQ06lEhZ0Gi0ap8lhqbE2Bn5h3/G2D1k0Dx+yjeVVNmt/xOQIRG38A==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + ".wasp/out/sdk/wasp/node_modules/@node-rs/argon2-darwin-arm64": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@node-rs/argon2-darwin-arm64/-/argon2-darwin-arm64-1.7.0.tgz", + "integrity": "sha512-ZIz4L6HGOB9U1kW23g+m7anGNuTZ0RuTw0vNp3o+2DWpb8u8rODq6A8tH4JRL79S+Co/Nq608m9uackN2pe0Rw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + ".wasp/out/sdk/wasp/node_modules/@node-rs/argon2-darwin-x64": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@node-rs/argon2-darwin-x64/-/argon2-darwin-x64-1.7.0.tgz", + "integrity": "sha512-5oi/pxqVhODW/pj1+3zElMTn/YukQeywPHHYDbcAW3KsojFjKySfhcJMd1DjKTc+CHQI+4lOxZzSUzK7mI14Hw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + ".wasp/out/sdk/wasp/node_modules/@node-rs/argon2-freebsd-x64": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@node-rs/argon2-freebsd-x64/-/argon2-freebsd-x64-1.7.0.tgz", + "integrity": "sha512-Ify08683hA4QVXYoIm5SUWOY5DPIT/CMB0CQT+IdxQAg/F+qp342+lUkeAtD5bvStQuCx/dFO3bnnzoe2clMhA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10" + } + }, + ".wasp/out/sdk/wasp/node_modules/@node-rs/argon2-linux-arm-gnueabihf": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@node-rs/argon2-linux-arm-gnueabihf/-/argon2-linux-arm-gnueabihf-1.7.0.tgz", + "integrity": "sha512-7DjDZ1h5AUHAtRNjD19RnQatbhL+uuxBASuuXIBu4/w6Dx8n7YPxwTP4MXfsvuRgKuMWiOb/Ub/HJ3kXVCXRkg==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + ".wasp/out/sdk/wasp/node_modules/@node-rs/argon2-linux-arm64-gnu": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@node-rs/argon2-linux-arm64-gnu/-/argon2-linux-arm64-gnu-1.7.0.tgz", + "integrity": "sha512-nJDoMP4Y3YcqGswE4DvP080w6O24RmnFEDnL0emdI8Nou17kNYBzP2546Nasx9GCyLzRcYQwZOUjrtUuQ+od2g==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + ".wasp/out/sdk/wasp/node_modules/@node-rs/argon2-linux-arm64-musl": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@node-rs/argon2-linux-arm64-musl/-/argon2-linux-arm64-musl-1.7.0.tgz", + "integrity": "sha512-BKWS8iVconhE3jrb9mj6t1J9vwUqQPpzCbUKxfTGJfc+kNL58F1SXHBoe2cDYGnHrFEHTY0YochzXoAfm4Dm/A==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + ".wasp/out/sdk/wasp/node_modules/@node-rs/argon2-linux-x64-gnu": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@node-rs/argon2-linux-x64-gnu/-/argon2-linux-x64-gnu-1.7.0.tgz", + "integrity": "sha512-EmgqZOlf4Jurk/szW1iTsVISx25bKksVC5uttJDUloTgsAgIGReCpUUO1R24pBhu9ESJa47iv8NSf3yAfGv6jQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + ".wasp/out/sdk/wasp/node_modules/@node-rs/argon2-linux-x64-musl": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@node-rs/argon2-linux-x64-musl/-/argon2-linux-x64-musl-1.7.0.tgz", + "integrity": "sha512-/o1efYCYIxjfuoRYyBTi2Iy+1iFfhqHCvvVsnjNSgO1xWiWrX0Rrt/xXW5Zsl7vS2Y+yu8PL8KFWRzZhaVxfKA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + ".wasp/out/sdk/wasp/node_modules/@node-rs/argon2-wasm32-wasi": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@node-rs/argon2-wasm32-wasi/-/argon2-wasm32-wasi-1.7.0.tgz", + "integrity": "sha512-Evmk9VcxqnuwQftfAfYEr6YZYSPLzmKUsbFIMep5nTt9PT4XYRFAERj7wNYp+rOcBenF3X4xoB+LhwcOMTNE5w==", + "cpu": [ + "wasm32" + ], + "optional": true, + "dependencies": { + "@emnapi/core": "^0.45.0", + "@emnapi/runtime": "^0.45.0", + "@tybys/wasm-util": "^0.8.1", + "memfs-browser": "^3.4.13000" + }, + "engines": { + "node": ">=14.0.0" + } + }, + ".wasp/out/sdk/wasp/node_modules/@node-rs/argon2-win32-arm64-msvc": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@node-rs/argon2-win32-arm64-msvc/-/argon2-win32-arm64-msvc-1.7.0.tgz", + "integrity": "sha512-qgsU7T004COWWpSA0tppDqDxbPLgg8FaU09krIJ7FBl71Sz8SFO40h7fDIjfbTT5w7u6mcaINMQ5bSHu75PCaA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + ".wasp/out/sdk/wasp/node_modules/@node-rs/argon2-win32-ia32-msvc": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@node-rs/argon2-win32-ia32-msvc/-/argon2-win32-ia32-msvc-1.7.0.tgz", + "integrity": "sha512-JGafwWYQ/HpZ3XSwP4adQ6W41pRvhcdXvpzIWtKvX+17+xEXAe2nmGWM6s27pVkg1iV2ZtoYLRDkOUoGqZkCcg==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + ".wasp/out/sdk/wasp/node_modules/@node-rs/argon2-win32-x64-msvc": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@node-rs/argon2-win32-x64-msvc/-/argon2-win32-x64-msvc-1.7.0.tgz", + "integrity": "sha512-9oq4ShyFakw8AG3mRls0AoCpxBFcimYx7+jvXeAf2OqKNO+mSA6eZ9z7KQeVCi0+SOEUYxMGf5UiGiDb9R6+9Q==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + ".wasp/out/sdk/wasp/node_modules/@node-rs/bcrypt": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@node-rs/bcrypt/-/bcrypt-1.9.0.tgz", + "integrity": "sha512-u2OlIxW264bFUfvbFqDz9HZKFjwe8FHFtn7T/U8mYjPZ7DWYpbUB+/dkW/QgYfMSfR0ejkyuWaBBe0coW7/7ig==", + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "optionalDependencies": { + "@node-rs/bcrypt-android-arm-eabi": "1.9.0", + "@node-rs/bcrypt-android-arm64": "1.9.0", + "@node-rs/bcrypt-darwin-arm64": "1.9.0", + "@node-rs/bcrypt-darwin-x64": "1.9.0", + "@node-rs/bcrypt-freebsd-x64": "1.9.0", + "@node-rs/bcrypt-linux-arm-gnueabihf": "1.9.0", + "@node-rs/bcrypt-linux-arm64-gnu": "1.9.0", + "@node-rs/bcrypt-linux-arm64-musl": "1.9.0", + "@node-rs/bcrypt-linux-x64-gnu": "1.9.0", + "@node-rs/bcrypt-linux-x64-musl": "1.9.0", + "@node-rs/bcrypt-wasm32-wasi": "1.9.0", + "@node-rs/bcrypt-win32-arm64-msvc": "1.9.0", + "@node-rs/bcrypt-win32-ia32-msvc": "1.9.0", + "@node-rs/bcrypt-win32-x64-msvc": "1.9.0" + } + }, + ".wasp/out/sdk/wasp/node_modules/@node-rs/bcrypt-android-arm-eabi": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-android-arm-eabi/-/bcrypt-android-arm-eabi-1.9.0.tgz", + "integrity": "sha512-nOCFISGtnodGHNiLrG0WYLWr81qQzZKYfmwHc7muUeq+KY0sQXyHOwZk9OuNQAWv/lnntmtbwkwT0QNEmOyLvA==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + ".wasp/out/sdk/wasp/node_modules/@node-rs/bcrypt-android-arm64": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-android-arm64/-/bcrypt-android-arm64-1.9.0.tgz", + "integrity": "sha512-+ZrIAtigVmjYkqZQTThHVlz0+TG6D+GDHWhVKvR2DifjtqJ0i+mb9gjo++hN+fWEQdWNGxKCiBBjwgT4EcXd6A==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + ".wasp/out/sdk/wasp/node_modules/@node-rs/bcrypt-darwin-arm64": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-darwin-arm64/-/bcrypt-darwin-arm64-1.9.0.tgz", + "integrity": "sha512-CQiS+F9Pa0XozvkXR1g7uXE9QvBOPOplDg0iCCPRYTN9PqA5qYxhwe48G3o+v2UeQceNRrbnEtWuANm7JRqIhw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + ".wasp/out/sdk/wasp/node_modules/@node-rs/bcrypt-darwin-x64": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-darwin-x64/-/bcrypt-darwin-x64-1.9.0.tgz", + "integrity": "sha512-4pTKGawYd7sNEjdJ7R/R67uwQH1VvwPZ0SSUMmeNHbxD5QlwAPXdDH11q22uzVXsvNFZ6nGQBg8No5OUGpx6Ug==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + ".wasp/out/sdk/wasp/node_modules/@node-rs/bcrypt-freebsd-x64": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-freebsd-x64/-/bcrypt-freebsd-x64-1.9.0.tgz", + "integrity": "sha512-UmWzySX4BJhT/B8xmTru6iFif3h0Rpx3TqxRLCcbgmH43r7k5/9QuhpiyzpvKGpKHJCFNm4F3rC2wghvw5FCIg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10" + } + }, + ".wasp/out/sdk/wasp/node_modules/@node-rs/bcrypt-linux-arm-gnueabihf": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-linux-arm-gnueabihf/-/bcrypt-linux-arm-gnueabihf-1.9.0.tgz", + "integrity": "sha512-8qoX4PgBND2cVwsbajoAWo3NwdfJPEXgpCsZQZURz42oMjbGyhhSYbovBCskGU3EBLoC8RA2B1jFWooeYVn5BA==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + ".wasp/out/sdk/wasp/node_modules/@node-rs/bcrypt-linux-arm64-gnu": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-linux-arm64-gnu/-/bcrypt-linux-arm64-gnu-1.9.0.tgz", + "integrity": "sha512-TuAC6kx0SbcIA4mSEWPi+OCcDjTQUMl213v5gMNlttF+D4ieIZx6pPDGTaMO6M2PDHTeCG0CBzZl0Lu+9b0c7Q==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + ".wasp/out/sdk/wasp/node_modules/@node-rs/bcrypt-linux-arm64-musl": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-linux-arm64-musl/-/bcrypt-linux-arm64-musl-1.9.0.tgz", + "integrity": "sha512-/sIvKDABOI8QOEnLD7hIj02BVaNOuCIWBKvxcJOt8+TuwJ6zmY1UI5kSv9d99WbiHjTp97wtAUbZQwauU4b9ew==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + ".wasp/out/sdk/wasp/node_modules/@node-rs/bcrypt-linux-x64-gnu": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-linux-x64-gnu/-/bcrypt-linux-x64-gnu-1.9.0.tgz", + "integrity": "sha512-DyyhDHDsLBsCKz1tZ1hLvUZSc1DK0FU0v52jK6IBQxrj24WscSU9zZe7ie/V9kdmA4Ep57BfpWX8Dsa2JxGdgQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + ".wasp/out/sdk/wasp/node_modules/@node-rs/bcrypt-linux-x64-musl": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-linux-x64-musl/-/bcrypt-linux-x64-musl-1.9.0.tgz", + "integrity": "sha512-duIiuqQ+Lew8ASSAYm6ZRqcmfBGWwsi81XLUwz86a2HR7Qv6V4yc3ZAUQovAikhjCsIqe8C11JlAZSK6+PlXYg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + ".wasp/out/sdk/wasp/node_modules/@node-rs/bcrypt-wasm32-wasi": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-wasm32-wasi/-/bcrypt-wasm32-wasi-1.9.0.tgz", + "integrity": "sha512-ylaGmn9Wjwv/D5lxtawttx3H6Uu2WTTR7lWlRHGT6Ga/MB1Vj4OjSGUW8G8zIVnKuXpGbZ92pgHlt4HUpSLctw==", + "cpu": [ + "wasm32" + ], + "optional": true, + "dependencies": { + "@emnapi/core": "^0.45.0", + "@emnapi/runtime": "^0.45.0", + "@tybys/wasm-util": "^0.8.1", + "memfs-browser": "^3.4.13000" + }, + "engines": { + "node": ">=14.0.0" + } + }, + ".wasp/out/sdk/wasp/node_modules/@node-rs/bcrypt-win32-arm64-msvc": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-win32-arm64-msvc/-/bcrypt-win32-arm64-msvc-1.9.0.tgz", + "integrity": "sha512-2h86gF7QFyEzODuDFml/Dp1MSJoZjxJ4yyT2Erf4NkwsiA5MqowUhUsorRwZhX6+2CtlGa7orbwi13AKMsYndw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + ".wasp/out/sdk/wasp/node_modules/@node-rs/bcrypt-win32-ia32-msvc": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-win32-ia32-msvc/-/bcrypt-win32-ia32-msvc-1.9.0.tgz", + "integrity": "sha512-kqxalCvhs4FkN0+gWWfa4Bdy2NQAkfiqq/CEf6mNXC13RSV673Ev9V8sRlQyNpCHCNkeXfOT9pgoBdJmMs9muA==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + ".wasp/out/sdk/wasp/node_modules/@node-rs/bcrypt-win32-x64-msvc": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-win32-x64-msvc/-/bcrypt-win32-x64-msvc-1.9.0.tgz", + "integrity": "sha512-2y0Tuo6ZAT2Cz8V7DHulSlv1Bip3zbzeXyeur+uR25IRNYXKvI/P99Zl85Fbuu/zzYAZRLLlGTRe6/9IHofe/w==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + ".wasp/out/sdk/wasp/node_modules/oslo": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/oslo/-/oslo-1.1.3.tgz", + "integrity": "sha512-hCz528UlNTiegplcyBg6AvG0HLNrnq06EJMp88Ze308GX1hszkb8u3puhNC4aqLMbYQ0hXpl+wQGnwxMtt5+5w==", + "dependencies": { + "@node-rs/argon2": "1.7.0", + "@node-rs/bcrypt": "1.9.0" } }, "node_modules/@adobe/css-tools": { @@ -59,7 +552,6 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", - "peer": true, "engines": { "node": ">=10" }, @@ -660,7 +1152,6 @@ "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", - "peer": true, "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", @@ -688,7 +1179,6 @@ "version": "0.3.3", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", - "peer": true, "dependencies": { "@jridgewell/set-array": "^1.0.1", "@jridgewell/sourcemap-codec": "^1.4.10", @@ -702,7 +1192,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "peer": true, "engines": { "node": ">=6.0.0" } @@ -711,7 +1200,6 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", - "peer": true, "engines": { "node": ">=6.0.0" } @@ -725,7 +1213,6 @@ "version": "0.3.22", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.22.tgz", "integrity": "sha512-Wf963MzWtA2sjrNt+g18IAln9lKnlRp+K2eH4jjIoF1wYeq3aMREpG09xhlhdzS0EjwU7qmUJYangWa+151vZw==", - "peer": true, "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" @@ -1324,7 +1811,6 @@ "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", "optional": true, - "peer": true, "engines": { "node": ">=14" } @@ -1715,7 +2201,8 @@ "node_modules/@tsconfig/node18": { "version": "18.2.2", "resolved": "https://registry.npmjs.org/@tsconfig/node18/-/node18-18.2.2.tgz", - "integrity": "sha512-d6McJeGsuoRlwWZmVIeE8CUA27lu6jLjvv1JzqmpsytOYYbVi1tHZEnwCNVOXnj4pyLvneZlFlpXUK+X9wBWyw==" + "integrity": "sha512-d6McJeGsuoRlwWZmVIeE8CUA27lu6jLjvv1JzqmpsytOYYbVi1tHZEnwCNVOXnj4pyLvneZlFlpXUK+X9wBWyw==", + "dev": true }, "node_modules/@tybys/wasm-util": { "version": "0.8.1", @@ -1768,6 +2255,11 @@ "@types/send": "*" } }, + "node_modules/@types/history": { + "version": "4.7.11", + "resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.11.tgz", + "integrity": "sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA==" + }, "node_modules/@types/js-levenshtein": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/@types/js-levenshtein/-/js-levenshtein-1.1.3.tgz", @@ -1824,6 +2316,25 @@ "@types/react": "*" } }, + "node_modules/@types/react-router": { + "version": "5.1.20", + "resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.20.tgz", + "integrity": "sha512-jGjmu/ZqS7FjSH6owMcD5qpq19+1RS9DeVRqfl1FeBMxTDQAGwlMWOcs52NDoXaNKyG3d1cYQFMs9rCrb88o9Q==", + "dependencies": { + "@types/history": "^4.7.11", + "@types/react": "*" + } + }, + "node_modules/@types/react-router-dom": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/@types/react-router-dom/-/react-router-dom-5.3.3.tgz", + "integrity": "sha512-kpqnYK4wcdm5UaWI3fLcELopqLrHgLqNsdpHauzlQktfkHL3npOSwtj1Uz9oKBAzs7lFtVkV8j83voAz2D8fhw==", + "dependencies": { + "@types/history": "^4.7.11", + "@types/react": "*", + "@types/react-router": "*" + } + }, "node_modules/@types/scheduler": { "version": "0.16.8", "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.8.tgz", @@ -2109,7 +2620,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", - "peer": true, "engines": { "node": ">=12" }, @@ -2121,7 +2631,6 @@ "version": "6.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", - "peer": true, "engines": { "node": ">=12" }, @@ -2132,8 +2641,7 @@ "node_modules/any-promise": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", - "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", - "peer": true + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==" }, "node_modules/anymatch": { "version": "3.1.3", @@ -2150,8 +2658,7 @@ "node_modules/arg": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", - "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", - "peer": true + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==" }, "node_modules/aria-hidden": { "version": "1.2.3", @@ -2205,6 +2712,42 @@ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" }, + "node_modules/autoprefixer": { + "version": "10.4.18", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.18.tgz", + "integrity": "sha512-1DKbDfsr6KUElM6wg+0zRNkB/Q7WcKYAaK+pzXn+Xqmszm/5Xa9coeNdtP88Vi+dPzZnMjhge8GIV49ZQkDa+g==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "browserslist": "^4.23.0", + "caniuse-lite": "^1.0.30001591", + "fraction.js": "^4.3.7", + "normalize-range": "^0.1.2", + "picocolors": "^1.0.0", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, "node_modules/available-typed-arrays": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.6.tgz", @@ -2229,8 +2772,7 @@ "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "peer": true + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, "node_modules/base64-js": { "version": "1.5.1", @@ -2304,7 +2846,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "peer": true, "dependencies": { "balanced-match": "^1.0.0" } @@ -2320,6 +2861,37 @@ "node": ">=8" } }, + "node_modules/browserslist": { + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz", + "integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001587", + "electron-to-chromium": "^1.4.668", + "node-releases": "^2.0.14", + "update-browserslist-db": "^1.0.13" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, "node_modules/buffer": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", @@ -2343,11 +2915,6 @@ "ieee754": "^1.1.13" } }, - "node_modules/buffer-equal-constant-time": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", - "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==" - }, "node_modules/bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -2386,11 +2953,29 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", - "peer": true, "engines": { "node": ">= 6" } }, + "node_modules/caniuse-lite": { + "version": "1.0.30001599", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001599.tgz", + "integrity": "sha512-LRAQHZ4yT1+f9LemSMeqdMpMxZcc4RMWdj4tiFe3G8tNkWK+E58g+/tzotb5cU6TbcVJLr4fySiAW7XmxQvZQA==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, "node_modules/chai": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/chai/-/chai-4.4.1.tgz", @@ -2638,7 +3223,6 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", - "peer": true, "engines": { "node": ">= 6" } @@ -2723,7 +3307,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", - "peer": true, "bin": { "cssesc": "bin/cssesc" }, @@ -2899,8 +3482,7 @@ "node_modules/didyoumean": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", - "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", - "peer": true + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==" }, "node_modules/diff-sequences": { "version": "29.6.3", @@ -2913,8 +3495,7 @@ "node_modules/dlv": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", - "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", - "peer": true + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==" }, "node_modules/dom-accessibility-api": { "version": "0.6.3", @@ -2936,32 +3517,27 @@ "node_modules/eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "peer": true + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" }, "node_modules/easy-bem": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/easy-bem/-/easy-bem-1.1.1.tgz", "integrity": "sha512-GJRqdiy2h+EXy6a8E6R+ubmqUM08BK0FWNq41k24fup6045biQ8NXxoXimiwegMQvFFV3t1emADdGNL1TlS61A==" }, - "node_modules/ecdsa-sig-formatter": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", - "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", - "dependencies": { - "safe-buffer": "^5.0.1" - } - }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, + "node_modules/electron-to-chromium": { + "version": "1.4.708", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.708.tgz", + "integrity": "sha512-iWgEEvREL4GTXXHKohhh33+6Y8XkPI5eHihDmm8zUk5Zo7HICEW+wI/j5kJ2tbuNUCXJ/sNXa03ajW635DiJXA==" + }, "node_modules/emoji-regex": { "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "peer": true + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" }, "node_modules/encodeurl": { "version": "1.0.2", @@ -3529,7 +4105,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", - "peer": true, "dependencies": { "cross-spawn": "^7.0.0", "signal-exit": "^4.0.1" @@ -3562,6 +4137,18 @@ "node": ">= 0.6" } }, + "node_modules/fraction.js": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", + "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", + "engines": { + "node": "*" + }, + "funding": { + "type": "patreon", + "url": "https://github.com/sponsors/rawify" + } + }, "node_modules/fresh": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", @@ -3570,6 +4157,12 @@ "node": ">= 0.6" } }, + "node_modules/fs-monkey": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.5.tgz", + "integrity": "sha512-8uMbBjrhzW76TYgEV27Y5E//W2f/lTFmx78P2w19FZSxarhI/798APGQyuGCwmkNxgwGRhrLfvWyLBvNtuOmew==", + "optional": true + }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -3648,7 +4241,6 @@ "version": "10.3.10", "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", - "peer": true, "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^2.3.5", @@ -3670,7 +4262,6 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "peer": true, "dependencies": { "is-glob": "^4.0.3" }, @@ -4153,7 +4744,6 @@ "version": "2.13.1", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", - "peer": true, "dependencies": { "hasown": "^2.0.0" }, @@ -4407,7 +4997,6 @@ "version": "2.3.6", "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", - "peer": true, "dependencies": { "@isaacs/cliui": "^8.0.2" }, @@ -4425,7 +5014,6 @@ "version": "1.21.0", "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.0.tgz", "integrity": "sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==", - "peer": true, "bin": { "jiti": "bin/jiti.js" } @@ -4492,56 +5080,10 @@ "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.1.tgz", "integrity": "sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA==" }, - "node_modules/jsonwebtoken": { - "version": "8.5.1", - "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", - "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==", - "dependencies": { - "jws": "^3.2.2", - "lodash.includes": "^4.3.0", - "lodash.isboolean": "^3.0.3", - "lodash.isinteger": "^4.0.4", - "lodash.isnumber": "^3.0.3", - "lodash.isplainobject": "^4.0.6", - "lodash.isstring": "^4.0.1", - "lodash.once": "^4.0.0", - "ms": "^2.1.1", - "semver": "^5.6.0" - }, - "engines": { - "node": ">=4", - "npm": ">=1.4.28" - } - }, - "node_modules/jsonwebtoken/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - }, - "node_modules/jwa": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", - "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", - "dependencies": { - "buffer-equal-constant-time": "1.0.1", - "ecdsa-sig-formatter": "1.0.11", - "safe-buffer": "^5.0.1" - } - }, - "node_modules/jws": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", - "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", - "dependencies": { - "jwa": "^1.4.1", - "safe-buffer": "^5.0.1" - } - }, "node_modules/lilconfig": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", - "peer": true, "engines": { "node": ">=10" } @@ -4549,8 +5091,7 @@ "node_modules/lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "peer": true + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" }, "node_modules/local-pkg": { "version": "0.5.0", @@ -4572,46 +5113,11 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, - "node_modules/lodash.includes": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", - "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==" - }, - "node_modules/lodash.isboolean": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", - "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==" - }, - "node_modules/lodash.isinteger": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", - "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==" - }, - "node_modules/lodash.isnumber": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", - "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==" - }, - "node_modules/lodash.isplainobject": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==" - }, - "node_modules/lodash.isstring": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", - "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==" - }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" }, - "node_modules/lodash.once": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", - "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==" - }, "node_modules/log-symbols": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", @@ -4679,7 +5185,6 @@ "version": "10.2.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", - "peer": true, "engines": { "node": "14 || >=16.14" } @@ -4719,6 +5224,27 @@ "node": ">= 0.6" } }, + "node_modules/memfs": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz", + "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==", + "optional": true, + "dependencies": { + "fs-monkey": "^1.0.4" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/memfs-browser": { + "version": "3.5.10302", + "resolved": "https://registry.npmjs.org/memfs-browser/-/memfs-browser-3.5.10302.tgz", + "integrity": "sha512-JJTc/nh3ig05O0gBBGZjTCPOyydaTxNF0uHYBrcc1gHNnO+KIHIvo0Y1FKCJsaei6FCl8C6xfQomXqu+cuzkIw==", + "optional": true, + "dependencies": { + "memfs": "3.5.3" + } + }, "node_modules/merge-descriptors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", @@ -4815,7 +5341,6 @@ "version": "9.0.3", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", - "peer": true, "dependencies": { "brace-expansion": "^2.0.1" }, @@ -4830,7 +5355,6 @@ "version": "7.0.4", "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", - "peer": true, "engines": { "node": ">=16 || 14 >=14.17" } @@ -4960,18 +5484,12 @@ "version": "2.7.0", "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", - "peer": true, "dependencies": { "any-promise": "^1.0.0", "object-assign": "^4.0.1", "thenify-all": "^1.0.0" } }, - "node_modules/nanoassert": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/nanoassert/-/nanoassert-1.1.0.tgz", - "integrity": "sha512-C40jQ3NzfkP53NsO8kEOFd79p4b9kDXQMwgiY1z8ZwrDZgUyom0AHwGegF4Dm99L+YoYhuaB0ceerUcXmqr1rQ==" - }, "node_modules/nanoid": { "version": "3.3.7", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", @@ -5035,15 +5553,10 @@ "webidl-conversions": "^3.0.0" } }, - "node_modules/node-gyp-build": { - "version": "4.8.0", - "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.0.tgz", - "integrity": "sha512-u6fs2AEUljNho3EYTJNBfImO5QTo/J/1Etd+NVdCj7qWKUSN/bSLkZwhDv7I+w/MSC6qJ4cknepkAYykDdK8og==", - "bin": { - "node-gyp-build": "bin.js", - "node-gyp-build-optional": "optional.js", - "node-gyp-build-test": "build-test.js" - } + "node_modules/node-releases": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", + "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==" }, "node_modules/normalize-path": { "version": "3.0.0", @@ -5053,6 +5566,14 @@ "node": ">=0.10.0" } }, + "node_modules/normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/npm-run-path": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.2.0.tgz", @@ -5095,7 +5616,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", - "peer": true, "engines": { "node": ">= 6" } @@ -5309,14 +5829,12 @@ "node_modules/path-parse": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "peer": true + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" }, "node_modules/path-scurry": { "version": "1.10.1", "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.1.tgz", "integrity": "sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==", - "peer": true, "dependencies": { "lru-cache": "^9.1.1 || ^10.0.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" @@ -5366,7 +5884,6 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", - "peer": true, "engines": { "node": ">=0.10.0" } @@ -5375,7 +5892,6 @@ "version": "4.0.6", "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", - "peer": true, "engines": { "node": ">= 6" } @@ -5421,7 +5937,6 @@ "version": "15.1.0", "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", - "peer": true, "dependencies": { "postcss-value-parser": "^4.0.0", "read-cache": "^1.0.0", @@ -5438,7 +5953,6 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz", "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==", - "peer": true, "dependencies": { "camelcase-css": "^2.0.1" }, @@ -5467,7 +5981,6 @@ "url": "https://github.com/sponsors/ai" } ], - "peer": true, "dependencies": { "lilconfig": "^3.0.0", "yaml": "^2.3.4" @@ -5492,7 +6005,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.0.tgz", "integrity": "sha512-p3cz0JV5vw/XeouBU3Ldnp+ZkBjE+n8ydJ4mcwBrOiXXPqNlrzGBqWs9X4MWF7f+iKUBu794Y8Hh8yawiJbCjw==", - "peer": true, "engines": { "node": ">=14" }, @@ -5504,7 +6016,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.1.tgz", "integrity": "sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==", - "peer": true, "dependencies": { "postcss-selector-parser": "^6.0.11" }, @@ -5523,7 +6034,6 @@ "version": "6.0.15", "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.15.tgz", "integrity": "sha512-rEYkQOMUCEMhsKbK66tbEU9QVIxbhN18YiniAwA7XQYTVBqrBy+P2p5JcdqsHgKM2zWylp8d7J6eszocfds5Sw==", - "peer": true, "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -5535,8 +6045,7 @@ "node_modules/postcss-value-parser": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", - "peer": true + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" }, "node_modules/pretty-format": { "version": "27.5.1", @@ -5819,7 +6328,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", - "peer": true, "dependencies": { "pify": "^2.3.0" } @@ -5899,7 +6407,6 @@ "version": "1.22.8", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", - "peer": true, "dependencies": { "is-core-module": "^2.13.0", "path-parse": "^1.0.7", @@ -6046,23 +6553,6 @@ "loose-envify": "^1.1.0" } }, - "node_modules/secure-password": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/secure-password/-/secure-password-4.0.0.tgz", - "integrity": "sha512-B268T/tx+hq7q85KH6gonEqK/lhrLhNtzYzqojuMtBPVFBtwiIwxqF+4yr9POsJu5cIxbJyM66eYfXZiPZUXRA==", - "dependencies": { - "nanoassert": "^1.0.0", - "sodium-native": "^3.1.1" - } - }, - "node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "bin": { - "semver": "bin/semver" - } - }, "node_modules/send": { "version": "0.18.0", "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", @@ -6353,15 +6843,6 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, - "node_modules/sodium-native": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/sodium-native/-/sodium-native-3.4.1.tgz", - "integrity": "sha512-PaNN/roiFWzVVTL6OqjzYct38NSXewdl2wz8SRB51Br/MLIJPrbM3XexhVWkq7D3UWMysfrhKVf1v1phZq6MeQ==", - "hasInstallScript": true, - "dependencies": { - "node-gyp-build": "^4.3.0" - } - }, "node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -6425,7 +6906,6 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "peer": true, "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", @@ -6443,7 +6923,6 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "peer": true, "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -6457,7 +6936,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "peer": true, "engines": { "node": ">=8" } @@ -6465,14 +6943,12 @@ "node_modules/string-width-cjs/node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "peer": true + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" }, "node_modules/string-width-cjs/node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "peer": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -6484,7 +6960,6 @@ "version": "7.1.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "peer": true, "dependencies": { "ansi-regex": "^6.0.1" }, @@ -6500,7 +6975,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "peer": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -6512,7 +6986,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "peer": true, "engines": { "node": ">=8" } @@ -6554,7 +7027,6 @@ "version": "3.35.0", "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz", "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==", - "peer": true, "dependencies": { "@jridgewell/gen-mapping": "^0.3.2", "commander": "^4.0.0", @@ -6598,7 +7070,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "peer": true, "engines": { "node": ">= 0.4" }, @@ -6629,7 +7100,6 @@ "version": "3.4.1", "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.1.tgz", "integrity": "sha512-qAYmXRfk3ENzuPBakNK0SRrUDipP8NQnEY6772uDhflcQz5EhRdD7JNZxyrFHVQNCwULPBn6FNPp9brpO7ctcA==", - "peer": true, "dependencies": { "@alloc/quick-lru": "^5.2.0", "arg": "^5.0.2", @@ -6666,7 +7136,6 @@ "version": "3.3.1", "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", - "peer": true, "dependencies": { "any-promise": "^1.0.0" } @@ -6675,7 +7144,6 @@ "version": "1.6.0", "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", - "peer": true, "dependencies": { "thenify": ">= 3.1.0 < 4" }, @@ -6785,8 +7253,7 @@ "node_modules/ts-interface-checker": { "version": "0.1.13", "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", - "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", - "peer": true + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==" }, "node_modules/tslib": { "version": "2.6.2", @@ -6863,6 +7330,35 @@ "node": ">= 0.8" } }, + "node_modules/update-browserslist-db": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", + "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, "node_modules/url-parse": { "version": "1.5.10", "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", @@ -8169,7 +8665,6 @@ "version": "8.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", - "peer": true, "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", @@ -8187,7 +8682,6 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "peer": true, "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -8204,7 +8698,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "peer": true, "engines": { "node": ">=8" } @@ -8213,7 +8706,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "peer": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -8227,14 +8719,12 @@ "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "peer": true + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" }, "node_modules/wrap-ansi-cjs/node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "peer": true, "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -8248,7 +8738,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "peer": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -8309,7 +8798,6 @@ "version": "2.3.4", "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.4.tgz", "integrity": "sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==", - "peer": true, "engines": { "node": ">= 14" } @@ -8397,8 +8885,7 @@ "@alloc/quick-lru": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", - "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", - "peer": true + "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==" }, "@babel/code-frame": { "version": "7.23.5", @@ -8746,7 +9233,6 @@ "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", - "peer": true, "requires": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", @@ -8768,7 +9254,6 @@ "version": "0.3.3", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", - "peer": true, "requires": { "@jridgewell/set-array": "^1.0.1", "@jridgewell/sourcemap-codec": "^1.4.10", @@ -8778,14 +9263,12 @@ "@jridgewell/resolve-uri": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "peer": true + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==" }, "@jridgewell/set-array": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", - "peer": true + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==" }, "@jridgewell/sourcemap-codec": { "version": "1.4.15", @@ -8796,7 +9279,6 @@ "version": "0.3.22", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.22.tgz", "integrity": "sha512-Wf963MzWtA2sjrNt+g18IAln9lKnlRp+K2eH4jjIoF1wYeq3aMREpG09xhlhdzS0EjwU7qmUJYangWa+151vZw==", - "peer": true, "requires": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" @@ -9114,8 +9596,7 @@ "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", - "optional": true, - "peer": true + "optional": true }, "@polka/url": { "version": "1.0.0-next.24", @@ -9333,7 +9814,8 @@ "@tsconfig/node18": { "version": "18.2.2", "resolved": "https://registry.npmjs.org/@tsconfig/node18/-/node18-18.2.2.tgz", - "integrity": "sha512-d6McJeGsuoRlwWZmVIeE8CUA27lu6jLjvv1JzqmpsytOYYbVi1tHZEnwCNVOXnj4pyLvneZlFlpXUK+X9wBWyw==" + "integrity": "sha512-d6McJeGsuoRlwWZmVIeE8CUA27lu6jLjvv1JzqmpsytOYYbVi1tHZEnwCNVOXnj4pyLvneZlFlpXUK+X9wBWyw==", + "dev": true }, "@tybys/wasm-util": { "version": "0.8.1", @@ -9386,6 +9868,11 @@ "@types/send": "*" } }, + "@types/history": { + "version": "4.7.11", + "resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.11.tgz", + "integrity": "sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA==" + }, "@types/js-levenshtein": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/@types/js-levenshtein/-/js-levenshtein-1.1.3.tgz", @@ -9442,6 +9929,25 @@ "@types/react": "*" } }, + "@types/react-router": { + "version": "5.1.20", + "resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.20.tgz", + "integrity": "sha512-jGjmu/ZqS7FjSH6owMcD5qpq19+1RS9DeVRqfl1FeBMxTDQAGwlMWOcs52NDoXaNKyG3d1cYQFMs9rCrb88o9Q==", + "requires": { + "@types/history": "^4.7.11", + "@types/react": "*" + } + }, + "@types/react-router-dom": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/@types/react-router-dom/-/react-router-dom-5.3.3.tgz", + "integrity": "sha512-kpqnYK4wcdm5UaWI3fLcELopqLrHgLqNsdpHauzlQktfkHL3npOSwtj1Uz9oKBAzs7lFtVkV8j83voAz2D8fhw==", + "requires": { + "@types/history": "^4.7.11", + "@types/react": "*", + "@types/react-router": "*" + } + }, "@types/scheduler": { "version": "0.16.8", "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.8.tgz", @@ -9656,20 +10162,17 @@ "ansi-regex": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", - "peer": true + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==" }, "ansi-styles": { "version": "6.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", - "peer": true + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==" }, "any-promise": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", - "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", - "peer": true + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==" }, "anymatch": { "version": "3.1.3", @@ -9683,8 +10186,7 @@ "arg": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", - "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", - "peer": true + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==" }, "aria-hidden": { "version": "1.2.3", @@ -9726,6 +10228,19 @@ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" }, + "autoprefixer": { + "version": "10.4.18", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.18.tgz", + "integrity": "sha512-1DKbDfsr6KUElM6wg+0zRNkB/Q7WcKYAaK+pzXn+Xqmszm/5Xa9coeNdtP88Vi+dPzZnMjhge8GIV49ZQkDa+g==", + "requires": { + "browserslist": "^4.23.0", + "caniuse-lite": "^1.0.30001591", + "fraction.js": "^4.3.7", + "normalize-range": "^0.1.2", + "picocolors": "^1.0.0", + "postcss-value-parser": "^4.2.0" + } + }, "available-typed-arrays": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.6.tgz", @@ -9744,8 +10259,7 @@ "balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "peer": true + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, "base64-js": { "version": "1.5.1", @@ -9795,7 +10309,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "peer": true, "requires": { "balanced-match": "^1.0.0" } @@ -9808,6 +10321,17 @@ "fill-range": "^7.0.1" } }, + "browserslist": { + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz", + "integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==", + "requires": { + "caniuse-lite": "^1.0.30001587", + "electron-to-chromium": "^1.4.668", + "node-releases": "^2.0.14", + "update-browserslist-db": "^1.0.13" + } + }, "buffer": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", @@ -9817,11 +10341,6 @@ "ieee754": "^1.1.13" } }, - "buffer-equal-constant-time": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", - "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==" - }, "bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -9847,8 +10366,12 @@ "camelcase-css": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", - "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", - "peer": true + "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==" + }, + "caniuse-lite": { + "version": "1.0.30001599", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001599.tgz", + "integrity": "sha512-LRAQHZ4yT1+f9LemSMeqdMpMxZcc4RMWdj4tiFe3G8tNkWK+E58g+/tzotb5cU6TbcVJLr4fySiAW7XmxQvZQA==" }, "chai": { "version": "4.4.1", @@ -10031,8 +10554,7 @@ "commander": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", - "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", - "peer": true + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==" }, "content-disposition": { "version": "0.5.4", @@ -10092,8 +10614,7 @@ "cssesc": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", - "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", - "peer": true + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==" }, "cssstyle": { "version": "3.0.0", @@ -10220,8 +10741,7 @@ "didyoumean": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", - "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", - "peer": true + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==" }, "diff-sequences": { "version": "29.6.3", @@ -10231,8 +10751,7 @@ "dlv": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", - "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", - "peer": true + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==" }, "dom-accessibility-api": { "version": "0.6.3", @@ -10250,32 +10769,27 @@ "eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "peer": true + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" }, "easy-bem": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/easy-bem/-/easy-bem-1.1.1.tgz", "integrity": "sha512-GJRqdiy2h+EXy6a8E6R+ubmqUM08BK0FWNq41k24fup6045biQ8NXxoXimiwegMQvFFV3t1emADdGNL1TlS61A==" }, - "ecdsa-sig-formatter": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", - "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", - "requires": { - "safe-buffer": "^5.0.1" - } - }, "ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, + "electron-to-chromium": { + "version": "1.4.708", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.708.tgz", + "integrity": "sha512-iWgEEvREL4GTXXHKohhh33+6Y8XkPI5eHihDmm8zUk5Zo7HICEW+wI/j5kJ2tbuNUCXJ/sNXa03ajW635DiJXA==" + }, "emoji-regex": { "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "peer": true + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" }, "encodeurl": { "version": "1.0.2", @@ -10678,7 +11192,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", - "peer": true, "requires": { "cross-spawn": "^7.0.0", "signal-exit": "^4.0.1" @@ -10699,11 +11212,22 @@ "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==" }, + "fraction.js": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", + "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==" + }, "fresh": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==" }, + "fs-monkey": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.5.tgz", + "integrity": "sha512-8uMbBjrhzW76TYgEV27Y5E//W2f/lTFmx78P2w19FZSxarhI/798APGQyuGCwmkNxgwGRhrLfvWyLBvNtuOmew==", + "optional": true + }, "fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -10751,7 +11275,6 @@ "version": "10.3.10", "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", - "peer": true, "requires": { "foreground-child": "^3.1.0", "jackspeak": "^2.3.5", @@ -10764,7 +11287,6 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "peer": true, "requires": { "is-glob": "^4.0.3" } @@ -11102,7 +11624,6 @@ "version": "2.13.1", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", - "peer": true, "requires": { "hasown": "^2.0.0" } @@ -11263,7 +11784,6 @@ "version": "2.3.6", "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", - "peer": true, "requires": { "@isaacs/cliui": "^8.0.2", "@pkgjs/parseargs": "^0.11.0" @@ -11272,8 +11792,7 @@ "jiti": { "version": "1.21.0", "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.0.tgz", - "integrity": "sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==", - "peer": true + "integrity": "sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==" }, "js-levenshtein": { "version": "1.1.6", @@ -11323,60 +11842,15 @@ "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.1.tgz", "integrity": "sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA==" }, - "jsonwebtoken": { - "version": "8.5.1", - "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", - "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==", - "requires": { - "jws": "^3.2.2", - "lodash.includes": "^4.3.0", - "lodash.isboolean": "^3.0.3", - "lodash.isinteger": "^4.0.4", - "lodash.isnumber": "^3.0.3", - "lodash.isplainobject": "^4.0.6", - "lodash.isstring": "^4.0.1", - "lodash.once": "^4.0.0", - "ms": "^2.1.1", - "semver": "^5.6.0" - }, - "dependencies": { - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - } - } - }, - "jwa": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", - "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", - "requires": { - "buffer-equal-constant-time": "1.0.1", - "ecdsa-sig-formatter": "1.0.11", - "safe-buffer": "^5.0.1" - } - }, - "jws": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", - "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", - "requires": { - "jwa": "^1.4.1", - "safe-buffer": "^5.0.1" - } - }, "lilconfig": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", - "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", - "peer": true + "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==" }, "lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "peer": true + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" }, "local-pkg": { "version": "0.5.0", @@ -11392,46 +11866,11 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, - "lodash.includes": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", - "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==" - }, - "lodash.isboolean": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", - "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==" - }, - "lodash.isinteger": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", - "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==" - }, - "lodash.isnumber": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", - "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==" - }, - "lodash.isplainobject": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==" - }, - "lodash.isstring": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", - "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==" - }, "lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" }, - "lodash.once": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", - "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==" - }, "log-symbols": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", @@ -11479,8 +11918,7 @@ "lru-cache": { "version": "10.2.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", - "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", - "peer": true + "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==" }, "lucia": { "version": "3.0.1", @@ -11508,6 +11946,24 @@ "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==" }, + "memfs": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz", + "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==", + "optional": true, + "requires": { + "fs-monkey": "^1.0.4" + } + }, + "memfs-browser": { + "version": "3.5.10302", + "resolved": "https://registry.npmjs.org/memfs-browser/-/memfs-browser-3.5.10302.tgz", + "integrity": "sha512-JJTc/nh3ig05O0gBBGZjTCPOyydaTxNF0uHYBrcc1gHNnO+KIHIvo0Y1FKCJsaei6FCl8C6xfQomXqu+cuzkIw==", + "optional": true, + "requires": { + "memfs": "3.5.3" + } + }, "merge-descriptors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", @@ -11574,7 +12030,6 @@ "version": "9.0.3", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", - "peer": true, "requires": { "brace-expansion": "^2.0.1" } @@ -11582,8 +12037,7 @@ "minipass": { "version": "7.0.4", "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", - "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", - "peer": true + "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==" }, "mitt": { "version": "3.0.0", @@ -11675,18 +12129,12 @@ "version": "2.7.0", "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", - "peer": true, "requires": { "any-promise": "^1.0.0", "object-assign": "^4.0.1", "thenify-all": "^1.0.0" } }, - "nanoassert": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/nanoassert/-/nanoassert-1.1.0.tgz", - "integrity": "sha512-C40jQ3NzfkP53NsO8kEOFd79p4b9kDXQMwgiY1z8ZwrDZgUyom0AHwGegF4Dm99L+YoYhuaB0ceerUcXmqr1rQ==" - }, "nanoid": { "version": "3.3.7", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", @@ -11726,16 +12174,21 @@ } } }, - "node-gyp-build": { - "version": "4.8.0", - "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.0.tgz", - "integrity": "sha512-u6fs2AEUljNho3EYTJNBfImO5QTo/J/1Etd+NVdCj7qWKUSN/bSLkZwhDv7I+w/MSC6qJ4cknepkAYykDdK8og==" + "node-releases": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", + "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==" }, "normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" }, + "normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==" + }, "npm-run-path": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.2.0.tgz", @@ -11764,8 +12217,7 @@ "object-hash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", - "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", - "peer": true + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==" }, "object-inspect": { "version": "1.13.1", @@ -11909,14 +12361,12 @@ "path-parse": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "peer": true + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" }, "path-scurry": { "version": "1.10.1", "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.1.tgz", "integrity": "sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==", - "peer": true, "requires": { "lru-cache": "^9.1.1 || ^10.0.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" @@ -11950,14 +12400,12 @@ "pify": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", - "peer": true + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==" }, "pirates": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", - "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", - "peer": true + "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==" }, "pkg-types": { "version": "1.0.3", @@ -11983,7 +12431,6 @@ "version": "15.1.0", "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", - "peer": true, "requires": { "postcss-value-parser": "^4.0.0", "read-cache": "^1.0.0", @@ -11994,7 +12441,6 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz", "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==", - "peer": true, "requires": { "camelcase-css": "^2.0.1" } @@ -12003,7 +12449,6 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz", "integrity": "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==", - "peer": true, "requires": { "lilconfig": "^3.0.0", "yaml": "^2.3.4" @@ -12012,8 +12457,7 @@ "lilconfig": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.0.tgz", - "integrity": "sha512-p3cz0JV5vw/XeouBU3Ldnp+ZkBjE+n8ydJ4mcwBrOiXXPqNlrzGBqWs9X4MWF7f+iKUBu794Y8Hh8yawiJbCjw==", - "peer": true + "integrity": "sha512-p3cz0JV5vw/XeouBU3Ldnp+ZkBjE+n8ydJ4mcwBrOiXXPqNlrzGBqWs9X4MWF7f+iKUBu794Y8Hh8yawiJbCjw==" } } }, @@ -12021,7 +12465,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.1.tgz", "integrity": "sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==", - "peer": true, "requires": { "postcss-selector-parser": "^6.0.11" } @@ -12030,7 +12473,6 @@ "version": "6.0.15", "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.15.tgz", "integrity": "sha512-rEYkQOMUCEMhsKbK66tbEU9QVIxbhN18YiniAwA7XQYTVBqrBy+P2p5JcdqsHgKM2zWylp8d7J6eszocfds5Sw==", - "peer": true, "requires": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -12039,8 +12481,7 @@ "postcss-value-parser": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", - "peer": true + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" }, "pretty-format": { "version": "27.5.1", @@ -12246,7 +12687,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", - "peer": true, "requires": { "pify": "^2.3.0" } @@ -12308,7 +12748,6 @@ "version": "1.22.8", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", - "peer": true, "requires": { "is-core-module": "^2.13.0", "path-parse": "^1.0.7", @@ -12403,20 +12842,6 @@ "loose-envify": "^1.1.0" } }, - "secure-password": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/secure-password/-/secure-password-4.0.0.tgz", - "integrity": "sha512-B268T/tx+hq7q85KH6gonEqK/lhrLhNtzYzqojuMtBPVFBtwiIwxqF+4yr9POsJu5cIxbJyM66eYfXZiPZUXRA==", - "requires": { - "nanoassert": "^1.0.0", - "sodium-native": "^3.1.1" - } - }, - "semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==" - }, "send": { "version": "0.18.0", "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", @@ -12637,14 +13062,6 @@ } } }, - "sodium-native": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/sodium-native/-/sodium-native-3.4.1.tgz", - "integrity": "sha512-PaNN/roiFWzVVTL6OqjzYct38NSXewdl2wz8SRB51Br/MLIJPrbM3XexhVWkq7D3UWMysfrhKVf1v1phZq6MeQ==", - "requires": { - "node-gyp-build": "^4.3.0" - } - }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -12696,7 +13113,6 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "peer": true, "requires": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", @@ -12707,7 +13123,6 @@ "version": "npm:string-width@4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "peer": true, "requires": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -12717,20 +13132,17 @@ "ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "peer": true + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" }, "emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "peer": true + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" }, "strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "peer": true, "requires": { "ansi-regex": "^5.0.1" } @@ -12741,7 +13153,6 @@ "version": "7.1.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "peer": true, "requires": { "ansi-regex": "^6.0.1" } @@ -12750,7 +13161,6 @@ "version": "npm:strip-ansi@6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "peer": true, "requires": { "ansi-regex": "^5.0.1" }, @@ -12758,8 +13168,7 @@ "ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "peer": true + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" } } }, @@ -12788,7 +13197,6 @@ "version": "3.35.0", "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz", "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==", - "peer": true, "requires": { "@jridgewell/gen-mapping": "^0.3.2", "commander": "^4.0.0", @@ -12818,8 +13226,7 @@ "supports-preserve-symlinks-flag": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "peer": true + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==" }, "symbol-tree": { "version": "3.2.4", @@ -12840,7 +13247,6 @@ "version": "3.4.1", "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.1.tgz", "integrity": "sha512-qAYmXRfk3ENzuPBakNK0SRrUDipP8NQnEY6772uDhflcQz5EhRdD7JNZxyrFHVQNCwULPBn6FNPp9brpO7ctcA==", - "peer": true, "requires": { "@alloc/quick-lru": "^5.2.0", "arg": "^5.0.2", @@ -12870,7 +13276,6 @@ "version": "3.3.1", "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", - "peer": true, "requires": { "any-promise": "^1.0.0" } @@ -12879,7 +13284,6 @@ "version": "1.6.0", "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", - "peer": true, "requires": { "thenify": ">= 3.1.0 < 4" } @@ -12962,8 +13366,7 @@ "ts-interface-checker": { "version": "0.1.13", "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", - "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", - "peer": true + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==" }, "tslib": { "version": "2.6.2", @@ -13015,6 +13418,15 @@ "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==" }, + "update-browserslist-db": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", + "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "requires": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + } + }, "url-parse": { "version": "1.5.10", "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", @@ -13545,33 +13957,269 @@ "wasp": { "version": "file:.wasp/out/sdk/wasp", "requires": { - "@lucia-auth/adapter-prisma": "^4.0.0-beta.9", + "@lucia-auth/adapter-prisma": "^4.0.0", "@prisma/client": "4.16.2", "@socket.io/component-emitter": "^4.0.0", "@stitches/react": "^1.2.8", "@tanstack/react-query": "^4.29.0", "@testing-library/jest-dom": "^6.3.0", "@testing-library/react": "^14.1.2", - "@tsconfig/node18": "*", + "@tsconfig/node18": "latest", "@types/express-serve-static-core": "^4.17.13", + "@types/react-router-dom": "^5.3.3", "@vitest/ui": "^1.2.1", + "autoprefixer": "^10.4.13", "axios": "^1.4.0", "express": "~4.18.1", "jsdom": "^21.1.1", - "jsonwebtoken": "^8.5.1", "lodash.merge": "^4.6.2", - "lucia": "^3.0.0-beta.14", + "lucia": "^3.0.1", "mitt": "3.0.0", "msw": "^1.1.0", + "oslo": "^1.1.2", + "postcss": "^8.4.21", "prisma": "4.16.2", "react": "^18.2.0", "react-hook-form": "^7.45.4", "react-router-dom": "^5.3.3", - "secure-password": "^4.0.0", "socket.io": "^4.6.1", "socket.io-client": "^4.6.1", "superjson": "^1.12.2", + "tailwindcss": "^3.2.7", "vitest": "^1.2.1" + }, + "dependencies": { + "@node-rs/argon2": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@node-rs/argon2/-/argon2-1.7.0.tgz", + "integrity": "sha512-zfULc+/tmcWcxn+nHkbyY8vP3+MpEqKORbszt4UkpqZgBgDAAIYvuDN/zukfTgdmo6tmJKKVfzigZOPk4LlIog==", + "requires": { + "@node-rs/argon2-android-arm-eabi": "1.7.0", + "@node-rs/argon2-android-arm64": "1.7.0", + "@node-rs/argon2-darwin-arm64": "1.7.0", + "@node-rs/argon2-darwin-x64": "1.7.0", + "@node-rs/argon2-freebsd-x64": "1.7.0", + "@node-rs/argon2-linux-arm-gnueabihf": "1.7.0", + "@node-rs/argon2-linux-arm64-gnu": "1.7.0", + "@node-rs/argon2-linux-arm64-musl": "1.7.0", + "@node-rs/argon2-linux-x64-gnu": "1.7.0", + "@node-rs/argon2-linux-x64-musl": "1.7.0", + "@node-rs/argon2-wasm32-wasi": "1.7.0", + "@node-rs/argon2-win32-arm64-msvc": "1.7.0", + "@node-rs/argon2-win32-ia32-msvc": "1.7.0", + "@node-rs/argon2-win32-x64-msvc": "1.7.0" + } + }, + "@node-rs/argon2-android-arm-eabi": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@node-rs/argon2-android-arm-eabi/-/argon2-android-arm-eabi-1.7.0.tgz", + "integrity": "sha512-udDqkr5P9E+wYX1SZwAVPdyfYvaF4ry9Tm+R9LkfSHbzWH0uhU6zjIwNRp7m+n4gx691rk+lqqDAIP8RLKwbhg==", + "optional": true + }, + "@node-rs/argon2-android-arm64": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@node-rs/argon2-android-arm64/-/argon2-android-arm64-1.7.0.tgz", + "integrity": "sha512-s9j/G30xKUx8WU50WIhF0fIl1EdhBGq0RQ06lEhZ0Gi0ap8lhqbE2Bn5h3/G2D1k0Dx+yjeVVNmt/xOQIRG38A==", + "optional": true + }, + "@node-rs/argon2-darwin-arm64": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@node-rs/argon2-darwin-arm64/-/argon2-darwin-arm64-1.7.0.tgz", + "integrity": "sha512-ZIz4L6HGOB9U1kW23g+m7anGNuTZ0RuTw0vNp3o+2DWpb8u8rODq6A8tH4JRL79S+Co/Nq608m9uackN2pe0Rw==", + "optional": true + }, + "@node-rs/argon2-darwin-x64": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@node-rs/argon2-darwin-x64/-/argon2-darwin-x64-1.7.0.tgz", + "integrity": "sha512-5oi/pxqVhODW/pj1+3zElMTn/YukQeywPHHYDbcAW3KsojFjKySfhcJMd1DjKTc+CHQI+4lOxZzSUzK7mI14Hw==", + "optional": true + }, + "@node-rs/argon2-freebsd-x64": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@node-rs/argon2-freebsd-x64/-/argon2-freebsd-x64-1.7.0.tgz", + "integrity": "sha512-Ify08683hA4QVXYoIm5SUWOY5DPIT/CMB0CQT+IdxQAg/F+qp342+lUkeAtD5bvStQuCx/dFO3bnnzoe2clMhA==", + "optional": true + }, + "@node-rs/argon2-linux-arm-gnueabihf": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@node-rs/argon2-linux-arm-gnueabihf/-/argon2-linux-arm-gnueabihf-1.7.0.tgz", + "integrity": "sha512-7DjDZ1h5AUHAtRNjD19RnQatbhL+uuxBASuuXIBu4/w6Dx8n7YPxwTP4MXfsvuRgKuMWiOb/Ub/HJ3kXVCXRkg==", + "optional": true + }, + "@node-rs/argon2-linux-arm64-gnu": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@node-rs/argon2-linux-arm64-gnu/-/argon2-linux-arm64-gnu-1.7.0.tgz", + "integrity": "sha512-nJDoMP4Y3YcqGswE4DvP080w6O24RmnFEDnL0emdI8Nou17kNYBzP2546Nasx9GCyLzRcYQwZOUjrtUuQ+od2g==", + "optional": true + }, + "@node-rs/argon2-linux-arm64-musl": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@node-rs/argon2-linux-arm64-musl/-/argon2-linux-arm64-musl-1.7.0.tgz", + "integrity": "sha512-BKWS8iVconhE3jrb9mj6t1J9vwUqQPpzCbUKxfTGJfc+kNL58F1SXHBoe2cDYGnHrFEHTY0YochzXoAfm4Dm/A==", + "optional": true + }, + "@node-rs/argon2-linux-x64-gnu": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@node-rs/argon2-linux-x64-gnu/-/argon2-linux-x64-gnu-1.7.0.tgz", + "integrity": "sha512-EmgqZOlf4Jurk/szW1iTsVISx25bKksVC5uttJDUloTgsAgIGReCpUUO1R24pBhu9ESJa47iv8NSf3yAfGv6jQ==", + "optional": true + }, + "@node-rs/argon2-linux-x64-musl": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@node-rs/argon2-linux-x64-musl/-/argon2-linux-x64-musl-1.7.0.tgz", + "integrity": "sha512-/o1efYCYIxjfuoRYyBTi2Iy+1iFfhqHCvvVsnjNSgO1xWiWrX0Rrt/xXW5Zsl7vS2Y+yu8PL8KFWRzZhaVxfKA==", + "optional": true + }, + "@node-rs/argon2-wasm32-wasi": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@node-rs/argon2-wasm32-wasi/-/argon2-wasm32-wasi-1.7.0.tgz", + "integrity": "sha512-Evmk9VcxqnuwQftfAfYEr6YZYSPLzmKUsbFIMep5nTt9PT4XYRFAERj7wNYp+rOcBenF3X4xoB+LhwcOMTNE5w==", + "optional": true, + "requires": { + "@emnapi/core": "^0.45.0", + "@emnapi/runtime": "^0.45.0", + "@tybys/wasm-util": "^0.8.1", + "memfs-browser": "^3.4.13000" + } + }, + "@node-rs/argon2-win32-arm64-msvc": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@node-rs/argon2-win32-arm64-msvc/-/argon2-win32-arm64-msvc-1.7.0.tgz", + "integrity": "sha512-qgsU7T004COWWpSA0tppDqDxbPLgg8FaU09krIJ7FBl71Sz8SFO40h7fDIjfbTT5w7u6mcaINMQ5bSHu75PCaA==", + "optional": true + }, + "@node-rs/argon2-win32-ia32-msvc": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@node-rs/argon2-win32-ia32-msvc/-/argon2-win32-ia32-msvc-1.7.0.tgz", + "integrity": "sha512-JGafwWYQ/HpZ3XSwP4adQ6W41pRvhcdXvpzIWtKvX+17+xEXAe2nmGWM6s27pVkg1iV2ZtoYLRDkOUoGqZkCcg==", + "optional": true + }, + "@node-rs/argon2-win32-x64-msvc": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@node-rs/argon2-win32-x64-msvc/-/argon2-win32-x64-msvc-1.7.0.tgz", + "integrity": "sha512-9oq4ShyFakw8AG3mRls0AoCpxBFcimYx7+jvXeAf2OqKNO+mSA6eZ9z7KQeVCi0+SOEUYxMGf5UiGiDb9R6+9Q==", + "optional": true + }, + "@node-rs/bcrypt": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@node-rs/bcrypt/-/bcrypt-1.9.0.tgz", + "integrity": "sha512-u2OlIxW264bFUfvbFqDz9HZKFjwe8FHFtn7T/U8mYjPZ7DWYpbUB+/dkW/QgYfMSfR0ejkyuWaBBe0coW7/7ig==", + "requires": { + "@node-rs/bcrypt-android-arm-eabi": "1.9.0", + "@node-rs/bcrypt-android-arm64": "1.9.0", + "@node-rs/bcrypt-darwin-arm64": "1.9.0", + "@node-rs/bcrypt-darwin-x64": "1.9.0", + "@node-rs/bcrypt-freebsd-x64": "1.9.0", + "@node-rs/bcrypt-linux-arm-gnueabihf": "1.9.0", + "@node-rs/bcrypt-linux-arm64-gnu": "1.9.0", + "@node-rs/bcrypt-linux-arm64-musl": "1.9.0", + "@node-rs/bcrypt-linux-x64-gnu": "1.9.0", + "@node-rs/bcrypt-linux-x64-musl": "1.9.0", + "@node-rs/bcrypt-wasm32-wasi": "1.9.0", + "@node-rs/bcrypt-win32-arm64-msvc": "1.9.0", + "@node-rs/bcrypt-win32-ia32-msvc": "1.9.0", + "@node-rs/bcrypt-win32-x64-msvc": "1.9.0" + } + }, + "@node-rs/bcrypt-android-arm-eabi": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-android-arm-eabi/-/bcrypt-android-arm-eabi-1.9.0.tgz", + "integrity": "sha512-nOCFISGtnodGHNiLrG0WYLWr81qQzZKYfmwHc7muUeq+KY0sQXyHOwZk9OuNQAWv/lnntmtbwkwT0QNEmOyLvA==", + "optional": true + }, + "@node-rs/bcrypt-android-arm64": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-android-arm64/-/bcrypt-android-arm64-1.9.0.tgz", + "integrity": "sha512-+ZrIAtigVmjYkqZQTThHVlz0+TG6D+GDHWhVKvR2DifjtqJ0i+mb9gjo++hN+fWEQdWNGxKCiBBjwgT4EcXd6A==", + "optional": true + }, + "@node-rs/bcrypt-darwin-arm64": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-darwin-arm64/-/bcrypt-darwin-arm64-1.9.0.tgz", + "integrity": "sha512-CQiS+F9Pa0XozvkXR1g7uXE9QvBOPOplDg0iCCPRYTN9PqA5qYxhwe48G3o+v2UeQceNRrbnEtWuANm7JRqIhw==", + "optional": true + }, + "@node-rs/bcrypt-darwin-x64": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-darwin-x64/-/bcrypt-darwin-x64-1.9.0.tgz", + "integrity": "sha512-4pTKGawYd7sNEjdJ7R/R67uwQH1VvwPZ0SSUMmeNHbxD5QlwAPXdDH11q22uzVXsvNFZ6nGQBg8No5OUGpx6Ug==", + "optional": true + }, + "@node-rs/bcrypt-freebsd-x64": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-freebsd-x64/-/bcrypt-freebsd-x64-1.9.0.tgz", + "integrity": "sha512-UmWzySX4BJhT/B8xmTru6iFif3h0Rpx3TqxRLCcbgmH43r7k5/9QuhpiyzpvKGpKHJCFNm4F3rC2wghvw5FCIg==", + "optional": true + }, + "@node-rs/bcrypt-linux-arm-gnueabihf": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-linux-arm-gnueabihf/-/bcrypt-linux-arm-gnueabihf-1.9.0.tgz", + "integrity": "sha512-8qoX4PgBND2cVwsbajoAWo3NwdfJPEXgpCsZQZURz42oMjbGyhhSYbovBCskGU3EBLoC8RA2B1jFWooeYVn5BA==", + "optional": true + }, + "@node-rs/bcrypt-linux-arm64-gnu": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-linux-arm64-gnu/-/bcrypt-linux-arm64-gnu-1.9.0.tgz", + "integrity": "sha512-TuAC6kx0SbcIA4mSEWPi+OCcDjTQUMl213v5gMNlttF+D4ieIZx6pPDGTaMO6M2PDHTeCG0CBzZl0Lu+9b0c7Q==", + "optional": true + }, + "@node-rs/bcrypt-linux-arm64-musl": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-linux-arm64-musl/-/bcrypt-linux-arm64-musl-1.9.0.tgz", + "integrity": "sha512-/sIvKDABOI8QOEnLD7hIj02BVaNOuCIWBKvxcJOt8+TuwJ6zmY1UI5kSv9d99WbiHjTp97wtAUbZQwauU4b9ew==", + "optional": true + }, + "@node-rs/bcrypt-linux-x64-gnu": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-linux-x64-gnu/-/bcrypt-linux-x64-gnu-1.9.0.tgz", + "integrity": "sha512-DyyhDHDsLBsCKz1tZ1hLvUZSc1DK0FU0v52jK6IBQxrj24WscSU9zZe7ie/V9kdmA4Ep57BfpWX8Dsa2JxGdgQ==", + "optional": true + }, + "@node-rs/bcrypt-linux-x64-musl": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-linux-x64-musl/-/bcrypt-linux-x64-musl-1.9.0.tgz", + "integrity": "sha512-duIiuqQ+Lew8ASSAYm6ZRqcmfBGWwsi81XLUwz86a2HR7Qv6V4yc3ZAUQovAikhjCsIqe8C11JlAZSK6+PlXYg==", + "optional": true + }, + "@node-rs/bcrypt-wasm32-wasi": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-wasm32-wasi/-/bcrypt-wasm32-wasi-1.9.0.tgz", + "integrity": "sha512-ylaGmn9Wjwv/D5lxtawttx3H6Uu2WTTR7lWlRHGT6Ga/MB1Vj4OjSGUW8G8zIVnKuXpGbZ92pgHlt4HUpSLctw==", + "optional": true, + "requires": { + "@emnapi/core": "^0.45.0", + "@emnapi/runtime": "^0.45.0", + "@tybys/wasm-util": "^0.8.1", + "memfs-browser": "^3.4.13000" + } + }, + "@node-rs/bcrypt-win32-arm64-msvc": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-win32-arm64-msvc/-/bcrypt-win32-arm64-msvc-1.9.0.tgz", + "integrity": "sha512-2h86gF7QFyEzODuDFml/Dp1MSJoZjxJ4yyT2Erf4NkwsiA5MqowUhUsorRwZhX6+2CtlGa7orbwi13AKMsYndw==", + "optional": true + }, + "@node-rs/bcrypt-win32-ia32-msvc": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-win32-ia32-msvc/-/bcrypt-win32-ia32-msvc-1.9.0.tgz", + "integrity": "sha512-kqxalCvhs4FkN0+gWWfa4Bdy2NQAkfiqq/CEf6mNXC13RSV673Ev9V8sRlQyNpCHCNkeXfOT9pgoBdJmMs9muA==", + "optional": true + }, + "@node-rs/bcrypt-win32-x64-msvc": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-win32-x64-msvc/-/bcrypt-win32-x64-msvc-1.9.0.tgz", + "integrity": "sha512-2y0Tuo6ZAT2Cz8V7DHulSlv1Bip3zbzeXyeur+uR25IRNYXKvI/P99Zl85Fbuu/zzYAZRLLlGTRe6/9IHofe/w==", + "optional": true + }, + "oslo": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/oslo/-/oslo-1.1.3.tgz", + "integrity": "sha512-hCz528UlNTiegplcyBg6AvG0HLNrnq06EJMp88Ze308GX1hszkb8u3puhNC4aqLMbYQ0hXpl+wQGnwxMtt5+5w==", + "requires": { + "@node-rs/argon2": "1.7.0", + "@node-rs/bcrypt": "1.9.0" + } + } } }, "wcwidth": { @@ -13684,7 +14332,6 @@ "version": "8.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", - "peer": true, "requires": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", @@ -13695,7 +14342,6 @@ "version": "npm:wrap-ansi@7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "peer": true, "requires": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -13705,14 +14351,12 @@ "ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "peer": true + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" }, "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "peer": true, "requires": { "color-convert": "^2.0.1" } @@ -13720,14 +14364,12 @@ "emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "peer": true + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" }, "string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "peer": true, "requires": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -13738,7 +14380,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "peer": true, "requires": { "ansi-regex": "^5.0.1" } @@ -13774,8 +14415,7 @@ "yaml": { "version": "2.3.4", "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.4.tgz", - "integrity": "sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==", - "peer": true + "integrity": "sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==" }, "yargs": { "version": "17.7.2", diff --git a/examples/websockets-realtime-voting/src/client/MainPage.tsx b/examples/websockets-realtime-voting/src/client/MainPage.tsx index 7843689c2c..9f3e5aa46f 100644 --- a/examples/websockets-realtime-voting/src/client/MainPage.tsx +++ b/examples/websockets-realtime-voting/src/client/MainPage.tsx @@ -17,7 +17,7 @@ const MainPage = () => { const { socket } = useSocket(); - const username = getUsername(user); + const username = user ? getUsername(user) : null; useSocketListener("updateState", (newState) => { setPoll(newState); diff --git a/waspc/examples/crud-testing/main.wasp b/waspc/examples/crud-testing/main.wasp index d75c9a86b0..b05ebd7e02 100644 --- a/waspc/examples/crud-testing/main.wasp +++ b/waspc/examples/crud-testing/main.wasp @@ -1,6 +1,6 @@ app crudTesting { wasp: { - version: "^0.12.0" + version: "^0.13.0" }, head: [ "" diff --git a/waspc/examples/pg-vector-example/main.wasp b/waspc/examples/pg-vector-example/main.wasp index 8e869b72d0..320a12a09e 100644 --- a/waspc/examples/pg-vector-example/main.wasp +++ b/waspc/examples/pg-vector-example/main.wasp @@ -1,6 +1,6 @@ app pgVectorExample { wasp: { - version: "^0.12.0" + version: "^0.13.0" }, title: "PG Vector Example", dependencies: [ diff --git a/waspc/examples/todo-typescript/main.wasp b/waspc/examples/todo-typescript/main.wasp index 5dc798f707..ed3e815841 100644 --- a/waspc/examples/todo-typescript/main.wasp +++ b/waspc/examples/todo-typescript/main.wasp @@ -1,6 +1,6 @@ app TodoTypescript { wasp: { - version: "^0.12.0" + version: "^0.13.0" }, title: "ToDo TypeScript", diff --git a/web/docs/auth/email.md b/web/docs/auth/email.md index 25711abee5..c1228cc6e0 100644 --- a/web/docs/auth/email.md +++ b/web/docs/auth/email.md @@ -51,7 +51,7 @@ Let's start with adding the following to our `main.wasp` file: ```wasp title="main.wasp" app myApp { wasp: { - version: "^0.11.0" + version: "^0.13.0" }, title: "My App", auth: { @@ -85,7 +85,7 @@ app myApp { ```wasp title="main.wasp" app myApp { wasp: { - version: "^0.11.0" + version: "^0.13.0" }, title: "My App", auth: { diff --git a/web/docs/auth/username-and-pass.md b/web/docs/auth/username-and-pass.md index 17ddaf64bc..1f6c5aff26 100644 --- a/web/docs/auth/username-and-pass.md +++ b/web/docs/auth/username-and-pass.md @@ -44,7 +44,7 @@ Let's start with adding the following to our `main.wasp` file: ```wasp title="main.wasp" {11} app myApp { wasp: { - version: "^0.11.0" + version: "^0.13.0" }, title: "My App", auth: { @@ -64,7 +64,7 @@ app myApp { ```wasp title="main.wasp" {11} app myApp { wasp: { - version: "^0.11.0" + version: "^0.13.0" }, title: "My App", auth: { @@ -627,7 +627,7 @@ To make things a bit easier for you, Wasp offers the `getUsername` helper. ```wasp title="main.wasp" app myApp { wasp: { - version: "^0.11.0" + version: "^0.13.0" }, title: "My App", auth: { @@ -649,7 +649,7 @@ psl=} ```wasp title="main.wasp" app myApp { wasp: { - version: "^0.11.0" + version: "^0.13.0" }, title: "My App", auth: { @@ -678,7 +678,7 @@ psl=} ```wasp title="main.wasp" app myApp { wasp: { - version: "^0.11.0" + version: "^0.13.0" }, title: "My App", auth: { @@ -699,7 +699,7 @@ app myApp { ```wasp title="main.wasp" app myApp { wasp: { - version: "^0.11.0" + version: "^0.13.0" }, title: "My App", auth: { diff --git a/web/docs/data-model/crud.md b/web/docs/data-model/crud.md index c832f2976b..7622b15edc 100644 --- a/web/docs/data-model/crud.md +++ b/web/docs/data-model/crud.md @@ -73,7 +73,7 @@ We can start by running `wasp new tasksCrudApp` and then adding the following to ```wasp title="main.wasp" app tasksCrudApp { wasp: { - version: "^0.11.0" + version: "^0.13.0" }, title: "Tasks Crud App", diff --git a/web/docs/introduction/introduction.md b/web/docs/introduction/introduction.md index a389806a91..f41f1b9168 100644 --- a/web/docs/introduction/introduction.md +++ b/web/docs/introduction/introduction.md @@ -56,7 +56,7 @@ Let's give our app a title and let's immediately turn on the full-stack authenti ```wasp title="main.wasp" app RecipeApp { title: "My Recipes", - wasp: { version: "^0.12.0" }, + wasp: { version: "^0.13.0" }, auth: { methods: { usernameAndPassword: {} }, onAuthFailedRedirectTo: "/login", diff --git a/web/docs/migrate-from-0-11-to-0-12.md b/web/docs/migrate-from-0-11-to-0-12.md index f27d7a60c1..f9a6630508 100644 --- a/web/docs/migrate-from-0-11-to-0-12.md +++ b/web/docs/migrate-from-0-11-to-0-12.md @@ -178,9 +178,9 @@ You can easily migrate your old Wasp project to the new structure by following a series of steps. Assuming you have a project called `foo` inside the directory `foo`, you should: -0. **Install the latest `0.12.x` version** of Wasp. +0. **Install the `0.12.x` version** of Wasp. ```bash - curl -sSL https://get.wasp-lang.dev/installer.sh | sh -s + curl -sSL https://get.wasp-lang.dev/installer.sh | sh -s -- -v 0.12.4 ``` 1. Make sure to **backup or save your project** before starting the procedure (e.g., by committing it to source control or creating a copy). diff --git a/web/docs/project/customizing-app.md b/web/docs/project/customizing-app.md index b3f18ff22c..1d569a4329 100644 --- a/web/docs/project/customizing-app.md +++ b/web/docs/project/customizing-app.md @@ -9,7 +9,7 @@ Each Wasp project can have only one `app` type declaration. It is used to config ```wasp app todoApp { wasp: { - version: "^0.12.0" + version: "^0.13.0" }, title: "ToDo App", head: [ @@ -27,7 +27,7 @@ You may want to change the title of your app, which appears in the browser tab, ```wasp app myApp { wasp: { - version: "^0.12.0" + version: "^0.13.0" }, title: "BookFace" } @@ -42,7 +42,7 @@ An example of adding extra style sheets and scripts: ```wasp app myApp { wasp: { - version: "^0.12.0" + version: "^0.13.0" }, title: "My App", head: [ // optional @@ -58,7 +58,7 @@ app myApp { ```wasp app todoApp { wasp: { - version: "^0.12.0" + version: "^0.13.0" }, title: "ToDo App", head: [ diff --git a/web/docs/tutorial/02-project-structure.md b/web/docs/tutorial/02-project-structure.md index 3def533f67..1355f783f3 100644 --- a/web/docs/tutorial/02-project-structure.md +++ b/web/docs/tutorial/02-project-structure.md @@ -67,7 +67,7 @@ The default `main.wasp` file generated with `wasp new` on the previous page look ```wasp title="main.wasp" app TodoApp { wasp: { - version: "^0.12.0" // Pins the version of Wasp to use. + version: "^0.13.0" // Pins the version of Wasp to use. }, title: "TodoApp" // Used as the browser tab title. Note that all strings in Wasp are double quoted! } @@ -87,7 +87,7 @@ page MainPage { ```wasp title="main.wasp" app TodoApp { wasp: { - version: "^0.12.0" // Pins the version of Wasp to use. + version: "^0.13.0" // Pins the version of Wasp to use. }, title: "TodoApp" // Used as the browser tab title. Note that all strings in Wasp are double quoted! } diff --git a/web/docs/tutorial/03-pages.md b/web/docs/tutorial/03-pages.md index e5295410bb..8fb2377e5a 100644 --- a/web/docs/tutorial/03-pages.md +++ b/web/docs/tutorial/03-pages.md @@ -190,7 +190,7 @@ Your Wasp file should now look like this: ```wasp title="main.wasp" app TodoApp { wasp: { - version: "^0.12.0" + version: "^0.13.0" }, title: "TodoApp" } @@ -207,7 +207,7 @@ page MainPage { ```wasp title="main.wasp" app TodoApp { wasp: { - version: "^0.12.0" + version: "^0.13.0" }, title: "TodoApp" } diff --git a/web/docs/tutorial/07-auth.md b/web/docs/tutorial/07-auth.md index 1dafdaa371..05597ca3ea 100644 --- a/web/docs/tutorial/07-auth.md +++ b/web/docs/tutorial/07-auth.md @@ -38,7 +38,7 @@ Next, tell Wasp to use full-stack [authentication](../auth/overview): ```wasp title="main.wasp" app TodoApp { wasp: { - version: "^0.12.0" + version: "^0.13.0" }, title: "TodoApp", // highlight-start From 63012827b098275581ff46f698835fdbfa9cf319 Mon Sep 17 00:00:00 2001 From: Mihovil Ilakovac Date: Mon, 18 Mar 2024 23:51:27 +0100 Subject: [PATCH 12/20] Updates Mage client Fly config Signed-off-by: Mihovil Ilakovac --- mage/fly-client.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mage/fly-client.toml b/mage/fly-client.toml index de608846ac..c2e024dd38 100644 --- a/mage/fly-client.toml +++ b/mage/fly-client.toml @@ -9,6 +9,6 @@ primary_region = "mad" [http_service] internal_port = 8043 force_https = true - auto_stop_machines = true - auto_start_machines = true - min_machines_running = 0 + auto_stop_machines = false + auto_start_machines = false + min_machines_running = 1 From f6d4a8dcf8643368ac4ea91fd006a959938e7a44 Mon Sep 17 00:00:00 2001 From: Mihovil Ilakovac Date: Tue, 19 Mar 2024 16:43:33 +0100 Subject: [PATCH 13/20] Updates Mage to use 0.13.0 (#1906) --- mage/Dockerfile | 2 +- mage/main.wasp | 2 +- mage/package-lock.json | 102 ---------------------------------------- mage/src/server/auth.ts | 16 +++---- 4 files changed, 8 insertions(+), 114 deletions(-) diff --git a/mage/Dockerfile b/mage/Dockerfile index 346d918dc8..4d04e149d1 100644 --- a/mage/Dockerfile +++ b/mage/Dockerfile @@ -41,7 +41,7 @@ RUN cd .wasp/build/server && npm run bundle # TODO: Use pm2? # TODO: Use non-root user (node). FROM base AS server-production -RUN curl -sSL https://get.wasp-lang.dev/installer.sh | sh -s -- -v 0.12.3 +RUN curl -sSL https://get.wasp-lang.dev/installer.sh | sh -s -- -v 0.13.0 ENV PATH "$PATH:/root/.local/bin" ENV NODE_ENV production WORKDIR /app diff --git a/mage/main.wasp b/mage/main.wasp index 9abc89f413..719ea822ce 100644 --- a/mage/main.wasp +++ b/mage/main.wasp @@ -1,6 +1,6 @@ app waspAi { wasp: { - version: "^0.12.2" + version: "^0.13.0" }, title: "MAGE - GPT Web App Generator ✨", head: [ diff --git a/mage/package-lock.json b/mage/package-lock.json index c8cd0cae48..a3e617e6e8 100644 --- a/mage/package-lock.json +++ b/mage/package-lock.json @@ -50,7 +50,6 @@ "axios": "^1.4.0", "express": "~4.18.1", "jsdom": "^21.1.1", - "jsonwebtoken": "^8.5.1", "lodash.merge": "^4.6.2", "lucia": "^3.0.1", "mitt": "3.0.0", @@ -2826,11 +2825,6 @@ "ieee754": "^1.1.13" } }, - "node_modules/buffer-equal-constant-time": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", - "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==" - }, "node_modules/buffer-writer": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-2.0.0.tgz", @@ -3489,14 +3483,6 @@ "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" }, - "node_modules/ecdsa-sig-formatter": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", - "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", - "dependencies": { - "safe-buffer": "^5.0.1" - } - }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -4870,51 +4856,6 @@ "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.1.tgz", "integrity": "sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA==" }, - "node_modules/jsonwebtoken": { - "version": "8.5.1", - "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", - "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==", - "dependencies": { - "jws": "^3.2.2", - "lodash.includes": "^4.3.0", - "lodash.isboolean": "^3.0.3", - "lodash.isinteger": "^4.0.4", - "lodash.isnumber": "^3.0.3", - "lodash.isplainobject": "^4.0.6", - "lodash.isstring": "^4.0.1", - "lodash.once": "^4.0.0", - "ms": "^2.1.1", - "semver": "^5.6.0" - }, - "engines": { - "node": ">=4", - "npm": ">=1.4.28" - } - }, - "node_modules/jsonwebtoken/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - }, - "node_modules/jwa": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", - "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", - "dependencies": { - "buffer-equal-constant-time": "1.0.1", - "ecdsa-sig-formatter": "1.0.11", - "safe-buffer": "^5.0.1" - } - }, - "node_modules/jws": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", - "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", - "dependencies": { - "jwa": "^1.4.1", - "safe-buffer": "^5.0.1" - } - }, "node_modules/lilconfig": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", @@ -4953,46 +4894,11 @@ "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" }, - "node_modules/lodash.includes": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", - "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==" - }, - "node_modules/lodash.isboolean": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", - "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==" - }, - "node_modules/lodash.isinteger": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", - "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==" - }, - "node_modules/lodash.isnumber": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", - "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==" - }, - "node_modules/lodash.isplainobject": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==" - }, - "node_modules/lodash.isstring": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", - "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==" - }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" }, - "node_modules/lodash.once": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", - "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==" - }, "node_modules/log-symbols": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", @@ -7031,14 +6937,6 @@ "loose-envify": "^1.1.0" } }, - "node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "bin": { - "semver": "bin/semver" - } - }, "node_modules/send": { "version": "0.18.0", "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", diff --git a/mage/src/server/auth.ts b/mage/src/server/auth.ts index 42800d27cf..fdecd1dbdf 100644 --- a/mage/src/server/auth.ts +++ b/mage/src/server/auth.ts @@ -1,29 +1,25 @@ import { defineUserSignupFields } from 'wasp/server/auth' export const googleUserSignupFields = defineUserSignupFields({ - email: async (data) => (data.profile as any)?.emails?.[0]?.value, - username: async (data) => (data.profile as any)?.emails?.[0]?.value, + email: async (data: any) => data.profile.email, + username: async (data: any) => data.profile?.email, }); export const getGoogleAuthConfig = () => { return { - clientID: process.env.GOOGLE_CLIENT_ID, - clientSecret: process.env.GOOGLE_CLIENT_SECRET, - scope: ["profile", "email"], + scopes: ["profile", "email"], }; }; // NOTE: if we don't want to access users' emails, we can use scope ["user:read"] // instead of ["user"] and access data.profile.username instead export const gitHubUserSignupFields = defineUserSignupFields({ - email: async (data) => (data.profile as any)?.emails?.[0]?.value, - username: async (data) => (data.profile as any)?.username, + email: async (data: any) => data.profile.email, + username: async (data: any) => data.profile.login, }) export function getGitHubAuthConfig() { return { - clientID: process.env.GITHUB_CLIENT_ID, // look up from env or elsewhere - clientSecret: process.env.GITHUB_CLIENT_SECRET, // look up from env or elsewhere - scope: ["user"], + scopes: ["user"], }; } From f255fb834c97a39f3ccaf28d5930fc56394504ad Mon Sep 17 00:00:00 2001 From: Mihovil Ilakovac Date: Tue, 19 Mar 2024 16:44:13 +0100 Subject: [PATCH 14/20] Adds versioned 0.13.0 docs (#1907) --- web/docs/_sendingEmailsInDevelopment.md | 7 - .../_sendingEmailsInDevelopment.md | 7 - .../advanced/accessing-app-config.md | 60 + .../version-0.13.0/advanced/apis.md | 343 ++++ .../deployment/DeploymentOptionsGrid.css | 29 + .../deployment/DeploymentOptionsGrid.tsx | 50 + .../_addExternalAuthEnvVarsReminder.md | 3 + .../deployment/_building-the-web-client.md | 13 + .../version-0.13.0/advanced/deployment/cli.md | 253 +++ .../advanced/deployment/manually.md | 586 +++++++ .../advanced/deployment/overview.md | 44 + .../advanced/email/_dummy-provider-note.md | 4 + .../version-0.13.0/advanced/email/email.md | 401 +++++ .../version-0.13.0/advanced/jobs.md | 425 +++++ .../version-0.13.0/advanced/links.md | 134 ++ .../advanced/middleware-config.md | 279 ++++ .../version-0.13.0/advanced/web-sockets.md | 337 ++++ .../version-0.13.0/auth/Pills.css | 17 + .../version-0.13.0/auth/Pills.jsx | 86 ++ .../auth/_multiple-identities-warning.md | 6 + .../auth/_read-more-about-auth-entities.md | 1 + .../version-0.13.0/auth/_user-fields.md | 8 + .../auth/_user-signup-fields-explainer.md | 38 + .../version-0.13.0/auth/email.md | 1119 ++++++++++++++ .../auth/entities/_get-email.md | 47 + .../auth/entities/_get-username.md | 47 + .../version-0.13.0/auth/entities/entities.md | 448 ++++++ .../version-0.13.0/auth/overview.md | 1195 ++++++++++++++ .../auth/social-auth/SocialAuthGrid.css | 29 + .../auth/social-auth/SocialAuthGrid.tsx | 58 + .../auth/social-auth/_api-reference-intro.md | 10 + .../auth/social-auth/_default-behaviour.md | 3 + .../auth/social-auth/_getuserfields-type.md | 3 + .../social-auth/_override-example-intro.md | 10 + .../auth/social-auth/_override-intro.md | 10 + .../auth/social-auth/_using-auth-note.md | 3 + .../social-auth/_wasp-file-structure-note.md | 15 + .../version-0.13.0/auth/social-auth/github.md | 562 +++++++ .../version-0.13.0/auth/social-auth/google.md | 588 +++++++ .../auth/social-auth/keycloak.md | 547 +++++++ .../auth/social-auth/overview.md | 355 +++++ web/versioned_docs/version-0.13.0/auth/ui.md | 616 ++++++++ .../version-0.13.0/auth/username-and-pass.md | 723 +++++++++ web/versioned_docs/version-0.13.0/contact.md | 5 + .../version-0.13.0/contributing.md | 19 + .../version-0.13.0/data-model/backends.md | 486 ++++++ .../version-0.13.0/data-model/crud.md | 745 +++++++++ .../version-0.13.0/data-model/entities.md | 105 ++ .../data-model/operations/_superjson-note.md | 14 + .../data-model/operations/actions.md | 833 ++++++++++ .../data-model/operations/overview.md | 12 + .../data-model/operations/queries.md | 648 ++++++++ .../version-0.13.0/general/cli.md | 188 +++ .../version-0.13.0/general/language.md | 88 ++ .../introduction/editor-setup.md | 23 + .../introduction/introduction.md | 203 +++ .../introduction/quick-start.md | 150 ++ .../migrate-from-0-11-to-0-12.md | 1375 +++++++++++++++++ .../migrate-from-0-12-to-0-13.md | 134 ++ .../version-0.13.0/project/_baseDirEnvNote.md | 6 + .../version-0.13.0/project/client-config.md | 449 ++++++ .../version-0.13.0/project/css-frameworks.md | 110 ++ .../project/custom-vite-config.md | 122 ++ .../version-0.13.0/project/customizing-app.md | 133 ++ .../version-0.13.0/project/dependencies.md | 30 + .../version-0.13.0/project/env-vars.md | 134 ++ .../version-0.13.0/project/server-config.md | 251 +++ .../project/starter-templates.md | 89 ++ .../version-0.13.0/project/static-assets.md | 67 + .../version-0.13.0/project/testing.md | 385 +++++ .../version-0.13.0/telemetry.md | 59 + .../version-0.13.0/tutorial/01-create.md | 53 + .../tutorial/02-project-structure.md | 126 ++ .../version-0.13.0/tutorial/03-pages.md | 228 +++ .../version-0.13.0/tutorial/04-entities.md | 48 + .../version-0.13.0/tutorial/05-queries.md | 248 +++ .../version-0.13.0/tutorial/06-actions.md | 462 ++++++ .../version-0.13.0/tutorial/07-auth.md | 547 +++++++ web/versioned_docs/version-0.13.0/vision.md | 30 + .../wasp-ai/creating-new-app.md | 47 + .../wasp-ai/developing-existing-app.md | 9 + .../version-0.13.0/wasp-ai/wasp-ai-1.png | Bin 0 -> 314644 bytes .../version-0.13.0/wasp-ai/wasp-ai-2.png | Bin 0 -> 304752 bytes .../version-0.13.0/writingguide.md | 157 ++ .../version-0.13.0-sidebars.json | 152 ++ web/versions.json | 1 + 86 files changed, 18476 insertions(+), 14 deletions(-) delete mode 100644 web/docs/_sendingEmailsInDevelopment.md delete mode 100644 web/versioned_docs/version-0.12.0/_sendingEmailsInDevelopment.md create mode 100644 web/versioned_docs/version-0.13.0/advanced/accessing-app-config.md create mode 100644 web/versioned_docs/version-0.13.0/advanced/apis.md create mode 100644 web/versioned_docs/version-0.13.0/advanced/deployment/DeploymentOptionsGrid.css create mode 100644 web/versioned_docs/version-0.13.0/advanced/deployment/DeploymentOptionsGrid.tsx create mode 100644 web/versioned_docs/version-0.13.0/advanced/deployment/_addExternalAuthEnvVarsReminder.md create mode 100644 web/versioned_docs/version-0.13.0/advanced/deployment/_building-the-web-client.md create mode 100644 web/versioned_docs/version-0.13.0/advanced/deployment/cli.md create mode 100644 web/versioned_docs/version-0.13.0/advanced/deployment/manually.md create mode 100644 web/versioned_docs/version-0.13.0/advanced/deployment/overview.md create mode 100644 web/versioned_docs/version-0.13.0/advanced/email/_dummy-provider-note.md create mode 100644 web/versioned_docs/version-0.13.0/advanced/email/email.md create mode 100644 web/versioned_docs/version-0.13.0/advanced/jobs.md create mode 100644 web/versioned_docs/version-0.13.0/advanced/links.md create mode 100644 web/versioned_docs/version-0.13.0/advanced/middleware-config.md create mode 100644 web/versioned_docs/version-0.13.0/advanced/web-sockets.md create mode 100644 web/versioned_docs/version-0.13.0/auth/Pills.css create mode 100644 web/versioned_docs/version-0.13.0/auth/Pills.jsx create mode 100644 web/versioned_docs/version-0.13.0/auth/_multiple-identities-warning.md create mode 100644 web/versioned_docs/version-0.13.0/auth/_read-more-about-auth-entities.md create mode 100644 web/versioned_docs/version-0.13.0/auth/_user-fields.md create mode 100644 web/versioned_docs/version-0.13.0/auth/_user-signup-fields-explainer.md create mode 100644 web/versioned_docs/version-0.13.0/auth/email.md create mode 100644 web/versioned_docs/version-0.13.0/auth/entities/_get-email.md create mode 100644 web/versioned_docs/version-0.13.0/auth/entities/_get-username.md create mode 100644 web/versioned_docs/version-0.13.0/auth/entities/entities.md create mode 100644 web/versioned_docs/version-0.13.0/auth/overview.md create mode 100644 web/versioned_docs/version-0.13.0/auth/social-auth/SocialAuthGrid.css create mode 100644 web/versioned_docs/version-0.13.0/auth/social-auth/SocialAuthGrid.tsx create mode 100644 web/versioned_docs/version-0.13.0/auth/social-auth/_api-reference-intro.md create mode 100644 web/versioned_docs/version-0.13.0/auth/social-auth/_default-behaviour.md create mode 100644 web/versioned_docs/version-0.13.0/auth/social-auth/_getuserfields-type.md create mode 100644 web/versioned_docs/version-0.13.0/auth/social-auth/_override-example-intro.md create mode 100644 web/versioned_docs/version-0.13.0/auth/social-auth/_override-intro.md create mode 100644 web/versioned_docs/version-0.13.0/auth/social-auth/_using-auth-note.md create mode 100644 web/versioned_docs/version-0.13.0/auth/social-auth/_wasp-file-structure-note.md create mode 100644 web/versioned_docs/version-0.13.0/auth/social-auth/github.md create mode 100644 web/versioned_docs/version-0.13.0/auth/social-auth/google.md create mode 100644 web/versioned_docs/version-0.13.0/auth/social-auth/keycloak.md create mode 100644 web/versioned_docs/version-0.13.0/auth/social-auth/overview.md create mode 100644 web/versioned_docs/version-0.13.0/auth/ui.md create mode 100644 web/versioned_docs/version-0.13.0/auth/username-and-pass.md create mode 100644 web/versioned_docs/version-0.13.0/contact.md create mode 100644 web/versioned_docs/version-0.13.0/contributing.md create mode 100644 web/versioned_docs/version-0.13.0/data-model/backends.md create mode 100644 web/versioned_docs/version-0.13.0/data-model/crud.md create mode 100644 web/versioned_docs/version-0.13.0/data-model/entities.md create mode 100644 web/versioned_docs/version-0.13.0/data-model/operations/_superjson-note.md create mode 100644 web/versioned_docs/version-0.13.0/data-model/operations/actions.md create mode 100644 web/versioned_docs/version-0.13.0/data-model/operations/overview.md create mode 100644 web/versioned_docs/version-0.13.0/data-model/operations/queries.md create mode 100644 web/versioned_docs/version-0.13.0/general/cli.md create mode 100644 web/versioned_docs/version-0.13.0/general/language.md create mode 100644 web/versioned_docs/version-0.13.0/introduction/editor-setup.md create mode 100644 web/versioned_docs/version-0.13.0/introduction/introduction.md create mode 100644 web/versioned_docs/version-0.13.0/introduction/quick-start.md create mode 100644 web/versioned_docs/version-0.13.0/migrate-from-0-11-to-0-12.md create mode 100644 web/versioned_docs/version-0.13.0/migrate-from-0-12-to-0-13.md create mode 100644 web/versioned_docs/version-0.13.0/project/_baseDirEnvNote.md create mode 100644 web/versioned_docs/version-0.13.0/project/client-config.md create mode 100644 web/versioned_docs/version-0.13.0/project/css-frameworks.md create mode 100644 web/versioned_docs/version-0.13.0/project/custom-vite-config.md create mode 100644 web/versioned_docs/version-0.13.0/project/customizing-app.md create mode 100644 web/versioned_docs/version-0.13.0/project/dependencies.md create mode 100644 web/versioned_docs/version-0.13.0/project/env-vars.md create mode 100644 web/versioned_docs/version-0.13.0/project/server-config.md create mode 100644 web/versioned_docs/version-0.13.0/project/starter-templates.md create mode 100644 web/versioned_docs/version-0.13.0/project/static-assets.md create mode 100644 web/versioned_docs/version-0.13.0/project/testing.md create mode 100644 web/versioned_docs/version-0.13.0/telemetry.md create mode 100644 web/versioned_docs/version-0.13.0/tutorial/01-create.md create mode 100644 web/versioned_docs/version-0.13.0/tutorial/02-project-structure.md create mode 100644 web/versioned_docs/version-0.13.0/tutorial/03-pages.md create mode 100644 web/versioned_docs/version-0.13.0/tutorial/04-entities.md create mode 100644 web/versioned_docs/version-0.13.0/tutorial/05-queries.md create mode 100644 web/versioned_docs/version-0.13.0/tutorial/06-actions.md create mode 100644 web/versioned_docs/version-0.13.0/tutorial/07-auth.md create mode 100644 web/versioned_docs/version-0.13.0/vision.md create mode 100644 web/versioned_docs/version-0.13.0/wasp-ai/creating-new-app.md create mode 100644 web/versioned_docs/version-0.13.0/wasp-ai/developing-existing-app.md create mode 100644 web/versioned_docs/version-0.13.0/wasp-ai/wasp-ai-1.png create mode 100644 web/versioned_docs/version-0.13.0/wasp-ai/wasp-ai-2.png create mode 100644 web/versioned_docs/version-0.13.0/writingguide.md create mode 100644 web/versioned_sidebars/version-0.13.0-sidebars.json diff --git a/web/docs/_sendingEmailsInDevelopment.md b/web/docs/_sendingEmailsInDevelopment.md deleted file mode 100644 index e0917d5cbb..0000000000 --- a/web/docs/_sendingEmailsInDevelopment.md +++ /dev/null @@ -1,7 +0,0 @@ -:::info Sending emails while developing - -When you run your app in development mode, the emails are not sent. Instead, they are logged to the console. - -To enable sending emails in development mode, you need to set the `SEND_EMAILS_IN_DEVELOPMENT` env variable to `true` in your `.env.server` file. - -::: diff --git a/web/versioned_docs/version-0.12.0/_sendingEmailsInDevelopment.md b/web/versioned_docs/version-0.12.0/_sendingEmailsInDevelopment.md deleted file mode 100644 index e0917d5cbb..0000000000 --- a/web/versioned_docs/version-0.12.0/_sendingEmailsInDevelopment.md +++ /dev/null @@ -1,7 +0,0 @@ -:::info Sending emails while developing - -When you run your app in development mode, the emails are not sent. Instead, they are logged to the console. - -To enable sending emails in development mode, you need to set the `SEND_EMAILS_IN_DEVELOPMENT` env variable to `true` in your `.env.server` file. - -::: diff --git a/web/versioned_docs/version-0.13.0/advanced/accessing-app-config.md b/web/versioned_docs/version-0.13.0/advanced/accessing-app-config.md new file mode 100644 index 0000000000..1a79ab327e --- /dev/null +++ b/web/versioned_docs/version-0.13.0/advanced/accessing-app-config.md @@ -0,0 +1,60 @@ +--- +title: Accessing the configuration +--- + +Whenever you start a Wasp app, you are starting two processes. + - **The client process** - A React app that implements your app's frontend. + + During development, this is a dev server with hot reloading. In production, + it's a simple process that serves pre-built static files with environment variables + embedded during the build (details depend on [how you deploy + it](/docs/advanced/deployment/overview)). + + - **The server process** - An Express server that implements your app's backend. + + During development, this is an Express server controlled by a + [`nodemon`](https://www.npmjs.com/package/nodemon) process that takes care of + hot reloading and restarts. In production, it's a regular Express server run + using Node. + +Check [the introduction](/docs) for a more in-depth explanation of Wasp's runtime architecture. + +You can configure both processes through environment variables. See [the +deployment instructions](/docs/advanced/deployment/manually#environment-variables) for a full list +of supported variables. + +Wasp gives you runtime access to the processes' configurations through **configuration objects**. + +## Server configuration object + +The server configuration object contains these fields: + +- `frontendUrl: String` - Set it with env var `WASP_WEB_CLIENT_URL`. + + The URL of your client (the app's frontend).
+ Wasp automatically sets it during development when you run `wasp start`.
+ In production, you should set it to your client's URL as the server sees it + (i.e., with the DNS and proxies considered). + +You can access it like this: +```js +import { config } from 'wasp/server' + +console.log(config.frontendUrl) +``` + +## Client configuration object +The client configuration object contains these fields: +- `apiUrl: String` - Set it with env var `REACT_APP_API_URL` + + The URL of your server (the app's backend).
+ Wasp automatically sets it during development when you run `wasp start`.
+ In production, it should contain the value of your server's URL as the user's browser + sees it (i.e., with the DNS and proxies considered). + +You can access it like this: +```js +import { config } from 'wasp/client' + +console.log(config.apiUrl) +``` diff --git a/web/versioned_docs/version-0.13.0/advanced/apis.md b/web/versioned_docs/version-0.13.0/advanced/apis.md new file mode 100644 index 0000000000..4468829404 --- /dev/null +++ b/web/versioned_docs/version-0.13.0/advanced/apis.md @@ -0,0 +1,343 @@ +--- +title: Custom HTTP API Endpoints +--- + +import { ShowForTs, ShowForJs } from '@site/src/components/TsJsHelpers' +import { Required } from '@site/src/components/Tag' + +In Wasp, the default client-server interaction mechanism is through [Operations](../data-model/operations/overview). However, if you need a specific URL method/path, or a specific response, Operations may not be suitable for you. For these cases, you can use an `api`. Best of all, they should look and feel very familiar. + +## How to Create an API + +APIs are used to tie a JS function to a certain endpoint e.g. `POST /something/special`. They are distinct from Operations and have no client-side helpers (like `useQuery`). + +To create a Wasp API, you must: + +1. Declare the API in Wasp using the `api` declaration +2. Define the API's NodeJS implementation + +After completing these two steps, you'll be able to call the API from the client code (via our `Axios` wrapper), or from the outside world. + +### Declaring the API in Wasp + +First, we need to declare the API in the Wasp file and you can easily do this with the `api` declaration: + + + + +```wasp title="main.wasp" +// ... + +api fooBar { // APIs and their implementations don't need to (but can) have the same name. + fn: import { fooBar } from "@src/apis", + httpRoute: (GET, "/foo/bar") +} +``` + + + +```wasp title="main.wasp" +// ... + +api fooBar { // APIs and their implementations don't need to (but can) have the same name. + fn: import { fooBar } from "@src/apis", + httpRoute: (GET, "/foo/bar") +} +``` + + + +Read more about the supported fields in the [API Reference](#api-reference). + + +### Defining the API's NodeJS Implementation + + + +:::note +To make sure the Wasp compiler generates the types for APIs for use in the NodeJS implementation, you should add your `api` declarations to your `.wasp` file first _and_ keep the `wasp start` command running. +::: + + +After you defined the API, it should be implemented as a NodeJS function that takes three arguments: + +1. `req`: Express Request object +2. `res`: Express Response object +3. `context`: An additional context object **injected into the API by Wasp**. This object contains user session information, as well as information about entities. The examples here won't use the context for simplicity purposes. You can read more about it in the [section about using entities in APIs](#using-entities-in-apis). + + + + +```ts title="src/apis.js" +export const fooBar = (req, res, context) => { + res.set("Access-Control-Allow-Origin", "*"); // Example of modifying headers to override Wasp default CORS middleware. + res.json({ msg: `Hello, ${context.user ? "registered user" : "stranger"}!` }); +}; +``` + + + + +```ts title="src/apis.ts" +import { FooBar } from "wasp/server/api"; // This type is generated by Wasp based on the `api` declaration above. + +export const fooBar: FooBar = (req, res, context) => { + res.set("Access-Control-Allow-Origin", "*"); // Example of modifying headers to override Wasp default CORS middleware. + res.json({ msg: `Hello, ${context.user ? "registered user" : "stranger"}!` }); +}; +``` + + + + + + +#### Providing Extra Type Information + +We'll see how we can provide extra type information to an API function. + +Let's say you wanted to create some `GET` route that would take an email address as a param, and provide them the answer to "Life, the Universe and Everything." 😀 What would this look like in TypeScript? + +Define the API in Wasp: + +```wasp title="main.wasp" +api fooBar { + fn: import { fooBar } from "@src/apis", + entities: [Task], + httpRoute: (GET, "/foo/bar/:email") +} +``` + +We can use the `FooBar` type to which we'll provide the generic **params** and **response** types, which then gives us full type safety in the implementation. + +```ts title="src/apis.ts" +import { FooBar } from "wasp/server/api"; + +export const fooBar: FooBar< + { email: string }, // params + { answer: number } // response +> = (req, res, _context) => { + console.log(req.params.email); + res.json({ answer: 42 }); +}; +``` + + + +## Using the API + +### Using the API externally + +To use the API externally, you simply call the endpoint using the method and path you used. + +For example, if your app is running at `https://example.com` then from the above you could issue a `GET` to `https://example/com/foo/callback` (in your browser, Postman, `curl`, another web service, etc.). + +### Using the API from the Client + +To use the API from your client, including with auth support, you can import the Axios wrapper from `wasp/client/api` and invoke a call. For example: + + + + +```jsx title="src/pages/SomePage.jsx" +import React, { useEffect } from "react"; +import { api } from "wasp/client/api"; + +async function fetchCustomRoute() { + const res = await api.get("/foo/bar"); + console.log(res.data); +} + +export const Foo = () => { + useEffect(() => { + fetchCustomRoute(); + }, []); + + return <>// ...; +}; +``` + + + +```tsx title="src/pages/SomePage.tsx" +import React, { useEffect } from "react"; +import { api } from "wasp/client/api"; + +async function fetchCustomRoute() { + const res = await api.get("/foo/bar"); + console.log(res.data); +} + +export const Foo = () => { + useEffect(() => { + fetchCustomRoute(); + }, []); + + return <>// ...; +}; +``` + + + +#### Making Sure CORS Works + +APIs are designed to be as flexible as possible, hence they don't utilize the default middleware like Operations do. As a result, to use these APIs on the client side, you must ensure that CORS (Cross-Origin Resource Sharing) is enabled. + +You can do this by defining custom middleware for your APIs in the Wasp file. + + + + +For example, an `apiNamespace` is a simple declaration used to apply some `middlewareConfigFn` to all APIs under some specific path: + +```wasp title="main.wasp" +apiNamespace fooBar { + middlewareConfigFn: import { fooBarNamespaceMiddlewareFn } from "@src/apis", + path: "/foo" +} +``` + +And then in the implementation file: + +```js title="src/apis.js" +export const apiMiddleware = (config) => { + return config; +}; +``` + + + + +For example, an `apiNamespace` is a simple declaration used to apply some `middlewareConfigFn` to all APIs under some specific path: + +```wasp title="main.wasp" +apiNamespace fooBar { + middlewareConfigFn: import { fooBarNamespaceMiddlewareFn } from "@src/apis", + path: "/foo" +} +``` + +And then in the implementation file (returning the default config): + +```ts title="src/apis.ts" +import { MiddlewareConfigFn } from "wasp/server"; +export const apiMiddleware: MiddlewareConfigFn = (config) => { + return config; +}; +``` + + + + +We are returning the default middleware which enables CORS for all APIs under the `/foo` path. + +For more information about middleware configuration, please see: [Middleware Configuration](../advanced/middleware-config) + +## Using Entities in APIs + +In many cases, resources used in APIs will be [Entities](../data-model/entities.md). +To use an Entity in your API, add it to the `api` declaration in Wasp: + + + + +```wasp {3} title="main.wasp" +api fooBar { + fn: import { fooBar } from "@src/apis", + entities: [Task], + httpRoute: (GET, "/foo/bar") +} +``` + + + +```wasp {3} title="main.wasp" +api fooBar { + fn: import { fooBar } from "@src/apis", + entities: [Task], + httpRoute: (GET, "/foo/bar") +} +``` + + + +Wasp will inject the specified Entity into the APIs `context` argument, giving you access to the Entity's Prisma API: + + + + +```ts title="src/apis.js" +export const fooBar = (req, res, context) => { + res.json({ count: await context.entities.Task.count() }); +}; +``` + + + + +```ts title="src/apis.ts" +import { FooBar } from "wasp/server/api"; + +export const fooBar: FooBar = (req, res, context) => { + res.json({ count: await context.entities.Task.count() }); +}; +``` + + + + +The object `context.entities.Task` exposes `prisma.task` from [Prisma's CRUD API](https://www.prisma.io/docs/reference/tools-and-interfaces/prisma-client/crud). + +## API Reference + + + + +```wasp title="main.wasp" +api fooBar { + fn: import { fooBar } from "@src/apis", + httpRoute: (GET, "/foo/bar"), + entities: [Task], + auth: true, + middlewareConfigFn: import { apiMiddleware } from "@src/apis" +} +``` + + + +```wasp title="main.wasp" +api fooBar { + fn: import { fooBar } from "@src/apis", + httpRoute: (GET, "/foo/bar"), + entities: [Task], + auth: true, + middlewareConfigFn: import { apiMiddleware } from "@src/apis" +} +``` + + + +The `api` declaration has the following fields: + +- `fn: ExtImport` + + The import statement of the APIs NodeJs implementation. + +- `httpRoute: (HttpMethod, string)` + + The HTTP (method, path) pair, where the method can be one of: + + - `ALL`, `GET`, `POST`, `PUT` or `DELETE` + - and path is an Express path `string`. + +- `entities: [Entity]` + + A list of entities you wish to use inside your API. You can read more about it [here](#using-entities-in-apis). + +- `auth: bool` + + If auth is enabled, this will default to `true` and provide a `context.user` object. If you do not wish to attempt to parse the JWT in the Authorization Header, you should set this to `false`. + +- `middlewareConfigFn: ExtImport` + + The import statement to an Express middleware config function for this API. See more in [middleware section](../advanced/middleware-config) of the docs. diff --git a/web/versioned_docs/version-0.13.0/advanced/deployment/DeploymentOptionsGrid.css b/web/versioned_docs/version-0.13.0/advanced/deployment/DeploymentOptionsGrid.css new file mode 100644 index 0000000000..8c0f1cf0ce --- /dev/null +++ b/web/versioned_docs/version-0.13.0/advanced/deployment/DeploymentOptionsGrid.css @@ -0,0 +1,29 @@ +.deployment-methods-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); + grid-gap: 0.5rem; + margin-bottom: 1rem; +} +.deployment-method-box { + display: flex; + flex-direction: column; + justify-content: center; + border: 1px solid var(--ifm-color-emphasis-300); + border-radius: var(--ifm-pagination-nav-border-radius); + padding: 1.5rem; + transition: all 0.1s ease-in-out; +} +.deployment-method-box:hover { + border-color: var(--ifm-pagination-nav-color-hover); +} +.deployment-method-box h3 { + margin: 0; + color: var(--ifm-link-color); +} +.deployment-method-box p { + margin: 0; + color: var(--ifm-color-secondary-contrast-foreground); +} +.deployment-methods-info { + color: var(--ifm-color-secondary-contrast-foreground); +} diff --git a/web/versioned_docs/version-0.13.0/advanced/deployment/DeploymentOptionsGrid.tsx b/web/versioned_docs/version-0.13.0/advanced/deployment/DeploymentOptionsGrid.tsx new file mode 100644 index 0000000000..e29452acfe --- /dev/null +++ b/web/versioned_docs/version-0.13.0/advanced/deployment/DeploymentOptionsGrid.tsx @@ -0,0 +1,50 @@ +import React from 'react' +import './DeploymentOptionsGrid.css' + +export function DeploymentOptionsGrid() { + const deploymentMethods = [ + { + title: 'Using Wasp CLI', + description: 'One command deployment & redeployment', + linkToDocs: '/docs/advanced/deployment/cli', + }, + { + title: 'Deploying Manually', + description: 'Build the app and deploy it manually', + linkToDocs: '/docs/advanced/deployment/manually', + }, + ] + return ( + <> +

+

+ Click on each deployment method for more details. +

+ + ) +} + +function DeploymentOptionBox({ + linkToDocs, + title, + description, +}: { + linkToDocs: string + title: string + description: string +}) { + return ( +
+

{title} »

+

{description}

+
+ ) +} diff --git a/web/versioned_docs/version-0.13.0/advanced/deployment/_addExternalAuthEnvVarsReminder.md b/web/versioned_docs/version-0.13.0/advanced/deployment/_addExternalAuthEnvVarsReminder.md new file mode 100644 index 0000000000..29c532d974 --- /dev/null +++ b/web/versioned_docs/version-0.13.0/advanced/deployment/_addExternalAuthEnvVarsReminder.md @@ -0,0 +1,3 @@ +:::tip Using an external auth method? +If your app is using an external authentication method(s) supported by Wasp (such as [Google](../../auth/social-auth/google#4-adding-environment-variables) or [GitHub](../../auth/social-auth/github#4-adding-environment-variables)), make sure to additionally set the necessary environment variables specifically required by these method(s). +::: diff --git a/web/versioned_docs/version-0.13.0/advanced/deployment/_building-the-web-client.md b/web/versioned_docs/version-0.13.0/advanced/deployment/_building-the-web-client.md new file mode 100644 index 0000000000..cd49d1b191 --- /dev/null +++ b/web/versioned_docs/version-0.13.0/advanced/deployment/_building-the-web-client.md @@ -0,0 +1,13 @@ +To build the web app, position yourself in `.wasp/build/web-app` directory: + +``` +cd .wasp/build/web-app +``` + +Run + +``` +npm install && REACT_APP_API_URL= npm run build +``` + +where `` is the URL of the Wasp server that you previously deployed. diff --git a/web/versioned_docs/version-0.13.0/advanced/deployment/cli.md b/web/versioned_docs/version-0.13.0/advanced/deployment/cli.md new file mode 100644 index 0000000000..03187804ed --- /dev/null +++ b/web/versioned_docs/version-0.13.0/advanced/deployment/cli.md @@ -0,0 +1,253 @@ +--- +title: Deploying with the Wasp CLI +--- + +import { Required } from '@site/src/components/Tag'; + +Wasp CLI can deploy your full-stack application with only a single command. +The command automates the manual deployment process and is the recommended way of deploying Wasp apps. + +## Supported Providers + +Wasp supports automated deployment to the following providers: + +- [Fly.io](#flyio) - they offer 5$ free credit each month +- Railway (coming soon, track it here [#1157](https://github.com/wasp-lang/wasp/pull/1157)) + +## Fly.io + +### Prerequisites + +Fly provides [free allowances](https://fly.io/docs/about/pricing/#plans) for up to 3 VMs (so deploying a Wasp app to a new account is free), but all plans require you to add your credit card information before you can proceed. If you don't, the deployment will fail. + +You can add the required credit card information on the [account's billing page](https://fly.io/dashboard/personal/billing). + +:::info Fly.io CLI +You will need the [`flyctl` CLI](https://fly.io/docs/hands-on/install-flyctl/) installed on your machine before you can deploy to Fly.io. +::: + +### Deploying + +Using the Wasp CLI, you can easily deploy a new app to [Fly.io](https://fly.io) with just a single command: + +```shell +wasp deploy fly launch my-wasp-app mia +``` + +:::caution Specifying Org +If your account is a member of more than one organization on Fly.io, you will need to specify under which one you want to execute the command. To do that, provide an additional `--org ` option. You can find out the names(slugs) of your organizations by running `fly orgs list`. +::: + + + +Please do not CTRL-C or exit your terminal while the commands are running. + + +Under the covers, this runs the equivalent of the following commands: + +```shell +wasp deploy fly setup my-wasp-app mia +wasp deploy fly create-db mia +wasp deploy fly deploy +``` + +The commands above use the app basename `my-wasp-app` and deploy it to the _Miami, Florida (US) region_ (called `mia`). Read more about Fly.io regions [here](#flyio-regions). + +:::caution Unique Name +Your app name must be unique across all of Fly or deployment will fail. +::: + +The basename is used to create all three app tiers, resulting in three separate apps in your Fly dashboard: + +- `my-wasp-app-client` +- `my-wasp-app-server` +- `my-wasp-app-db` + +You'll notice that Wasp creates two new files in your project root directory: +- `fly-server.toml` +- `fly-client.toml` + +You should include these files in your version control so that you can deploy your app with a single command in the future. + +### Using a Custom Domain For Your App + +Setting up a custom domain is a three-step process: + +1. You need to add your domain to your Fly client app. You can do this by running: + +```shell +wasp deploy fly cmd --context client certs create mycoolapp.com +``` + +:::note Use Your Domain +Make sure to replace `mycoolapp.com` with your domain in all of the commands mentioned in this section. +::: + +This command will output the instructions to add the DNS records to your domain. It will look something like this: + +```shell-session +You can direct traffic to mycoolapp.com by: + +1: Adding an A record to your DNS service which reads + + A @ 66.241.1XX.154 + +You can validate your ownership of mycoolapp.com by: + +2: Adding an AAAA record to your DNS service which reads: + + AAAA @ 2a09:82XX:1::1:ff40 +``` + +2. You need to add the DNS records for your domain: + + _This will depend on your domain provider, but it should be a matter of adding an A record for `@` and an AAAA record for `@` with the values provided by the previous command._ + +3. You need to set your domain as the `WASP_WEB_CLIENT_URL` environment variable for your server app: + +```shell +wasp deploy fly cmd --context server secrets set WASP_WEB_CLIENT_URL=https://mycoolapp.com +``` + + + +We need to do this to keep our CORS configuration up to date. + + +That's it, your app should be available at `https://mycoolapp.com`! 🎉 + +## API Reference + +### `launch` + +`launch` is a convenience command that runs `setup`, `create-db`, and `deploy` in sequence. + +```shell +wasp deploy fly launch +``` + +It accepts the following arguments: + +- `` - the name of your app +- `` - the region where your app will be deployed + + Read how to find the available regions [here](#flyio-regions). + +It gives you the same result as running the following commands: + +```shell +wasp deploy fly setup +wasp deploy fly create-db +wasp deploy fly deploy +``` + +#### Environment Variables + +If you are deploying an app that requires any other environment variables (like social auth secrets), you can set them with the `--server-secret` option: + +``` +wasp deploy fly launch my-wasp-app mia --server-secret GOOGLE_CLIENT_ID=<...> --server-secret GOOGLE_CLIENT_SECRET=<...> +``` + +### `setup` + +`setup` will create your client and server apps on Fly, and add some secrets, but does _not_ deploy them. + +```shell +wasp deploy fly setup +``` + +It accepts the following arguments: + +- `` - the name of your app +- `` - the region where your app will be deployed + + Read how to find the available regions [here](#flyio-regions). + +After running `setup`, Wasp creates two new files in your project root directory: `fly-server.toml` and `fly-client.toml`. +You should include these files in your version control. + +You **can edit the `fly-server.toml` and `fly-client.toml` files** to further configure your Fly deployments. Wasp will use the TOML files when you run `deploy`. + +If you want to maintain multiple apps, you can add the `--fly-toml-dir ` option to point to different directories, like "dev" or "staging". + +:::caution Execute Only Once +You should only run `setup` once per app. If you run it multiple times, it will create unnecessary apps on Fly. +::: + +### `create-db` + +`create-db` will create a new database for your app. + +```shell +wasp deploy fly create-db +``` + +It accepts the following arguments: + +- `` - the region where your app will be deployed + + Read how to find the available regions [here](#flyio-regions). + +:::caution Execute Only Once +You should only run `create-db` once per app. If you run it multiple times, it will create multiple databases, but your app needs only one. +::: + +### `deploy` + +```shell +wasp deploy fly deploy +``` + +`deploy` pushes your client and server live. + +Run this command whenever you want to **update your deployed app** with the latest changes: + +```shell +wasp deploy fly deploy +``` + +### `cmd` + +If want to run arbitrary Fly commands (e.g. `flyctl secrets list` for your server app), here's how to do it: + +```shell +wasp deploy fly cmd secrets list --context server +``` + +### Fly.io Regions + +> Fly.io runs applications physically close to users: in datacenters around the world, on servers we run ourselves. You can currently deploy your apps in 34 regions, connected to a global Anycast network that makes sure your users hit our nearest server, whether they’re in Tokyo, São Paolo, or Frankfurt. + + + +Read more on Fly regions [here](https://fly.io/docs/reference/regions/). + + +You can find the list of all available Fly regions by running: + +```shell +flyctl platform regions +``` + +#### Environment Variables + +If you are deploying an app that requires any other environment variables (like social auth secrets), you can set them with the `secrets set` command: + +``` +wasp deploy fly cmd secrets set GOOGLE_CLIENT_ID=<...> GOOGLE_CLIENT_SECRET=<...> --context=server +``` + +### Mutliple Fly Organizations + +If you have multiple organizations, you can specify a `--org` option. For example: + +```shell +wasp deploy fly launch my-wasp-app mia --org hive +``` + +### Building Locally + +Fly.io offers support for both **locally** built Docker containers and **remotely** built ones. However, for simplicity and reproducibility, the CLI defaults to the use of a remote Fly.io builder. + +If you want to build locally, supply the `--build-locally` option to `wasp deploy fly launch` or `wasp deploy fly deploy`. diff --git a/web/versioned_docs/version-0.13.0/advanced/deployment/manually.md b/web/versioned_docs/version-0.13.0/advanced/deployment/manually.md new file mode 100644 index 0000000000..95fdd3f9dd --- /dev/null +++ b/web/versioned_docs/version-0.13.0/advanced/deployment/manually.md @@ -0,0 +1,586 @@ +--- +title: Deploying Manually +--- + +import useBaseUrl from '@docusaurus/useBaseUrl'; +import AddExternalAuthEnvVarsReminder from './\_addExternalAuthEnvVarsReminder.md' +import BuildingTheWebClient from './\_building-the-web-client.md' +import { Required } from '@site/src/components/Tag' + +This document explains how to build and prepare your Wasp app for deployment. +You can then deploy the built Wasp app wherever and however you want, as long as your provider/server +supports Wasp's build format. + +After going through the general steps that apply to all deployments, you can +follow step-by-step guides for deploying your Wasp app to the most popular +providers: + +- [Fly.io](#flyio) +- [Netlify](#netlify) +- [Railway](#railway) +- [Heroku](#heroku) + +No worries, you can still deploy your app if your desired provider isn't on the +list - it just means we don't yet have a step-by-step guide for you to follow. +Feel free to [open a +PR](https://github.com/wasp-lang/wasp/edit/release/web/docs/advanced/deployment/manually.md) +if you'd like to write one yourself :) + + +## Deploying a Wasp App + +Deploying a Wasp app comes down to the following: + +1. Generating deployable code. +1. Deploying the API server (backend). +1. Deploying the web client (frontend). +1. Deploying a PostgreSQL database and keeping it running. + +Let's go through each of these steps. + +### 1. Generating Deployable Code + +Running the command `wasp build` generates deployable code for the whole app in the `.wasp/build/` directory. + +``` +wasp build +``` + +:::caution PostgreSQL in production +You won't be able to build the app if you are using SQLite as a database (which is the default database). +You'll have to [switch to PostgreSQL](../../data-model/backends#migrating-from-sqlite-to-postgresql) before deploying to production. +::: + +### 2. Deploying the API Server (backend) + +There's a Dockerfile that defines an image for building the server in the `.wasp/build` directory. + +To run the server in production, deploy this Docker image to a hosting provider and ensure the required environment variables on the provider are correctly set up (the mechanism of setting these up is specific per provider). +All necessary environment variables are listed in the next section. + +#### Environment Variables + +Here are the environment variables your server will be looking for: + +- `DATABASE_URL` + + The URL of the Postgres database you want your app to use (e.g., `postgresql://mydbuser:mypass@localhost:5432/nameofmydb`). + +- `WASP_WEB_CLIENT_URL` + + The URL where you plan to deploy your frontend app is running (e.g., `https://.netlify.app`). + The server needs to know about it to properly configure Same-Origin Policy (CORS) headers. + +- `WASP_SERVER_URL` + + The URL where the server is running (e.g., `https://.fly.dev`). + The server needs it to properly redirect users when logging in with OAuth providers like Google or GitHub. + +- `JWT_SECRET` ( if using Wasp Auth) + + You only need this environment variable if you're using Wasp's `auth` features. + Set it to a random string at least 32 characters long (you can use an [online generator](https://djecrety.ir/)). + +- `PORT` + + The server's HTTP port number. This is where the server listens for requests (default: `3001`). + + + + +While these are the general instructions on deploying the server anywhere, we also have more detailed instructions for chosen providers below, so check that out for more guidance if you are deploying to one of those providers. + +### 3. Deploying the Web Client (frontend) + + + +The command above will build the web client and put it in the `build/` directory in the `web-app` directory. + +Since the app's frontend is just a bunch of static files, you can deploy it to any static hosting provider. + +### 4. Deploying the Database + +Any PostgreSQL database will do, as long as you provide the server with the correct `DATABASE_URL` env var and ensure that the database is accessible from the server. + +## Different Providers + +We'll cover a few different deployment providers below: + +- Fly.io (server and database) +- Netlify (client) +- Railway (server, client and database) +- Heroku (server and database) + +## Fly.io (server and database) + +We will show how to deploy the server and provision a database for it on Fly.io. + +:::tip We automated this process for you +If you want to do all of the work below with one command, you can use the [Wasp CLI](../../advanced/deployment/cli#flyio). + +Wasp CLI deploys the server, deploys the client, and sets up a database. +It also gives you a way to redeploy (update) your app with a single command. +::: + +Fly.io offers a variety of free services that are perfect for deploying your first Wasp app! You will need a Fly.io account and the [`flyctl` CLI](https://fly.io/docs/hands-on/install-flyctl/). + +:::note +Fly.io offers support for both locally built Docker containers and remotely built ones. However, for simplicity and reproducibility, we will default to the use of a remote Fly.io builder. + +Additionally, `fly` is a symlink for `flyctl` on most systems and they can be used interchangeably. +::: + +Make sure you are logged in with `flyctl` CLI. You can check if you are logged in with `flyctl auth whoami`, and if you are not, you can log in with `flyctl auth login`. + +### Set Up a Fly.io App + +:::info +You need to do this only once per Wasp app. +::: + +Unless you already have a Fly.io app that you want to deploy to, let's create a new Fly.io app. + +After you have [built the app](#1-generating-deployable-code), position yourself in `.wasp/build/` directory: + +```shell +cd .wasp/build +``` + +Next, run the launch command to set up a new app and create a `fly.toml` file: + +```bash +flyctl launch --remote-only +``` + +This will ask you a series of questions, such as asking you to choose a region and whether you'd like a database. + +- Say **yes** to **Would you like to set up a Postgresql database now?** and select **Development**. Fly.io will set a `DATABASE_URL` for you. +- Say **no** to **Would you like to deploy now?** (and to any additional questions). + + We still need to set up several environment variables. + +:::info What if the database setup fails? +If your attempts to initiate a new app fail for whatever reason, then you should run `flyctl apps destroy ` before trying again. Fly does not allow you to create multiple apps with the same name. + +
+ + What does it look like when your DB is deployed correctly? + +
+

When your DB is deployed correctly, you'll see it in the Fly.io dashboard:

+ image +
+
+::: + +Next, let's copy the `fly.toml` file up to our Wasp project dir for safekeeping. +```shell +cp fly.toml ../../ +``` + +Next, let's add a few more environment variables: + +```bash +flyctl secrets set PORT=8080 +flyctl secrets set JWT_SECRET= +flyctl secrets set WASP_WEB_CLIENT_URL= +flyctl secrets set WASP_SERVER_URL= +``` + +:::note +If you do not know what your client URL is yet, don't worry. You can set `WASP_WEB_CLIENT_URL` after you deploy your client. +::: + + + +If you want to make sure you've added your secrets correctly, run `flyctl secrets list` in the terminal. Note that you will see hashed versions of your secrets to protect your sensitive data. + +### Deploy to a Fly.io App + +While still in the `.wasp/build/` directory, run: + +```bash +flyctl deploy --remote-only --config ../../fly.toml +``` + +This will build and deploy the backend of your Wasp app on Fly.io to `https://.fly.dev` 🤘🎸 + +Now, if you haven't, you can deploy your client and add the client URL by running `flyctl secrets set WASP_WEB_CLIENT_URL=`. We suggest using [Netlify](#netlify) for your client, but you can use any static hosting provider. + +Additionally, some useful `flyctl` commands: + +```bash +flyctl logs +flyctl secrets list +flyctl ssh console +``` + +### Redeploying After Wasp Builds + +When you rebuild your Wasp app (with `wasp build`), it will remove your `.wasp/build/` directory. In there, you may have a `fly.toml` from any prior Fly.io deployments. + +While we will improve this process in the future, in the meantime, you have a few options: + +1. Copy the `fly.toml` file to a versioned directory, like your Wasp project dir. + + From there, you can reference it in `flyctl deploy --config ` commands, like above. + +1. Backup the `fly.toml` file somewhere before running `wasp build`, and copy it into .wasp/build/ after. + + When the `fly.toml` file exists in .wasp/build/ dir, you do not need to specify the `--config `. + +1. Run `flyctl config save -a ` to regenerate the `fly.toml` file from the remote state stored in Fly.io. + +## Netlify (client) + +We'll show how to deploy the client on Netlify. + +Netlify is a static hosting solution that is free for many use cases. You will need a Netlify account and [Netlify CLI](https://docs.netlify.com/cli/get-started/) installed to follow these instructions. + +Make sure you are logged in with Netlify CLI. You can check if you are logged in with `netlify status`, and if you are not, you can log in with `netlify login`. + +First, make sure you have [built the Wasp app](#1-generating-deployable-code). We'll build the client web app next. + + + +We can now deploy the client with: + +```shell +netlify deploy +``` + + + +Carefully follow the instructions i.e. do you want to create a new app or use an existing one, the team under which your app will reside etc. + + + +The final step is to run: + +```shell +netlify deploy --prod` +``` + +That is it! Your client should be live at `https://.netlify.app` ✨ + +:::note +Make sure you set this URL as the `WASP_WEB_CLIENT_URL` environment variable in your server hosting environment (e.g., Fly.io or Heroku). +::: + +## Railway (server, client and database) + +We will show how to deploy the client, the server, and provision a database on Railway. + +Railway is a simple and great way to host your server and database. It's also possible to deploy your entire app: database, server, and client. You can use the platform for free for a limited time, or if you meet certain eligibility requirements. See their [plans page](https://docs.railway.app/reference/plans) for more info. + +### Prerequisites + +To get started, follow these steps: + +1. Make sure your Wasp app is built by running `wasp build` in the project dir. +2. Create a [Railway](https://railway.app/) account + + :::tip Free Tier + Sign up with your GitHub account to be eligible for the free tier + ::: + +3. Install the [Railway CLI](https://docs.railway.app/develop/cli#installation) +4. Run `railway login` and a browser tab will open to authenticate you. + +### Create New Project + +Let's create our Railway project: + +1. Go to your [Railway dashboard](https://railway.app/dashboard), click on **New Project**, and select `Provision PostgreSQL` from the dropdown menu. +2. Once it initializes, right-click on the **New** button in the top right corner and select **Empty Service**. +3. Once it initializes, click on it, go to **Settings > General** and change the name to `server` +4. Go ahead and create another empty service and name it `client` + +![Changing the name](/img/deploying/railway-rename.png) + +### Deploy Your App to Railway + +#### Setup Domains + +We'll need the domains for both the `server` and `client` services: + +1. Go to the `server` instance's `Settings` tab, and click `Generate Domain`. +2. Do the same under the `client`'s `Settings`. + +Copy the domains as we will need them later. + +#### Deploying the Server + +Let's deploy our server first: + +1. Move into your app's `.wasp/build/` directory: + + ```shell + cd .wasp/build + ``` + +2. Link your app build to your newly created Railway project: + + ```shell + railway link + ``` + +3. Go into the Railway dashboard and set up the required env variables: + + Open the `Settings` and go to the `Variables` tab: + + - click **Variable reference** and select `DATABASE_URL` (it will populate it with the correct value) + - add `WASP_WEB_CLIENT_URL` - enter the the `client` domain (e.g. `https://client-production-XXXX.up.railway.app`) + - add `WASP_SERVER_URL` - enter the the `server` domain (e.g. `https://server-production-XXXX.up.railway.app`) + - add `JWT_SECRET` - enter a random string at least 32 characters long (use an [online generator](https://djecrety.ir/)) + + + +4. Push and deploy the project: + +```shell +railway up +``` + +Select `server` when prompted with `Select Service`. + +Railway will now locate the Dockerfile and deploy your server 👍 + +#### Deploying the Client + +1. Next, change into your app's frontend build directory `.wasp/build/web-app`: + + ```shell + cd web-app + ``` + +2. Create the production build, using the `server` domain as the `REACT_APP_API_URL`: + + ```shell + npm install && REACT_APP_API_URL= npm run build + ``` + +3. Next, we want to link this specific frontend directory to our project as well: + + ```shell + railway link + ``` + +4. We need to configure Railway's static hosting for our client. + + :::info Setting Up Static Hosting + + Copy the `build` folder within the `web-app` directory to `dist`: + + ```shell + cp -r build dist + ``` + + We'll need to create the following files: + + - `Dockerfile` with: + + ```Dockerfile title="Dockerfile" + FROM pierrezemb/gostatic + CMD [ "-fallback", "index.html" ] + COPY ./dist/ /srv/http/ + ``` + + - `.dockerignore` with: + ```bash title=".dockerignore" + node_modules/ + ``` + + You'll need to repeat these steps **each time** you run `wasp build` as it will remove the `.wasp/build/web-app` directory. + +
+ + Here's a useful shell script to do the process + + + If you want to automate the process, save the following as `deploy_client.sh` in the root of your project: + + ```bash title="deploy_client.sh" + #!/usr/bin/env bash + + if [ -z "$REACT_APP_API_URL" ] + then + echo "REACT_APP_API_URL is not set" + exit 1 + fi + + wasp build + cd .wasp/build/web-app + + npm install && REACT_APP_API_URL=$REACT_APP_API_URL npm run build + + cp -r build dist + + dockerfile_contents=$(cat < Dockerfile + echo "$dockerignore_contents" > .dockerignore + + railway up + ``` + + Make it executable with: + + ```shell + chmod +x deploy_client.sh + ``` + + You can run it with: + + ```shell + REACT_APP_API_URL= ./deploy_client.sh + ``` + +
+ ::: + +5. Set the `PORT` environment variable to `8043` under the `Variables` tab. + +6. Deploy the client and select `client` when prompted with `Select Service`: + +```shell +railway up +``` + +#### Conclusion + +And now your Wasp should be deployed! 🐝 🚂 🚀 + +Back in your [Railway dashboard](https://railway.app/dashboard), click on your project and you should see your newly deployed services: Postgres, Server, and Client. + +### Updates & Redeploying + +When you make updates and need to redeploy: + +- run `wasp build` to rebuild your app +- run `railway up` in the `.wasp/build` directory (server) +- repeat all the steps in the `.wasp/build/web-app` directory (client) + +## Heroku (server and database) + +We will show how to deploy the server and provision a database for it on Heroku. + +:::note +Heroku used to offer free apps under certain limits. However, as of November 28, 2022, they ended support for their free tier. https://blog.heroku.com/next-chapter + +As such, we recommend using an alternative provider like [Fly.io](#flyio) for your first apps. +::: + +You will need Heroku account, `heroku` [CLI](https://devcenter.heroku.com/articles/heroku-cli) and `docker` CLI installed to follow these instructions. + +Make sure you are logged in with `heroku` CLI. You can check if you are logged in with `heroku whoami`, and if you are not, you can log in with `heroku login`. + +### Set Up a Heroku App + +:::info +You need to do this only once per Wasp app. +::: + +Unless you want to deploy to an existing Heroku app, let's create a new Heroku app: + +``` +heroku create +``` + +Unless you have an external Postgres database that you want to use, let's create a new database on Heroku and attach it to our app: + +``` +heroku addons:create --app heroku-postgresql:mini +``` + +:::caution +Heroku does not offer a free plan anymore and `mini` is their cheapest database instance - it costs $5/mo. +::: + +Heroku will also set `DATABASE_URL` env var for us at this point. If you are using an external database, you will have to set it up yourself. + +The `PORT` env var will also be provided by Heroku, so the ones left to set are the `JWT_SECRET`, `WASP_WEB_CLIENT_URL` and `WASP_SERVER_URL` env vars: + +``` +heroku config:set --app JWT_SECRET= +heroku config:set --app WASP_WEB_CLIENT_URL= +heroku config:set --app WASP_SERVER_URL= +``` + +:::note +If you do not know what your client URL is yet, don't worry. You can set `WASP_WEB_CLIENT_URL` after you deploy your client. +::: + +### Deploy to a Heroku App + +After you have [built the app](#1-generating-deployable-code), position yourself in `.wasp/build/` directory: + +```shell +cd .wasp/build +``` + +assuming you were at the root of your Wasp project at that moment. + +Log in to Heroku Container Registry: + +```shell +heroku container:login +``` + +Build the docker image and push it to Heroku: + +```shell +heroku container:push --app web +``` + +App is still not deployed at this point. +This step might take some time, especially the very first time, since there are no cached docker layers. + +:::note Note for Apple Silicon Users +Apple Silicon users need to build a non-Arm image, so the above step will not work at this time. Instead of `heroku container:push`, users instead should: + +```shell +docker buildx build --platform linux/amd64 -t . +docker tag registry.heroku.com//web +docker push registry.heroku.com//web +``` + +You are now ready to proceed to the next step. +::: + +Deploy the pushed image and restart the app: + +```shell +heroku container:release --app web +``` + +This is it, the backend is deployed at `https://-XXXX.herokuapp.com` 🎉 + +Find out the exact app URL with: + +```shell +heroku info --app +``` + +Additionally, you can check out the logs with: + +```shell +heroku logs --tail --app +``` + +:::note Using `pg-boss` with Heroku + +If you wish to deploy an app leveraging [Jobs](../../advanced/jobs) that use `pg-boss` as the executor to Heroku, you need to set an additional environment variable called `PG_BOSS_NEW_OPTIONS` to `{"connectionString":"","ssl":{"rejectUnauthorized":false}}`. This is because pg-boss uses the `pg` extension, which does not seem to connect to Heroku over SSL by default, which Heroku requires. Additionally, Heroku uses a self-signed cert, so we must handle that as well. + +Read more: https://devcenter.heroku.com/articles/connecting-heroku-postgres#connecting-in-node-js +::: diff --git a/web/versioned_docs/version-0.13.0/advanced/deployment/overview.md b/web/versioned_docs/version-0.13.0/advanced/deployment/overview.md new file mode 100644 index 0000000000..4d1ac99110 --- /dev/null +++ b/web/versioned_docs/version-0.13.0/advanced/deployment/overview.md @@ -0,0 +1,44 @@ +--- +title: Overview +--- + +import { DeploymentOptionsGrid } from './DeploymentOptionsGrid.tsx'; + +Wasp apps are full-stack apps that consist of: +- A Node.js server. +- A static client. +- A PostgreSQL database. + +You can deploy each part **anywhere** where you can usually deploy Node.js apps or static apps. For example, you can deploy your client on [Netlify](https://www.netlify.com/), the server on [Fly.io](https://fly.io/), and the database on [Neon](https://neon.tech/). + +To make deploying as smooth as possible, Wasp also offers a single-command deployment through the **Wasp CLI**. + + + +Regardless of how you choose to deploy your app (i.e., manually or using the Wasp CLI), you'll need to know about some common patterns covered below. + +## Customizing the Dockerfile +By default, Wasp generates a multi-stage Dockerfile. +This file is used to build and run a Docker image with the Wasp-generated server code. +It also runs any pending migrations. + +You can **add extra steps to this multi-stage `Dockerfile`** by creating your own `Dockerfile` in the project's root directory. +If Wasp finds a Dockerfile in the project's root, it appends its contents at the _bottom_ of the default multi-stage Dockerfile. + +Since the last definition in a Dockerfile wins, you can override or continue from any existing build stages. +You can also choose not to use any of our build stages and have your own custom Dockerfile used as-is. + +A few things to keep in mind: + +- If you override an intermediate build stage, no later build stages will be used unless you reproduce them below. +- The generated Dockerfile's content is dynamic and depends on which features your app uses. The content can also change in future releases, so please verify it from time to time. +- Make sure to supply `ENTRYPOINT` in your final build stage. Your changes won't have any effect if you don't. + +Read more in the official Docker docs on [multi-stage builds](https://docs.docker.com/build/building/multi-stage/). + +To see what your project's (potentially combined) Dockerfile will look like, run: +```shell +wasp dockerfile +``` + +Join our [Discord](https://discord.gg/rzdnErX) if you have any questions, or if you need more customization than this hook provides. diff --git a/web/versioned_docs/version-0.13.0/advanced/email/_dummy-provider-note.md b/web/versioned_docs/version-0.13.0/advanced/email/_dummy-provider-note.md new file mode 100644 index 0000000000..861476e6e9 --- /dev/null +++ b/web/versioned_docs/version-0.13.0/advanced/email/_dummy-provider-note.md @@ -0,0 +1,4 @@ +:::note Dummy Provider is not for production use + +The `Dummy` provider is not for production use. It is only meant to be used during development. If you try building your app with the `Dummy` provider, the build will fail. +::: \ No newline at end of file diff --git a/web/versioned_docs/version-0.13.0/advanced/email/email.md b/web/versioned_docs/version-0.13.0/advanced/email/email.md new file mode 100644 index 0000000000..d6288dc57c --- /dev/null +++ b/web/versioned_docs/version-0.13.0/advanced/email/email.md @@ -0,0 +1,401 @@ +--- +title: Sending Emails +--- + +import { Required } from '@site/src/components/Tag' +import { ShowForTs, ShowForJs } from '@site/src/components/TsJsHelpers' +import DummyProviderNote from './_dummy-provider-note.md' + +# Sending Emails + +With Wasp's email-sending feature, you can easily integrate email functionality into your web application. + + + + +```wasp title="main.wasp" +app Example { + ... + emailSender: { + provider: , + defaultFrom: { + name: "Example", + email: "hello@itsme.com" + }, + } +} +``` + + + + +```wasp title="main.wasp" +app Example { + ... + emailSender: { + provider: , + defaultFrom: { + name: "Example", + email: "hello@itsme.com" + }, + } +} +``` + + + + +Choose from one of the providers: + +- `Dummy` (development only), +- `Mailgun`, +- `SendGrid` +- or the good old `SMTP`. + +Optionally, define the `defaultFrom` field, so you don't need to provide it whenever sending an email. + +## Sending Emails + +Before jumping into details about setting up various providers, let's see how easy it is to send emails. + +You import the `emailSender` that is provided by the `wasp/server/email` module and call the `send` method on it. + + + + +```js title="src/actions/sendEmail.js" +import { emailSender } from "wasp/server/email"; + +// In some action handler... +const info = await emailSender.send({ + from: { + name: "John Doe", + email: "john@doe.com", + }, + to: "user@domain.com", + subject: "Saying hello", + text: "Hello world", + html: "Hello world", +}); +``` + + + + +```ts title="src/actions/sendEmail.ts" +import { emailSender } from "wasp/server/email"; + +// In some action handler... +const info = await emailSender.send({ + from: { + name: "John Doe", + email: "john@doe.com", + }, + to: "user@domain.com", + subject: "Saying hello", + text: "Hello world", + html: "Hello world", +}); +``` + + + + +Read more about the `send` method in the [API Reference](#javascript-api). + +The `send` method returns an object with the status of the sent email. It varies depending on the provider you use. + +## Providers + +We'll go over all of the available providers in the next section. For some of them, you'll need to set up some env variables. You can do that in the `.env.server` file. + +### Using the Dummy Provider + + + +To speed up development, Wasp offers a `Dummy` email sender that `console.log`s the emails in the console. Since it doesn't send emails for real, it doesn't require any setup. + +Set the provider to `Dummy` in your `main.wasp` file. + + + + +```wasp title="main.wasp" +app Example { + ... + emailSender: { + provider: Dummy, + } +} +``` + + + + +```wasp title="main.wasp" +app Example { + ... + emailSender: { + provider: Dummy, + } +} +``` + + + + +### Using the SMTP Provider + +First, set the provider to `SMTP` in your `main.wasp` file. + + + + +```wasp title="main.wasp" +app Example { + ... + emailSender: { + provider: SMTP, + } +} +``` + + + + +```wasp title="main.wasp" +app Example { + ... + emailSender: { + provider: SMTP, + } +} +``` + + + + +Then, add the following env variables to your `.env.server` file. + +```properties title=".env.server" +SMTP_HOST= +SMTP_USERNAME= +SMTP_PASSWORD= +SMTP_PORT= +``` + +Many transactional email providers (e.g. Mailgun, SendGrid but also others) can also use SMTP, so you can use them as well. + +### Using the Mailgun Provider + +Set the provider to `Mailgun` in the `main.wasp` file. + + + + +```wasp title="main.wasp" +app Example { + ... + emailSender: { + provider: Mailgun, + } +} +``` + + + + +```wasp title="main.wasp" +app Example { + ... + emailSender: { + provider: Mailgun, + } +} +``` + + + + +Then, get the Mailgun API key and domain and add them to your `.env.server` file. + +#### Getting the API Key and Domain + +1. Go to [Mailgun](https://www.mailgun.com/) and create an account. +2. Go to [API Keys](https://app.mailgun.com/app/account/security/api_keys) and create a new API key. +3. Copy the API key and add it to your `.env.server` file. +4. Go to [Domains](https://app.mailgun.com/app/domains) and create a new domain. +5. Copy the domain and add it to your `.env.server` file. + +```properties title=".env.server" +MAILGUN_API_KEY= +MAILGUN_DOMAIN= +``` + +### Using the SendGrid Provider + +Set the provider field to `SendGrid` in your `main.wasp` file. + + + + +```wasp title="main.wasp" +app Example { + ... + emailSender: { + provider: SendGrid, + } +} +``` + + + + +```wasp title="main.wasp" +app Example { + ... + emailSender: { + provider: SendGrid, + } +} +``` + + + + +Then, get the SendGrid API key and add it to your `.env.server` file. + +#### Getting the API Key + +1. Go to [SendGrid](https://sendgrid.com/) and create an account. +2. Go to [API Keys](https://app.sendgrid.com/settings/api_keys) and create a new API key. +3. Copy the API key and add it to your `.env.server` file. + +```properties title=".env.server" +SENDGRID_API_KEY= +``` + +## API Reference + +### `emailSender` dict + + + + +```wasp title="main.wasp" +app Example { + ... + emailSender: { + provider: , + defaultFrom: { + name: "Example", + email: "hello@itsme.com" + }, + } +} +``` + + + + +```wasp title="main.wasp" +app Example { + ... + emailSender: { + provider: , + defaultFrom: { + name: "Example", + email: "hello@itsme.com" + }, + } +} +``` + + + + +The `emailSender` dict has the following fields: + +- `provider: Provider` + + The provider you want to use. Choose from `Dummy`, `SMTP`, `Mailgun` or `SendGrid`. + + + +- `defaultFrom: dict` + + The default sender's details. If you set this field, you don't need to provide the `from` field when sending an email. + +### JavaScript API + +Using the `emailSender` in TypescriptJavaScript: + + + +```js title="src/actions/sendEmail.js" +import { emailSender } from "wasp/server/email"; + +// In some action handler... +const info = await emailSender.send({ + from: { + name: "John Doe", + email: "john@doe.com", + }, + to: "user@domain.com", + subject: "Saying hello", + text: "Hello world", + html: "Hello world", +}); +``` + + + + +```ts title="src/actions/sendEmail.ts" +import { emailSender } from "wasp/server/email"; + +// In some action handler... +const info = await emailSender.send({ + from: { + name: "John Doe", + email: "john@doe.com", + }, + to: "user@domain.com", + subject: "Saying hello", + text: "Hello world", + html: "Hello world", +}); +``` + + + + +The `send` method accepts an object with the following fields: + +- `from: object` + + The sender's details. If you set up `defaultFrom` field in the `emailSender` dict in Wasp file, this field is optional. + + - `name: string` + + The name of the sender. + + - `email: string` + + The email address of the sender. + +- `to: string` + + The recipient's email address. + +- `subject: string` + + The subject of the email. + +- `text: string` + + The text version of the email. + +- `html: string` + + The HTML version of the email diff --git a/web/versioned_docs/version-0.13.0/advanced/jobs.md b/web/versioned_docs/version-0.13.0/advanced/jobs.md new file mode 100644 index 0000000000..45525e8d4d --- /dev/null +++ b/web/versioned_docs/version-0.13.0/advanced/jobs.md @@ -0,0 +1,425 @@ +--- +title: Recurring Jobs +--- + +import { Required } from '@site/src/components/Tag' +import { ShowForTs, ShowForJs } from '@site/src/components/TsJsHelpers' + +In most web apps, users send requests to the server and receive responses with some data. When the server responds quickly, the app feels responsive and smooth. + +What if the server needs extra time to fully process the request? This might mean sending an email or making a slow HTTP request to an external API. In that case, it's a good idea to respond to the user as soon as possible and do the remaining work in the background. + +Wasp supports background jobs that can help you with this: + - Jobs persist between server restarts, + - Jobs can be retried if they fail, + - Jobs can be delayed until a future time, + - Jobs can have a recurring schedule. + +## Using Jobs + +### Job Definition and Usage + +Let's write an example Job that will print a message to the console and return a list of tasks from the database. + +1. Start by creating a Job declaration in your `.wasp` file: + + + + + ```wasp title="main.wasp" + job mySpecialJob { + executor: PgBoss, + perform: { + fn: import { foo } from "@src/workers/bar" + }, + entities: [Task], + } + ``` + + + + ```wasp title="main.wasp" + job mySpecialJob { + executor: PgBoss, + perform: { + fn: import { foo } from "@src/workers/bar" + }, + entities: [Task], + } + ``` + + + +2. After declaring the Job, implement its worker function: + + + + + ```js title="src/workers/bar.js" + export const foo = async ({ name }, context) => { + console.log(`Hello ${name}!`) + const tasks = await context.entities.Task.findMany({}) + return { tasks } + } + ``` + + + + ```ts title="src/workers/bar.ts" + import { type MySpecialJob } from 'wasp/server/jobs' + import { type Task } from 'wasp/entities' + + type Input = { name: string; } + type Output = { tasks: Task[]; } + + export const foo: MySpecialJob = async ({ name }, context) => { + console.log(`Hello ${name}!`) + const tasks = await context.entities.Task.findMany({}) + return { tasks } + } + ``` + + + + :::info The worker function + The worker function must be an `async` function. The function's return value represents the Job's result. + + The worker function accepts two arguments: + - `args`: The data passed into the job when it's submitted. + - `context: { entities }`: The context object containing entities you put in the Job declaration. + ::: + + + + `MySpecialJob` is a generic type Wasp generates to help you correctly type the Job's worker function, ensuring type information about the function's arguments and return value. Read more about type-safe jobs in the [Javascript API section](#javascript-api). + + +3. After successfully defining the job, you can submit work to be done in your [Operations](../data-model/operations/overview) or [setupFn](../project/server-config#setup-function) (or any other NodeJS code): + + + + + ```js title="someAction.js" + import { mySpecialJob } from 'wasp/server/jobs' + + const submittedJob = await mySpecialJob.submit({ job: "Johnny" }) + + // Or, if you'd prefer it to execute in the future, just add a .delay(). + // It takes a number of seconds, Date, or ISO date string. + await mySpecialJob + .delay(10) + .submit({ name: "Johnny" }) + ``` + + + + ```ts title="someAction.ts" + import { mySpecialJob } from 'wasp/server/jobs' + + const submittedJob = await mySpecialJob.submit({ job: "Johnny" }) + + // Or, if you'd prefer it to execute in the future, just add a .delay(). + // It takes a number of seconds, Date, or ISO date string. + await mySpecialJob + .delay(10) + .submit({ name: "Johnny" }) + ``` + + + +And that'is it. Your job will be executed by `PgBoss` as if you called `foo({ name: "Johnny" })`. + +In our example, `foo` takes an argument, but passing arguments to jobs is not a requirement. It depends on how you've implemented your worker function. + +### Recurring Jobs + +If you have work that needs to be done on some recurring basis, you can add a `schedule` to your job declaration: + + + + +```wasp {6-9} title="main.wasp" +job mySpecialJob { + executor: PgBoss, + perform: { + fn: import { foo } from "@src/workers/bar" + }, + schedule: { + cron: "0 * * * *", + args: {=json { "job": "args" } json=} // optional + } +} +``` + + + +```wasp {6-9} title="main.wasp" +job mySpecialJob { + executor: PgBoss, + perform: { + fn: import { foo } from "@src/workers/bar" + }, + schedule: { + cron: "0 * * * *", + args: {=json { "job": "args" } json=} // optional + } +} +``` + + + +In this example, you _don't_ need to invoke anything in JavaScriptTypescript. You can imagine `foo({ job: "args" })` getting automatically scheduled and invoked for you every hour. + + + + +## API Reference + +### Declaring Jobs + + + + +```wasp title="main.wasp" +job mySpecialJob { + executor: PgBoss, + perform: { + fn: import { foo } from "@src/workers/bar", + executorOptions: { + pgBoss: {=json { "retryLimit": 1 } json=} + } + }, + schedule: { + cron: "*/5 * * * *", + args: {=json { "foo": "bar" } json=}, + executorOptions: { + pgBoss: {=json { "retryLimit": 0 } json=} + } + }, + entities: [Task], +} +``` + + + +```wasp title="main.wasp" +job mySpecialJob { + executor: PgBoss, + perform: { + fn: import { foo } from "@src/workers/bar", + executorOptions: { + pgBoss: {=json { "retryLimit": 1 } json=} + } + }, + schedule: { + cron: "*/5 * * * *", + args: {=json { "foo": "bar" } json=}, + executorOptions: { + pgBoss: {=json { "retryLimit": 0 } json=} + } + }, + entities: [Task], +} +``` + + + +The Job declaration has the following fields: + +- `executor: JobExecutor` + + :::note Job executors + Our jobs need job executors to handle the _scheduling, monitoring, and execution_. + + `PgBoss` is currently our only job executor, and is recommended for low-volume production use cases. It requires your `app.db.system` to be `PostgreSQL`. + ::: + + We have selected [pg-boss](https://github.com/timgit/pg-boss/) as our first job executor to handle the low-volume, basic job queue workloads many web applications have. By using PostgreSQL (and [SKIP LOCKED](https://www.2ndquadrant.com/en/blog/what-is-select-skip-locked-for-in-postgresql-9-5/)) as its storage and synchronization mechanism, it allows us to provide many job queue pros without any additional infrastructure or complex management. + + :::info + Keep in mind that pg-boss jobs run alongside your other server-side code, so they are not appropriate for CPU-heavy workloads. Additionally, some care is required if you modify scheduled jobs. Please see pg-boss details below for more information. + +
+ pg-boss details + + pg-boss provides many useful features, which can be found [here](https://github.com/timgit/pg-boss/blob/8.4.2/README.md). + + When you add pg-boss to a Wasp project, it will automatically add a new schema to your database called `pgboss` with some internal tracking tables, including `job` and `schedule`. pg-boss tables have a `name` column in most tables that will correspond to your Job identifier. Additionally, these tables maintain arguments, states, return values, retry information, start and expiration times, and other metadata required by pg-boss. + + If you need to customize the creation of the pg-boss instance, you can set an environment variable called `PG_BOSS_NEW_OPTIONS` to a stringified JSON object containing [these initialization parameters](https://github.com/timgit/pg-boss/blob/8.4.2/docs/readme.md#newoptions). **NOTE**: Setting this overwrites all Wasp defaults, so you must include database connection information as well. + + ### pg-boss considerations + - Wasp starts pg-boss alongside your web server's application, where both are simultaneously operational. This means that jobs running via pg-boss and the rest of the server logic (like Operations) share the CPU, therefore you should avoid running CPU-intensive tasks via jobs. + - Wasp does not (yet) support independent, horizontal scaling of pg-boss-only applications, nor starting them as separate workers/processes/threads. + - The job name/identifier in your `.wasp` file is the same name that will be used in the `name` column of pg-boss tables. If you change a name that had a `schedule` associated with it, pg-boss will continue scheduling those jobs but they will have no handlers associated, and will thus become stale and expire. To resolve this, you can remove the applicable row from the `schedule` table in the `pgboss` schema of your database. + - If you remove a `schedule` from a job, you will need to do the above as well. + - If you wish to deploy to Heroku, you need to set an additional environment variable called `PG_BOSS_NEW_OPTIONS` to `{"connectionString":"","ssl":{"rejectUnauthorized":false}}`. This is because pg-boss uses the `pg` extension, which does not seem to connect to Heroku over SSL by default, which Heroku requires. Additionally, Heroku uses a self-signed cert, so we must handle that as well. + - https://devcenter.heroku.com/articles/connecting-heroku-postgres#connecting-in-node-js + +
+ + ::: + +- `perform: dict` + + - `fn: ExtImport` + + - An `async` function that performs the work. Since Wasp executes Jobs on the server, the import path must lead to a NodeJS file. + - It receives the following arguments: + - `args: Input`: The data passed to the job when it's submitted. + - `context: { entities: Entities }`: The context object containing any declared entities. + + Here's an example of a `perform.fn` function: + + + + + ```js title="src/workers/bar.js" + export const foo = async ({ name }, context) => { + console.log(`Hello ${name}!`) + const tasks = await context.entities.Task.findMany({}) + return { tasks } + } + ``` + + + + ```ts title="src/workers/bar.ts" + import { type MySpecialJob } from 'wasp/server/jobs' + + type Input = { name: string; } + type Output = { tasks: Task[]; } + + export const foo: MySpecialJob = async (args, context) => { + console.log(`Hello ${name}!`) + const tasks = await context.entities.Task.findMany({}) + return { tasks } + } + ``` + + Read more about type-safe jobs in the [Javascript API section](#javascript-api). + + + + - `executorOptions: dict` + + Executor-specific default options to use when submitting jobs. These are passed directly through and you should consult the documentation for the job executor. These can be overridden during invocation with `submit()` or in a `schedule`. + + - `pgBoss: JSON` + + See the docs for [pg-boss](https://github.com/timgit/pg-boss/blob/8.4.2/docs/readme.md#sendname-data-options). + +- `schedule: dict` + + - `cron: string` + + A 5-placeholder format cron expression string. See rationale for minute-level precision [here](https://github.com/timgit/pg-boss/blob/8.4.2/docs/readme.md#scheduling). + + _If you need help building cron expressions, Check out_ [Crontab guru](https://crontab.guru/#0_*_*_*_*). + + - `args: JSON` + + The arguments to pass to the `perform.fn` function when invoked. + + - `executorOptions: dict` + + Executor-specific options to use when submitting jobs. These are passed directly through and you should consult the documentation for the job executor. The `perform.executorOptions` are the default options, and `schedule.executorOptions` can override/extend those. + + - `pgBoss: JSON` + + See the docs for [pg-boss](https://github.com/timgit/pg-boss/blob/8.4.2/docs/readme.md#sendname-data-options). + +- `entities: [Entity]` + + A list of entities you wish to use inside your Job (similar to [Queries and Actions](../data-model/operations/queries#using-entities-in-queries)). + +### JavaScript API + +- Importing a Job: + + + + + ```js title="someAction.js" + import { mySpecialJob } from 'wasp/server/jobs' + ``` + + + + ```ts title="someAction.ts" + import { mySpecialJob, type MySpecialJob } from 'wasp/server/jobs' + ``` + + :::info Type-safe jobs + Wasp generates a generic type for each Job declaration, which you can use to type your `perform.fn` function. The type is named after the job declaration, and is available in the `wasp/server/jobs` module. In the example above, the type is `MySpecialJob`. + + The type takes two type arguments: + - `Input`: The type of the `args` argument of the `perform.fn` function. + - `Output`: The type of the return value of the `perform.fn` function. + ::: + + + + +- `submit(jobArgs, executorOptions)` + - `jobArgs: Input` + - `executorOptions: object` + + Submits a Job to be executed by an executor, optionally passing in a JSON job argument your job handler function receives, and executor-specific submit options. + + + + + ```js title="someAction.js" + const submittedJob = await mySpecialJob.submit({ job: "args" }) + ``` + + + + ```js title="someAction.ts" + const submittedJob = await mySpecialJob.submit({ job: "args" }) + ``` + + + +- `delay(startAfter)` + - `startAfter: int | string | Date` + + Delaying the invocation of the job handler. The delay can be one of: + - Integer: number of seconds to delay. [Default 0] + - String: ISO date string to run at. + - Date: Date to run at. + + + + + ```js title="someAction.js" + const submittedJob = await mySpecialJob + .delay(10) + .submit({ job: "args" }, { "retryLimit": 2 }) + ``` + + + + ```ts title="someAction.ts" + const submittedJob = await mySpecialJob + .delay(10) + .submit({ job: "args" }, { "retryLimit": 2 }) + ``` + + + +#### Tracking +The return value of `submit()` is an instance of `SubmittedJob`, which has the following fields: +- `jobId`: The ID for the job in that executor. +- `jobName`: The name of the job you used in your `.wasp` file. +- `executorName`: The Symbol of the name of the job executor. + +There are also some namespaced, job executor-specific objects. + +- For pg-boss, you may access: `pgBoss` + - `details()`: pg-boss specific job detail information. [Reference](https://github.com/timgit/pg-boss/blob/8.4.2/docs/readme.md#getjobbyidid) + - `cancel()`: attempts to cancel a job. [Reference](https://github.com/timgit/pg-boss/blob/8.4.2/docs/readme.md#cancelid) + - `resume()`: attempts to resume a canceled job. [Reference](https://github.com/timgit/pg-boss/blob/8.4.2/docs/readme.md#resumeid) diff --git a/web/versioned_docs/version-0.13.0/advanced/links.md b/web/versioned_docs/version-0.13.0/advanced/links.md new file mode 100644 index 0000000000..165b9cb18e --- /dev/null +++ b/web/versioned_docs/version-0.13.0/advanced/links.md @@ -0,0 +1,134 @@ +--- +title: Type-Safe Links +--- + +import { Required } from '@site/src/components/Tag' + +If you are using Typescript, you can use Wasp's custom `Link` component to create type-safe links to other pages on your site. + +## Using the `Link` Component + +After you defined a route: + +```wasp title="main.wasp" +route TaskRoute { path: "/task/:id", to: TaskPage } +page TaskPage { ... } +``` + +You can get the benefits of type-safe links by using the `Link` component from `wasp/client/router`: + +```jsx title="TaskList.tsx" +import { Link } from 'wasp/client/router' + +export const TaskList = () => { + // ... + + return ( +
+ {tasks.map((task) => ( + + {/* 👆 All the params must be correctly passed in */} + {task.description} + + ))} +
+ ) +} +``` + +### Using Search Query & Hash + +You can also pass `search` and `hash` props to the `Link` component: + +```tsx title="TaskList.tsx" + + {task.description} + +``` + +This will result in a link like this: `/task/1?sortBy=date#comments`. Check out the [API Reference](#link-component) for more details. + +## The `routes` Object + +You can also get all the pages in your app with the `routes` object: + +```jsx title="TaskList.tsx" +import { routes } from 'wasp/client/router' + +const linkToTask = routes.TaskRoute.build({ params: { id: 1 } }) +``` + +This will result in a link like this: `/task/1`. + +You can also pass `search` and `hash` props to the `build` function. Check out the [API Reference](#routes-object) for more details. + + +## API Reference + +### `Link` Component + +The `Link` component accepts the following props: +- `to` + + - A valid Wasp Route path from your `main.wasp` file. + +- `params: { [name: string]: string | number }` (if the path contains params) + + - An object with keys and values for each param in the path. + - For example, if the path is `/task/:id`, then the `params` prop must be `{ id: 1 }`. Wasp supports required and optional params. + +- `search: string[][] | Record | string | URLSearchParams` + + - Any valid input for `URLSearchParams` constructor. + - For example, the object `{ sortBy: 'date' }` becomes `?sortBy=date`. + +- `hash: string` +- all other props that the `react-router-dom`'s [Link](https://v5.reactrouter.com/web/api/Link) component accepts + + +### `routes` Object + +The `routes` object contains a function for each route in your app. + +```ts title="router.tsx" +export const routes = { + // RootRoute has a path like "/" + RootRoute: { + build: (options?: { + search?: string[][] | Record | string | URLSearchParams + hash?: string + }) => // ... + }, + + // DetailRoute has a path like "/task/:id/:something?" + DetailRoute: { + build: ( + options: { + params: { id: ParamValue; something?: ParamValue; }, + search?: string[][] | Record | string | URLSearchParams + hash?: string + } + ) => // ... + } +} +``` + +The `params` object is required if the route contains params. The `search` and `hash` parameters are optional. + +You can use the `routes` object like this: + +```tsx +import { routes } from 'wasp/client/router' + +const linkToRoot = routes.RootRoute.build() +const linkToTask = routes.DetailRoute.build({ params: { id: 1 } }) +``` diff --git a/web/versioned_docs/version-0.13.0/advanced/middleware-config.md b/web/versioned_docs/version-0.13.0/advanced/middleware-config.md new file mode 100644 index 0000000000..6385a56716 --- /dev/null +++ b/web/versioned_docs/version-0.13.0/advanced/middleware-config.md @@ -0,0 +1,279 @@ +--- +title: Configuring Middleware +--- +import { ShowForTs } from '@site/src/components/TsJsHelpers'; + +Wasp comes with a minimal set of useful Express middleware in every application. While this is good for most users, we realize some may wish to add, modify, or remove some of these choices both globally, or on a per-`api`/path basis. + +## Default Global Middleware 🌍 + +Wasp's Express server has the following middleware by default: + +- [Helmet](https://helmetjs.github.io/): Helmet helps you secure your Express apps by setting various HTTP headers. _It's not a silver bullet, but it's a good start._ +- [CORS](https://github.com/expressjs/cors#readme): CORS is a package for providing a middleware that can be used to enable [CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) with various options. + + :::note + CORS middleware is required for the frontend to communicate with the backend. + ::: +- [Morgan](https://github.com/expressjs/morgan#readme): HTTP request logger middleware. +- [express.json](https://expressjs.com/en/api.html#express.json) (which uses [body-parser](https://github.com/expressjs/body-parser#bodyparserjsonoptions)): parses incoming request bodies in a middleware before your handlers, making the result available under the `req.body` property. + + :::note + JSON middlware is required for [Operations](../data-model/operations/overview) to function properly. + ::: +- [express.urlencoded](https://expressjs.com/en/api.html#express.urlencoded) (which uses [body-parser](https://expressjs.com/en/resources/middleware/body-parser.html#bodyparserurlencodedoptions)): returns middleware that only parses urlencoded bodies and only looks at requests where the `Content-Type` header matches the type option. +- [cookieParser](https://github.com/expressjs/cookie-parser#readme): parses Cookie header and populates `req.cookies` with an object keyed by the cookie names. + +## Customization + +You have three places where you can customize middleware: +1. [global](#1-customize-global-middleware): here, any changes will apply by default *to all operations (`query` and `action`) and `api`.* This is helpful if you wanted to add support for multiple domains to CORS, for example. + + :::caution Modifying global middleware + Please treat modifications to global middleware with extreme care as they will affect all operations and APIs. If you are unsure, use one of the other two options. + ::: + +2. [per-api](#2-customize-api-specific-middleware): you can override middleware for a specific api route (e.g. `POST /webhook/callback`). This is helpful if you want to disable JSON parsing for some callback, for example. +3. [per-path](#3-customize-per-path-middleware): this is helpful if you need to customize middleware for all methods under a given path. + - It's helpful for things like "complex CORS requests" which may need to apply to both `OPTIONS` and `GET`, or to apply some middleware to a _set of `api` routes_. + +### Default Middleware Definitions + +Below is the actual definitions of default middleware which you can override. + + + + +```js +const defaultGlobalMiddleware = new Map([ + ['helmet', helmet()], + ['cors', cors({ origin: config.allowedCORSOrigins })], + ['logger', logger('dev')], + ['express.json', express.json()], + ['express.urlencoded', express.urlencoded({ extended: false })], + ['cookieParser', cookieParser()] +]) +``` + + + +```ts +export type MiddlewareConfig = Map + +// Used in the examples below 👇 +export type MiddlewareConfigFn = (middlewareConfig: MiddlewareConfig) => MiddlewareConfig + +const defaultGlobalMiddleware: MiddlewareConfig = new Map([ + ['helmet', helmet()], + ['cors', cors({ origin: config.allowedCORSOrigins })], + ['logger', logger('dev')], + ['express.json', express.json()], + ['express.urlencoded', express.urlencoded({ extended: false })], + ['cookieParser', cookieParser()] +]) +``` + + + +## 1. Customize Global Middleware + +If you would like to modify the middleware for _all_ operations and APIs, you can do something like: + + + + + +```wasp {6} title=main.wasp +app todoApp { + // ... + + server: { + setupFn: import setup from "@src/serverSetup", + middlewareConfigFn: import { serverMiddlewareFn } from "@src/serverSetup" + }, +} +``` + +```ts title=src/serverSetup.js +import cors from 'cors' +import { config } from 'wasp/server' + +export const serverMiddlewareFn = (middlewareConfig) => { + // Example of adding extra domains to CORS. + middlewareConfig.set('cors', cors({ origin: [config.frontendUrl, 'https://example1.com', 'https://example2.com'] })) + return middlewareConfig +} +``` + + + + +```wasp {6} title=main.wasp +app todoApp { + // ... + + server: { + setupFn: import setup from "@src/serverSetup", + middlewareConfigFn: import { serverMiddlewareFn } from "@src/serverSetup" + }, +} +``` + +```ts title=src/serverSetup.ts +import cors from 'cors' +import { config, type MiddlewareConfigFn } from 'wasp/server' + +export const serverMiddlewareFn: MiddlewareConfigFn = (middlewareConfig) => { + // Example of adding an extra domains to CORS. + middlewareConfig.set('cors', cors({ origin: [config.frontendUrl, 'https://example1.com', 'https://example2.com'] })) + return middlewareConfig +} +``` + + + + +## 2. Customize `api`-specific Middleware + +If you would like to modify the middleware for a single API, you can do something like: + + + + +```wasp {5} title=main.wasp +// ... + +api webhookCallback { + fn: import { webhookCallback } from "@src/apis", + middlewareConfigFn: import { webhookCallbackMiddlewareFn } from "@src/apis", + httpRoute: (POST, "/webhook/callback"), + auth: false +} +``` + +```ts title=src/apis.js +import express from 'express' + +export const webhookCallback = (req, res, _context) => { + res.json({ msg: req.body.length }) +} + +export const webhookCallbackMiddlewareFn = (middlewareConfig) => { + console.log('webhookCallbackMiddlewareFn: Swap express.json for express.raw') + + middlewareConfig.delete('express.json') + middlewareConfig.set('express.raw', express.raw({ type: '*/*' })) + + return middlewareConfig +} + +``` + + + +```wasp {5} title=main.wasp +// ... + +api webhookCallback { + fn: import { webhookCallback } from "@src/apis", + middlewareConfigFn: import { webhookCallbackMiddlewareFn } from "@src/apis", + httpRoute: (POST, "/webhook/callback"), + auth: false +} +``` + +```ts title=src/apis.ts +import express from 'express' +import { type WebhookCallback } from 'wasp/server/api' +import { type MiddlewareConfigFn } from 'wasp/server' + +export const webhookCallback: WebhookCallback = (req, res, _context) => { + res.json({ msg: req.body.length }) +} + +export const webhookCallbackMiddlewareFn: MiddlewareConfigFn = (middlewareConfig) => { + console.log('webhookCallbackMiddlewareFn: Swap express.json for express.raw') + + middlewareConfig.delete('express.json') + middlewareConfig.set('express.raw', express.raw({ type: '*/*' })) + + return middlewareConfig +} + +``` + + + +:::note +This gets installed on a per-method basis. Behind the scenes, this results in code like: + +```js +router.post('/webhook/callback', webhookCallbackMiddleware, ...) +``` +::: + +## 3. Customize Per-Path Middleware + +If you would like to modify the middleware for all API routes under some common path, you can define a `middlewareConfigFn` on an `apiNamespace`: + + + + +```wasp {4} title=main.wasp +// ... + +apiNamespace fooBar { + middlewareConfigFn: import { fooBarNamespaceMiddlewareFn } from "@src/apis", + path: "/foo/bar" +} +``` + +```ts title=src/apis.js +export const fooBarNamespaceMiddlewareFn = (middlewareConfig) => { + const customMiddleware = (_req, _res, next) => { + console.log('fooBarNamespaceMiddlewareFn: custom middleware') + next() + } + + middlewareConfig.set('custom.middleware', customMiddleware) + + return middlewareConfig +} +``` + + + +```wasp {4} title=main.wasp +// ... + +apiNamespace fooBar { + middlewareConfigFn: import { fooBarNamespaceMiddlewareFn } from "@src/apis", + path: "/foo/bar" +} +``` + +```ts title=src/apis.ts +import express from 'express' +import { type MiddlewareConfigFn } from 'wasp/server' + +export const fooBarNamespaceMiddlewareFn: MiddlewareConfigFn = (middlewareConfig) => { + const customMiddleware: express.RequestHandler = (_req, _res, next) => { + console.log('fooBarNamespaceMiddlewareFn: custom middleware') + next() + } + + middlewareConfig.set('custom.middleware', customMiddleware) + + return middlewareConfig +} +``` + + + +:::note +This gets installed at the router level for the path. Behind the scenes, this results in something like: + +```js +router.use('/foo/bar', fooBarNamespaceMiddleware) +``` +::: diff --git a/web/versioned_docs/version-0.13.0/advanced/web-sockets.md b/web/versioned_docs/version-0.13.0/advanced/web-sockets.md new file mode 100644 index 0000000000..010faef598 --- /dev/null +++ b/web/versioned_docs/version-0.13.0/advanced/web-sockets.md @@ -0,0 +1,337 @@ +--- +title: Web Sockets +--- +import useBaseUrl from '@docusaurus/useBaseUrl'; +import { ShowForTs } from '@site/src/components/TsJsHelpers'; +import { Required } from '@site/src/components/Tag'; + +Wasp provides a fully integrated WebSocket experience by utilizing [Socket.IO](https://socket.io/) on the client and server. + +We handle making sure your URLs are correctly setup, CORS is enabled, and provide a useful `useSocket` and `useSocketListener` abstractions for use in React components. + +To get started, you need to: +1. Define your WebSocket logic on the server. +2. Enable WebSockets in your Wasp file, and connect it with your server logic. +3. Use WebSockets on the client, in React, via `useSocket` and `useSocketListener`. +4. Optionally, type the WebSocket events and payloads for full-stack type safety. + +Let's go through setting up WebSockets step by step, starting with enabling WebSockets in your Wasp file. + +## Turn On WebSockets in Your Wasp File +We specify that we are using WebSockets by adding `webSocket` to our `app` and providing the required `fn`. You can optionally change the auto-connect behavior. + + + + +```wasp title=todoApp.wasp +app todoApp { + // ... + + webSocket: { + fn: import { webSocketFn } from "@src/webSocket", + autoConnect: true, // optional, default: true + }, +} +``` + + + +```wasp title=todoApp.wasp +app todoApp { + // ... + + webSocket: { + fn: import { webSocketFn } from "@src/webSocket", + autoConnect: true, // optional, default: true + }, +} +``` + + + +## Defining the Events Handler +Let's define the WebSockets server with all of the events and handler functions. + + + +:::info Full-stack type safety +Check this out: we'll define the event types and payloads on the server, and they will be **automatically exposed on the client**. This helps you avoid mistakes when emitting events or handling them. +::: + + +### `webSocketFn` Function +On the server, you will get Socket.IO `io: Server` argument and `context` for your WebSocket function. The `context` object give you access to all of the entities from your Wasp app. + +You can use this `io` object to register callbacks for all the regular [Socket.IO events](https://socket.io/docs/v4/server-api/). Also, if a user is logged in, you will have a `socket.data.user` on the server. + +This is how we can define our `webSocketFn` function: + + + + +```ts title=src/webSocket.js +import { v4 as uuidv4 } from 'uuid' +import { getFirstProviderUserId } from 'wasp/auth' + +export const webSocketFn = (io, context) => { + io.on('connection', (socket) => { + const username = getFirstProviderUserId(socket.data.user) ?? 'Unknown' + console.log('a user connected: ', username) + + socket.on('chatMessage', async (msg) => { + console.log('message: ', msg) + io.emit('chatMessage', { id: uuidv4(), username, text: msg }) + // You can also use your entities here: + // await context.entities.SomeEntity.create({ someField: msg }) + }) + }) +} +``` + + + +```ts title=src/webSocket.ts +import { v4 as uuidv4 } from 'uuid' +import { getFirstProviderUserId } from 'wasp/auth' +import { type WebSocketDefinition, type WaspSocketData } from 'wasp/server/webSocket' + +export const webSocketFn: WebSocketFn = (io, context) => { + io.on('connection', (socket) => { + const username = getFirstProviderUserId(socket.data.user) ?? 'Unknown' + console.log('a user connected: ', username) + + socket.on('chatMessage', async (msg) => { + console.log('message: ', msg) + io.emit('chatMessage', { id: uuidv4(), username, text: msg }) + // You can also use your entities here: + // await context.entities.SomeEntity.create({ someField: msg }) + }) + }) +} + +// Typing our WebSocket function with the events and payloads +// allows us to get type safety on the client as well + +type WebSocketFn = WebSocketDefinition< + ClientToServerEvents, + ServerToClientEvents, + InterServerEvents, + SocketData +> + +interface ServerToClientEvents { + chatMessage: (msg: { id: string, username: string, text: string }) => void; +} + +interface ClientToServerEvents { + chatMessage: (msg: string) => void; +} + +interface InterServerEvents {} + +// Data that is attached to the socket. +// NOTE: Wasp automatically injects the JWT into the connection, +// and if present/valid, the server adds a user to the socket. +interface SocketData extends WaspSocketData {} +``` + + + +## Using the WebSocket On The Client + + + +:::info Full-stack type safety +All the hooks we use are typed with the events and payloads you defined on the server. VS Code will give you autocomplete for the events and payloads, and you will get type errors if you make a mistake. +::: + + +### `useSocket` Hook + +Client access to WebSockets is provided by the `useSocket` hook. It returns: +- `socket: Socket` for sending and receiving events. +- `isConnected: boolean` for showing a display of the Socket.IO connection status. + - Note: Wasp automatically connects and establishes a WebSocket connection from the client to the server by default, so you do not need to explicitly `socket.connect()` or `socket.disconnect()`. + - If you set `autoConnect: false` in your Wasp file, then you should call these as needed. + +All components using `useSocket` share the same underlying `socket`. + +### `useSocketListener` Hook + +Additionally, there is a `useSocketListener: (event, callback) => void` hook which is used for registering event handlers. It takes care of unregistering the handler on unmount. + + + + + +```tsx title=src/ChatPage.jsx +import React, { useState } from 'react' +import { + useSocket, + useSocketListener, +} from 'wasp/client/webSocket' + +export const ChatPage = () => { + const [messageText, setMessageText] = useState('') + const [messages, setMessages] = useState([]) + const { socket, isConnected } = useSocket() + + useSocketListener('chatMessage', logMessage) + + function logMessage(msg) { + setMessages((priorMessages) => [msg, ...priorMessages]) + } + + function handleSubmit(e) { + e.preventDefault() + socket.emit('chatMessage', messageText) + setMessageText('') + } + + const messageList = messages.map((msg) => ( +
  • + {msg.username}: {msg.text} +
  • + )) + const connectionIcon = isConnected ? '🟢' : '🔴' + + return ( + <> +

    Chat {connectionIcon}

    +
    +
    +
    +
    + setMessageText(e.target.value)} + /> +
    +
    + +
    +
    +
    +
      {messageList}
    +
    + + ) +} +``` +
    + + +Wasp's **full-stack type safety** kicks in here: all the event types and payloads are automatically inferred from the server and are available on the client 🔥 + +You can additionally use the `ClientToServerPayload` and `ServerToClientPayload` helper types to get the payload type for a specific event. + +```tsx title=src/ChatPage.tsx +import React, { useState } from 'react' +import { + useSocket, + useSocketListener, + ServerToClientPayload, +} from 'wasp/client/webSocket' + +export const ChatPage = () => { + const [messageText, setMessageText] = useState< + // We are using a helper type to get the payload type for the "chatMessage" event. + ClientToServerPayload<'chatMessage'> + >('') + const [messages, setMessages] = useState< + ServerToClientPayload<'chatMessage'>[] + >([]) + // The "socket" instance is typed with the types you defined on the server. + const { socket, isConnected } = useSocket() + + // This is a type-safe event handler: "chatMessage" event and its payload type + // are defined on the server. + useSocketListener('chatMessage', logMessage) + + function logMessage(msg: ServerToClientPayload<'chatMessage'>) { + setMessages((priorMessages) => [msg, ...priorMessages]) + } + + function handleSubmit(e: React.FormEvent) { + e.preventDefault() + // This is a type-safe event emitter: "chatMessage" event and its payload type + // are defined on the server. + socket.emit('chatMessage', messageText) + setMessageText('') + } + + const messageList = messages.map((msg) => ( +
  • + {msg.username}: {msg.text} +
  • + )) + const connectionIcon = isConnected ? '🟢' : '🔴' + + return ( + <> +

    Chat {connectionIcon}

    +
    +
    +
    +
    + setMessageText(e.target.value)} + /> +
    +
    + +
    +
    +
    +
      {messageList}
    +
    + + ) +} +``` +
    +
    + +## API Reference + + + + +```wasp title=todoApp.wasp +app todoApp { + // ... + + webSocket: { + fn: import { webSocketFn } from "@src/webSocket", + autoConnect: true, // optional, default: true + }, +} +``` + + + +```wasp title=todoApp.wasp +app todoApp { + // ... + + webSocket: { + fn: import { webSocketFn } from "@src/webSocket", + autoConnect: true, // optional, default: true + }, +} +``` + + + +The `webSocket` dict has the following fields: + +- `fn: WebSocketFn` + + The function that defines the WebSocket events and handlers. + +- `autoConnect: bool` + + Whether to automatically connect to the WebSocket server. Default: `true`. diff --git a/web/versioned_docs/version-0.13.0/auth/Pills.css b/web/versioned_docs/version-0.13.0/auth/Pills.css new file mode 100644 index 0000000000..4764c128f9 --- /dev/null +++ b/web/versioned_docs/version-0.13.0/auth/Pills.css @@ -0,0 +1,17 @@ +:root { + --auth-pills-color: #333; + --auth-pills-email: #e0f2fe; + --auth-pills-github: #f1f5f9; + --auth-pills-google: #ecfccb; + --auth-pills-keycloak: #d0ebf5; + --auth-pills-username-and-pass: #fce7f3; +} + +:root[data-theme='dark'] { + --auth-pills-color: #fff; + --auth-pills-email: #0c4a6e; + --auth-pills-github: #334155; + --auth-pills-google: #365314; + --auth-pills-keycloak: #2d5866; + --auth-pills-username-and-pass: #831843; +} diff --git a/web/versioned_docs/version-0.13.0/auth/Pills.jsx b/web/versioned_docs/version-0.13.0/auth/Pills.jsx new file mode 100644 index 0000000000..94317100a4 --- /dev/null +++ b/web/versioned_docs/version-0.13.0/auth/Pills.jsx @@ -0,0 +1,86 @@ +import React from 'react' +import './Pills.css' +import Link from '@docusaurus/Link' + +export function Pill({ children, linkToPage, style = {} }) { + return ( + + {children} + + ) +} + +export function EmailPill() { + return ( + + Email + + ) +} + +export function UsernameAndPasswordPill() { + return ( + + Username & Password + + ) +} + +export function GithubPill() { + return ( + + Github + + ) +} + +export function GooglePill() { + return ( + + Google + + ) +} + +export function KeycloakPill() { + return ( + + Keycloak + + ) +} diff --git a/web/versioned_docs/version-0.13.0/auth/_multiple-identities-warning.md b/web/versioned_docs/version-0.13.0/auth/_multiple-identities-warning.md new file mode 100644 index 0000000000..ea8f5d8251 --- /dev/null +++ b/web/versioned_docs/version-0.13.0/auth/_multiple-identities-warning.md @@ -0,0 +1,6 @@ +:::caution Using multiple auth identities for a single user + +Wasp currently doesn't support multiple auth identities for a single user. This means, for example, that a user can't have both an email-based auth identity and a Google-based auth identity. This is something we will add in the future with the introduction of the [account merging feature](https://github.com/wasp-lang/wasp/issues/954). + +Account merging means that multiple auth identities can be merged into a single user account. For example, a user's email and Google identity can be merged into a single user account. Then the user can log in with either their email or Google account and they will be logged into the same account. +::: diff --git a/web/versioned_docs/version-0.13.0/auth/_read-more-about-auth-entities.md b/web/versioned_docs/version-0.13.0/auth/_read-more-about-auth-entities.md new file mode 100644 index 0000000000..bafd959cac --- /dev/null +++ b/web/versioned_docs/version-0.13.0/auth/_read-more-about-auth-entities.md @@ -0,0 +1 @@ +You can read more about how the `User` entity is connected to the rest of the auth system in the [Auth Entities](./entities) section of the docs. \ No newline at end of file diff --git a/web/versioned_docs/version-0.13.0/auth/_user-fields.md b/web/versioned_docs/version-0.13.0/auth/_user-fields.md new file mode 100644 index 0000000000..32319805d7 --- /dev/null +++ b/web/versioned_docs/version-0.13.0/auth/_user-fields.md @@ -0,0 +1,8 @@ +import { Required } from '@site/src/components/Tag'; + +The user entity needs to have the following fields: +- `id` + + It can be of any type, but it needs to be marked with `@id` + +You can add any other fields you want to the user entity. Make sure to also define them in the `userSignupFields` field if they need to be set during the sign-up process. \ No newline at end of file diff --git a/web/versioned_docs/version-0.13.0/auth/_user-signup-fields-explainer.md b/web/versioned_docs/version-0.13.0/auth/_user-signup-fields-explainer.md new file mode 100644 index 0000000000..525a801c89 --- /dev/null +++ b/web/versioned_docs/version-0.13.0/auth/_user-signup-fields-explainer.md @@ -0,0 +1,38 @@ +`userSignupFields` defines all the extra fields that need to be set on the `User` during the sign-up process. For example, if you have `address` and `phone` fields on your `User` entity, you can set them by defining the `userSignupFields` like this: + + + + +```ts title="src/auth.js" +import { defineUserSignupFields } from 'wasp/server/auth' + +export const userSignupFields = defineUserSignupFields({ + address: (data) => { + if (!data.address) { + throw new Error('Address is required') + } + return data.address + } + phone: (data) => data.phone, +}) +``` + + + + +```ts title="src/auth.ts" +import { defineUserSignupFields } from 'wasp/server/auth' + +export const userSignupFields = defineUserSignupFields({ + address: (data) => { + if (!data.address) { + throw new Error('Address is required') + } + return data.address + } + phone: (data) => data.phone, +}) +``` + + + diff --git a/web/versioned_docs/version-0.13.0/auth/email.md b/web/versioned_docs/version-0.13.0/auth/email.md new file mode 100644 index 0000000000..c1228cc6e0 --- /dev/null +++ b/web/versioned_docs/version-0.13.0/auth/email.md @@ -0,0 +1,1119 @@ +--- +title: Email +--- + +import { Required } from '@site/src/components/Tag'; +import MultipleIdentitiesWarning from './\_multiple-identities-warning.md'; +import ReadMoreAboutAuthEntities from './\_read-more-about-auth-entities.md'; +import GetEmail from './entities/\_get-email.md'; +import UserSignupFieldsExplainer from './\_user-signup-fields-explainer.md'; +import UserFields from './\_user-fields.md'; + +Wasp supports e-mail authentication out of the box, along with email verification and "forgot your password?" flows. It provides you with the server-side implementation and email templates for all of these flows. + +![Auth UI](/img/authui/all_screens.gif) + + + +## Setting Up Email Authentication + +We'll need to take the following steps to set up email authentication: +1. Enable email authentication in the Wasp file +1. Add the `User` entity +1. Add the auth routes and pages +1. Use Auth UI components in our pages +1. Set up the email sender + +Structure of the `main.wasp` file we will end up with: + +```wasp title="main.wasp" +// Configuring e-mail authentication +app myApp { + auth: { ... } +} + +// Defining User entity +entity User { ... } + +// Defining routes and pages +route SignupRoute { ... } +page SignupPage { ... } +// ... +``` + +### 1. Enable Email Authentication in `main.wasp` + +Let's start with adding the following to our `main.wasp` file: + + + + +```wasp title="main.wasp" +app myApp { + wasp: { + version: "^0.13.0" + }, + title: "My App", + auth: { + // 1. Specify the user entity (we'll define it next) + userEntity: User, + methods: { + // 2. Enable email authentication + email: { + // 3. Specify the email from field + fromField: { + name: "My App Postman", + email: "hello@itsme.com" + }, + // 4. Specify the email verification and password reset options (we'll talk about them later) + emailVerification: { + clientRoute: EmailVerificationRoute, + }, + passwordReset: { + clientRoute: PasswordResetRoute, + }, + }, + }, + onAuthFailedRedirectTo: "/login", + onAuthSucceededRedirectTo: "/" + }, +} +``` + + + +```wasp title="main.wasp" +app myApp { + wasp: { + version: "^0.13.0" + }, + title: "My App", + auth: { + // 1. Specify the user entity (we'll define it next) + userEntity: User, + methods: { + // 2. Enable email authentication + email: { + // 3. Specify the email from field + fromField: { + name: "My App Postman", + email: "hello@itsme.com" + }, + // 4. Specify the email verification and password reset options (we'll talk about them later) + emailVerification: { + clientRoute: EmailVerificationRoute, + }, + passwordReset: { + clientRoute: PasswordResetRoute, + }, + }, + }, + onAuthFailedRedirectTo: "/login", + onAuthSucceededRedirectTo: "/" + }, +} +``` + + + +Read more about the `email` auth method options [here](#fields-in-the-email-dict). + +### 2. Add the User Entity + +The `User` entity can be as simple as including only the `id` field: + + + + +```wasp title="main.wasp" +// 5. Define the user entity +entity User {=psl + // highlight-next-line + id Int @id @default(autoincrement()) + // Add your own fields below + // ... +psl=} +``` + + + +```wasp title="main.wasp" +// 5. Define the user entity +entity User {=psl + // highlight-next-line + id Int @id @default(autoincrement()) + // Add your own fields below + // ... +psl=} +``` + + + + + + +### 3. Add the Routes and Pages + +Next, we need to define the routes and pages for the authentication pages. + +Add the following to the `main.wasp` file: + + + + +```wasp title="main.wasp" +// ... + +// 6. Define the routes +route LoginRoute { path: "/login", to: LoginPage } +page LoginPage { + component: import { Login } from "@src/pages/auth.jsx" +} + +route SignupRoute { path: "/signup", to: SignupPage } +page SignupPage { + component: import { Signup } from "@src/pages/auth.jsx" +} + +route RequestPasswordResetRoute { path: "/request-password-reset", to: RequestPasswordResetPage } +page RequestPasswordResetPage { + component: import { RequestPasswordReset } from "@src/pages/auth.jsx", +} + +route PasswordResetRoute { path: "/password-reset", to: PasswordResetPage } +page PasswordResetPage { + component: import { PasswordReset } from "@src/pages/auth.jsx", +} + +route EmailVerificationRoute { path: "/email-verification", to: EmailVerificationPage } +page EmailVerificationPage { + component: import { EmailVerification } from "@src/pages/auth.jsx", +} +``` + + + +```wasp title="main.wasp" +// ... + +// 6. Define the routes +route LoginRoute { path: "/login", to: LoginPage } +page LoginPage { + component: import { Login } from "@src/pages/auth.tsx" +} + +route SignupRoute { path: "/signup", to: SignupPage } +page SignupPage { + component: import { Signup } from "@src/pages/auth.tsx" +} + +route RequestPasswordResetRoute { path: "/request-password-reset", to: RequestPasswordResetPage } +page RequestPasswordResetPage { + component: import { RequestPasswordReset } from "@src/pages/auth.tsx", +} + +route PasswordResetRoute { path: "/password-reset", to: PasswordResetPage } +page PasswordResetPage { + component: import { PasswordReset } from "@src/pages/auth.tsx", +} + +route EmailVerificationRoute { path: "/email-verification", to: EmailVerificationPage } +page EmailVerificationPage { + component: import { EmailVerification } from "@src/pages/auth.tsx", +} +``` + + + +We'll define the React components for these pages in the `src/pages/auth.{jsx,tsx}` file below. + +### 4. Create the Client Pages + +:::info +We are using [Tailwind CSS](https://tailwindcss.com/) to style the pages. Read more about how to add it [here](../project/css-frameworks). +::: + +Let's create a `auth.{jsx,tsx}` file in the `src/pages` folder and add the following to it: + + + + +```tsx title="src/pages/auth.jsx" +import { + LoginForm, + SignupForm, + VerifyEmailForm, + ForgotPasswordForm, + ResetPasswordForm, +} from 'wasp/client/auth' +import { Link } from 'react-router-dom' + +export function Login() { + return ( + + +
    + + Don't have an account yet? go to signup. + +
    + + Forgot your password? reset it + . + +
    + ); +} + +export function Signup() { + return ( + + +
    + + I already have an account (go to login). + +
    + ); +} + +export function EmailVerification() { + return ( + + +
    + + If everything is okay, go to login + +
    + ); +} + +export function RequestPasswordReset() { + return ( + + + + ); +} + +export function PasswordReset() { + return ( + + +
    + + If everything is okay, go to login + +
    + ); +} + +// A layout component to center the content +export function Layout({ children }) { + return ( +
    +
    +
    +
    {children}
    +
    +
    +
    + ); +} +``` +
    + + +```tsx title="src/pages/auth.tsx" +import { + LoginForm, + SignupForm, + VerifyEmailForm, + ForgotPasswordForm, + ResetPasswordForm, +} from 'wasp/client/auth' +import { Link } from 'react-router-dom' + +export function Login() { + return ( + + +
    + + Don't have an account yet? go to signup. + +
    + + Forgot your password? reset it + . + +
    + ); +} + +export function Signup() { + return ( + + +
    + + I already have an account (go to login). + +
    + ); +} + +export function EmailVerification() { + return ( + + +
    + + If everything is okay, go to login + +
    + ); +} + +export function RequestPasswordReset() { + return ( + + + + ); +} + +export function PasswordReset() { + return ( + + +
    + + If everything is okay, go to login + +
    + ); +} + +// A layout component to center the content +export function Layout({ children }: { children: React.ReactNode }) { + return ( +
    +
    +
    +
    {children}
    +
    +
    +
    + ); +} +``` +
    +
    + +We imported the generated Auth UI components and used them in our pages. Read more about the Auth UI components [here](../auth/ui). + +### 5. Set up an Email Sender + +To support e-mail verification and password reset flows, we need an e-mail sender. Luckily, Wasp supports several email providers out of the box. + +We'll use the `Dummy` provider to speed up the setup. It just logs the emails to the console instead of sending them. You can use any of the [supported email providers](../advanced/email#providers). + +To set up the `Dummy` provider to send emails, add the following to the `main.wasp` file: + + + + +```wasp title="main.wasp" +app myApp { + // ... + // 7. Set up the email sender + emailSender: { + provider: Dummy, + } +} +``` + + + +```wasp title="main.wasp" +app myApp { + // ... + // 7. Set up the email sender + emailSender: { + provider: Dummy, + } +} +``` + + + +### Conclusion + +That's it! We have set up email authentication in our app. 🎉 + +Running `wasp db migrate-dev` and then `wasp start` should give you a working app with email authentication. If you want to put some of the pages behind authentication, read the [auth overview](../auth/overview). + +## Login and Signup Flows + +### Login + +![Auth UI](/img/authui/login.png) + +### Signup + +![Auth UI](/img/authui/signup.png) + +Some of the behavior you get out of the box: +1. Rate limiting + + We are limiting the rate of sign-up requests to **1 request per minute** per email address. This is done to prevent spamming. + +2. Preventing user email leaks + + If somebody tries to signup with an email that already exists and it's verified, we _pretend_ that the account was created instead of saying it's an existing account. This is done to prevent leaking the user's email address. + +3. Allowing registration for unverified emails + + If a user tries to register with an existing but **unverified** email, we'll allow them to do that. This is done to prevent bad actors from locking out other users from registering with their email address. + +4. Password validation + + Read more about the default password validation rules and how to override them in [auth overview docs](../auth/overview). + +## Email Verification Flow + +:::info Automatic email verification in development + +In development mode, you can skip the email verification step by setting the `SKIP_EMAIL_VERIFICATION_IN_DEV` environment variable to `true` in your `.env.server` file: + +```env title=".env.server" +SKIP_EMAIL_VERIFICATION_IN_DEV=true +``` + +This is useful when you are developing your app and don't want to go through the email verification flow every time you sign up. It can be also useful when you are writing automated tests for your app. +::: + +By default, Wasp requires the e-mail to be verified before allowing the user to log in. This is done by sending a verification email to the user's email address and requiring the user to click on a link in the email to verify their email address. + +Our setup looks like this: + + + + +```wasp title="main.wasp" +// ... + +emailVerification: { + clientRoute: EmailVerificationRoute, +} +``` + + + +```wasp title="main.wasp" +// ... + +emailVerification: { + clientRoute: EmailVerificationRoute, +} +``` + + + +When the user receives an e-mail, they receive a link that goes to the client route specified in the `clientRoute` field. In our case, this is the `EmailVerificationRoute` route we defined in the `main.wasp` file. + +The content of the e-mail can be customized, read more about it [here](#emailverification-emailverificationconfig-). + +### Email Verification Page + +We defined our email verification page in the `auth.{jsx,tsx}` file. + +![Auth UI](/img/authui/email_verification.png) + +## Password Reset Flow + +Users can request a password and then they'll receive an e-mail with a link to reset their password. + +Some of the behavior you get out of the box: +1. Rate limiting + + We are limiting the rate of sign-up requests to **1 request per minute** per email address. This is done to prevent spamming. + +2. Preventing user email leaks + + If somebody requests a password reset with an unknown email address, we'll give back the same response as if the user requested a password reset successfully. This is done to prevent leaking information. + +Our setup in `main.wasp` looks like this: + + + + +```wasp title="main.wasp" +// ... + +passwordReset: { + clientRoute: PasswordResetRoute, +} +``` + + + +```wasp title="main.wasp" +// ... + +passwordReset: { + clientRoute: PasswordResetRoute, +} +``` + + + +### Request Password Reset Page + +Users request their password to be reset by going to the `/request-password-reset` route. We defined our request password reset page in the `auth.{jsx,tsx}` file. + +![Request password reset page](/img/authui/forgot_password_after.png) + +### Password Reset Page + +When the user receives an e-mail, they receive a link that goes to the client route specified in the `clientRoute` field. In our case, this is the `PasswordResetRoute` route we defined in the `main.wasp` file. + +![Request password reset page](/img/authui/reset_password_after.png) + +Users can enter their new password there. + +The content of the e-mail can be customized, read more about it [here](#passwordreset-passwordresetconfig-). + +## Creating a Custom Sign-up Action + +:::caution Creating a custom sign-up action + +We don't recommend creating a custom sign-up action unless you have a good reason to do so. It is a complex process and you can easily make a mistake that will compromise the security of your app. +::: + +The code of your custom sign-up action can look like this: + + + + +```wasp title="main.wasp" +// ... + +action customSignup { + fn: import { signup } from "@src/auth/signup.js", +} +``` + +```js title="src/auth/signup.js" +import { + ensurePasswordIsPresent, + ensureValidPassword, + ensureValidEmail, + createProviderId, + sanitizeAndSerializeProviderData, + deserializeAndSanitizeProviderData, + findAuthIdentity, + createUser, + createEmailVerificationLink, + sendEmailVerificationEmail, +} from 'wasp/server/auth' + +export const signup = async (args, _context) => { + ensureValidEmail(args) + ensurePasswordIsPresent(args) + ensureValidPassword(args) + + try { + const providerId = createProviderId('email', args.email) + const existingAuthIdentity = await findAuthIdentity(providerId) + + if (existingAuthIdentity) { + const providerData = deserializeAndSanitizeProviderData(existingAuthIdentity.providerData) + // Your custom code here + } else { + // sanitizeAndSerializeProviderData will hash the user's password + const newUserProviderData = await sanitizeAndSerializeProviderData({ + hashedPassword: args.password, + isEmailVerified: false, + emailVerificationSentAt: null, + passwordResetSentAt: null, + }) + await createUser( + providerId, + providerData, + // Any additional data you want to store on the User entity + {}, + ) + + // Verification link links to a client route e.g. /email-verification + const verificationLink = await createEmailVerificationLink(args.email, '/email-verification'); + try { + await sendEmailVerificationEmail( + args.email, + { + from: { + name: "My App Postman", + email: "hello@itsme.com", + }, + to: args.email, + subject: "Verify your email", + text: `Click the link below to verify your email: ${verificationLink}`, + html: ` +

    Click the link below to verify your email

    + Verify email + `, + } + ); + } catch (e: unknown) { + console.error("Failed to send email verification email:", e); + throw new HttpError(500, "Failed to send email verification email."); + } + } + } catch (e) { + return { + success: false, + message: e.message, + } + } + + // Your custom code after sign-up. + // ... + + return { + success: true, + message: 'User created successfully', + } +} +``` +
    + + +```wasp title="main.wasp" +// ... + +action customSignup { + fn: import { signup } from "@src/auth/signup.js", +} +``` + +```ts title="src/auth/signup.ts" +import { + ensurePasswordIsPresent, + ensureValidPassword, + ensureValidEmail, + createProviderId, + sanitizeAndSerializeProviderData, + deserializeAndSanitizeProviderData, + findAuthIdentity, + createUser, + createEmailVerificationLink, + sendEmailVerificationEmail, +} from 'wasp/server/auth' +import type { CustomSignup } from 'wasp/server/operations' + +type CustomSignupInput = { + email: string + password: string +} +type CustomSignupOutput = { + success: boolean + message: string +} + +export const signup: CustomSignup = async (args, _context) => { + ensureValidEmail(args) + ensurePasswordIsPresent(args) + ensureValidPassword(args) + + try { + const providerId = createProviderId('email', args.email) + const existingAuthIdentity = await findAuthIdentity(providerId) + + if (existingAuthIdentity) { + const providerData = deserializeAndSanitizeProviderData<'email'>(existingAuthIdentity.providerData) + // Your custom code here + } else { + // sanitizeAndSerializeProviderData will hash the user's password + const newUserProviderData = await sanitizeAndSerializeProviderData<'email'>({ + hashedPassword: args.password, + isEmailVerified: false, + emailVerificationSentAt: null, + passwordResetSentAt: null, + }) + await createUser( + providerId, + providerData, + // Any additional data you want to store on the User entity + {}, + ) + + // Verification link links to a client route e.g. /email-verification + const verificationLink = await createEmailVerificationLink(args.email, '/email-verification'); + try { + await sendEmailVerificationEmail( + args.email, + { + from: { + name: "My App Postman", + email: "hello@itsme.com", + }, + to: args.email, + subject: "Verify your email", + text: `Click the link below to verify your email: ${verificationLink}`, + html: ` +

    Click the link below to verify your email

    + Verify email + `, + } + ); + } catch (e: unknown) { + console.error("Failed to send email verification email:", e); + throw new HttpError(500, "Failed to send email verification email."); + } + } + } catch (e) { + return { + success: false, + message: e.message, + } + } + + // Your custom code after sign-up. + // ... + + return { + success: true, + message: 'User created successfully', + } +} +``` +
    +
    + +We suggest using the built-in field validators for your authentication flow. You can import them from `wasp/server/auth`. These are the same validators that Wasp uses internally for the default authentication flow. + +#### Email + +- `ensureValidEmail(args)` + + Checks if the email is valid and throws an error if it's not. Read more about the validation rules [here](../auth/overview#default-validations). + +#### Password + +- `ensurePasswordIsPresent(args)` + + Checks if the password is present and throws an error if it's not. + +- `ensureValidPassword(args)` + + Checks if the password is valid and throws an error if it's not. Read more about the validation rules [here](../auth/overview#default-validations). + +## Using Auth + +To read more about how to set up the logout button and how to get access to the logged-in user in our client and server code, read the [auth overview docs](../auth/overview). + +### `getEmail` + +If you are looking to access the user's email in your code, you can do that by accessing the info about the user that is stored in the `user.auth.identities` array. + +To make things a bit easier for you, Wasp offers the `getEmail` helper. + + + +## API Reference + +Let's go over the options we can specify when using email authentication. + +### `userEntity` fields + + + + +```wasp title="main.wasp" +app myApp { + title: "My app", + // ... + + auth: { + userEntity: User, + methods: { + email: { + // We'll explain these options below + }, + }, + onAuthFailedRedirectTo: "/someRoute" + }, + // ... +} + +entity User {=psl + // highlight-next-line + id Int @id @default(autoincrement()) +psl=} +``` + + + + +```wasp title="main.wasp" +app myApp { + title: "My app", + // ... + + auth: { + userEntity: User, + methods: { + email: { + // We'll explain these options below + }, + }, + onAuthFailedRedirectTo: "/someRoute" + }, + // ... +} + +entity User {=psl + // highlight-next-line + id Int @id @default(autoincrement()) +psl=} +``` + + + + + +### Fields in the `email` dict + + + + +```wasp title="main.wasp" +app myApp { + title: "My app", + // ... + + auth: { + userEntity: User, + methods: { + email: { + userSignupFields: import { userSignupFields } from "@src/auth.js", + fromField: { + name: "My App", + email: "hello@itsme.com" + }, + emailVerification: { + clientRoute: EmailVerificationRoute, + getEmailContentFn: import { getVerificationEmailContent } from "@src/auth/email.js", + }, + passwordReset: { + clientRoute: PasswordResetRoute, + getEmailContentFn: import { getPasswordResetEmailContent } from "@src/auth/email.js", + }, + }, + }, + onAuthFailedRedirectTo: "/someRoute" + }, + // ... +} +``` + + + +```wasp title="main.wasp" +app myApp { + title: "My app", + // ... + + auth: { + userEntity: User, + methods: { + email: { + userSignupFields: import { userSignupFields } from "@src/auth.js", + fromField: { + name: "My App", + email: "hello@itsme.com" + }, + emailVerification: { + clientRoute: EmailVerificationRoute, + getEmailContentFn: import { getVerificationEmailContent } from "@src/auth/email.js", + }, + passwordReset: { + clientRoute: PasswordResetRoute, + getEmailContentFn: import { getPasswordResetEmailContent } from "@src/auth/email.js", + }, + }, + }, + onAuthFailedRedirectTo: "/someRoute" + }, + // ... +} +``` + + + +#### `userSignupFields: ExtImport` + + +Read more about the `userSignupFields` function [here](./overview#1-defining-extra-fields). + +#### `fromField: EmailFromField` +`fromField` is a dict that specifies the name and e-mail address of the sender of the e-mails sent by your app. + +It has the following fields: +- `name`: name of the sender +- `email`: e-mail address of the sender + +#### `emailVerification: EmailVerificationConfig` +`emailVerification` is a dict that specifies the details of the e-mail verification process. + +It has the following fields: +- `clientRoute: Route`: a route that is used for the user to verify their e-mail address. + + Client route should handle the process of taking a token from the URL and sending it to the server to verify the e-mail address. You can use our `verifyEmail` action for that. + + + + + ```js title="src/pages/EmailVerificationPage.jsx" + import { verifyEmail } from 'wasp/client/auth' + ... + await verifyEmail({ token }); + ``` + + + + ```ts title="src/pages/EmailVerificationPage.tsx" + import { verifyEmail } from 'wasp/client/auth' + ... + await verifyEmail({ token }); + ``` + + + + :::note + We used Auth UI above to avoid doing this work of sending the token to the server manually. + ::: + +- `getEmailContentFn: ExtImport`: a function that returns the content of the e-mail that is sent to the user. + + Defining `getEmailContentFn` can be done by defining a file in the `src` directory. + + + + + ```ts title="src/email.js" + export const getVerificationEmailContent = ({ verificationLink }) => ({ + subject: 'Verify your email', + text: `Click the link below to verify your email: ${verificationLink}`, + html: ` +

    Click the link below to verify your email

    + Verify email + `, + }) + ``` +
    + + + ```ts title="src/email.ts" + import { GetVerificationEmailContentFn } from 'wasp/server/auth' + + export const getVerificationEmailContent: GetVerificationEmailContentFn = ({ + verificationLink, + }) => ({ + subject: 'Verify your email', + text: `Click the link below to verify your email: ${verificationLink}`, + html: ` +

    Click the link below to verify your email

    + Verify email + `, + }) + ``` +
    +
    + + This is the default content of the e-mail, you can customize it to your liking. + + +#### `passwordReset: PasswordResetConfig` +`passwordReset` is a dict that specifies the password reset process. + +It has the following fields: +- `clientRoute: Route`: a route that is used for the user to reset their password. + + Client route should handle the process of taking a token from the URL and a new password from the user and sending it to the server. You can use our `requestPasswordReset` and `resetPassword` actions to do that. + + + + + ```js title="src/pages/ForgotPasswordPage.jsx" + import { requestPasswordReset } from 'wasp/client/auth' + ... + await requestPasswordReset({ email }); + ``` + + ```js title="src/pages/PasswordResetPage.jsx" + import { resetPassword } from 'wasp/client/auth' + ... + await resetPassword({ password, token }) + ``` + + + + ```ts title="src/pages/ForgotPasswordPage.tsx" + import { requestPasswordReset } from 'wasp/client/auth' + ... + await requestPasswordReset({ email }); + ``` + + ```ts title="src/pages/PasswordResetPage.tsx" + import { resetPassword } from 'wasp/client/auth' + ... + await resetPassword({ password, token }) + ``` + + + + :::note + We used Auth UI above to avoid doing this work of sending the password request and the new password to the server manually. + ::: + +- `getEmailContentFn: ExtImport`: a function that returns the content of the e-mail that is sent to the user. + + Defining `getEmailContentFn` is done by defining a function that looks like this: + + + + + ```ts title="src/email.js" + export const getPasswordResetEmailContent = ({ passwordResetLink }) => ({ + subject: 'Password reset', + text: `Click the link below to reset your password: ${passwordResetLink}`, + html: ` +

    Click the link below to reset your password

    + Reset password + `, + }) + ``` +
    + + + ```ts title="src/email.ts" + import { GetPasswordResetEmailContentFn } from 'wasp/server/auth' + + export const getPasswordResetEmailContent: GetPasswordResetEmailContentFn = ({ + passwordResetLink, + }) => ({ + subject: 'Password reset', + text: `Click the link below to reset your password: ${passwordResetLink}`, + html: ` +

    Click the link below to reset your password

    + Reset password + `, + }) + ``` +
    +
    + + This is the default content of the e-mail, you can customize it to your liking. diff --git a/web/versioned_docs/version-0.13.0/auth/entities/_get-email.md b/web/versioned_docs/version-0.13.0/auth/entities/_get-email.md new file mode 100644 index 0000000000..943027a9ca --- /dev/null +++ b/web/versioned_docs/version-0.13.0/auth/entities/_get-email.md @@ -0,0 +1,47 @@ +The `getEmail` helper returns the user's email or `null` if the user doesn't have an email auth identity. + + + + +```jsx title="src/MainPage.jsx" +import { getEmail } from 'wasp/auth' + +const MainPage = ({ user }) => { + const email = getEmail(user) + // ... +} +``` + +```js title=src/tasks.js +import { getEmail } from 'wasp/auth' + +export const createTask = async (args, context) => { + const email = getEmail(context.user) + // ... +} +``` + + + + + +```tsx title="src/MainPage.tsx" +import { getEmail, AuthUser } from 'wasp/auth' + +const MainPage = ({ user }: { user: AuthUser }) => { + const email = getEmail(user) + // ... +} +``` + +```ts title=src/tasks.ts +import { getEmail } from 'wasp/auth' + +export const createTask: CreateTask<...> = async (args, context) => { + const email = getEmail(context.user) + // ... +} +``` + + + diff --git a/web/versioned_docs/version-0.13.0/auth/entities/_get-username.md b/web/versioned_docs/version-0.13.0/auth/entities/_get-username.md new file mode 100644 index 0000000000..c5b118473f --- /dev/null +++ b/web/versioned_docs/version-0.13.0/auth/entities/_get-username.md @@ -0,0 +1,47 @@ +The `getUsername` helper returns the user's username or `null` if the user doesn't have a username auth identity. + + + + +```jsx title="src/MainPage.jsx" +import { getUsername } from 'wasp/auth' + +const MainPage = ({ user }) => { + const username = getUsername(user) + // ... +} +``` + +```js title=src/tasks.js +import { getUsername } from 'wasp/auth' + +export const createTask = async (args, context) => { + const username = getUsername(context.user) + // ... +} +``` + + + + + +```tsx title="src/MainPage.tsx" +import { getUsername, AuthUser } from 'wasp/auth' + +const MainPage = ({ user }: { user: AuthUser }) => { + const username = getUsername(user) + // ... +} +``` + +```ts title=src/tasks.ts +import { getUsername } from 'wasp/auth' + +export const createTask: CreateTask<...> = async (args, context) => { + const username = getUsername(context.user) + // ... +} +``` + + + \ No newline at end of file diff --git a/web/versioned_docs/version-0.13.0/auth/entities/entities.md b/web/versioned_docs/version-0.13.0/auth/entities/entities.md new file mode 100644 index 0000000000..ab01ed93f0 --- /dev/null +++ b/web/versioned_docs/version-0.13.0/auth/entities/entities.md @@ -0,0 +1,448 @@ +--- +title: Auth Entities +--- + +import ImgWithCaption from '@site/blog/components/ImgWithCaption' +import { Internal } from '@site/src/components/Tag' +import MultipleIdentitiesWarning from '../\_multiple-identities-warning.md'; +import GetEmail from './\_get-email.md'; +import GetUsername from './\_get-username.md'; + +Wasp supports multiple different authentication methods and for each method, we need to store different information about the user. For example, if you are using the [Username & password](./username-and-pass) authentication method, we need to store the user's username and password. On the other hand, if you are using the [Email](./email) authentication method, you will need to store the user's email, password and for example, their email verification status. + +## Entities Explained + +To store user information, Wasp creates a few entities behind the scenes. In this section, we will explain what entities are created and how they are connected. + +### User Entity + +When you want to add authentication to your app, you need to specify the user entity e.g. `User` in your Wasp file. This entity is a "business logic user" which represents a user of your app. + +You can use this entity to store any information about the user that you want to store. For example, you might want to store the user's name or address. You can also use the user entity to define the relations between users and other entities in your app. For example, you might want to define a relation between a user and the tasks that they have created. + +```wasp +entity User {=psl + id Int @id @default(autoincrement()) + // Any other fields you want to store about the user +psl=} +``` + +You **own** the user entity and you can modify it as you wish. You can add new fields to it, remove fields from it, or change the type of the fields. You can also add new relations to it or remove existing relations from it. + + + +On the other hand, the `Auth`, `AuthIdentity` and `Session` entities are created behind the scenes and are used to store the user's login credentials. You as the developer don't need to care about this entity most of the time. Wasp **owns** these entities. + +In the case you want to create a custom signup action, you will need to use the `Auth` and `AuthIdentity` entities directly. + +### Example App Model +Let's imagine we created a simple tasks management app: + + - The app has email and Google-based auth. + - Users can create tasks and see the tasks that they have created. + +Let's look at how would that look in the database: + + + +If we take a look at an example user in the database, we can see: +- The business logic user, `User` is connected to multiple `Task` entities. + - In this example, "Example User" has two tasks. +- The `User` is connected to exactly one `Auth` entity. +- Each `Auth` entity can have multiple `AuthIdentity` entities. + - In this example, the `Auth` entity has two `AuthIdentity` entities: one for the email-based auth and one for the Google-based auth. +- Each `Auth` entity can have multiple `Session` entities. + - In this example, the `Auth` entity has one `Session` entity. + + + +### `Auth` Entity + +Wasp's internal `Auth` entity is used to connect the business logic user, `User` with the user's login credentials. + +```wasp +entity Auth {=psl + id String @id @default(uuid()) + userId Int? @unique + // Wasp injects this relation on the User entity as well + user User? @relation(fields: [userId], references: [id], onDelete: Cascade) + identities AuthIdentity[] + sessions Session[] +psl=} +``` + +The `Auth` fields: + +- `id` is a unique identifier of the `Auth` entity. +- `userId` is a foreign key to the `User` entity. + - It is used to connect the `Auth` entity with the business logic user. +- `user` is a relation to the `User` entity. + - This relation is injected on the `User` entity as well. +- `identities` is a relation to the `AuthIdentity` entity. +- `sessions` is a relation to the `Session` entity. + +### `AuthIdentity` Entity + +The `AuthIdentity` entity is used to store the user's login credentials for various authentication methods. + +```wasp +entity AuthIdentity {=psl + providerName String + providerUserId String + providerData String @default("{}") + authId String + auth Auth @relation(fields: [authId], references: [id], onDelete: Cascade) + + @@id([providerName, providerUserId]) +psl=} +``` + +The `AuthIdentity` fields: +- `providerName` is the name of the authentication provider. + - For example, `email` or `google`. +- `providerUserId` is the user's ID in the authentication provider. + - For example, the user's email or Google ID. +- `providerData` is a JSON string that contains additional data about the user from the authentication provider. + - For example, for password based auth, this field contains the user's hashed password. + - This field is a `String` and not a `Json` type because [Prisma doesn't support the `Json` type for SQLite](https://github.com/prisma/prisma/issues/3786). +- `authId` is a foreign key to the `Auth` entity. + - It is used to connect the `AuthIdentity` entity with the `Auth` entity. +- `auth` is a relation to the `Auth` entity. + +### `Session` Entity + +The `Session` entity is used to store the user's session information. It is used to keep the user logged in between page refreshes. + +```wasp +entity Session {=psl + id String @id @unique + expiresAt DateTime + userId String + auth Auth @relation(references: [id], fields: [userId], onDelete: Cascade) + + @@index([userId]) +psl=} +``` + +The `Session` fields: +- `id` is a unique identifier of the `Session` entity. +- `expiresAt` is the date when the session expires. +- `userId` is a foreign key to the `Auth` entity. + - It is used to connect the `Session` entity with the `Auth` entity. +- `auth` is a relation to the `Auth` entity. + +## Accessing the Auth Fields + +If you are looking to access the user's email or username in your code, you can do that by accessing the info about the user that is stored in the `AuthIdentity` entity. + +Everywhere where Wasp gives you the `user` object, it also includes the `auth` relation with the `identities` relation. This means that you can access the auth identity info by using the `user.auth.identities` array. + +To make things a bit easier for you, Wasp offers a few helper functions that you can use to access the auth identity info. + +### `getEmail` + + + +### `getUsername` + + + +### `getFirstProviderUserId` + +The `getFirstProviderUserId` helper returns the first user ID (e.g. `username` or `email`) that it finds for the user or `null` if it doesn't find any. + +[As mentioned before](#authidentity-entity-), the `providerUserId` field is how providers identify our users. For example, the user's `username` in the case of the username auth or the user's `email` in the case of the email auth. This can be useful if you support multiple authentication methods and you need *any* ID that identifies the user in your app. + + + + +```jsx title="src/MainPage.jsx" +import { getFirstProviderUserId } from 'wasp/auth' + +const MainPage = ({ user }) => { + const userId = getFirstProviderUserId(user) + // ... +} +``` + +```js title=src/tasks.js +import { getFirstProviderUserId } from 'wasp/auth' + +export const createTask = async (args, context) => { + const userId = getFirstProviderUserId(context.user) + // ... +} +``` + + + + + +```tsx title="src/MainPage.tsx" +import { getFirstProviderUserId, AuthUser } from 'wasp/auth' + +const MainPage = ({ user }: { user: AuthUser }) => { + const userId = getFirstProviderUserId(user) + // ... +} +``` + +```ts title=src/tasks.ts +import { getFirstProviderUserId } from 'wasp/auth' + +export const createTask: CreateTask<...> = async (args, context) => { + const userId = getFirstProviderUserId(context.user) + // ... +} +``` + + + + +### `findUserIdentity` + +You can find a specific auth identity by using the `findUserIdentity` helper function. This function takes a `user` and a `providerName` and returns the first `providerName` identity that it finds or `null` if it doesn't find any. + +Possible provider names are: +- `email` +- `username` +- `google` +- `github` + +This can be useful if you want to check if the user has a specific auth identity. For example, you might want to check if the user has an email auth identity or Google auth identity. + + + + +```jsx title="src/MainPage.jsx" +import { findUserIdentity } from 'wasp/auth' + +const MainPage = ({ user }) => { + const emailIdentity = findUserIdentity(user, 'email') + const googleIdentity = findUserIdentity(user, 'google') + if (emailIdentity) { + // ... + } else if (googleIdentity) { + // ... + } + // ... +} +``` + +```js title=src/tasks.js +import { findUserIdentity } from 'wasp/client/auth' + +export const createTask = async (args, context) => { + const emailIdentity = findUserIdentity(context.user, 'email') + const googleIdentity = findUserIdentity(context.user, 'google') + if (emailIdentity) { + // ... + } else if (googleIdentity) { + // ... + } + // ... +} +``` + + + + + +```tsx title="src/MainPage.tsx" +import { findUserIdentity, AuthUser } from 'wasp/auth' + +const MainPage = ({ user }: { user: AuthUser }) => { + const emailIdentity = findUserIdentity(user, 'email') + const googleIdentity = findUserIdentity(user, 'google') + if (emailIdentity) { + // ... + } else if (googleIdentity) { + // ... + } + // ... +} +``` + +```ts title=src/tasks.ts +import { findUserIdentity } from 'wasp/client/auth' + +export const createTask: CreateTask<...> = async (args, context) => { + const emailIdentity = findUserIdentity(context.user, 'email') + const googleIdentity = findUserIdentity(context.user, 'google') + if (emailIdentity) { + // ... + } else if (googleIdentity) { + // ... + } + // ... +} +``` + + + + +## Custom Signup Action + +Let's take a look at how you can use the `Auth` and `AuthIdentity` entities to create custom login and signup actions. For example, you might want to create a custom signup action that creates a user in your app and also creates a user in a third-party service. + +:::info Custom Signup Examples + +In the [Email](./email#creating-a-custom-sign-up-action) section of the docs we give you an example for custom email signup and in the [Username & password](./username-and-pass#2-creating-your-custom-sign-up-action) section of the docs we give you an example for custom username & password signup. +::: + +Below is a simplified version of a custom signup action which you probably wouldn't use in your app but it shows you how you can use the `Auth` and `AuthIdentity` entities to create a custom signup action. + + + + +```wasp title="main.wasp" +// ... + +action customSignup { + fn: import { signup } from "@src/auth/signup.js", + entities: [User] +} +``` + + +```js title="src/auth/signup.js" +import { + createProviderId, + sanitizeAndSerializeProviderData, + createUser, +} from 'wasp/server/auth' + +export const signup = async (args, { entities: { User } }) => { + try { + // Provider ID is a combination of the provider name and the provider user ID + // And it is used to uniquely identify the user in your app + const providerId = createProviderId('username', args.username) + // sanitizeAndSerializeProviderData hashes the password and returns a JSON string + const providerData = await sanitizeAndSerializeProviderData({ + hashedPassword: args.password, + }) + + await createUser( + providerId, + providerData, + // Any additional data you want to store on the User entity + {}, + ) + + // This is equivalent to: + // await User.create({ + // data: { + // auth: { + // create: { + // identities: { + // create: { + // providerName: 'username', + // providerUserId: args.username + // providerData, + // }, + // }, + // } + // }, + // } + // }) + } catch (e) { + return { + success: false, + message: e.message, + } + } + + // Your custom code after sign-up. + // ... + + return { + success: true, + message: 'User created successfully', + } +} +``` + + + +```wasp title="main.wasp" +// ... + +action customSignup { + fn: import { signup } from "@src/auth/signup.js", + entities: [User] +} +``` + +```ts title="src/auth/signup.ts" +import { + createProviderId, + sanitizeAndSerializeProviderData, + createUser, +} from 'wasp/server/auth' +import type { CustomSignup } from 'wasp/server/operations' + +type CustomSignupInput = { + username: string + password: string +} +type CustomSignupOutput = { + success: boolean + message: string +} + +export const signup: CustomSignup< + CustomSignupInput, + CustomSignupOutput +> = async (args, { entities: { User } }) => { + try { + // Provider ID is a combination of the provider name and the provider user ID + // And it is used to uniquely identify the user in your app + const providerId = createProviderId('username', args.username) + // sanitizeAndSerializeProviderData hashes the password and returns a JSON string + const providerData = await sanitizeAndSerializeProviderData<'username'>({ + hashedPassword: args.password, + }) + + await createUser( + providerId, + providerData, + // Any additional data you want to store on the User entity + {}, + ) + + // This is equivalent to: + // await User.create({ + // data: { + // auth: { + // create: { + // identities: { + // create: { + // providerName: 'username', + // providerUserId: args.username + // providerData, + // }, + // }, + // } + // }, + // } + // }) + } catch (e) { + return { + success: false, + message: e.message, + } + } + + // Your custom code after sign-up. + // ... + + return { + success: true, + message: 'User created successfully', + } +} +``` + + + +You can use whichever method suits your needs better: either the `createUser` function or Prisma's `User.create` method. The `createUser` function is a bit more convenient to use because it hides some of the complexity. On the other hand, the `User.create` method gives you more control over the data that is stored in the `Auth` and `AuthIdentity` entities. \ No newline at end of file diff --git a/web/versioned_docs/version-0.13.0/auth/overview.md b/web/versioned_docs/version-0.13.0/auth/overview.md new file mode 100644 index 0000000000..c3666b81f4 --- /dev/null +++ b/web/versioned_docs/version-0.13.0/auth/overview.md @@ -0,0 +1,1195 @@ +--- +title: Overview +--- + +import { AuthMethodsGrid } from "@site/src/components/AuthMethodsGrid"; +import { Required } from '@site/src/components/Tag'; +import ReadMoreAboutAuthEntities from './\_read-more-about-auth-entities.md'; + +Auth is an essential piece of any serious application. That's why Wasp provides authentication and authorization support out of the box. + +Here's a 1-minute tour of how full-stack auth works in Wasp: + +
    + +
    + +Enabling auth for your app is optional and can be done by configuring the `auth` field of your `app` declaration: + + + + +```wasp title="main.wasp" +app MyApp { + title: "My app", + //... + auth: { + userEntity: User, + methods: { + usernameAndPassword: {}, // use this or email, not both + email: {}, // use this or usernameAndPassword, not both + google: {}, + gitHub: {}, + }, + onAuthFailedRedirectTo: "/someRoute" + } +} + +//... +``` + + + + +```wasp title="main.wasp" +app MyApp { + title: "My app", + //... + auth: { + userEntity: User, + methods: { + usernameAndPassword: {}, // use this or email, not both + email: {}, // use this or usernameAndPassword, not both + google: {}, + gitHub: {}, + }, + onAuthFailedRedirectTo: "/someRoute" + } +} + +//... +``` + + + + + + +Read more about the `auth` field options in the [API Reference](#api-reference) section. + + + +We will provide a quick overview of auth in Wasp and link to more detailed documentation for each auth method. + +## Available auth methods + +Wasp supports the following auth methods: + + + +Let's say we enabled the [Username & password](../auth/username-and-pass) authentication. + +We get an auth backend with signup and login endpoints. We also get the `user` object in our [Operations](../data-model/operations/overview) and we can decide what to do based on whether the user is logged in or not. + +We would also get the [Auth UI](../auth/ui) generated for us. We can set up our login and signup pages where our users can **create their account** and **login**. We can then protect certain pages by setting `authRequired: true` for them. This will make sure that only logged-in users can access them. + +We will also have access to the `user` object in our frontend code, so we can show different UI to logged-in and logged-out users. For example, we can show the user's name in the header alongside a **logout button** or a login button if the user is not logged in. + +## Protecting a page with `authRequired` + +When declaring a page, you can set the `authRequired` property. + +If you set it to `true`, only authenticated users can access the page. Unauthenticated users are redirected to a route defined by the `app.auth.onAuthFailedRedirectTo` field. + + + + +```wasp title="main.wasp" +page MainPage { + component: import Main from "@src/pages/Main", + authRequired: true +} +``` + + + + +```wasp title="main.wasp" +page MainPage { + component: import Main from "@src/pages/Main", + authRequired: true +} +``` + + + + +:::caution Requires auth method +You can only use `authRequired` if your app uses one of the [available auth methods](#available-auth-methods). +::: + +If `authRequired` is set to `true`, the page's React component (specified by the `component` property) receives the `user` object as a prop. Read more about the `user` object in the [Accessing the logged-in user section](#accessing-the-logged-in-user). + +## Logout action + +We provide an action for logging out the user. Here's how you can use it: + + + + +```jsx title="src/components/LogoutButton.jsx" +import { logout } from 'wasp/client/auth' + +const LogoutButton = () => { + return +} +``` + + + + +```tsx title="src/components/LogoutButton.tsx" +import { logout } from 'wasp/client/auth' + +const LogoutButton = () => { + return +} +``` + + + + +## Accessing the logged-in user + +You can get access to the `user` object both on the server and on the client. The `user` object contains the logged-in user's data. + +The `user` object has all the fields that you defined in your `User` entity, plus the `auth` field which contains the auth identities connected to the user. For example, if the user signed up with their email, the `user` object might look something like this: + +```js +const user = { + id: "19c7d164-b5cb-4dde-a0cc-0daea77cf854", + + // Your entity's fields. + address: "My address", + // ... + + // Auth identities connected to the user. + auth: { + id: "26ab6f96-ed76-4ee5-9ac3-2fd0bf19711f", + identities: [ + { + providerName: "email", + providerUserId: "some@email.com", + providerData: { ... }, + }, + ] + }, +} +``` + + + +### On the client + +There are two ways to access the `user` object on the client: + +- the `user` prop +- the `useAuth` hook + +#### Using the `user` prop + +If the page's declaration sets `authRequired` to `true`, the page's React component receives the `user` object as a prop: + + + + +```wasp title="main.wasp" +// ... + +page AccountPage { + component: import Account from "@src/pages/Account", + authRequired: true +} +``` + +```jsx title="src/pages/Account.jsx" +import Button from './Button' +import { logout } from 'wasp/client/auth' + +const AccountPage = ({ user }) => { + return ( +
    + + {JSON.stringify(user, null, 2)} +
    + ) +} + +export default AccountPage +``` + +
    + + +```wasp title="main.wasp" +// ... + +page AccountPage { + component: import Account from "@src/pages/Account", + authRequired: true +} +``` + +```tsx title="src/pages/Account.tsx" +import { type AuthUser } from 'wasp/auth' +import Button from './Button' +import { logout } from 'wasp/client/auth' + +const AccountPage = ({ user }: { user: AuthUser }) => { + return ( +
    + + {JSON.stringify(user, null, 2)} +
    + ) +} + +export default AccountPage +``` + +
    +
    + +#### Using the `useAuth` hook + +Wasp provides a React hook you can use in the client components - `useAuth`. + +This hook is a thin wrapper over Wasp's `useQuery` hook and returns data in the same format. + + + + +```jsx title="src/pages/MainPage.jsx" +import { useAuth, logout } from 'wasp/client/auth' +import { Link } from 'react-router-dom' +import Todo from '../Todo' + +export function Main() { + const { data: user } = useAuth() + + if (!user) { + return ( + + Please login or{' '} + sign up. + + ) + } else { + return ( + <> + + + + ) + } +} +``` + + + + +```tsx title="src/pages/MainPage.tsx" +import { useAuth, logout } from 'wasp/client/auth' +import { Link } from 'react-router-dom' +import Todo from '../Todo' + +export function Main() { + const { data: user } = useAuth() + + if (!user) { + return ( + + Please login or sign up. + + ) + } else { + return ( + <> + + + < /> + ) + } +} +``` + + + + +:::tip +Since the `user` prop is only available in a page's React component: use the `user` prop in the page's React component and the `useAuth` hook in any other React component. +::: + +### On the server + +#### Using the `context.user` object + +When authentication is enabled, all [queries and actions](../data-model/operations/overview) have access to the `user` object through the `context` argument. `context.user` contains all User entity's fields and the auth identities connected to the user. We strip out the `hashedPassword` field from the identities for security reasons. + + + + +```js title="src/actions.js" +import { HttpError } from 'wasp/server' + +export const createTask = async (task, context) => { + if (!context.user) { + throw new HttpError(403) + } + + const Task = context.entities.Task + return Task.create({ + data: { + description: task.description, + user: { + connect: { id: context.user.id }, + }, + }, + }) +} +``` + + + + +```ts title="src/actions.ts" +import { type Task } from 'wasp/entities' +import { type CreateTask } from 'wasp/server/operations' +import { HttpError } from 'wasp/server' + +type CreateTaskPayload = Pick + +export const createTask: CreateTask = async ( + args, + context +) => { + if (!context.user) { + throw new HttpError(403) + } + + const Task = context.entities.Task + return Task.create({ + data: { + description: args.description, + user: { + connect: { id: context.user.id }, + }, + }, + }) +} +``` + + + + +To implement access control in your app, each operation must check `context.user` and decide what to do. For example, if `context.user` is `undefined` inside a private operation, the user's access should be denied. + +When using WebSockets, the `user` object is also available on the `socket.data` object. Read more in the [WebSockets section](../advanced/web-sockets#websocketfn-function). + +## Sessions + +Wasp's auth uses sessions to keep track of the logged-in user. The session is stored in `localStorage` on the client and in the database on the server. Under the hood, Wasp uses the excellent [Lucia Auth v3](https://v3.lucia-auth.com/) library for session management. + +When users log in, Wasp creates a session for them and stores it in the database. The session is then sent to the client and stored in `localStorage`. When users log out, Wasp deletes the session from the database and from `localStorage`. + +## User Entity + +### Password Hashing + +If you are saving a user's password in the database, you should **never** save it as plain text. You can use Wasp's helper functions for serializing and deserializing provider data which will automatically hash the password for you: + +```wasp title="main.wasp" +// ... + +action updatePassword { + fn: import { updatePassword } from "@src/auth", +} +``` + + + + +```js title="src/auth.js" +import { + createProviderId, + findAuthIdentity, + updateAuthIdentityProviderData, + deserializeAndSanitizeProviderData, +} from 'wasp/server/auth'; + +export const updatePassword = async (args, context) => { + const providerId = createProviderId('email', args.email) + const authIdentity = await findAuthIdentity(providerId) + if (!authIdentity) { + throw new HttpError(400, "Unknown user") + } + + const providerData = deserializeAndSanitizeProviderData(authIdentity.providerData) + + // Updates the password and hashes it automatically. + await updateAuthIdentityProviderData(providerId, providerData, { + hashedPassword: args.password, + }) +} +``` + + + + +```ts title="src/auth.ts" +import { + createProviderId, + findAuthIdentity, + updateAuthIdentityProviderData, + deserializeAndSanitizeProviderData, +} from 'wasp/server/auth'; +import { type UpdatePassword } from 'wasp/server/operations' + +export const updatePassword: UpdatePassword< + { email: string; password: string }, + void, +> = async (args, context) => { + const providerId = createProviderId('email', args.email) + const authIdentity = await findAuthIdentity(providerId) + if (!authIdentity) { + throw new HttpError(400, "Unknown user") + } + + const providerData = deserializeAndSanitizeProviderData<'email'>(authIdentity.providerData) + + // Updates the password and hashes it automatically. + await updateAuthIdentityProviderData(providerId, providerData, { + hashedPassword: args.password, + }) +} +``` + + + + +### Default Validations + +When you are using the default authentication flow, Wasp validates the fields with some default validations. These validations run if you use Wasp's built-in [Auth UI](./ui) or if you use the provided auth actions. + +If you decide to create your [custom auth actions](./username-and-pass#2-creating-your-custom-sign-up-action), you'll need to run the validations yourself. + +Default validations depend on the auth method you use. + +#### Username & Password + +If you use [Username & password](./username-and-pass) authentication, the default validations are: + +- The `username` must not be empty +- The `password` must not be empty, have at least 8 characters, and contain a number + +Note that `username`s are stored in a **case-insensitive** manner. + +#### Email + +If you use [Email](./email) authentication, the default validations are: + +- The `email` must not be empty and a valid email address +- The `password` must not be empty, have at least 8 characters, and contain a number + +Note that `email`s are stored in a **case-insensitive** manner. + +## Customizing the Signup Process + +Sometimes you want to include **extra fields** in your signup process, like first name and last name and save them in the `User` entity. + +For this to happen: + +- you need to define the fields that you want saved in the database, +- you need to customize the `SignupForm` (in the case of [Email](./email) or [Username & Password](./username-and-pass) auth) + + +Other times, you might need to just add some **extra UI** elements to the form, like a checkbox for terms of service. In this case, customizing only the UI components is enough. + +Let's see how to do both. + +### 1. Defining Extra Fields + +If we want to **save** some extra fields in our signup process, we need to tell our app they exist. + +We do that by defining an object where the keys represent the field name, and the values are functions that receive the data sent from the client\* and return the value of the field. + + + +\* We exclude the `password` field from this object to prevent it from being saved as plain-text in the database. The `password` field is handled by Wasp's auth backend. + + +First, we add the `auth.methods.{authMethod}.userSignupFields` field in our `main.wasp` file. The `{authMethod}` depends on the auth method you are using. + +For example, if you are using [Username & Password](./username-and-pass), you would add the `auth.methods.usernameAndPassword.userSignupFields` field: + + + + +```wasp title="main.wasp" +app crudTesting { + // ... + auth: { + userEntity: User, + methods: { + usernameAndPassword: { + userSignupFields: import { userSignupFields } from "@src/auth/signup", + }, + }, + onAuthFailedRedirectTo: "/login", + }, +} + +entity User {=psl + id Int @id @default(autoincrement()) + address String? +psl=} +``` + +Then we'll define the `userSignupFields` object in the `src/auth/signup.js` file: + +```ts title="src/auth/signup.js" +import { defineUserSignupFields } from 'wasp/server/auth' + +export const userSignupFields = defineUserSignupFields({ + address: async (data) => { + const address = data.address + if (typeof address !== 'string') { + throw new Error('Address is required') + } + if (address.length < 5) { + throw new Error('Address must be at least 5 characters long') + } + return address + }, +}) +``` + + + + +```wasp title="main.wasp" +app crudTesting { + // ... + auth: { + userEntity: User, + methods: { + usernameAndPassword: { + userSignupFields: import { userSignupFields } from "@src/auth/signup", + }, + }, + onAuthFailedRedirectTo: "/login", + }, +} + +entity User {=psl + id Int @id @default(autoincrement()) + address String? +psl=} +``` + +Then we'll define the `userSignupFields` object in the `src/auth/signup.js` file: + +```ts title="src/auth/signup.ts" +import { defineUserSignupFields } from 'wasp/server/auth' + +export const userSignupFields = defineUserSignupFields({ + address: async (data) => { + const address = data.address + if (typeof address !== 'string') { + throw new Error('Address is required') + } + if (address.length < 5) { + throw new Error('Address must be at least 5 characters long') + } + return address + }, +}) +``` + + + + + + +Read more about the `userSignupFields` object in the [API Reference](#signup-fields-customization). + + +Keep in mind, that these field names need to exist on the `userEntity` you defined in your `main.wasp` file e.g. `address` needs to be a field on the `User` entity. + +The field function will receive the data sent from the client and it needs to return the value that will be saved into the database. If the field is invalid, the function should throw an error. + +:::info Using Validation Libraries + +You can use any validation library you want to validate the fields. For example, you can use `zod` like this: + +
    +Click to see the code + + + + +```js title="src/auth/signup.js" +import { defineUserSignupFields } from 'wasp/server/auth' +import * as z from 'zod' + +export const userSignupFields = defineUserSignupFields({ + address: (data) => { + const AddressSchema = z + .string({ + required_error: 'Address is required', + invalid_type_error: 'Address must be a string', + }) + .min(10, 'Address must be at least 10 characters long') + const result = AddressSchema.safeParse(data.address) + if (result.success === false) { + throw new Error(result.error.issues[0].message) + } + return result.data + }, +}) +``` + + + + +```ts title="src/auth/signup.ts" +import { defineUserSignupFields } from 'wasp/server/auth' +import * as z from 'zod' + +export const userSignupFields = defineUserSignupFields({ + address: (data) => { + const AddressSchema = z + .string({ + required_error: 'Address is required', + invalid_type_error: 'Address must be a string', + }) + .min(10, 'Address must be at least 10 characters long') + const result = AddressSchema.safeParse(data.address) + if (result.success === false) { + throw new Error(result.error.issues[0].message) + } + return result.data + }, +}) +``` + + + +
    + +::: + +Now that we defined the fields, Wasp knows how to: + +1. Validate the data sent from the client +2. Save the data to the database + +Next, let's see how to customize [Auth UI](../auth/ui) to include those fields. + +### 2. Customizing the Signup Component + +:::tip Using Custom Signup Component + +If you are not using Wasp's Auth UI, you can skip this section. Just make sure to include the extra fields in your custom signup form. + +Read more about using the signup actions for: + +- email auth [here](../auth/email#fields-in-the-email-dict) +- username & password auth [here](../auth/username-and-pass#customizing-the-auth-flow) +::: + +If you are using Wasp's Auth UI, you can customize the `SignupForm` component by passing the `additionalFields` prop to it. It can be either a list of extra fields or a render function. + +#### Using a List of Extra Fields + +When you pass in a list of extra fields to the `SignupForm`, they are added to the form one by one, in the order you pass them in. + +Inside the list, there can be either **objects** or **render functions** (you can combine them): + +1. Objects are a simple way to describe new fields you need, but a bit less flexible than render functions. +2. Render functions can be used to render any UI you want, but they require a bit more code. The render functions receive the `react-hook-form` object and the form state object as arguments. + + + + +```jsx title="src/SignupPage.jsx" +import { + SignupForm, + FormError, + FormInput, + FormItemGroup, + FormLabel, +} from 'wasp/client/auth' + +export const SignupPage = () => { + return ( + { + return ( + + Phone Number + + {form.formState.errors.phoneNumber && ( + + {form.formState.errors.phoneNumber.message} + + )} + + ) + }, + ]} + /> + ) +} +``` + + + + +```tsx title="src/SignupPage.tsx" +import { + SignupForm, + FormError, + FormInput, + FormItemGroup, + FormLabel, +} from 'wasp/client/auth' + +export const SignupPage = () => { + return ( + { + return ( + + Phone Number + + {form.formState.errors.phoneNumber && ( + + {form.formState.errors.phoneNumber.message} + + )} + + ) + }, + ]} + /> + ) +} +``` + + + + + + +Read more about the extra fields in the [API Reference](#signupform-customization). + + +#### Using a Single Render Function + +Instead of passing in a list of extra fields, you can pass in a render function which will receive the `react-hook-form` object and the form state object as arguments. What ever the render function returns, will be rendered below the default fields. + + + + +```jsx title="src/SignupPage.jsx" +import { SignupForm, FormItemGroup } from 'wasp/client/auth' + +export const SignupPage = () => { + return ( + { + const username = form.watch('username') + return ( + username && ( + + Hello there {username} 👋 + + ) + ) + }} + /> + ) +} +``` + + + + +```tsx title="src/SignupPage.tsx" +import { SignupForm, FormItemGroup } from 'wasp/client/auth' + +export const SignupPage = () => { + return ( + { + const username = form.watch('username') + return ( + username && ( + + Hello there {username} 👋 + + ) + ) + }} + /> + ) +} +``` + + + + + + +Read more about the render function in the [API Reference](#signupform-customization). + + +## API Reference + +### Auth Fields + + + + +```wasp title="main.wasp" + title: "My app", + //... + auth: { + userEntity: User, + methods: { + usernameAndPassword: {}, // use this or email, not both + email: {}, // use this or usernameAndPassword, not both + google: {}, + gitHub: {}, + }, + onAuthFailedRedirectTo: "/someRoute", + signup: { ... } + } +} + +//... +``` + + + + +```wasp title="main.wasp" +app MyApp { + title: "My app", + //... + auth: { + userEntity: User, + methods: { + usernameAndPassword: {}, // use this or email, not both + email: {}, // use this or usernameAndPassword, not both + google: {}, + gitHub: {}, + }, + onAuthFailedRedirectTo: "/someRoute", + signup: { ... } + } +} + +//... +``` + + + + +`app.auth` is a dictionary with the following fields: + +#### `userEntity: entity` + +The entity representing the user connected to your business logic. + + + +#### `methods: dict` + +A dictionary of auth methods enabled for the app. + + + +#### `onAuthFailedRedirectTo: String` + +The route to which Wasp should redirect unauthenticated user when they try to access a private page (i.e., a page that has `authRequired: true`). +Check out these [essentials docs on auth](../tutorial/auth#adding-auth-to-the-project) to see an example of usage. + +#### `onAuthSucceededRedirectTo: String` + +The route to which Wasp will send a successfully authenticated after a successful login/signup. +The default value is `"/"`. + +:::note +Automatic redirect on successful login only works when using the Wasp-provided [Auth UI](../auth/ui). +::: + +#### `signup: SignupOptions` + +Read more about the signup process customization API in the [Signup Fields Customization](#signup-fields-customization) section. + +### Signup Fields Customization + +If you want to add extra fields to the signup process, the server needs to know how to save them to the database. You do that by defining the `auth.methods.{authMethod}.userSignupFields` field in your `main.wasp` file. + + + + +```wasp title="main.wasp" +app crudTesting { + // ... + auth: { + userEntity: User, + methods: { + usernameAndPassword: { + // highlight-next-line + userSignupFields: import { userSignupFields } from "@src/auth/signup", + }, + }, + onAuthFailedRedirectTo: "/login", + }, +} +``` + +Then we'll export the `userSignupFields` object from the `src/auth/signup.js` file: + +```ts title="src/auth/signup.js" +import { defineUserSignupFields } from 'wasp/server/auth' + +export const userSignupFields = defineUserSignupFields({ + address: async (data) => { + const address = data.address + if (typeof address !== 'string') { + throw new Error('Address is required') + } + if (address.length < 5) { + throw new Error('Address must be at least 5 characters long') + } + return address + }, +}) +``` + + + + +```wasp title="main.wasp" +app crudTesting { + // ... + auth: { + userEntity: User, + methods: { + usernameAndPassword: { + // highlight-next-line + userSignupFields: import { userSignupFields } from "@src/auth/signup", + }, + }, + onAuthFailedRedirectTo: "/login", + }, +} +``` + +Then we'll export the `userSignupFields` object from the `src/auth/signup.ts` file: + +```ts title="src/auth/signup.ts" +import { defineUserSignupFields } from 'wasp/server/auth' + +export const userSignupFields = defineUserSignupFields({ + address: async (data) => { + const address = data.address + if (typeof address !== 'string') { + throw new Error('Address is required') + } + if (address.length < 5) { + throw new Error('Address must be at least 5 characters long') + } + return address + }, +}) +``` + + + + +The `userSignupFields` object is an object where the keys represent the field name, and the values are functions that receive the data sent from the client\* and return the value of the field. + +If the value that the function received is invalid, the function should throw an error. + + + +\* We exclude the `password` field from this object to prevent it from being saved as plain text in the database. The `password` field is handled by Wasp's auth backend. + + +### `SignupForm` Customization + +To customize the `SignupForm` component, you need to pass in the `additionalFields` prop. It can be either a list of extra fields or a render function. + + + + +```jsx title="src/SignupPage.jsx" +import { + SignupForm, + FormError, + FormInput, + FormItemGroup, + FormLabel, +} from 'wasp/client/auth' + +export const SignupPage = () => { + return ( + { + return ( + + Phone Number + + {form.formState.errors.phoneNumber && ( + + {form.formState.errors.phoneNumber.message} + + )} + + ) + }, + ]} + /> + ) +} +``` + + + + +```tsx title="src/SignupPage.tsx" +import { + SignupForm, + FormError, + FormInput, + FormItemGroup, + FormLabel, +} from 'wasp/client/auth' + +export const SignupPage = () => { + return ( + { + return ( + + Phone Number + + {form.formState.errors.phoneNumber && ( + + {form.formState.errors.phoneNumber.message} + + )} + + ) + }, + ]} + /> + ) +} +``` + + + + +The extra fields can be either **objects** or **render functions** (you can combine them): + +1. Objects are a simple way to describe new fields you need, but a bit less flexible than render functions. + + The objects have the following properties: + + - `name` + - the name of the field + - `label` + + - the label of the field (used in the UI) + + - `type` + + - the type of the field, which can be `input` or `textarea` + + - `validations` + - an object with the validation rules for the field. The keys are the validation names, and the values are the validation error messages. Read more about the available validation rules in the [react-hook-form docs](https://react-hook-form.com/api/useform/register#register). + +2. Render functions receive the `react-hook-form` object and the form state as arguments, and they can use them to render arbitrary UI elements. + + The render function has the following signature: + + ```ts + ;(form: UseFormReturn, state: FormState) => React.ReactNode + ``` + + - `form` + + - the `react-hook-form` object, read more about it in the [react-hook-form docs](https://react-hook-form.com/api/useform) + - you need to use the `form.register` function to register your fields + + - `state` + + - the form state object which has the following properties: + - `isLoading: boolean` + - whether the form is currently submitting diff --git a/web/versioned_docs/version-0.13.0/auth/social-auth/SocialAuthGrid.css b/web/versioned_docs/version-0.13.0/auth/social-auth/SocialAuthGrid.css new file mode 100644 index 0000000000..8efd3b68b0 --- /dev/null +++ b/web/versioned_docs/version-0.13.0/auth/social-auth/SocialAuthGrid.css @@ -0,0 +1,29 @@ +.social-auth-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); + grid-gap: 0.5rem; + margin-bottom: 1rem; +} +.auth-method-box { + display: flex; + flex-direction: column; + justify-content: center; + border: 1px solid var(--ifm-color-emphasis-300); + border-radius: var(--ifm-pagination-nav-border-radius); + padding: 1.5rem; + transition: all 0.1s ease-in-out; +} +.auth-method-box:hover { + border-color: var(--ifm-pagination-nav-color-hover); +} +.auth-method-box h3 { + margin: 0; + color: var(--ifm-link-color); +} +.auth-method-box p { + margin: 0; + color: var(--ifm-color-secondary-contrast-foreground); +} +.social-auth-info { + color: var(--ifm-color-secondary-contrast-foreground); +} diff --git a/web/versioned_docs/version-0.13.0/auth/social-auth/SocialAuthGrid.tsx b/web/versioned_docs/version-0.13.0/auth/social-auth/SocialAuthGrid.tsx new file mode 100644 index 0000000000..4aa2217974 --- /dev/null +++ b/web/versioned_docs/version-0.13.0/auth/social-auth/SocialAuthGrid.tsx @@ -0,0 +1,58 @@ +import React from 'react' +import Link from '@docusaurus/Link' +import './SocialAuthGrid.css' + +export function SocialAuthGrid({ + pagePart = '', // e.g. #overrides +}) { + const authMethods = [ + { + title: 'Google', + description: 'Users sign in with their Google account.', + linkToDocs: '/docs/auth/social-auth/google' + pagePart, + }, + { + title: 'Github', + description: 'Users sign in with their Github account.', + linkToDocs: '/docs/auth/social-auth/github' + pagePart, + }, + { + title: 'Keycloak', + description: 'Users sign in with their Keycloak account.', + linkToDocs: '/docs/auth/social-auth/keycloak' + pagePart, + }, + ] + return ( + <> +
    + {authMethods.map((authMethod) => ( + + ))} +
    +

    + Click on each provider for more details. +

    + + ) +} + +function AuthMethodBox({ + linkToDocs, + title, + description, +}: { + linkToDocs: string + title: string + description: string +}) { + return ( + +

    {title} »

    +

    {description}

    + + ) +} diff --git a/web/versioned_docs/version-0.13.0/auth/social-auth/_api-reference-intro.md b/web/versioned_docs/version-0.13.0/auth/social-auth/_api-reference-intro.md new file mode 100644 index 0000000000..f9b90f022b --- /dev/null +++ b/web/versioned_docs/version-0.13.0/auth/social-auth/_api-reference-intro.md @@ -0,0 +1,10 @@ +Provider-specific behavior comes down to implementing two functions. + +- `configFn` +- `userSignupFields` + +The reference shows how to define both. + +For behavior common to all providers, check the general [API Reference](../../auth/overview.md#api-reference). + + diff --git a/web/versioned_docs/version-0.13.0/auth/social-auth/_default-behaviour.md b/web/versioned_docs/version-0.13.0/auth/social-auth/_default-behaviour.md new file mode 100644 index 0000000000..a5e2462374 --- /dev/null +++ b/web/versioned_docs/version-0.13.0/auth/social-auth/_default-behaviour.md @@ -0,0 +1,3 @@ +When a user **signs in for the first time**, Wasp creates a new user account and links it to the chosen auth provider account for future logins. + + diff --git a/web/versioned_docs/version-0.13.0/auth/social-auth/_getuserfields-type.md b/web/versioned_docs/version-0.13.0/auth/social-auth/_getuserfields-type.md new file mode 100644 index 0000000000..091473d851 --- /dev/null +++ b/web/versioned_docs/version-0.13.0/auth/social-auth/_getuserfields-type.md @@ -0,0 +1,3 @@ +Wasp automatically generates the `defineUserSignupFields` function to help you correctly type your `userSignupFields` object. + + diff --git a/web/versioned_docs/version-0.13.0/auth/social-auth/_override-example-intro.md b/web/versioned_docs/version-0.13.0/auth/social-auth/_override-example-intro.md new file mode 100644 index 0000000000..5b89b83a92 --- /dev/null +++ b/web/versioned_docs/version-0.13.0/auth/social-auth/_override-example-intro.md @@ -0,0 +1,10 @@ +When a user logs in using a social login provider, the backend receives some data about the user. +Wasp lets you access this data inside the `userSignupFields` getters. + +For example, the User entity can include a `displayName` field which you can set based on the details received from the provider. + +Wasp also lets you customize the configuration of the providers' settings using the `configFn` function. + +Let's use this example to show both fields in action: + + diff --git a/web/versioned_docs/version-0.13.0/auth/social-auth/_override-intro.md b/web/versioned_docs/version-0.13.0/auth/social-auth/_override-intro.md new file mode 100644 index 0000000000..ea438c6fc2 --- /dev/null +++ b/web/versioned_docs/version-0.13.0/auth/social-auth/_override-intro.md @@ -0,0 +1,10 @@ +By default, Wasp doesn't store any information it receives from the social login provider. It only stores the user's ID specific to the provider. + +There are two mechanisms used for overriding the default behavior: + +- `userSignupFields` +- `configFn` + +Let's explore them in more detail. + + diff --git a/web/versioned_docs/version-0.13.0/auth/social-auth/_using-auth-note.md b/web/versioned_docs/version-0.13.0/auth/social-auth/_using-auth-note.md new file mode 100644 index 0000000000..7fe740be18 --- /dev/null +++ b/web/versioned_docs/version-0.13.0/auth/social-auth/_using-auth-note.md @@ -0,0 +1,3 @@ +To read more about how to set up the logout button and get access to the logged-in user in both client and server code, read the docs on [using auth](../../auth/overview). + + diff --git a/web/versioned_docs/version-0.13.0/auth/social-auth/_wasp-file-structure-note.md b/web/versioned_docs/version-0.13.0/auth/social-auth/_wasp-file-structure-note.md new file mode 100644 index 0000000000..b30c2c2daa --- /dev/null +++ b/web/versioned_docs/version-0.13.0/auth/social-auth/_wasp-file-structure-note.md @@ -0,0 +1,15 @@ +Here's a skeleton of how our `main.wasp` should look like after we're done: + +```wasp title="main.wasp" +// Configuring the social authentication +app myApp { + auth: { ... } +} + +// Defining entities +entity User { ... } + +// Defining routes and pages +route LoginRoute { ... } +page LoginPage { ... } +``` diff --git a/web/versioned_docs/version-0.13.0/auth/social-auth/github.md b/web/versioned_docs/version-0.13.0/auth/social-auth/github.md new file mode 100644 index 0000000000..f1359d0890 --- /dev/null +++ b/web/versioned_docs/version-0.13.0/auth/social-auth/github.md @@ -0,0 +1,562 @@ +--- +title: GitHub +--- + +import useBaseUrl from '@docusaurus/useBaseUrl'; +import DefaultBehaviour from './\_default-behaviour.md'; +import OverrideIntro from './\_override-intro.md'; +import OverrideExampleIntro from './\_override-example-intro.md'; +import UsingAuthNote from './\_using-auth-note.md'; +import WaspFileStructureNote from './\_wasp-file-structure-note.md'; +import GetUserFieldsType from './\_getuserfields-type.md'; +import ApiReferenceIntro from './\_api-reference-intro.md'; +import UserSignupFieldsExplainer from '../\_user-signup-fields-explainer.md'; + +Wasp supports Github Authentication out of the box. +GitHub is a great external auth choice when you're building apps for developers, as most of them already have a GitHub account. + +Letting your users log in using their GitHub accounts turns the signup process into a breeze. + +Let's walk through enabling Github Authentication, explain some of the default settings, and show how to override them. + +## Setting up Github Auth + +Enabling GitHub Authentication comes down to a series of steps: + +1. Enabling GitHub authentication in the Wasp file. +1. Adding the `User` entity. +1. Creating a GitHub OAuth app. +1. Adding the necessary Routes and Pages +1. Using Auth UI components in our Pages. + + + +### 1. Adding Github Auth to Your Wasp File + +Let's start by properly configuring the Auth object: + + + + +```wasp title="main.wasp" +app myApp { + wasp: { + version: "^0.13.0" + }, + title: "My App", + auth: { + // highlight-next-line + // 1. Specify the User entity (we'll define it next) + // highlight-next-line + userEntity: User, + methods: { + // highlight-next-line + // 2. Enable Github Auth + // highlight-next-line + gitHub: {} + }, + onAuthFailedRedirectTo: "/login" + }, +} +``` + + + + +```wasp title="main.wasp" +app myApp { + wasp: { + version: "^0.13.0" + }, + title: "My App", + auth: { + // highlight-next-line + // 1. Specify the User entity (we'll define it next) + // highlight-next-line + userEntity: User, + methods: { + // highlight-next-line + // 2. Enable Github Auth + // highlight-next-line + gitHub: {} + }, + onAuthFailedRedirectTo: "/login" + }, +} +``` + + + + +### 2. Add the User Entity + +Let's now define the `app.auth.userEntity` entity: + + + + +```wasp title="main.wasp" +// ... +// 3. Define the User entity +// highlight-next-line +entity User {=psl + id Int @id @default(autoincrement()) + // ... +psl=} +``` + + + + +```wasp title="main.wasp" +// ... +// 3. Define the User entity +// highlight-next-line +entity User {=psl + id Int @id @default(autoincrement()) + // ... +psl=} +``` + + + + +### 3. Creating a GitHub OAuth App + +To use GitHub as an authentication method, you'll first need to create a GitHub OAuth App and provide Wasp with your client key and secret. Here's how you do it: + +1. Log into your GitHub account and navigate to: https://github.com/settings/developers. +2. Select **New OAuth App**. +3. Supply required information. + +GitHub Applications Screenshot + +- For **Authorization callback URL**: + - For development, put: `http://localhost:3001/auth/github/callback`. + - Once you know on which URL your API server will be deployed, you can create a new app with that URL instead e.g. `https://your-server-url.com/auth/github/callback`. + +4. Hit **Register application**. +5. Hit **Generate a new client secret** on the next page. +6. Copy your Client ID and Client secret as you'll need them in the next step. + +### 4. Adding Environment Variables + +Add these environment variables to the `.env.server` file at the root of your project (take their values from the previous step): + +```bash title=".env.server" +GITHUB_CLIENT_ID=your-github-client-id +GITHUB_CLIENT_SECRET=your-github-client-secret +``` + +### 5. Adding the Necessary Routes and Pages + +Let's define the necessary authentication Routes and Pages. + +Add the following code to your `main.wasp` file: + + + + +```wasp title="main.wasp" +// ... + +// 6. Define the routes +route LoginRoute { path: "/login", to: LoginPage } +page LoginPage { + component: import { Login } from "@src/pages/auth.jsx" +} +``` + + + + +```wasp title="main.wasp" +// ... + +// 6. Define the routes +route LoginRoute { path: "/login", to: LoginPage } +page LoginPage { + component: import { Login } from "@src/pages/auth.tsx" +} +``` + + + + +We'll define the React components for these pages in the `src/pages/auth.{jsx,tsx}` file below. + +### 6. Creating the Client Pages + +:::info +We are using [Tailwind CSS](https://tailwindcss.com/) to style the pages. Read more about how to add it [here](../../project/css-frameworks). +::: + +Let's create a `auth.{jsx,tsx}` file in the `src/pages` folder and add the following to it: + + + + +```tsx title="src/pages/auth.jsx" +import { LoginForm } from 'wasp/client/auth' + +export function Login() { + return ( + + + + ) +} + +// A layout component to center the content +export function Layout({ children }) { + return ( +
    +
    +
    +
    {children}
    +
    +
    +
    + ) +} +``` + +
    + + +```tsx title="src/pages/auth.tsx" +import { LoginForm } from 'wasp/client/auth' + +export function Login() { + return ( + + + + ) +} + +// A layout component to center the content +export function Layout({ children }: { children: React.ReactNode }) { + return ( +
    +
    +
    +
    {children}
    +
    +
    +
    + ) +} +``` + +
    +
    + +We imported the generated Auth UI components and used them in our pages. Read more about the Auth UI components [here](../../auth/ui). + +### Conclusion + +Yay, we've successfully set up Github Auth! 🎉 + +![Github Auth](/img/auth/github.png) + +Running `wasp db migrate-dev` and `wasp start` should now give you a working app with authentication. +To see how to protect specific pages (i.e., hide them from non-authenticated users), read the docs on [using auth](../../auth/overview). + +## Default Behaviour + +Add `gitHub: {}` to the `auth.methods` dictionary to use it with default settings. + + + + +```wasp title=main.wasp +app myApp { + wasp: { + version: "^0.13.0" + }, + title: "My App", + auth: { + userEntity: User, + methods: { + // highlight-next-line + gitHub: {} + }, + onAuthFailedRedirectTo: "/login" + }, +} +``` + + + + +```wasp title=main.wasp +app myApp { + wasp: { + version: "^0.13.0" + }, + title: "My App", + auth: { + userEntity: User, + methods: { + // highlight-next-line + gitHub: {} + }, + onAuthFailedRedirectTo: "/login" + }, +} +``` + + + + + + +## Overrides + + + +### Data Received From GitHub + +We are using GitHub's API and its `/user` and `/user/emails` endpoints to get the user data. + +:::info We combine the data from the two endpoints + +You'll find the emails in the `emails` property in the object that you receive in `userSignupFields`. + +This is because we combine the data from the `/user` and `/user/emails` endpoints **if the `user` or `user:email` scope is requested.** + +::: + +The data we receive from GitHub on the `/user` endpoint looks something this: + +```json +{ + "login": "octocat", + "id": 1, + "name": "monalisa octocat", + "avatar_url": "https://github.com/images/error/octocat_happy.gif", + "gravatar_id": "", + // ... +} +``` + +And the data from the `/user/emails` endpoint looks something like this: + +```json +[ + { + "email": "octocat@github.com", + "verified": true, + "primary": true, + "visibility": "public" + } +] +``` + +The fields you receive will depend on the scopes you requested. By default we don't specify any scopes. If you want to get the emails, you need to specify the `user` or `user:email` scope in the `configFn` function. + + + +For an up to date info about the data received from GitHub, please refer to the [GitHub API documentation](https://docs.github.com/en/rest/users/users?apiVersion=2022-11-28#get-the-authenticated-user). + + +### Using the Data Received From GitHub + + + + + + +```wasp title="main.wasp" +app myApp { + wasp: { + version: "^0.13.0" + }, + title: "My App", + auth: { + userEntity: User, + methods: { + gitHub: { + // highlight-next-line + configFn: import { getConfig } from "@src/auth/github.js", + // highlight-next-line + userSignupFields: import { userSignupFields } from "@src/auth/github.js" + } + }, + onAuthFailedRedirectTo: "/login" + }, +} + +entity User {=psl + id Int @id @default(autoincrement()) + username String @unique + displayName String +psl=} + +// ... +``` + +```js title=src/auth/github.js +export const userSignupFields = { + username: () => "hardcoded-username", + displayName: (data) => data.profile.name, +}; + +export function getConfig() { + return { + scopes: ['user'], + }; +} +``` + + + + +```wasp title="main.wasp" +app myApp { + wasp: { + version: "^0.13.0" + }, + title: "My App", + auth: { + userEntity: User, + methods: { + gitHub: { + // highlight-next-line + configFn: import { getConfig } from "@src/auth/github.js", + // highlight-next-line + userSignupFields: import { userSignupFields } from "@src/auth/github.js" + } + }, + onAuthFailedRedirectTo: "/login" + }, +} + +entity User {=psl + id Int @id @default(autoincrement()) + username String @unique + displayName String +psl=} + +// ... +``` + +```ts title=src/auth/github.ts +import { defineUserSignupFields } from 'wasp/server/auth' + +export const userSignupFields = defineUserSignupFields({ + username: () => "hardcoded-username", + displayName: (data: any) => data.profile.name, +}) + +export function getConfig() { + return { + scopes: ['user'], + } +} +``` + + + + + + +## Using Auth + + + +## API Reference + + + + + + +```wasp title="main.wasp" +app myApp { + wasp: { + version: "^0.13.0" + }, + title: "My App", + auth: { + userEntity: User, + methods: { + gitHub: { + // highlight-next-line + configFn: import { getConfig } from "@src/auth/github.js", + // highlight-next-line + userSignupFields: import { userSignupFields } from "@src/auth/github.js" + } + }, + onAuthFailedRedirectTo: "/login" + }, +} +``` + + + + +```wasp title="main.wasp" +app myApp { + wasp: { + version: "^0.13.0" + }, + title: "My App", + auth: { + userEntity: User, + methods: { + gitHub: { + // highlight-next-line + configFn: import { getConfig } from "@src/auth/github.js", + // highlight-next-line + userSignupFields: import { userSignupFields } from "@src/auth/github.js" + } + }, + onAuthFailedRedirectTo: "/login" + }, +} +``` + + + + +The `gitHub` dict has the following properties: + +- #### `configFn: ExtImport` + + This function should return an object with the scopes for the OAuth provider. + + + + + ```js title=src/auth/github.js + export function getConfig() { + return { + scopes: [], + } + } + ``` + + + + + ```ts title=src/auth/github.ts + export function getConfig() { + return { + scopes: [], + } + } + ``` + + + + +- #### `userSignupFields: ExtImport` + + + + Read more about the `userSignupFields` function [here](../overview#1-defining-extra-fields). diff --git a/web/versioned_docs/version-0.13.0/auth/social-auth/google.md b/web/versioned_docs/version-0.13.0/auth/social-auth/google.md new file mode 100644 index 0000000000..a9028eeb1c --- /dev/null +++ b/web/versioned_docs/version-0.13.0/auth/social-auth/google.md @@ -0,0 +1,588 @@ +--- +title: Google +--- + +import useBaseUrl from '@docusaurus/useBaseUrl'; +import DefaultBehaviour from './\_default-behaviour.md'; +import OverrideIntro from './\_override-intro.md'; +import OverrideExampleIntro from './\_override-example-intro.md'; +import UsingAuthNote from './\_using-auth-note.md'; +import WaspFileStructureNote from './\_wasp-file-structure-note.md'; +import GetUserFieldsType from './\_getuserfields-type.md'; +import ApiReferenceIntro from './\_api-reference-intro.md'; +import UserSignupFieldsExplainer from '../\_user-signup-fields-explainer.md'; + +Wasp supports Google Authentication out of the box. +Google Auth is arguably the best external auth option, as most users on the web already have Google accounts. + +Enabling it lets your users log in using their existing Google accounts, greatly simplifying the process and enhancing the user experience. + +Let's walk through enabling Google authentication, explain some of the default settings, and show how to override them. + +## Setting up Google Auth + +Enabling Google Authentication comes down to a series of steps: + +1. Enabling Google authentication in the Wasp file. +1. Adding the `User` entity. +1. Creating a Google OAuth app. +1. Adding the necessary Routes and Pages +1. Using Auth UI components in our Pages. + + + +### 1. Adding Google Auth to Your Wasp File + +Let's start by properly configuring the Auth object: + + + + +```wasp title="main.wasp" +app myApp { + wasp: { + version: "^0.13.0" + }, + title: "My App", + auth: { + // 1. Specify the User entity (we'll define it next) + // highlight-next-line + userEntity: User, + methods: { + // 2. Enable Google Auth + // highlight-next-line + google: {} + }, + onAuthFailedRedirectTo: "/login" + }, +} +``` + + + + +```wasp title="main.wasp" +app myApp { + wasp: { + version: "^0.13.0" + }, + title: "My App", + auth: { + // 1. Specify the User entity (we'll define it next) + // highlight-next-line + userEntity: User, + methods: { + // 2. Enable Google Auth + // highlight-next-line + google: {} + }, + onAuthFailedRedirectTo: "/login" + }, +} +``` + + + + +`userEntity` is explained in [the social auth overview](../../auth/social-auth/overview#social-login-entity). + +### 2. Adding the User Entity + +Let's now define the `app.auth.userEntity` entity: + + + + +```wasp title="main.wasp" +// ... +// 3. Define the User entity +// highlight-next-line +entity User {=psl + id Int @id @default(autoincrement()) + // ... +psl=} +``` + + + + +```wasp title="main.wasp" +// ... +// 3. Define the User entity +// highlight-next-line +entity User {=psl + id Int @id @default(autoincrement()) + // ... +psl=} +``` + + + + +### 3. Creating a Google OAuth App + +To use Google as an authentication method, you'll first need to create a Google project and provide Wasp with your client key and secret. Here's how you do it: + +1. Create a Google Cloud Platform account if you do not already have one: https://cloud.google.com/ +2. Create and configure a new Google project here: https://console.cloud.google.com/home/dashboard + +![Google Console Screenshot 1](/img/integrations-google-1.jpg) + +![Google Console Screenshot 2](/img/integrations-google-2.jpg) + +3. Search for **OAuth** in the top bar, click on **OAuth consent screen**. + +![Google Console Screenshot 3](/img/integrations-google-3.jpg) + +- Select what type of app you want, we will go with **External**. + + ![Google Console Screenshot 4](/img/integrations-google-4.jpg) + +- Fill out applicable information on Page 1. + + ![Google Console Screenshot 5](/img/integrations-google-5.jpg) + +- On Page 2, Scopes, you should select `userinfo.profile`. You can optionally search for other things, like `email`. + + ![Google Console Screenshot 6](/img/integrations-google-6.jpg) + + ![Google Console Screenshot 7](/img/integrations-google-7.jpg) + + ![Google Console Screenshot 8](/img/integrations-google-8.jpg) + +- Add any test users you want on Page 3. + + ![Google Console Screenshot 9](/img/integrations-google-9.jpg) + +4. Next, click **Credentials**. + +![Google Console Screenshot 10](/img/integrations-google-10.jpg) + +- Select **Create Credentials**. +- Select **OAuth client ID**. + + ![Google Console Screenshot 11](/img/integrations-google-11.jpg) + +- Complete the form + + ![Google Console Screenshot 12](/img/integrations-google-12.jpg) + +- Under Authorized redirect URIs, put in: `http://localhost:3001/auth/google/callback` + + ![Google Console Screenshot 13](/img/integrations-google-13.jpg) + + - Once you know on which URL(s) your API server will be deployed, also add those URL(s). + - For example: `https://your-server-url.com/auth/google/callback` + +- When you save, you can click the Edit icon and your credentials will be shown. + + ![Google Console Screenshot 14](/img/integrations-google-14.jpg) + +5. Copy your Client ID and Client secret as you will need them in the next step. + +### 4. Adding Environment Variables + +Add these environment variables to the `.env.server` file at the root of your project (take their values from the previous step): + +```bash title=".env.server" +GOOGLE_CLIENT_ID=your-google-client-id +GOOGLE_CLIENT_SECRET=your-google-client-secret +``` + +### 5. Adding the Necessary Routes and Pages + +Let's define the necessary authentication Routes and Pages. + +Add the following code to your `main.wasp` file: + + + + +```wasp title="main.wasp" +// ... + +// 6. Define the routes +route LoginRoute { path: "/login", to: LoginPage } +page LoginPage { + component: import { Login } from "@src/pages/auth.jsx" +} +``` + + + + +```wasp title="main.wasp" +// ... + +// 6. Define the routes +route LoginRoute { path: "/login", to: LoginPage } +page LoginPage { + component: import { Login } from "@src/pages/auth.tsx" +} +``` + + + + +We'll define the React components for these pages in the `src/pages/auth.{jsx,tsx}` file below. + +### 6. Create the Client Pages + +:::info +We are using [Tailwind CSS](https://tailwindcss.com/) to style the pages. Read more about how to add it [here](../../project/css-frameworks). +::: + +Let's now create a `auth.{jsx,tsx}` file in the `src/pages`. +It should have the following code: + + + + +```tsx title="src/pages/auth.jsx" +import { LoginForm } from 'wasp/client/auth' + +export function Login() { + return ( + + + + ) +} + +// A layout component to center the content +export function Layout({ children }) { + return ( +
    +
    +
    +
    {children}
    +
    +
    +
    + ) +} +``` + +
    + + +```tsx title="src/pages/auth.tsx" +import { LoginForm } from 'wasp/client/auth' + +export function Login() { + return ( + + + + ) +} + +// A layout component to center the content +export function Layout({ children }: { children: React.ReactNode }) { + return ( +
    +
    +
    +
    {children}
    +
    +
    +
    + ) +} +``` + +
    +
    + +:::info Auth UI +Our pages use an automatically-generated Auth UI component. Read more about Auth UI components [here](../../auth/ui). +::: + +### Conclusion + +Yay, we've successfully set up Google Auth! 🎉 + +![Google Auth](/img/auth/google.png) + +Running `wasp db migrate-dev` and `wasp start` should now give you a working app with authentication. +To see how to protect specific pages (i.e., hide them from non-authenticated users), read the docs on [using auth](../../auth/overview). + +## Default Behaviour + +Add `google: {}` to the `auth.methods` dictionary to use it with default settings: + + + + +```wasp title=main.wasp +app myApp { + wasp: { + version: "^0.13.0" + }, + title: "My App", + auth: { + userEntity: User, + methods: { + // highlight-next-line + google: {} + }, + onAuthFailedRedirectTo: "/login" + }, +} +``` + + + + +```wasp title=main.wasp +app myApp { + wasp: { + version: "^0.13.0" + }, + title: "My App", + auth: { + userEntity: User, + methods: { + // highlight-next-line + google: {} + }, + onAuthFailedRedirectTo: "/login" + }, +} +``` + + + + + + +## Overrides + + + +### Data Received From Google + +We are using Google's API and its `/userinfo` endpoint to fetch the user's data. + +The data received from Google is an object which can contain the following fields: + +```json +[ + "name", + "given_name", + "family_name", + "email", + "email_verified", + "aud", + "exp", + "iat", + "iss", + "locale", + "picture", + "sub" +] +``` + +The fields you receive depend on the scopes you request. The default scope is set to `profile` only. If you want to get the user's email, you need to specify the `email` scope in the `configFn` function. + + + +For an up to date info about the data received from Google, please refer to the [Google API documentation](https://developers.google.com/identity/openid-connect/openid-connect#an-id-tokens-payload). + + +### Using the Data Received From Google + + + + + + +```wasp title="main.wasp" +app myApp { + wasp: { + version: "^0.13.0" + }, + title: "My App", + auth: { + userEntity: User, + methods: { + google: { + // highlight-next-line + configFn: import { getConfig } from "@src/auth/google.js", + // highlight-next-line + userSignupFields: import { userSignupFields } from "@src/auth/google.js" + } + }, + onAuthFailedRedirectTo: "/login" + }, +} + +entity User {=psl + id Int @id @default(autoincrement()) + username String @unique + displayName String +psl=} + +// ... +``` + +```js title=src/auth/google.js +export const userSignupFields = { + username: () => "hardcoded-username", + displayName: (data) => data.profile.name, +} + +export function getConfig() { + return { + scopes: ['profile', 'email'], + } +} +``` + + + + +```wasp title="main.wasp" +app myApp { + wasp: { + version: "^0.13.0" + }, + title: "My App", + auth: { + userEntity: User, + methods: { + google: { + // highlight-next-line + configFn: import { getConfig } from "@src/auth/google.js", + // highlight-next-line + userSignupFields: import { userSignupFields } from "@src/auth/google.js" + } + }, + onAuthFailedRedirectTo: "/login" + }, +} + +entity User {=psl + id Int @id @default(autoincrement()) + username String @unique + displayName String +psl=} + +// ... +``` + +```ts title=src/auth/google.ts +import { defineUserSignupFields } from 'wasp/server/auth' + +export const userSignupFields = defineUserSignupFields({ + username: () => "hardcoded-username", + displayName: (data: any) => data.profile.name, +}) + +export function getConfig() { + return { + scopes: ['profile', 'email'], + } +} +``` + + + + + + +## Using Auth + + + +## API Reference + + + + + + +```wasp title="main.wasp" +app myApp { + wasp: { + version: "^0.13.0" + }, + title: "My App", + auth: { + userEntity: User, + methods: { + google: { + // highlight-next-line + configFn: import { getConfig } from "@src/auth/google.js", + // highlight-next-line + userSignupFields: import { userSignupFields } from "@src/auth/google.js" + } + }, + onAuthFailedRedirectTo: "/login" + }, +} +``` + + + + +```wasp title="main.wasp" +app myApp { + wasp: { + version: "^0.13.0" + }, + title: "My App", + auth: { + userEntity: User, + methods: { + google: { + // highlight-next-line + configFn: import { getConfig } from "@src/auth/google.js", + // highlight-next-line + userSignupFields: import { userSignupFields } from "@src/auth/google.js" + } + }, + onAuthFailedRedirectTo: "/login" + }, +} +``` + + + + +The `google` dict has the following properties: + +- #### `configFn: ExtImport` + + This function must return an object with the scopes for the OAuth provider. + + + + + ```js title=src/auth/google.js + export function getConfig() { + return { + scopes: ['profile', 'email'], + } + } + ``` + + + + + ```ts title=src/auth/google.ts + export function getConfig() { + return { + scopes: ['profile', 'email'], + } + } + ``` + + + + +- #### `userSignupFields: ExtImport` + + + + Read more about the `userSignupFields` function [here](../overview#1-defining-extra-fields). diff --git a/web/versioned_docs/version-0.13.0/auth/social-auth/keycloak.md b/web/versioned_docs/version-0.13.0/auth/social-auth/keycloak.md new file mode 100644 index 0000000000..c1843c9034 --- /dev/null +++ b/web/versioned_docs/version-0.13.0/auth/social-auth/keycloak.md @@ -0,0 +1,547 @@ +--- +title: Keycloak +--- + +import useBaseUrl from '@docusaurus/useBaseUrl'; +import DefaultBehaviour from './\_default-behaviour.md'; +import OverrideIntro from './\_override-intro.md'; +import OverrideExampleIntro from './\_override-example-intro.md'; +import UsingAuthNote from './\_using-auth-note.md'; +import WaspFileStructureNote from './\_wasp-file-structure-note.md'; +import GetUserFieldsType from './\_getuserfields-type.md'; +import ApiReferenceIntro from './\_api-reference-intro.md'; +import UserSignupFieldsExplainer from '../\_user-signup-fields-explainer.md'; + +Wasp supports Keycloak Authentication out of the box. + +[Keycloak](https://www.keycloak.org/) is an open-source identity and access management solution for modern applications and services. Keycloak provides both SAML and OpenID protocol solutions. It also has a very flexible and powerful administration UI. + +Let's walk through enabling Keycloak authentication, explain some of the default settings, and show how to override them. + +## Setting up Keycloak Auth + +Enabling Keycloak Authentication comes down to a series of steps: + +1. Enabling Keycloak authentication in the Wasp file. +1. Adding the `User` entity. +1. Creating a Keycloak client. +1. Adding the necessary Routes and Pages +1. Using Auth UI components in our Pages. + + + +### 1. Adding Keycloak Auth to Your Wasp File + +Let's start by properly configuring the Auth object: + + + + +```wasp title="main.wasp" +app myApp { + wasp: { + version: "^0.13.0" + }, + title: "My App", + auth: { + // 1. Specify the User entity (we'll define it next) + // highlight-next-line + userEntity: User, + methods: { + // 2. Enable Keycloak Auth + // highlight-next-line + keycloak: {} + }, + onAuthFailedRedirectTo: "/login" + }, +} +``` + + + + +```wasp title="main.wasp" +app myApp { + wasp: { + version: "^0.13.0" + }, + title: "My App", + auth: { + // 1. Specify the User entity (we'll define it next) + // highlight-next-line + userEntity: User, + methods: { + // 2. Enable Keycloak Auth + // highlight-next-line + keycloak: {} + }, + onAuthFailedRedirectTo: "/login" + }, +} +``` + + + + +The `userEntity` is explained in [the social auth overview](../../auth/social-auth/overview#social-login-entity). + +### 2. Adding the User Entity + +Let's now define the `app.auth.userEntity` entity: + + + + +```wasp title="main.wasp" +// ... +// 3. Define the User entity +// highlight-next-line +entity User {=psl + id Int @id @default(autoincrement()) + // ... +psl=} +``` + + + + +```wasp title="main.wasp" +// ... +// 3. Define the User entity +// highlight-next-line +entity User {=psl + id Int @id @default(autoincrement()) + // ... +psl=} +``` + + + + +### 3. Creating a Keycloak Client + +1. Log into your Keycloak admin console. +1. Under **Clients**, click on **Create Client**. + + ![Keycloak Screenshot 1](/img/auth/keycloak/1-keycloak.png) + +1. Fill in the **Client ID** and choose a name for the client. + + ![Keycloak Screenshot 2](/img/auth/keycloak/2-keycloak.png) + +1. In the next step, enable **Client Authentication**. + + ![Keycloak Screenshot 3](/img/auth/keycloak/3-keycloak.png) + +1. Under **Valid Redirect URIs**, add `http://localhost:3001/auth/keycloak/callback` for local development. + + ![Keycloak Screenshot 4](/img/auth/keycloak/4-keycloak.png) + + - Once you know on which URL(s) your API server will be deployed, also add those URL(s). + - For example: `https://my-server-url.com/auth/keycloak/callback`. + +1. Click **Save**. +1. In the **Credentials** tab, copy the **Client Secret** value, which we'll use in the next step. + + ![Keycloak Screenshot 5](/img/auth/keycloak/5-keycloak.png) + +### 4. Adding Environment Variables + +Add these environment variables to the `.env.server` file at the root of your project (take their values from the previous step): + +```bash title=".env.server" +KEYCLOAK_CLIENT_ID=your-keycloak-client-id +KEYCLOAK_CLIENT_SECRET=your-keycloak-client-secret +KEYCLOAK_REALM_URL=https://your-keycloak-url.com/realms/master +``` + +We assumed in the `KEYCLOAK_REALM_URL` env variable that you are using the `master` realm. If you are using a different realm, replace `master` with your realm name. + +### 5. Adding the Necessary Routes and Pages + +Let's define the necessary authentication Routes and Pages. + +Add the following code to your `main.wasp` file: + + + + +```wasp title="main.wasp" +// ... + +// 6. Define the routes +route LoginRoute { path: "/login", to: LoginPage } +page LoginPage { + component: import { Login } from "@src/pages/auth.jsx" +} +``` + + + + +```wasp title="main.wasp" +// ... + +// 6. Define the routes +route LoginRoute { path: "/login", to: LoginPage } +page LoginPage { + component: import { Login } from "@src/pages/auth.tsx" +} +``` + + + + +We'll define the React components for these pages in the `src/pages/auth.{jsx,tsx}` file below. + +### 6. Create the Client Pages + +:::info +We are using [Tailwind CSS](https://tailwindcss.com/) to style the pages. Read more about how to add it [here](../../project/css-frameworks). +::: + +Let's now create an `auth.{jsx,tsx}` file in the `src/pages`. +It should have the following code: + + + + +```tsx title="src/pages/auth.jsx" +import { LoginForm } from 'wasp/client/auth' + +export function Login() { + return ( + + + + ) +} + +// A layout component to center the content +export function Layout({ children }) { + return ( +
    +
    +
    +
    {children}
    +
    +
    +
    + ) +} +``` + +
    + + +```tsx title="src/pages/auth.tsx" +import { LoginForm } from 'wasp/client/auth' + +export function Login() { + return ( + + + + ) +} + +// A layout component to center the content +export function Layout({ children }: { children: React.ReactNode }) { + return ( +
    +
    +
    +
    {children}
    +
    +
    +
    + ) +} +``` + +
    +
    + +:::info Auth UI +Our pages use an automatically generated Auth UI component. Read more about Auth UI components [here](../../auth/ui). +::: + +### Conclusion + +Yay, we've successfully set up Keycloak Auth! + +Running `wasp db migrate-dev` and `wasp start` should now give you a working app with authentication. +To see how to protect specific pages (i.e., hide them from non-authenticated users), read the docs on [using auth](../../auth/overview). + +## Default Behaviour + +Add `keycloak: {}` to the `auth.methods` dictionary to use it with default settings: + + + + +```wasp title=main.wasp +app myApp { + wasp: { + version: "^0.13.0" + }, + title: "My App", + auth: { + userEntity: User, + methods: { + // highlight-next-line + keycloak: {} + }, + onAuthFailedRedirectTo: "/login" + }, +} +``` + + + + +```wasp title=main.wasp +app myApp { + wasp: { + version: "^0.13.0" + }, + title: "My App", + auth: { + userEntity: User, + methods: { + // highlight-next-line + keycloak: {} + }, + onAuthFailedRedirectTo: "/login" + }, +} +``` + + + + + + +## Overrides + + + +### Data Received From Keycloak + +We are using Keycloak's API and its `/userinfo` endpoint to fetch the user's data. + +```ts title="Keycloak user data" +{ + sub: '5adba8fc-3ea6-445a-a379-13f0bb0b6969', + email_verified: true, + name: 'Test User', + preferred_username: 'test', + given_name: 'Test', + family_name: 'User', + email: 'test@example.com' +} +``` + +The fields you receive will depend on the scopes you requested. The default scope is set to `profile` only. If you want to get the user's email, you need to specify the `email` scope in the `configFn` function. + + + +For up-to-date info about the data received from Keycloak, please refer to the [Keycloak API documentation](https://www.keycloak.org/docs-api/23.0.7/javadocs/org/keycloak/representations/UserInfo.html). + + +### Using the Data Received From Keycloak + + + + + + +```wasp title="main.wasp" +app myApp { + wasp: { + version: "^0.13.0" + }, + title: "My App", + auth: { + userEntity: User, + methods: { + keycloak: { + // highlight-next-line + configFn: import { getConfig } from "@src/auth/keycloak.js", + // highlight-next-line + userSignupFields: import { userSignupFields } from "@src/auth/keycloak.js" + } + }, + onAuthFailedRedirectTo: "/login" + }, +} + +entity User {=psl + id Int @id @default(autoincrement()) + username String @unique + displayName String +psl=} + +// ... +``` + +```js title=src/auth/keycloak.js +export const userSignupFields = { + username: () => "hardcoded-username", + displayName: (data) => data.profile.name, +} + +export function getConfig() { + return { + scopes: ['profile', 'email'], + } +} +``` + + + + +```wasp title="main.wasp" +app myApp { + wasp: { + version: "^0.13.0" + }, + title: "My App", + auth: { + userEntity: User, + methods: { + keycloak: { + // highlight-next-line + configFn: import { getConfig } from "@src/auth/keycloak.js", + // highlight-next-line + userSignupFields: import { userSignupFields } from "@src/auth/keycloak.js" + } + }, + onAuthFailedRedirectTo: "/login" + }, +} + +entity User {=psl + id Int @id @default(autoincrement()) + username String @unique + displayName String +psl=} + +// ... +``` + +```ts title=src/auth/keycloak.ts +import { defineUserSignupFields } from 'wasp/server/auth' + +export const userSignupFields = defineUserSignupFields({ + username: () => "hardcoded-username", + displayName: (data: any) => data.profile.name, +}) + +export function getConfig() { + return { + scopes: ['profile', 'email'], + } +} +``` + + + + + + +## Using Auth + + + +## API Reference + + + + + + +```wasp title="main.wasp" +app myApp { + wasp: { + version: "^0.13.0" + }, + title: "My App", + auth: { + userEntity: User, + methods: { + keycloak: { + // highlight-next-line + configFn: import { getConfig } from "@src/auth/keycloak.js", + // highlight-next-line + userSignupFields: import { userSignupFields } from "@src/auth/keycloak.js" + } + }, + onAuthFailedRedirectTo: "/login" + }, +} +``` + + + + +```wasp title="main.wasp" +app myApp { + wasp: { + version: "^0.13.0" + }, + title: "My App", + auth: { + userEntity: User, + methods: { + keycloak: { + // highlight-next-line + configFn: import { getConfig } from "@src/auth/keycloak.js", + // highlight-next-line + userSignupFields: import { userSignupFields } from "@src/auth/keycloak.js" + } + }, + onAuthFailedRedirectTo: "/login" + }, +} +``` + + + + +The `keycloak` dict has the following properties: + +- #### `configFn: ExtImport` + + This function must return an object with the scopes for the OAuth provider. + + + + + ```js title=src/auth/keycloak.js + export function getConfig() { + return { + scopes: ['profile', 'email'], + } + } + ``` + + + + + ```ts title=src/auth/keycloak.ts + export function getConfig() { + return { + scopes: ['profile', 'email'], + } + } + ``` + + + + +- #### `userSignupFields: ExtImport` + + + + Read more about the `userSignupFields` function [here](../overview#1-defining-extra-fields). \ No newline at end of file diff --git a/web/versioned_docs/version-0.13.0/auth/social-auth/overview.md b/web/versioned_docs/version-0.13.0/auth/social-auth/overview.md new file mode 100644 index 0000000000..c3c046e53d --- /dev/null +++ b/web/versioned_docs/version-0.13.0/auth/social-auth/overview.md @@ -0,0 +1,355 @@ +--- +title: Overview +--- + +import { SocialAuthGrid } from './SocialAuthGrid'; +import DefaultBehaviour from './\_default-behaviour.md'; +import OverrideIntro from './\_override-intro.md'; +import GetUserFieldsType from './\_getuserfields-type.md'; + +Social login options (e.g., _Log in with Google_) are a great (maybe even the best) solution for handling user accounts. +A famous old developer joke tells us _"The best auth system is the one you never have to make."_ + +Wasp wants to make adding social login options to your app as painless as possible. + +Using different social providers gives users a chance to sign into your app via their existing accounts on other platforms (Google, GitHub, etc.). + +This page goes through the common behaviors between all supported social login providers and shows you how to customize them. +It also gives an overview of Wasp's UI helpers - the quickest possible way to get started with social auth. + +## Available Providers + +Wasp currently supports the following social login providers: + + + +## User Entity + +Wasp requires you to declare a `userEntity` for all `auth` methods (social or otherwise). +This field tells Wasp which Entity represents the user. + +Here's what the full setup looks like: + + + + +```wasp title=main.wasp +app myApp { + wasp: { + version: "^0.13.0" + }, + title: "My App", + auth: { + // highlight-next-line + userEntity: User, + methods: { + google: {} + }, + onAuthFailedRedirectTo: "/login" + }, +} + +// highlight-next-line +entity User {=psl + id Int @id @default(autoincrement()) + //... +psl=} +``` + + + + +```wasp title=main.wasp +app myApp { + wasp: { + version: "^0.13.0" + }, + title: "My App", + auth: { + // highlight-next-line + userEntity: User, + methods: { + google: {} + }, + onAuthFailedRedirectTo: "/login" + }, +} + +// highlight-next-line +entity User {=psl + id Int @id @default(autoincrement()) + //... +psl=} +``` + + + + + + +To learn more about what the fields on these entities represent, look at the [API Reference](#api-reference). + + + +## Default Behavior + + + +## Overrides + +By default, Wasp doesn't store any information it receives from the social login provider. It only stores the user's ID specific to the provider. + +If you wish to store more information about the user, you can override the default behavior. You can do this by defining the `userSignupFields` and `configFn` fields in `main.wasp` for each provider. + +You can create custom signup setups, such as allowing users to define a custom username after they sign up with a social provider. + +### Example: Allowing User to Set Their Username + +If you want to modify the signup flow (e.g., let users choose their own usernames), you will need to go through three steps: + +1. The first step is adding a `isSignupComplete` property to your `User` Entity. This field will signal whether the user has completed the signup process. +2. The second step is overriding the default signup behavior. +3. The third step is implementing the rest of your signup flow and redirecting users where appropriate. + +Let's go through both steps in more detail. + +#### 1. Adding the `isSignupComplete` Field to the `User` Entity + + + + +```wasp title=main.wasp +entity User {=psl + id Int @id @default(autoincrement()) + username String? @unique + // highlight-next-line + isSignupComplete Boolean @default(false) +psl=} +``` + + + + +```wasp title=main.wasp +entity User {=psl + id Int @id @default(autoincrement()) + username String? @unique + // highlight-next-line + isSignupComplete Boolean @default(false) +psl=} +``` + + + + +#### 2. Overriding the Default Behavior + +Declare an import under `app.auth.methods.google.userSignupFields` (the example assumes you're using Google): + + + + +```wasp title=main.wasp +app myApp { + wasp: { + version: "^0.13.0" + }, + title: "My App", + auth: { + userEntity: User, + methods: { + google: { + // highlight-next-line + userSignupFields: import { userSignupFields } from "@src/auth/google.js" + } + }, + onAuthFailedRedirectTo: "/login" + }, +} + +// ... +``` + +And implement the imported function. + +```js title=src/auth/google.js +export const userSignupFields = { + isSignupComplete: () => false, +} +``` + + + + +```wasp title=main.wasp +app myApp { + wasp: { + version: "^0.13.0" + }, + title: "My App", + auth: { + userEntity: User, + methods: { + google: { + // highlight-next-line + userSignupFields: import { userSignupFields } from "@src/auth/google.js" + } + }, + onAuthFailedRedirectTo: "/login" + }, +} + +// ... +``` + +And implement the imported function: + +```ts title=src/auth/google.ts +import { defineUserSignupFields } from 'wasp/server/auth' + +export const userSignupFields = defineUserSignupFields({ + isSignupComplete: () => false, +}) +``` + + + + + + +#### 3. Showing the Correct State on the Client + +You can query the user's `isSignupComplete` flag on the client with the [`useAuth()`](../../auth/overview) hook. +Depending on the flag's value, you can redirect users to the appropriate signup step. + +For example: + +1. When the user lands on the homepage, check the value of `user.isSignupComplete`. +2. If it's `false`, it means the user has started the signup process but hasn't yet chosen their username. Therefore, you can redirect them to `EditUserDetailsPage` where they can edit the `username` property. + + + + +```jsx title=src/HomePage.jsx +import { useAuth } from 'wasp/client/auth' +import { Redirect } from 'react-router-dom' + +export function HomePage() { + const { data: user } = useAuth() + + if (user.isSignupComplete === false) { + return + } + + // ... +} +``` + + + + +```tsx title=src/HomePage.tsx +import { useAuth } from 'wasp/client/auth' +import { Redirect } from 'react-router-dom' + +export function HomePage() { + const { data: user } = useAuth() + + if (user.isSignupComplete === false) { + return + } + + // ... +} +``` + +The same general principle applies to more complex signup procedures, just change the boolean `isSignupComplete` property to a property like `currentSignupStep` that can hold more values. + + + + +### Using the User's Provider Account Details + +Account details are provider-specific. +Each provider has their own rules for defining the `userSignupFields` and `configFn` fields: + + + +## UI Helpers + +:::tip Use Auth UI +[Auth UI](../../auth/ui) is a common name for all high-level auth forms that come with Wasp. + +These include fully functional auto-generated login and signup forms with working social login buttons. +If you're looking for the fastest way to get your auth up and running, that's where you should look. + +The UI helpers described below are lower-level and are useful for creating your custom forms. +::: + +Wasp provides sign-in buttons and URLs for each of the supported social login providers. + + + + +```jsx title=src/LoginPage.jsx +import { + GoogleSignInButton, + googleSignInUrl, + GitHubSignInButton, + gitHubSignInUrl, +} from 'wasp/client/auth' + +export const LoginPage = () => { + return ( + <> + + + {/* or */} + Sign in with Google + Sign in with GitHub + + ) +} +``` + + + + +```tsx title=src/LoginPage.tsx +import { + GoogleSignInButton, + googleSignInUrl, + GitHubSignInButton, + gitHubSignInUrl, +} from 'wasp/client/auth' + +export const LoginPage = () => { + return ( + <> + + + {/* or */} + Sign in with Google + Sign in with GitHub + + ) +} +``` + + + + +If you need even more customization, you can create your custom components using `signInUrl`s. + +## API Reference + +### Fields in the `app.auth` Dictionary and Overrides + +For more information on: + +- Allowed fields in `app.auth` +- `userSignupFields` and `configFn` functions + +Check the provider-specific API References: + + \ No newline at end of file diff --git a/web/versioned_docs/version-0.13.0/auth/ui.md b/web/versioned_docs/version-0.13.0/auth/ui.md new file mode 100644 index 0000000000..68ddd91874 --- /dev/null +++ b/web/versioned_docs/version-0.13.0/auth/ui.md @@ -0,0 +1,616 @@ +--- +title: Auth UI +--- + +import { EmailPill, UsernameAndPasswordPill, GithubPill, GooglePill, KeycloakPill } from "./Pills"; + +To make using authentication in your app as easy as possible, Wasp generates the server-side code but also the client-side UI for you. It enables you to quickly get the login, signup, password reset and email verification flows in your app. + +Below we cover all of the available UI components and how to use them. + +![Auth UI](/img/authui/all_screens.gif) + +## Overview + +After Wasp generates the UI components for your auth, you can use it as is, or customize it to your liking. + +Based on the authentication providers you enabled in your `main.wasp` file, the Auth UI will show the corresponding UI (form and buttons). For example, if you enabled e-mail authentication: + + + + +```wasp {5} title="main.wasp" +app MyApp { + //... + auth: { + methods: { + email: {}, + }, + // ... + } +} +``` + + + + +```wasp {5} title="main.wasp" +app MyApp { + //... + auth: { + methods: { + email: {}, + }, + // ... + } +} +``` + + + + +You'll get the following UI: + +![Auth UI](/img/authui/login.png) + +And then if you enable Google and Github: + + + + +```wasp title="main.wasp" {6-7} +app MyApp { + //... + auth: { + methods: { + email: {}, + google: {}, + github: {}, + }, + // ... + } +} +``` + + + + +```wasp title="main.wasp" {6-7} +app MyApp { + //... + auth: { + methods: { + email: {}, + google: {}, + github: {}, + }, + // ... + } +} +``` + + + + +The form will automatically update to look like this: + +![Auth UI](/img/authui/multiple_providers.png) + +Let's go through all of the available components and how to use them. + +## Auth Components + +The following components are available for you to use in your app: + +- [Login form](#login-form) +- [Signup form](#signup-form) +- [Forgot password form](#forgot-password-form) +- [Reset password form](#reset-password-form) +- [Verify email form](#verify-email-form) + +### Login Form + +Used with , , , and authentication. + +![Login form](/img/authui/login.png) + +You can use the `LoginForm` component to build your login page: + + + + +```wasp title="main.wasp" +// ... + +route LoginRoute { path: "/login", to: LoginPage } +page LoginPage { + component: import { LoginPage } from "@src/LoginPage.jsx" +} +``` + +```tsx title="src/LoginPage.jsx" +import { LoginForm } from 'wasp/client/auth' + +// Use it like this +export function LoginPage() { + return +} +``` + + + + +```wasp title="main.wasp" +// ... + +route LoginRoute { path: "/login", to: LoginPage } +page LoginPage { + component: import { LoginPage } from "@src/LoginPage.tsx" +} +``` + +```tsx title="src/LoginPage.tsx" +import { LoginForm } from 'wasp/client/auth' + +// Use it like this +export function LoginPage() { + return +} +``` + + + + +It will automatically show the correct authentication providers based on your `main.wasp` file. + +### Signup Form + +Used with , , , and authentication. + +![Signup form](/img/authui/signup.png) + +You can use the `SignupForm` component to build your signup page: + + + + +```wasp title="main.wasp" +// ... + +route SignupRoute { path: "/signup", to: SignupPage } +page SignupPage { + component: import { SignupPage } from "@src/SignupPage.jsx" +} +``` + +```tsx title="src/SignupPage.jsx" +import { SignupForm } from 'wasp/client/auth' + +// Use it like this +export function SignupPage() { + return +} +``` + + + + +```wasp title="main.wasp" +// ... + +route SignupRoute { path: "/signup", to: SignupPage } +page SignupPage { + component: import { SignupPage } from "@src/SignupPage.tsx" +} +``` + +```tsx title="src/SignupPage.tsx" +import { SignupForm } from 'wasp/client/auth' + +// Use it like this +export function SignupPage() { + return +} +``` + + + + +It will automatically show the correct authentication providers based on your `main.wasp` file. + +Read more about customizing the signup process like adding additional fields or extra UI in the [Auth Overview](../auth/overview#customizing-the-signup-process) section. + +### Forgot Password Form + +Used with authentication. + +If users forget their password, they can use this form to reset it. + +![Forgot password form](/img/authui/forgot_password.png) + +You can use the `ForgotPasswordForm` component to build your own forgot password page: + + + + +```wasp title="main.wasp" +// ... + +route RequestPasswordResetRoute { path: "/request-password-reset", to: RequestPasswordResetPage } +page RequestPasswordResetPage { + component: import { ForgotPasswordPage } from "@src/ForgotPasswordPage.jsx" +} +``` + +```tsx title="src/ForgotPasswordPage.jsx" +import { ForgotPasswordForm } from 'wasp/client/auth' + +// Use it like this +export function ForgotPasswordPage() { + return +} +``` + + + + +```wasp title="main.wasp" +// ... + +route RequestPasswordResetRoute { path: "/request-password-reset", to: RequestPasswordResetPage } +page RequestPasswordResetPage { + component: import { ForgotPasswordPage } from "@src/ForgotPasswordPage.tsx" +} +``` + +```tsx title="src/ForgotPasswordPage.tsx" +import { ForgotPasswordForm } from 'wasp/client/auth' + +// Use it like this +export function ForgotPasswordPage() { + return +} +``` + + + + +### Reset Password Form + +Used with authentication. + +After users click on the link in the email they receive after submitting the forgot password form, they will be redirected to this form where they can reset their password. + +![Reset password form](/img/authui/reset_password.png) + +You can use the `ResetPasswordForm` component to build your reset password page: + + + + +```wasp title="main.wasp" +// ... + +route PasswordResetRoute { path: "/password-reset", to: PasswordResetPage } +page PasswordResetPage { + component: import { ResetPasswordPage } from "@src/ResetPasswordPage.jsx" +} +``` + +```tsx title="src/ResetPasswordPage.jsx" +import { ResetPasswordForm } from 'wasp/client/auth' + +// Use it like this +export function ResetPasswordPage() { + return +} +``` + + + + +```wasp title="main.wasp" +// ... + +route PasswordResetRoute { path: "/password-reset", to: PasswordResetPage } +page PasswordResetPage { + component: import { ResetPasswordPage } from "@src/ResetPasswordPage.tsx" +} +``` + +```tsx title="src/ResetPasswordPage.tsx" +import { ResetPasswordForm } from 'wasp/client/auth' + +// Use it like this +export function ResetPasswordPage() { + return +} +``` + + + + +### Verify Email Form + +Used with authentication. + +After users sign up, they will receive an email with a link to this form where they can verify their email. + +![Verify email form](/img/authui/email_verification.png) + +You can use the `VerifyEmailForm` component to build your email verification page: + + + + +```wasp title="main.wasp" +// ... + +route EmailVerificationRoute { path: "/email-verification", to: EmailVerificationPage } +page EmailVerificationPage { + component: import { VerifyEmailPage } from "@src/VerifyEmailPage.jsx" +} +``` + +```tsx title="src/VerifyEmailPage.jsx" +import { VerifyEmailForm } from 'wasp/client/auth' + +// Use it like this +export function VerifyEmailPage() { + return +} +``` + + + + +```wasp title="main.wasp" +// ... + +route EmailVerificationRoute { path: "/email-verification", to: EmailVerificationPage } +page EmailVerificationPage { + component: import { VerifyEmailPage } from "@src/VerifyEmailPage.tsx" +} +``` + +```tsx title="src/VerifyEmailPage.tsx" +import { VerifyEmailForm } from 'wasp/client/auth' + +// Use it like this +export function VerifyEmailPage() { + return +} +``` + + + + +## Customization 💅🏻 + +You customize all of the available forms by passing props to them. + +Props you can pass to all of the forms: + +1. `appearance` - customize the form colors (via design tokens) +2. `logo` - path to your logo +3. `socialLayout` - layout of the social buttons, which can be `vertical` or `horizontal` + +### 1. Customizing the Colors + +We use [Stitches](https://stitches.dev/) to style the Auth UI. You can customize the styles by overriding the default theme tokens. + +:::info List of all available tokens + +See the [list of all available tokens](https://github.com/wasp-lang/wasp/blob/release/waspc/data/Generator/templates/react-app/src/stitches.config.js) which you can override. + +::: + + + + +```js title="src/appearance.js" +export const authAppearance = { + colors: { + brand: '#5969b8', // blue + brandAccent: '#de5998', // pink + submitButtonText: 'white', + }, +} +``` + +```jsx title="src/LoginPage.jsx" +import { LoginForm } from 'wasp/client/auth' +import { authAppearance } from './appearance' + +export function LoginPage() { + return ( + + ) +} +``` + + + + +```ts title="src/appearance.ts" +import type { CustomizationOptions } from 'wasp/client/auth' + +export const authAppearance: CustomizationOptions['appearance'] = { + colors: { + brand: '#5969b8', // blue + brandAccent: '#de5998', // pink + submitButtonText: 'white', + }, +} +``` + +```tsx title="src/LoginPage.tsx" +import { LoginForm } from 'wasp/client/auth' +import { authAppearance } from './appearance' + +export function LoginPage() { + return ( + + ) +} +``` + + + + +We recommend defining your appearance in a separate file and importing it into your components. + +### 2. Using Your Logo + +You can add your logo to the Auth UI by passing the `logo` prop to any of the components. + + + + +```tsx title="src/LoginPage.jsx" +import { LoginForm } from 'wasp/client/auth' +import Logo from './logo.png' + +export function LoginPage() { + return ( + + ) +} +``` + + + + +```tsx title="src/LoginPage.tsx" +import { LoginForm } from 'wasp/client/auth' +import Logo from './logo.png' + +export function LoginPage() { + return ( + + ) +} +``` + + + + +### 3. Social Buttons Layout + +You can change the layout of the social buttons by passing the `socialLayout` prop to any of the components. It can be either `vertical` or `horizontal` (default). + +If we pass in `vertical`: + + + + +```tsx title="src/LoginPage.jsx" +import { LoginForm } from 'wasp/client/auth' + +export function LoginPage() { + return ( + + ) +} +``` + + + + +```tsx title="src/LoginPage.tsx" +import { LoginForm } from 'wasp/client/auth' + +export function LoginPage() { + return ( + + ) +} +``` + + + + +We get this: + +![Vertical social buttons](/img/authui/vertical_social_buttons.png) + +### Let's Put Everything Together 🪄 + +If we provide the logo and custom colors: + + + + +```ts title="src/appearance.js" +export const appearance = { + colors: { + brand: '#5969b8', // blue + brandAccent: '#de5998', // pink + submitButtonText: 'white', + }, +} +``` + +```tsx title="src/LoginPage.jsx" +import { LoginForm } from 'wasp/client/auth' + +import { authAppearance } from './appearance' +import todoLogo from './todoLogo.png' + +export function LoginPage() { + return +} +``` + + + + +```ts title="src/appearance.ts" +import type { CustomizationOptions } from 'wasp/client/auth' + +export const appearance: CustomizationOptions['appearance'] = { + colors: { + brand: '#5969b8', // blue + brandAccent: '#de5998', // pink + submitButtonText: 'white', + }, +} +``` + +```tsx title="src/LoginPage.tsx" +import { LoginForm } from 'wasp/client/auth' + +import { authAppearance } from './appearance' +import todoLogo from './todoLogo.png' + +export function LoginPage() { + return +} +``` + + + + +We get a form looking like this: + +
    + Custom login form +
    diff --git a/web/versioned_docs/version-0.13.0/auth/username-and-pass.md b/web/versioned_docs/version-0.13.0/auth/username-and-pass.md new file mode 100644 index 0000000000..1f6c5aff26 --- /dev/null +++ b/web/versioned_docs/version-0.13.0/auth/username-and-pass.md @@ -0,0 +1,723 @@ +--- +title: Username & Password +--- + +import { Required } from '@site/src/components/Tag'; +import MultipleIdentitiesWarning from './\_multiple-identities-warning.md'; +import ReadMoreAboutAuthEntities from './\_read-more-about-auth-entities.md'; +import GetUsername from './entities/\_get-username.md'; +import UserSignupFieldsExplainer from './\_user-signup-fields-explainer.md'; +import UserFieldsExplainer from './\_user-fields.md'; + +Wasp supports username & password authentication out of the box with login and signup flows. It provides you with the server-side implementation and the UI components for the client-side. + +## Setting Up Username & Password Authentication + +To set up username authentication we need to: +1. Enable username authentication in the Wasp file +1. Add the `User` entity +1. Add the auth routes and pages +1. Use Auth UI components in our pages + +Structure of the `main.wasp` file we will end up with: + +```wasp title="main.wasp" +// Configuring e-mail authentication +app myApp { + auth: { ... } +} +// Defining User entity +entity User { ... } +// Defining routes and pages +route SignupRoute { ... } +page SignupPage { ... } +// ... +``` + +### 1. Enable Username Authentication + +Let's start with adding the following to our `main.wasp` file: + + + + +```wasp title="main.wasp" {11} +app myApp { + wasp: { + version: "^0.13.0" + }, + title: "My App", + auth: { + // 1. Specify the user entity (we'll define it next) + userEntity: User, + methods: { + // 2. Enable username authentication + usernameAndPassword: {}, + }, + onAuthFailedRedirectTo: "/login" + } +} +``` + + + +```wasp title="main.wasp" {11} +app myApp { + wasp: { + version: "^0.13.0" + }, + title: "My App", + auth: { + // 1. Specify the user entity (we'll define it next) + userEntity: User, + methods: { + // 2. Enable username authentication + usernameAndPassword: {}, + }, + onAuthFailedRedirectTo: "/login" + } +} +``` + + + +Read more about the `usernameAndPassword` auth method options [here](#fields-in-the-usernameandpassword-dict). + +### 2. Add the User Entity + +The `User` entity can be as simple as including only the `id` field: + + + + +```wasp title="main.wasp" +// 3. Define the user entity +entity User {=psl + // highlight-next-line + id Int @id @default(autoincrement()) + // Add your own fields below + // ... +psl=} +``` + + + +```wasp title="main.wasp" +// 3. Define the user entity +entity User {=psl + // highlight-next-line + id Int @id @default(autoincrement()) + // Add your own fields below + // ... +psl=} +``` + + + + + +### 3. Add the Routes and Pages + +Next, we need to define the routes and pages for the authentication pages. + +Add the following to the `main.wasp` file: + + + + +```wasp title="main.wasp" +// ... +// 4. Define the routes +route LoginRoute { path: "/login", to: LoginPage } +page LoginPage { + component: import { Login } from "@src/pages/auth.jsx" +} +route SignupRoute { path: "/signup", to: SignupPage } +page SignupPage { + component: import { Signup } from "@src/pages/auth.jsx" +} +``` + + + +```wasp title="main.wasp" +// ... +// 4. Define the routes +route LoginRoute { path: "/login", to: LoginPage } +page LoginPage { + component: import { Login } from "@src/pages/auth.tsx" +} +route SignupRoute { path: "/signup", to: SignupPage } +page SignupPage { + component: import { Signup } from "@src/pages/auth.tsx" +} +``` + + + +We'll define the React components for these pages in the `src/pages/auth.{jsx,tsx}` file below. + +### 4. Create the Client Pages + +:::info +We are using [Tailwind CSS](https://tailwindcss.com/) to style the pages. Read more about how to add it [here](../project/css-frameworks). +::: + +Let's create a `auth.{jsx,tsx}` file in the `src/pages` folder and add the following to it: + + + + +```tsx title="src/pages/auth.jsx" +import { LoginForm, SignupForm } from 'wasp/client/auth' +import { Link } from 'react-router-dom' + +export function Login() { + return ( + + +
    + + Don't have an account yet? go to signup. + +
    + ); +} + +export function Signup() { + return ( + + +
    + + I already have an account (go to login). + +
    + ); +} + +// A layout component to center the content +export function Layout({ children }) { + return ( +
    +
    +
    +
    {children}
    +
    +
    +
    + ); +} +``` +
    + + +```tsx title="src/pages/auth.tsx" +import { LoginForm, SignupForm } from 'wasp/client/auth' +import { Link } from 'react-router-dom' + +export function Login() { + return ( + + +
    + + Don't have an account yet? go to signup. + +
    + ); +} + +export function Signup() { + return ( + + +
    + + I already have an account (go to login). + +
    + ); +} + +// A layout component to center the content +export function Layout({ children }: { children: React.ReactNode }) { + return ( +
    +
    +
    +
    {children}
    +
    +
    +
    + ); +} +``` +
    +
    + +We imported the generated Auth UI components and used them in our pages. Read more about the Auth UI components [here](../auth/ui). + +### Conclusion + +That's it! We have set up username authentication in our app. 🎉 + +Running `wasp db migrate-dev` and then `wasp start` should give you a working app with username authentication. If you want to put some of the pages behind authentication, read the [auth overview docs](../auth/overview). + + + +## Customizing the Auth Flow + +The login and signup flows are pretty standard: they allow the user to sign up and then log in with their username and password. The signup flow validates the username and password and then creates a new user entity in the database. + +Read more about the default username and password validation rules in the [auth overview docs](../auth/overview#default-validations). + +If you require more control in your authentication flow, you can achieve that in the following ways: +1. Create your UI and use `signup` and `login` actions. +1. Create your custom sign-up action which uses the lower-level API, along with your custom code. + +### 1. Using the `signup` and `login` actions + +#### `login()` +An action for logging in the user. + +It takes two arguments: + + - `username: string` + + Username of the user logging in. + + - `password: string` + + Password of the user logging in. + +You can use it like this: + + + + +```jsx title="src/pages/auth.jsx" +import { login } from 'wasp/client/auth' + +import { useState } from 'react' +import { useHistory, Link } from 'react-router-dom' + +export function LoginPage() { + const [username, setUsername] = useState('') + const [password, setPassword] = useState('') + const [error, setError] = useState(null) + const history = useHistory() + + async function handleSubmit(event) { + event.preventDefault() + try { + await login(username, password) + history.push('/') + } catch (error) { + setError(error) + } + } + + return ( +
    + {/* ... */} +
    + ); +} +``` +
    + + +```tsx title="src/pages/auth.tsx" +import { login } from 'wasp/client/auth' + +import { useState } from 'react' +import { useHistory, Link } from 'react-router-dom' + +export function LoginPage() { + const [username, setUsername] = useState('') + const [password, setPassword] = useState('') + const [error, setError] = useState(null) + const history = useHistory() + + async function handleSubmit(event: React.FormEvent) { + event.preventDefault() + try { + await login(username, password) + history.push('/') + } catch (error: unknown) { + setError(error as Error) + } + } + + return ( +
    + {/* ... */} +
    + ); +} +``` +
    +
    + +:::note +When using the exposed `login()` function, make sure to implement your redirect on success login logic (e.g. redirecting to home). +::: + +#### `signup()` +An action for signing up the user. This action does not log in the user, you still need to call `login()`. + +It takes one argument: +- `userFields: object` + + It has the following fields: + - `username: string` + + - `password: string` + + :::info + By default, Wasp will only save the `username` and `password` fields. If you want to add extra fields to your signup process, read about [defining extra signup fields](../auth/overview#customizing-the-signup-process). + ::: + +You can use it like this: + + + + +```jsx title="src/pages/auth.jsx" +import { signup, login } from 'wasp/client/auth' + +import { useState } from 'react' +import { useHistory } from 'react-router-dom' +import { Link } from 'react-router-dom' + +export function Signup() { + const [username, setUsername] = useState('') + const [password, setPassword] = useState('') + const [error, setError] = useState(null) + const history = useHistory() + + async function handleSubmit(event) { + event.preventDefault() + try { + await signup({ + username, + password, + }) + await login(username, password) + history.push("/") + } catch (error) { + setError(error) + } + } + + return ( +
    + {/* ... */} +
    + ); +} +``` +
    + + +```tsx title="src/pages/auth.tsx" +import { signup, login } from 'wasp/client/auth' + +import { useState } from 'react' +import { useHistory } from 'react-router-dom' +import { Link } from 'react-router-dom' + +export function Signup() { + const [username, setUsername] = useState('') + const [password, setPassword] = useState('') + const [error, setError] = useState(null) + const history = useHistory() + + async function handleSubmit(event: React.FormEvent) { + event.preventDefault() + try { + await signup({ + username, + password, + }) + await login(username, password) + history.push("/") + } catch (error: unknown) { + setError(error as Error) + } + } + + return ( +
    + {/* ... */} +
    + ); +} +``` +
    +
    + +### 2. Creating your custom sign-up action + +The code of your custom sign-up action can look like this: + + + + +```wasp title="main.wasp" +// ... + +action customSignup { + fn: import { signup } from "@src/auth/signup.js", +} +``` + + +```js title="src/auth/signup.js" +import { + ensurePasswordIsPresent, + ensureValidPassword, + ensureValidUsername, + createProviderId, + sanitizeAndSerializeProviderData, + createUser, +} from 'wasp/server/auth' + +export const signup = async (args, _context) => { + ensureValidUsername(args) + ensurePasswordIsPresent(args) + ensureValidPassword(args) + + try { + const providerId = createProviderId('username', args.username) + const providerData = await sanitizeAndSerializeProviderData({ + hashedPassword: args.password, + }) + + await createUser( + providerId, + providerData, + // Any additional data you want to store on the User entity + {}, + ) + } catch (e) { + return { + success: false, + message: e.message, + } + } + + // Your custom code after sign-up. + // ... + + return { + success: true, + message: 'User created successfully', + } +} +``` + + + +```wasp title="main.wasp" +// ... + +action customSignup { + fn: import { signup } from "@src/auth/signup.js", +} +``` + +```ts title="src/auth/signup.ts" +import { + ensurePasswordIsPresent, + ensureValidPassword, + ensureValidUsername, + createProviderId, + sanitizeAndSerializeProviderData, + createUser, +} from 'wasp/server/auth' +import type { CustomSignup } from 'wasp/server/operations' + +type CustomSignupInput = { + username: string + password: string +} +type CustomSignupOutput = { + success: boolean + message: string +} + +export const signup: CustomSignup< + CustomSignupInput, + CustomSignupOutput +> = async (args, _context) => { + ensureValidUsername(args) + ensurePasswordIsPresent(args) + ensureValidPassword(args) + + try { + const providerId = createProviderId('username', args.username) + const providerData = await sanitizeAndSerializeProviderData<'username'>({ + hashedPassword: args.password, + }) + + await createUser( + providerId, + providerData, + // Any additional data you want to store on the User entity + {}, + ) + } catch (e) { + return { + success: false, + message: e.message, + } + } + + // Your custom code after sign-up. + // ... + + return { + success: true, + message: 'User created successfully', + } +} +``` + + + +We suggest using the built-in field validators for your authentication flow. You can import them from `wasp/server/auth`. These are the same validators that Wasp uses internally for the default authentication flow. + +#### Username + +- `ensureValidUsername(args)` + + Checks if the username is valid and throws an error if it's not. Read more about the validation rules [here](../auth/overview#default-validations). + +#### Password + +- `ensurePasswordIsPresent(args)` + + Checks if the password is present and throws an error if it's not. + +- `ensureValidPassword(args)` + + Checks if the password is valid and throws an error if it's not. Read more about the validation rules [here](../auth/overview#default-validations). + +## Using Auth + +To read more about how to set up the logout button and how to get access to the logged-in user in our client and server code, read the [auth overview docs](../auth/overview). + +### `getUsername` + +If you are looking to access the user's username in your code, you can do that by accessing the info about the user that is stored in the `user.auth.identities` array. + +To make things a bit easier for you, Wasp offers the `getUsername` helper. + + + +## API Reference + +### `userEntity` fields + + + + +```wasp title="main.wasp" +app myApp { + wasp: { + version: "^0.13.0" + }, + title: "My App", + auth: { + userEntity: User, + methods: { + usernameAndPassword: {}, + }, + onAuthFailedRedirectTo: "/login" + } +} + +entity User {=psl + id Int @id @default(autoincrement()) +psl=} +``` + + + +```wasp title="main.wasp" +app myApp { + wasp: { + version: "^0.13.0" + }, + title: "My App", + auth: { + userEntity: User, + methods: { + usernameAndPassword: {}, + }, + onAuthFailedRedirectTo: "/login" + } +} + +entity User {=psl + id Int @id @default(autoincrement()) +psl=} +``` + + + + + +### Fields in the `usernameAndPassword` dict + + + + +```wasp title="main.wasp" +app myApp { + wasp: { + version: "^0.13.0" + }, + title: "My App", + auth: { + userEntity: User, + methods: { + usernameAndPassword: { + userSignupFields: import { userSignupFields } from "@src/auth/email.js", + }, + }, + onAuthFailedRedirectTo: "/login" + } +} +// ... +``` + + + +```wasp title="main.wasp" +app myApp { + wasp: { + version: "^0.13.0" + }, + title: "My App", + auth: { + userEntity: User, + methods: { + usernameAndPassword: { + userSignupFields: import { userSignupFields } from "@src/auth/email.js", + }, + }, + onAuthFailedRedirectTo: "/login" + } +} +// ... +``` + + + +#### `userSignupFields: ExtImport` + + +Read more about the `userSignupFields` function [here](./overview#1-defining-extra-fields). diff --git a/web/versioned_docs/version-0.13.0/contact.md b/web/versioned_docs/version-0.13.0/contact.md new file mode 100644 index 0000000000..5ddbedafbc --- /dev/null +++ b/web/versioned_docs/version-0.13.0/contact.md @@ -0,0 +1,5 @@ +--- +title: Contact +--- + +You can find us on [Discord](https://discord.gg/rzdnErX) or you can reach out to us via email at hi@wasp-lang.dev. diff --git a/web/versioned_docs/version-0.13.0/contributing.md b/web/versioned_docs/version-0.13.0/contributing.md new file mode 100644 index 0000000000..2325a17861 --- /dev/null +++ b/web/versioned_docs/version-0.13.0/contributing.md @@ -0,0 +1,19 @@ +--- +title: Contributing +sidebar_label: Contributing +slug: /contributing +--- + +import DiscordLink from '@site/blog/components/DiscordLink'; + +Any way you want to contribute is a good way, and we'd be happy to meet you! A single entry point for all contributors is the [CONTRIBUTING.md](https://github.com/wasp-lang/wasp/blob/main/CONTRIBUTING.md) file in our Github repo. All the requirements and instructions are there, so please check [CONTRIBUTING.md](https://github.com/wasp-lang/wasp/blob/main/CONTRIBUTING.md) for more details. + +Some side notes to make your journey easier: + +1. Join us on and let's talk! We can discuss language design, new/existing features, and weather, or you can tell us how you feel about Wasp :). + +2. Wasp's compiler is built with Haskell. That means you'll need to be somewhat familiar with this language if you'd like to contribute to the compiler itself. But Haskell is just a part of Wasp, and you can contribute to lot of parts that require web dev skills, either by coding or by suggesting how to improve Wasp and its design as a web framework. If you don't have Haskell knowledge (or any dev experience at all) - no problem. There are a lot of JS-related tasks and documentation updates as well! + +3. If there's something you'd like to bring to our attention, go to [docs GitHub repo](https://github.com/wasp-lang/wasp) and make an issue/PR! + +Happy hacking! diff --git a/web/versioned_docs/version-0.13.0/data-model/backends.md b/web/versioned_docs/version-0.13.0/data-model/backends.md new file mode 100644 index 0000000000..bf075b3400 --- /dev/null +++ b/web/versioned_docs/version-0.13.0/data-model/backends.md @@ -0,0 +1,486 @@ +--- +title: Databases +--- + +import { Required } from '@site/src/components/Tag' + +[Entities](../data-model/entities.md), [Operations](../data-model/operations/overview) and [Automatic CRUD](../data-model/crud.md) together make a high-level interface for working with your app's data. Still, all that data has to live somewhere, so let's see how Wasp deals with databases. + +## Supported Database Backends + +Wasp supports multiple database backends. We'll list and explain each one. + +### SQLite + +The default database Wasp uses is [SQLite](https://www.sqlite.org/index.html). + +SQLite is a great way for getting started with a new project because it doesn't require any configuration, but Wasp can only use it in development. Once you want to deploy your Wasp app to production, you'll need to switch to PostgreSQL and stick with it. + +Fortunately, migrating from SQLite to PostgreSQL is pretty simple, and we have [a guide](#migrating-from-sqlite-to-postgresql) to help you. + +### PostgreSQL + +[PostgreSQL](https://www.postgresql.org/) is the most advanced open-source database and one of the most popular databases overall. +It's been in active development for 20+ years. +Therefore, if you're looking for a battle-tested database, look no further. + +To use Wasp with PostgreSQL, you'll have to ensure a database instance is running during development. Wasp needs access to your database for commands such as `wasp start` or `wasp db migrate-dev` and expects to find a connection string in the `DATABASE_URL` environment variable. + +We cover all supported ways of connecting to a database in [the next section](#connecting-to-a-database). + +### Migrating from SQLite to PostgreSQL + +To run your Wasp app in production, you'll need to switch from SQLite to PostgreSQL. + +1. Set the `app.db.system` field to PostgreSQL. + +```wasp title=main.wasp +app MyApp { + title: "My app", + // ... + db: { + system: PostgreSQL, + // ... + } +} +``` + +2. Delete all the old migrations, since they are SQLite migrations and can't be used with PostgreSQL, as well as the SQLite database by running [`wasp clean`](https://wasp-lang.dev/docs/general/cli#project-commands): + +```bash +rm -r migrations/ +wasp clean +``` + +3. Ensure your new database is running (check the [section on connecing to a database](#connecting-to-a-database) to see how). Leave it running, since we need it for the next step. +4. In a different terminal, run `wasp db migrate-dev` to apply the changes and create a new initial migration. +5. That is it, you are all done! + +## Connecting to a Database + +Assuming you're not using SQLite, Wasp offers two ways of connecting your app to a database instance: + +1. A ready-made dev database that requires minimal setup and is great for quick prototyping. +2. A "real" database Wasp can connect to and use in production. + +### Using the Dev Database Provided by Wasp + +The command `wasp start db` will start a default PostgreSQL dev database for you. + +Your Wasp app will automatically connect to it, just keep `wasp start db` running in the background. +Also, make sure that: + +- You have [Docker installed](https://www.docker.com/get-started/) and in `PATH`. +- The port `5432` isn't taken. + +### Connecting to an existing database + +If you want to spin up your own dev database (or connect to an external one), you can tell Wasp about it using the `DATABASE_URL` environment variable. Wasp will use the value of `DATABASE_URL` as a connection string. + +The easiest way to set the necessary `DATABASE_URL` environment variable is by adding it to the [.env.server](../project/env-vars) file in the root dir of your Wasp project (if that file doesn't yet exist, create it). + +Alternatively, you can set it inline when running `wasp` (this applies to all environment variables): + +```bash +DATABASE_URL= wasp ... +``` + +This trick is useful for running a certain `wasp` command on a specific database. +For example, you could do: + +```bash +DATABASE_URL= wasp db seed myProductionSeed +``` + +This command seeds the data for a fresh staging or production database. +To more precisely understand how seeding works, keep reading. + +## Seeding the Database + +**Database seeding** is a term used for populating the database with some initial data. + +Seeding is most commonly used for two following scenarios: + +1. To put the development database into a state convenient for working and testing. +2. To initialize any database (`dev`, `staging`, or `prod`) with essential data it requires to operate. + For example, populating the Currency table with default currencies, or the Country table with all available countries. + +### Writing a Seed Function + +You can define as many **seed functions** as you want in an array under the `app.db.seeds` field: + + + + +```wasp title=main.wasp +app MyApp { + // ... + db: { + // ... + seeds: [ + import { devSeedSimple } from "@src/dbSeeds.js", + import { prodSeed } from "@src/dbSeeds.js" + ] + } +} +``` + + + + +```wasp title=main.wasp +app MyApp { + // ... + db: { + // ... + seeds: [ + import { devSeedSimple } from "@src/dbSeeds.js", + import { prodSeed } from "@src/dbSeeds.js" + ] + } +} +``` + + + + +Each seed function must be an async function that takes one argument, `prisma`, which is a [Prisma Client](https://www.prisma.io/docs/concepts/components/prisma-client/crud) instance used to interact with the database. +This is the same Prisma Client instance that Wasp uses internally and thus includes all of the usual features (e.g., password hashing). + +Since a seed function falls under server-side code, it can import other server-side functions. This is convenient because you might want to seed the database using Actions. + +Here's an example of a seed function that imports an Action: + + + + +```js +import { createTask } from './actions.js' +import { sanitizeAndSerializeProviderData } from 'wasp/server/auth' + +export const devSeedSimple = async (prisma) => { + const user = await createUser(prisma, { + username: 'RiuTheDog', + password: 'bark1234', + }) + + await createTask( + { description: 'Chase the cat' }, + { user, entities: { Task: prisma.task } } + ) +} + +async function createUser(prisma, data) { + const newUser = await prismaClient.user.create({ + data: { + auth: { + create: { + identities: { + create: { + providerName: 'username', + providerUserId: data.username, + providerData: sanitizeAndSerializeProviderData({ + password: data.password + }), + }, + }, + }, + }, + }, + }) + + return newUser +} +``` + + + + +```ts +import { createTask } from './actions.js' +import { sanitizeAndSerializeProviderData } from 'wasp/server/auth' +import { type AuthUser } from 'wasp/auth' +import { PrismaClient } from '@prisma/client' + +export const devSeedSimple = async (prisma: PrismaClient) => { + const user = await createUser(prisma, { + username: 'RiuTheDog', + password: 'bark1234', + }) + + await createTask( + { description: 'Chase the cat', isDone: false }, + { user, entities: { Task: prisma.task } } + ) +}; + +async function createUser( + prisma: PrismaClient, + data: { username: string, password: string } +): Promise { + const newUser = await prismaClient.user.create({ + data: { + auth: { + create: { + identities: { + create: { + providerName: 'username', + providerUserId: data.username, + providerData: sanitizeAndSerializeProviderData<'username'>({ + password: data.password + }), + }, + }, + }, + }, + }, + }) + + return newUser +} +``` + + + + +### Running seed functions + +Run the command `wasp db seed` and Wasp will ask you which seed function you'd like to run (if you've defined more than one). + +Alternatively, run the command `wasp db seed ` to choose a specific seed function right away, for example: + +``` +wasp db seed devSeedSimple +``` + +Check the [API Reference](#cli-commands-for-seeding-the-database) for more details on these commands. + +:::tip +You'll often want to call `wasp db seed` right after you run `wasp db reset`, as it makes sense to fill the database with initial data after clearing it. +::: + +## Prisma Configuration + +Wasp uses [Prisma](https://www.prisma.io/) to interact with the database. Prisma is a "Next-generation Node.js and TypeScript ORM" that provides a type-safe API for working with your database. + +### Prisma Preview Features + +Prisma is still in active development and some of its features are not yet stable. To use them, you have to enable them in the `app.db.prisma.clientPreviewFeatures` field: + +```wasp title="main.wasp" +app MyApp { + // ... + db: { + system: PostgreSQL, + prisma: { + clientPreviewFeatures: ["postgresqlExtensions"] + } + } +} +``` + + + +Read more about Prisma preview features in the [Prisma docs](https://www.prisma.io/docs/concepts/components/preview-features/client-preview-features). + + +### PostgreSQL Extensions + +PostgreSQL supports [extensions](https://www.postgresql.org/docs/current/contrib.html) that add additional functionality to the database. For example, the [hstore](https://www.postgresql.org/docs/13/hstore.html) extension adds support for storing key-value pairs in a single column. + +To use PostgreSQL extensions with Prisma, you have to enable them in the `app.db.prisma.dbExtensions` field: + +```wasp title="main.wasp" +app MyApp { + // ... + db: { + system: PostgreSQL, + prisma: { + clientPreviewFeatures: ["postgresqlExtensions"] + dbExtensions: [ + { name: "hstore", schema: "myHstoreSchema" }, + { name: "pg_trgm" }, + { name: "postgis", version: "2.1" }, + ] + } + } +} +``` + + + +Read more about PostgreSQL configuration in Wasp in the [API Reference](#the-appdb-field). + + +## API Reference + +You can tell Wasp which database to use in the `app` declaration's `db` field: + +### The `app.db` Field + +Here's an example that uses the `app.db` field to its full potential: + + + + +```wasp title=main.wasp +app MyApp { + title: "My app", + // ... + db: { + system: PostgreSQL, + seeds: [ + import devSeed from "@src/dbSeeds.js" + ], + prisma: { + clientPreviewFeatures: ["extendedWhereUnique"] + } + } +} +``` + + + + +```wasp title=main.wasp +app MyApp { + title: "My app", + // ... + db: { + system: PostgreSQL, + seeds: [ + import devSeed from "@src/dbSeeds.js" + ], + prisma: { + clientPreviewFeatures: ["extendedWhereUnique"] + } + } +} +``` + + + + +`app.db` is a dictionary with the following fields (all fields are optional): + +- `system: DbSystem` + + The database system Wasp should use. It can be either PostgreSQL or SQLite. + The default value for the field is SQLite (this default value also applies if the entire `db` field is left unset). + Whenever you modify the `db.system` field, make sure to run `wasp db migrate-dev` to apply the changes. + +- `seeds: [ExtImport]` + + Defines the seed functions you can use with the `wasp db seed` command to seed your database with initial data. + Read the [Seeding section](#seeding-the-database) for more details. + +- `prisma: PrismaOptions` + + Additional configuration for Prisma. + + ```wasp title="main.wasp" + app MyApp { + // ... + db: { + // ... + prisma: { + clientPreviewFeatures: ["postgresqlExtensions"], + dbExtensions: [ + { name: "hstore", schema: "myHstoreSchema" }, + { name: "pg_trgm" }, + { name: "postgis", version: "2.1" }, + ] + } + } + } + ``` + + It's a dictionary with the following fields: + + - `clientPreviewFeatures : [string]` + + Allows you to define [Prisma client preview features](https://www.prisma.io/docs/concepts/components/preview-features/client-preview-features), like for example, `"postgresqlExtensions"`. + + - `dbExtensions: DbExtension[]` + + It allows you to define PostgreSQL extensions that should be enabled for your database. Read more about [PostgreSQL extensions in Prisma](https://www.prisma.io/docs/concepts/components/prisma-schema/postgresql-extensions). + + For each extension you define a dict with the following fields: + + - `name: string` + + The name of the extension you would normally put in the Prisma file. + + ```prisma title="schema.prisma" + extensions = [hstore(schema: "myHstoreSchema"), pg_trgm, postgis(version: "2.1")] + // 👆 Extension name + ``` + + - `map: string` + + It sets the `map` argument of the extension. Explanation for the field from the Prisma docs: + > This is the database name of the extension. If this argument is not specified, the name of the extension in the Prisma schema must match the database name. + + - `schema: string` + + It sets the `schema` argument of the extension. Explanation for the field from the Prisma docs: + > This is the name of the schema in which to activate the extension's objects. If this argument is not specified, the current default object creation schema is used. + + - `version: string` + + It sets the `version` argument of the extension. Explanation for the field from the Prisma docs: + > This is the version of the extension to activate. If this argument is not specified, the value given in the extension's control file is used. + +### CLI Commands for Seeding the Database + +Use one of the following commands to run the seed functions: + +- `wasp db seed` + + If you've only defined a single seed function, this command runs it. If you've defined multiple seed functions, it asks you to choose one interactively. + +- `wasp db seed ` + + This command runs the seed function with the specified name. The name is the identifier used in its `import` expression in the `app.db.seeds` list. + For example, to run the seed function `devSeedSimple` which was defined like this: + + + + + ```wasp title=main.wasp + app MyApp { + // ... + db: { + // ... + seeds: [ + // ... + import { devSeedSimple } from "@src/dbSeeds.js", + ] + } + } + ``` + + + + + ```wasp title=main.wasp + app MyApp { + // ... + db: { + // ... + seeds: [ + // ... + import { devSeedSimple } from "@src/dbSeeds.js", + ] + } + } + ``` + + + + + Use the following command: + + ``` + wasp db seed devSeedSimple + ``` diff --git a/web/versioned_docs/version-0.13.0/data-model/crud.md b/web/versioned_docs/version-0.13.0/data-model/crud.md new file mode 100644 index 0000000000..7622b15edc --- /dev/null +++ b/web/versioned_docs/version-0.13.0/data-model/crud.md @@ -0,0 +1,745 @@ +--- +title: Automatic CRUD +--- + +import { Required } from '@site/src/components/Tag'; +import { ShowForTs } from '@site/src/components/TsJsHelpers'; +import ImgWithCaption from '@site/blog/components/ImgWithCaption' + +If you have a lot of experience writing full-stack apps, you probably ended up doing some of the same things many times: listing data, adding data, editing it, and deleting it. + +Wasp makes handling these boring bits easy by offering a higher-level concept called Automatic CRUD. + +With a single declaration, you can tell Wasp to automatically generate server-side logic (i.e., Queries and Actions) for creating, reading, updating and deleting [Entities](../data-model/entities). As you update definitions for your Entities, Wasp automatically regenerates the backend logic. + +:::caution Early preview +This feature is currently in early preview and we are actively working on it. Read more about [our plans](#future-of-crud-operations-in-wasp) for CRUD operations. +::: + +## Overview + +Imagine we have a `Task` entity and we want to enable CRUD operations for it. + +```wasp title="main.wasp" +entity Task {=psl + id Int @id @default(autoincrement()) + description String + isDone Boolean +psl=} +``` + +We can then define a new `crud` called `Tasks`. + +We specify to use the `Task` entity and we enable the `getAll`, `get`, `create` and `update` operations (let's say we don't need the `delete` operation). + +```wasp title="main.wasp" +crud Tasks { + entity: Task, + operations: { + getAll: { + isPublic: true, // by default only logged in users can perform operations + }, + get: {}, + create: { + overrideFn: import { createTask } from "@src/tasks.js", + }, + update: {}, + }, +} +``` + +1. It uses default implementation for `getAll`, `get`, and `update`, +2. ... while specifying a custom implementation for `create`. +3. `getAll` will be public (no auth needed), while the rest of the operations will be private. + +Here's what it looks like when visualized: + + + +We can now use the CRUD queries and actions we just specified in our client code. + +Keep reading for an example of Automatic CRUD in action, or skip ahead for the [API Reference](#api-reference) + +## Example: A Simple TODO App + +Let's create a full-app example that uses automatic CRUD. We'll stick to using the `Task` entity from the previous example, but we'll add a `User` entity and enable [username and password](../auth/username-and-pass) based auth. + + + +### Creating the App + +We can start by running `wasp new tasksCrudApp` and then adding the following to the `main.wasp` file: + +```wasp title="main.wasp" +app tasksCrudApp { + wasp: { + version: "^0.13.0" + }, + title: "Tasks Crud App", + + // We enabled auth and set the auth method to username and password + auth: { + userEntity: User, + methods: { + usernameAndPassword: {}, + }, + onAuthFailedRedirectTo: "/login", + }, +} + +entity User {=psl + id Int @id @default(autoincrement()) + tasks Task[] +psl=} + +// We defined a Task entity on which we'll enable CRUD later on +entity Task {=psl + id Int @id @default(autoincrement()) + description String + isDone Boolean + userId Int + user User @relation(fields: [userId], references: [id]) +psl=} + +// Tasks app routes +route RootRoute { path: "/", to: MainPage } +page MainPage { + component: import { MainPage } from "@src/MainPage.jsx", + authRequired: true, +} + +route LoginRoute { path: "/login", to: LoginPage } +page LoginPage { + component: import { LoginPage } from "@src/LoginPage.jsx", +} + +route SignupRoute { path: "/signup", to: SignupPage } +page SignupPage { + component: import { SignupPage } from "@src/SignupPage.jsx", +} +``` + +We can then run `wasp db migrate-dev` to create the database and run the migrations. + +### Adding CRUD to the `Task` Entity ✨ + +Let's add the following `crud` declaration to our `main.wasp` file: + +```wasp title="main.wasp" +// ... + +crud Tasks { + entity: Task, + operations: { + getAll: {}, + create: { + overrideFn: import { createTask } from "@src/tasks.js", + }, + }, +} +``` + +You'll notice that we enabled only `getAll` and `create` operations. This means that only these operations will be available. + +We also overrode the `create` operation with a custom implementation. This means that the `create` operation will not be generated, but instead, the `createTask` function from `@src/tasks.js` will be used. + +### Our Custom `create` Operation + +Here's the `src/tasks.{js,ts}` file: + + + + +```js title=src/tasks.js +import { HttpError } from 'wasp/server' + +export const createTask = async (args, context) => { + if (!context.user) { + throw new HttpError(401, 'User not authenticated.') + } + + const { description, isDone } = args + const { Task } = context.entities + + return await Task.create({ + data: { + description, + isDone, + // highlight-start + // Connect the task to the user that is creating it + user: { + connect: { + id: context.user.id, + }, + }, + // highlight-end + }, + }) +} +``` + + + + +```ts title=src/tasks.ts +import { type Tasks } from 'wasp/server/crud' +import { type Task } from 'wasp/entities' +import { HttpError } from 'wasp/server' + +type CreateTaskInput = { description: string; isDone: boolean } + +export const createTask: Tasks.CreateAction = async ( + args, + context +) => { + if (!context.user) { + throw new HttpError(401, 'User not authenticated.') + } + + const { description, isDone } = args + const { Task } = context.entities + + return await Task.create({ + data: { + description, + isDone, + // highlight-start + // Connect the task to the user that is creating it + user: { + connect: { + id: context.user.id, + }, + }, + // highlight-end + }, + }) +} +``` + + + + +We made a custom `create` operation because we want to make sure that the task is connected to the user that is creating it. +Automatic CRUD doesn't support this by default (yet!). +Read more about the default implementations [here](#declaring-a-crud-with-default-options). + +### Using the Generated CRUD Operations on the Client + +And let's use the generated operations in our client code: + + + + +```jsx title="src/MainPage.jsx" +// highlight-next-line +import { Tasks } from 'wasp/client/crud' +import { useState } from 'react' + +export const MainPage = () => { + // highlight-next-line + const { data: tasks, isLoading, error } = Tasks.getAll.useQuery() + // highlight-next-line + const createTask = Tasks.create.useAction() + const [taskDescription, setTaskDescription] = useState('') + + function handleCreateTask() { + createTask({ description: taskDescription, isDone: false }) + setTaskDescription('') + } + + if (isLoading) return
    Loading...
    + if (error) return
    Error: {error.message}
    + return ( +
    +
    + setTaskDescription(e.target.value)} + /> + +
    +
      + {tasks.map((task) => ( +
    • {task.description}
    • + ))} +
    +
    + ) +} +``` + +
    + + +```tsx title="src/MainPage.tsx" +// highlight-next-line +import { Tasks } from 'wasp/client/crud' +import { useState } from 'react' + +export const MainPage = () => { + // highlight-next-line + // Thanks to full-stack type safety, all payload types are inferred + // highlight-next-line + // automatically + // highlight-next-line + const { data: tasks, isLoading, error } = Tasks.getAll.useQuery() + // highlight-next-line + const createTask = Tasks.create.useAction() + const [taskDescription, setTaskDescription] = useState('') + + function handleCreateTask() { + createTask({ description: taskDescription, isDone: false }) + setTaskDescription('') + } + + if (isLoading) return
    Loading...
    + if (error) return
    Error: {error.message}
    + return ( +
    +
    + setTaskDescription(e.target.value)} + /> + +
    +
      + {tasks.map((task) => ( +
    • {task.description}
    • + ))} +
    +
    + ) +} +``` + +
    +
    + +And here are the login and signup pages, where we are using Wasp's [Auth UI](../auth/ui) components: + + + + +```jsx title="src/LoginPage.jsx" +import { LoginForm } from 'wasp/client/auth' +import { Link } from 'react-router-dom' + +export function LoginPage() { + return ( +
    + +
    + Create an account +
    +
    + ) +} +``` + +
    + + +```tsx title="src/LoginPage.tsx" +import { LoginForm } from 'wasp/client/auth' +import { Link } from 'react-router-dom' + +export function LoginPage() { + return ( +
    + +
    + Create an account +
    +
    + ) +} +``` + +
    +
    + + + + +```jsx title="src/SignupPage.jsx" +import { SignupForm } from 'wasp/client/auth' + +export function SignupPage() { + return ( +
    + +
    + ) +} +``` + +
    + + +```tsx title="src/SignupPage.tsx" +import { SignupForm } from 'wasp/client/auth' + +export function SignupPage() { + return ( +
    + +
    + ) +} +``` + +
    +
    + +That's it. You can now run `wasp start` and see the app in action. ⚡️ + +You should see a login page and a signup page. After you log in, you should see a page with a list of tasks and a form to create new tasks. + +## Future of CRUD Operations in Wasp + +CRUD operations currently have a limited set of knowledge about the business logic they are implementing. + +- For example, they don't know that a task should be connected to the user that is creating it. This is why we had to override the `create` operation in the example above. +- Another thing: they are not aware of the authorization rules. For example, they don't know that a user should not be able to create a task for another user. In the future, we will be adding role-based authorization to Wasp, and we plan to make CRUD operations aware of the authorization rules. +- Another issue is input validation and sanitization. For example, we might want to make sure that the task description is not empty. + +CRUD operations are a mechanism for getting a backend up and running quickly, but it depends on the information it can get from the Wasp app. The more information that it can pick up from your app, the more powerful it will be out of the box. + +We plan on supporting CRUD operations and growing them to become the easiest way to create your backend. Follow along on [this GitHub issue](https://github.com/wasp-lang/wasp/issues/1253) to see how we are doing. + +## API Reference + +CRUD declaration work on top of existing entity declaration. We'll fully explore the API using two examples: + +1. A basic CRUD declaration that relies on default options. +2. A more involved CRUD declaration that uses extra options and overrides. + +### Declaring a CRUD With Default Options + +If we create CRUD operations for an entity named `Task`, like this: + + + + +```wasp title="main.wasp" +crud Tasks { // crud name here is "Tasks" + entity: Task, + operations: { + get: {}, + getAll: {}, + create: {}, + update: {}, + delete: {}, + }, +} +``` + +Wasp will give you the following default implementations: + +**get** - returns one entity based on the `id` field + +```js +// ... +// Wasp uses the field marked with `@id` in Prisma schema as the id field. +return Task.findUnique({ where: { id: args.id } }) +``` + +**getAll** - returns all entities + +```js +// ... + +// If the operation is not public, Wasp checks if an authenticated user +// is making the request. + +return Task.findMany() +``` + +**create** - creates a new entity + +```js +// ... +return Task.create({ data: args.data }) +``` + +**update** - updates an existing entity + +```js +// ... +// Wasp uses the field marked with `@id` in Prisma schema as the id field. +return Task.update({ where: { id: args.id }, data: args.data }) +``` + +**delete** - deletes an existing entity + +```js +// ... +// Wasp uses the field marked with `@id` in Prisma schema as the id field. +return Task.delete({ where: { id: args.id } }) +``` + + + + +```wasp title="main.wasp" +crud Tasks { // crud name here is "Tasks" + entity: Task, + operations: { + get: {}, + getAll: {}, + create: {}, + update: {}, + delete: {}, + }, +} +``` + +Wasp will give you the following default implementations: + +**get** - returns one entity based on the `id` field + +```ts +// ... +// Wasp uses the field marked with `@id` in Prisma schema as the id field. +return Task.findUnique({ where: { id: args.id } }) +``` + +**getAll** - returns all entities + +```ts +// ... + +// If the operation is not public, Wasp checks if an authenticated user +// is making the request. + +return Task.findMany() +``` + +**create** - creates a new entity + +```ts +// ... +return Task.create({ data: args.data }) +``` + +**update** - updates an existing entity + +```ts +// ... +// Wasp uses the field marked with `@id` in Prisma schema as the id field. +return Task.update({ where: { id: args.id }, data: args.data }) +``` + +**delete** - deletes an existing entity + +```ts +// ... +// Wasp uses the field marked with `@id` in Prisma schema as the id field. +return Task.delete({ where: { id: args.id } }) +``` + + + + +:::info Current Limitations +In the default `create` and `update` implementations, we are saving all of the data that the client sends to the server. This is not always desirable, i.e. in the case when the client should not be able to modify all of the data in the entity. + +[In the future](#future-of-crud-operations-in-wasp), we are planning to add validation of action input, where only the data that the user is allowed to change will be saved. + +For now, the solution is to provide an override function. You can override the default implementation by using the `overrideFn` option and implementing the validation logic yourself. + +::: + +### Declaring a CRUD With All Available Options + +Here's an example of a more complex CRUD declaration: + + + + +```wasp title="main.wasp" +crud Tasks { // crud name here is "Tasks" + entity: Task, + operations: { + getAll: { + isPublic: true, // optional, defaults to false + }, + get: {}, + create: { + overrideFn: import { createTask } from "@src/tasks.js", // optional + }, + update: {}, + }, +} +``` + + + + +```wasp title="main.wasp" +crud Tasks { // crud name here is "Tasks" + entity: Task, + operations: { + getAll: { + isPublic: true, // optional, defaults to false + }, + get: {}, + create: { + overrideFn: import { createTask } from "@src/tasks.js", // optional + }, + update: {}, + }, +} +``` + + + + +The CRUD declaration features the following fields: + +- `entity: Entity` + + The entity to which the CRUD operations will be applied. + +- `operations: { [operationName]: CrudOperationOptions }` + + The operations to be generated. The key is the name of the operation, and the value is the operation configuration. + + - The possible values for `operationName` are: + - `getAll` + - `get` + - `create` + - `update` + - `delete` + - `CrudOperationOptions` can have the following fields: + - `isPublic: bool` - Whether the operation is public or not. If it is public, no auth is required to access it. If it is not public, it will be available only to authenticated users. Defaults to `false`. + - `overrideFn: ExtImport` - The import statement of the optional override implementation in Node.js. + +#### Defining the overrides + +Like with actions and queries, you can define the implementation in a Javascript/Typescript file. The overrides are functions that take the following arguments: + +- `args` + + The arguments of the operation i.e. the data sent from the client. + +- `context` + + Context contains the `user` making the request and the `entities` object with the entity that's being operated on. + + + +You can also import types for each of the functions you want to override by importing the `{crud name}` from `wasp/server/crud`. The available types are: + +- `{crud name}.GetAllQuery` +- `{crud name}.GetQuery` +- `{crud name}.CreateAction` +- `{crud name}.UpdateAction` +- `{crud name}.DeleteAction` + +If you have a CRUD named `Tasks`, you would import the types like this: + +```ts +import { type Tasks } from 'wasp/server/crud' + +// Each of the types is a generic type, so you can use it like this: +export const getAllOverride: Tasks.GetAllQuery = async ( + args, + context +) => { + // ... +} +``` + + + +For a usage example, check the [example guide](../data-model/crud#adding-crud-to-the-task-entity-). + +#### Using the CRUD operations in client code + +On the client, you import the CRUD operations from `wasp/client/crud` by import the `{crud name}` object. For example, if you have a CRUD called `Tasks`, you would import the operations like this: + + + + +```jsx title="SomePage.jsx" +import { Tasks } from 'wasp/client/crud' +``` + + + + +```tsx title="SomePage.tsx" +import { Tasks } from 'wasp/client/crud' +``` + + + + +You can then access the operations like this: + + + + +```jsx title="SomePage.jsx" +const { data } = Tasks.getAll.useQuery() +const { data } = Tasks.get.useQuery({ id: 1 }) +const createAction = Tasks.create.useAction() +const updateAction = Tasks.update.useAction() +const deleteAction = Tasks.delete.useAction() +``` + + + + +```tsx title="SomePage.tsx" +const { data } = Tasks.getAll.useQuery() +const { data } = Tasks.get.useQuery({ id: 1 }) +const createAction = Tasks.create.useAction() +const updateAction = Tasks.update.useAction() +const deleteAction = Tasks.delete.useAction() +``` + + + + +All CRUD operations are implemented with [Queries and Actions](../data-model/operations/overview) under the hood, which means they come with all the features you'd expect (e.g., automatic SuperJSON serialization, full-stack type safety when using TypeScript) + +--- + +Join our **community** on [Discord](https://discord.com/invite/rzdnErX), where we chat about full-stack web stuff. Join us to see what we are up to, share your opinions or get help with CRUD operations. diff --git a/web/versioned_docs/version-0.13.0/data-model/entities.md b/web/versioned_docs/version-0.13.0/data-model/entities.md new file mode 100644 index 0000000000..7b363bcbb0 --- /dev/null +++ b/web/versioned_docs/version-0.13.0/data-model/entities.md @@ -0,0 +1,105 @@ +--- +title: Entities +--- + +Entities are the foundation of your app's data model. In short, an Entity defines a model in your database. + +Wasp uses the excellent [Prisma ORM](https://www.prisma.io/) to implement all database functionality and occasionally enhances it with a thin abstraction layer. +Wasp Entities directly correspond to [Prisma's data model](https://www.prisma.io/docs/concepts/components/prisma-schema/data-model). Still, you don't need to be familiar with Prisma to effectively use Wasp, as it comes with a simple API wrapper for working with Prisma's core features. + +The only requirement for defining Wasp Entities is familiarity with the **_Prisma Schema Language (PSL)_**, a simple definition language explicitly created for defining models in Prisma. +The language is declarative and very intuitive. We'll also go through an example later in the text, so there's no need to go and thoroughly learn it right away. Still, if you're curious, look no further than Prisma's official documentation: + +- [Basic intro and examples](https://www.prisma.io/docs/reference/tools-and-interfaces/prisma-schema) +- [A more exhaustive language specification](https://www.prisma.io/docs/reference/api-reference/prisma-schema-reference) + +## Defining an Entity + +As mentioned, an `entity` declaration represents a database model. + +Each `Entity` declaration corresponds 1-to-1 to [Prisma's data model](https://www.prisma.io/docs/concepts/components/prisma-schema/data-model). Here's how you could define an Entity that represents a Task: + + + + +```wasp +entity Task {=psl + id Int @id @default(autoincrement()) + description String + isDone Boolean @default(false) +psl=} +``` + + + + +```wasp +entity Task {=psl + id Int @id @default(autoincrement()) + description String + isDone Boolean @default(false) +psl=} +``` + + + + +Let's go through this declaration in detail: + +- `entity Task` - This tells Wasp that we wish to define an Entity (i.e., database model) called `Task`. Wasp automatically creates a table called `tasks`. +- `{=psl ... psl=}` - Wasp treats everything that comes between the two `psl` tags as [PSL (Prisma Schema Language)](https://www.prisma.io/docs/reference/tools-and-interfaces/prisma-schema). + +The above PSL definition tells Wasp to create a table for storing Tasks where each task has three fields (i.e., the `tasks` table has three columns): + +- `id` - An integer value serving as a primary key. The database automatically generates it by incrementing the previously generated `id`. +- `description` - A string value for storing the task's description. +- `isDone` - A boolean value indicating the task's completion status. If you don't set it when creating a new task, the database sets it to `false` by default. + +### Working with Entities + +Let's see how you can define and work with Wasp Entities: + +1. Create/update some Entities in your `.wasp` file. +2. Run `wasp db migrate-dev`. This command syncs the database model with the Entity definitions in your `.wasp` file. It does this by creating migration scripts. +3. Migration scripts are automatically placed in the `migrations/` folder. Make sure to commit this folder into version control. +4. Use Wasp's JavasScript API to work with the database when implementing Operations (we'll cover this in detail when we talk about [operations](../data-model/operations/overview)). + +#### Using Entities in Operations + +Most of the time, you will be working with Entities within the context of [Operations (Queries & Actions)](../data-model/operations/overview). We'll see how that's done on the next page. + +#### Using Entities directly + +If you need more control, you can directly interact with Entities by importing and using the [Prisma Client](https://www.prisma.io/docs/concepts/components/prisma-client/crud). We recommend sticking with conventional Wasp-provided mechanisms, only resorting to directly using the Prisma client only if you need a feature Wasp doesn't provide. + +You can only use the Prisma Client in your Wasp server code. You can import it like this: + + + +```js +import { prisma } from 'wasp/server' + +prisma.task.create({ + description: "Read the Entities doc", + isDone: true // almost :) +}) +``` + + + + +```ts +import { prisma } from 'wasp/server' + +prisma.task.create({ + description: "Read the Entities doc", + isDone: true // almost :) +}) +``` + + + + +### Next steps + +Now that we've seen how to define Entities that represent Wasp's core data model, we'll see how to make the most of them in other parts of Wasp. Keep reading to learn all about Wasp Operations! diff --git a/web/versioned_docs/version-0.13.0/data-model/operations/_superjson-note.md b/web/versioned_docs/version-0.13.0/data-model/operations/_superjson-note.md new file mode 100644 index 0000000000..9890d512c2 --- /dev/null +++ b/web/versioned_docs/version-0.13.0/data-model/operations/_superjson-note.md @@ -0,0 +1,14 @@ +import { ShowForTs } from '@site/src/components/TsJsHelpers'; + +:::tip +Wasp uses [superjson](https://github.com/blitz-js/superjson) under the hood. +This means you're not limited to only sending and receiving JSON payloads. + +You can send and receive any superjson-compatible payload (like Dates, Sets, Lists, circular references, etc.) and let Wasp handle the (de)serialization. + + + +As long as you're annotating your Queries with the correct automatically generated types, TypeScript ensures your payloads are valid (i.e., Wasp knows how to serialize and deserialize them). + + +::: diff --git a/web/versioned_docs/version-0.13.0/data-model/operations/actions.md b/web/versioned_docs/version-0.13.0/data-model/operations/actions.md new file mode 100644 index 0000000000..0603f7cda1 --- /dev/null +++ b/web/versioned_docs/version-0.13.0/data-model/operations/actions.md @@ -0,0 +1,833 @@ +--- +title: Actions +--- + +import { Required } from '@site/src/components/Tag'; +import { ShowForTs } from '@site/src/components/TsJsHelpers'; +import SuperjsonNote from './\_superjson-note.md'; + +We'll explain what Actions are and how to use them. If you're looking for a detailed API specification, skip ahead to the [API Reference](#api-reference). + +Actions are quite similar to [Queries](../../data-model/operations/queries.md), but with a key distinction: Actions are designed to modify and add data, while Queries are solely for reading data. Examples of Actions include adding a comment to a blog post, liking a video, or updating a product's price. + +Actions and Queries work together to keep data caches up-to-date. + +:::tip +Actions are almost identical to Queries in terms of their API. +Therefore, if you're already familiar with Queries, you might find reading the entire guide repetitive. + +We instead recommend skipping ahead and only reading [the differences between Queries and Actions](#differences-between-queries-and-actions), and consulting the [API Reference](#api-reference) as needed. +::: + +## Working with Actions + +Actions are declared in Wasp and implemented in NodeJS. Wasp runs Actions within the server's context, but it also generates code that allows you to call them from anywhere in your code (either client or server) using the same interface. + +This means you don't have to worry about building an HTTP API for the Action, managing server-side request handling, or even dealing with client-side response handling and caching. +Instead, just focus on developing the business logic inside your Action, and let Wasp handle the rest! + +To create an Action, you need to: + +1. Declare the Action in Wasp using the `action` declaration. +2. Implement the Action's NodeJS functionality. + +Once these two steps are completed, you can use the Action from anywhere in your code. + +### Declaring Actions + +To create an Action in Wasp, we begin with an `action` declaration. Let's declare two Actions - one for creating a task, and another for marking tasks as done: + + + + +```wasp title="main.wasp" +// ... + +action createTask { + fn: import { createTask } from "@src/actions.js" +} + +action markTaskAsDone { + fn: import { markTaskAsDone } from "@src/actions.js" +} + +``` + + + + +```wasp title="main.wasp" +// ... + +action createTask { + fn: import { createTask } from "@src/actions.js" +} + +action markTaskAsDone { + fn: import { markTaskAsDone } from "@src/actions.js" +} +``` + + + + + + +If you want to know about all supported options for the `action` declaration, take a look at the [API Reference](#api-reference). + + + +The names of Wasp Actions and their implementations don't necessarily have to match. However, to avoid confusion, we'll keep them the same. + + + +After declaring a Wasp Action, two important things happen: + +- Wasp **generates a server-side NodeJS function** that shares its name with the Action. + +- Wasp **generates a client-side JavaScript function** that shares its name with the Action (e.g., `markTaskAsDone`). + This function takes a single optional argument - an object containing any serializable data you wish to use inside the Action. + Wasp will send this object over the network and pass it into the Action's implementation as its first positional argument (more on this when we look at the implementations). + Such an abstraction works thanks to an HTTP API route handler Wasp generates on the server, which calls the Action's NodeJS implementation under the hood. + +Generating these two functions ensures a uniform calling interface across the entire app (both client and server). + +### Implementing Actions in Node + +Now that we've declared the Action, what remains is to implement it. We've instructed Wasp to look for the Actions' implementations in the file `src/actions.{js,ts}`, so that's where we should export them from. + +Here's how you might implement the previously declared Actions `createTask` and `markTaskAsDone`: + + + + +```js title="src/actions.js" +// our "database" +let nextId = 4 +const tasks = [ + { id: 1, description: 'Buy some eggs', isDone: true }, + { id: 2, description: 'Make an omelette', isDone: false }, + { id: 3, description: 'Eat breakfast', isDone: false }, +] + +// You don't need to use the arguments if you don't need them +export const createTask = (args) => { + const newTask = { + id: nextId, + isDone: false, + description: args.description, + } + nextId += 1 + tasks.push(newTask) + return newTask +} + +// The 'args' object is something sent by the caller (most often from the client) +export const markTaskAsDone = (args) => { + const task = tasks.find((task) => task.id === args.id) + if (!task) { + // We'll show how to properly handle such errors later + return + } + task.isDone = true +} +``` + + + + + + +```ts title="src/actions.ts" +import { type CreateTask, type MarkTaskAsDone } from 'wasp/server/operations' + +type Task = { + id: number + description: string + isDone: boolean +} + +// our "database" +let nextId = 4 +const tasks = [ + { id: 1, description: 'Buy some eggs', isDone: true }, + { id: 2, description: 'Make an omelette', isDone: false }, + { id: 3, description: 'Eat breakfast', isDone: false }, +] + +// You don't need to use the arguments if you don't need them +export const createTask: CreateTask, Task> = ( + args +) => { + const newTask = { + id: nextId, + isDone: false, + description: args.description, + } + nextId += 1 + tasks.push(newTask) + return newTask +} + +// The 'args' object is something sent by the caller (most often from the client) +export const markTaskAsDone: MarkTaskAsDone, void> = ( + args +) => { + const task = tasks.find((task) => task.id === args.id) + if (!task) { + // We'll show how to properly handle such errors later + return + } + task.isDone = true +} +``` + +Wasp automatically generates the types `CreateTask` and `MarkTaskAsDone` based on the declarations in your Wasp file: + +- `CreateTask` is a generic type that Wasp automatically generated based on the Action declaration for `createTask`. +- `MarkTaskAsDone` is a generic type that Wasp automatically generated based on the Action declaration for `markTaskAsDone`. + +You can use these types to specify the Action's input and output types. + +The Action `createTask` expects to get an object of type `{ description: string }` and returns the newly created task (an object of type `Task`). + +The Action `markTaskAsDone`, expects an object of type `{ id: number }` and doesn't return anything (i.e., its return type is `void`). + +We've derived most of the payload types from the type `Task`. + +Annotating the Actions is optional, but highly recommended. Doing so enables **full-stack type safety**. We'll see what this means when calling the Action from the client. + +:::tip +Wasp uses [superjson](https://github.com/blitz-js/superjson) under the hood. In other words, you don't need to limit yourself to only sending and receiving JSON payloads. + +Send and receive any superjson-compatible payload (e.g., Dates, Sets, Lists, circular references, etc.) and let Wasp take care of the (de)serialization. + +As long as you're annotating your Actions with correct automatically generated types, TypeScript ensures your payloads are valid (i.e., that Wasp knows how to serialize and deserialize them). +::: + + + + + + +For a detailed explanation of the Action definition API (i.e., arguments and return values), check the [API Reference](#api-reference). + + + +### Using Actions + +To use an Action, you can import it from `wasp/client/operations` and call it directly. As mentioned, the usage doesn't change depending on whether you're on the server or the client: + + + + +```js +import { createTask, markTasAsDone } from 'wasp/client/operations' + +// ... + +const newTask = await createTask({ description: 'Learn TypeScript' }) +await markTasAsDone({ id: 1 }) +``` + + + + +```ts +import { createTask, markTasAsDone } from 'wasp/client/operations' + +// TypeScript automatically infers the return values and type-checks +// the payloads. +const newTask = await createTask({ description: 'Keep learning TypeScript' }) +await markTasAsDone({ id: 1 }) +``` + + + + +When using Actions on the client, you'll most likely want to use them inside a component: + + + + +```jsx title=src/pages/Task.jsx +import React from 'react' +// highlight-next-line +import { useQuery, getTask, markTaskAsDone } from 'wasp/client/operations' + +export const TaskPage = ({ id }) => { + const { data: task } = useQuery(getTask, { id }) + + if (!task) { + return

    "Loading"

    + } + + const { description, isDone } = task + return ( +
    +

    + Description: + {description} +

    +

    + Is done: + {isDone ? 'Yes' : 'No'} +

    + {isDone || ( + // highlight-next-line + + )} +
    + ) +} +``` + +
    + + +```tsx title=src/pages/Task.tsx +import React from 'react' +// highlight-next-line +import { useQuery, getTask, markTaskAsDone } from 'wasp/client/operations' + +export const TaskPage = ({ id }: { id: number }) => { + const { data: task } = useQuery(getTask, { id }) + + if (!task) { + return

    "Loading"

    + } + + const { description, isDone } = task + return ( +
    +

    + Description: + {description} +

    +

    + Is done: + {isDone ? 'Yes' : 'No'} +

    + {isDone || ( + // highlight-next-line + + )} +
    + ) +} +``` + +
    +
    + +Since Actions don't require reactivity, they are safe to use inside components without a hook. Still, Wasp provides comes with the `useAction` hook you can use to enhance actions. Read all about it in the [API Reference](#api-reference). + +### Error Handling + +For security reasons, all exceptions thrown in the Action's NodeJS implementation are sent to the client as responses with the HTTP status code `500`, with all other details removed. +Hiding error details by default helps against accidentally leaking possibly sensitive information over the network. + +If you do want to pass additional error information to the client, you can construct and throw an appropriate `HttpError` in your implementation: + + + + +```js title=src/actions.js +import { HttpError } from 'wasp/server' + +export const createTask = async (args, context) => { + throw new HttpError( + 403, // status code + "You can't do this!", // message + { foo: 'bar' } // data + ) +} +``` + + + + +```ts title=src/actions.ts +import { type CreateTask } from 'wasp/server/operations' +import { HttpError } from 'wasp/server' + +export const createTask: CreateTask = async (args, context) => { + throw new HttpError( + 403, // status code + "You can't do this!", // message + { foo: 'bar' } // data + ) +} +``` + + + + +### Using Entities in Actions + +In most cases, resources used in Actions will be [Entities](../../data-model/entities.md). +To use an Entity in your Action, add it to the `action` declaration in Wasp: + + + + +```wasp {4,9} title="main.wasp" + +action createTask { + fn: import { createTask } from "@src/actions.js", + entities: [Task] +} + +action markTaskAsDone { + fn: import { markTaskAsDone } from "@src/actions.js", + entities: [Task] +} +``` + + + + +```wasp {4,9} title="main.wasp" + +action createTask { + fn: import { createTask } from "@src/actions.js", + entities: [Task] +} + +action markTaskAsDone { + fn: import { markTaskAsDone } from "@src/actions.js", + entities: [Task] +} +``` + + + + +Wasp will inject the specified Entity into the Action's `context` argument, giving you access to the Entity's Prisma API. +Wasp invalidates frontend Query caches by looking at the Entities used by each Action/Query. Read more about Wasp's smart cache invalidation [here](#cache-invalidation). + + + + +```js title="src/actions.js" +// The 'args' object is the payload sent by the caller (most often from the client) +export const createTask = async (args, context) => { + const newTask = await context.entities.Task.create({ + data: { + description: args.description, + isDone: false, + }, + }) + return newTask +} + +export const markTaskAsDone = async (args, context) => { + await context.entities.Task.update({ + where: { id: args.id }, + data: { isDone: true }, + }) +} +``` + + + + +```ts title="src/actions.ts" +import { type CreateTask, type MarkTaskAsDone } from 'wasp/server/operations' +import { type Task } from 'wasp/entities' + +// The 'args' object is the payload sent by the caller (most often from the client) +export const createTask: CreateTask, Task> = async ( + args, + context +) => { + const newTask = await context.entities.Task.create({ + data: { + description: args.description, + isDone: false, + }, + }) + return newTask +} + +export const markTaskAsDone: MarkTaskAsDone, void> = async ( + args, + context +) => { + await context.entities.Task.update({ + where: { id: args.id }, + data: { isDone: true }, + }) +} +``` + +Again, annotating the Actions is optional, but greatly improves **full-stack type safety**. + + + + +The object `context.entities.Task` exposes `prisma.task` from [Prisma's CRUD API](https://www.prisma.io/docs/reference/tools-and-interfaces/prisma-client/crud). + +## Cache Invalidation + +One of the trickiest parts of managing a web app's state is making sure the data returned by the Queries is up to date. +Since Wasp uses _react-query_ for Query management, we must make sure to invalidate Queries (more specifically, their cached results managed by _react-query_) whenever they become stale. + +It's possible to invalidate the caches manually through several mechanisms _react-query_ provides (e.g., refetch, direct invalidation). +However, since manual cache invalidation quickly becomes complex and error-prone, Wasp offers a faster and a more effective solution to get you started: **automatic Entity-based Query cache invalidation**. +Because Actions can (and most often do) modify the state while Queries read it, Wasp invalidates a Query's cache whenever an Action that uses the same Entity is executed. + +For example, if the Action `createTask` and Query `getTasks` both use the Entity `Task`, executing `createTask` may cause the cached result of `getTasks` to become outdated. In response, Wasp will invalidate it, causing `getTasks` to refetch data from the server and update it. + +In practice, this means that Wasp keeps the Queries "fresh" without requiring you to think about cache invalidation. + +On the other hand, this kind of automatic cache invalidation can become wasteful (some updates might not be necessary) and will only work for Entities. If that's an issue, you can use the mechanisms provided by _react-query_ for now, and expect more direct support in Wasp for handling those use cases in a nice, elegant way. + +If you wish to optimistically set cache values after performing an Action, you can do so using [optimistic updates](https://stackoverflow.com/a/33009713). Configure them using Wasp's [useAction hook](#the-useaction-hook-and-optimistic-updates). This is currently the only manual cache invalidation mechanism Wasps supports natively. For everything else, you can always rely on _react-query_. + +## Differences Between Queries and Actions + +Actions and Queries are two closely related concepts in Wasp. They might seem to perform similar tasks, but Wasp treats them differently, and each concept represents a different thing. + +Here are the key differences between Queries and Actions: + +1. Actions can (and often should) modify the server's state, while Queries are only permitted to read it. Wasp relies on you adhering to this convention when performing cache invalidations, so it's crucial to follow it. +2. Actions don't need to be reactive, so you can call them directly. However, Wasp does provide a [`useAction` React hook](#the-useaction-hook-and-optimistic-updates) for adding extra behavior to the Action (like optimistic updates). +3. `action` declarations in Wasp are mostly identical to `query` declarations. The only difference lies in the declaration's name. + +## API Reference + +### Declaring Actions in Wasp + +The `action` declaration supports the following fields: + +- `fn: ExtImport` + + The import statement of the Action's NodeJs implementation. + +- `entities: [Entity]` + + A list of entities you wish to use inside your Action. + For instructions on using Entities in Actions, take a look at [the guide](#using-entities-in-actions). + +#### Example + + + + +Declaring the Action: + +```wasp +query createFoo { + fn: import { createFoo } from "@src/actions.js" + entities: [Foo] +} +``` + +Enables you to import and use it anywhere in your code (on the server or the client): + +```js +import { createFoo } from 'wasp/client/operations' +``` + + + + +Declaring the Action: + +```wasp +query createFoo { + fn: import { createFoo } from "@src/actions.js" + entities: [Foo] +} +``` + +Enables you to import and use it anywhere in your code (on the server or the client): + +```ts +// Use it on the client +import { createFoo } from 'wasp/client/operations' + +// Use it on the server +import { createFoo } from 'wasp/server/operations' +``` + +As well as the following type import on the server: + +```ts +import { type CreateFoo } from 'wasp/server/operations' +``` + + + + +### Implementing Actions + +The Action's implementation is a NodeJS function that takes two arguments (it can be an `async` function if you need to use the `await` keyword). +Since both arguments are positional, you can name the parameters however you want, but we'll stick with `args` and `context`: + +1. `args` (type depends on the Action) + + An object containing the data **passed in when calling the Action** (e.g., filtering conditions). + Check [the usage examples](#using-actions) to see how to pass this object to the Action. + +2. `context` (type depends on the Action) + + An additional context object **passed into the Action by Wasp**. This object contains user session information, as well as information about entities. Check the [section about using entities in Actions](#using-entities-in-actions) to see how to use the entities field on the `context` object, or the [auth section](../../auth/overview#using-the-contextuser-object) to see how to use the `user` object. + + + +Afer you [declare the Action](#declaring-actions), Wasp generates a generic type you can use when defining its implementation. +For the Action declared as `createSomething`, the generated type is called `CreateSomething`: + +```ts +import { type CreateSomething } from 'wasp/server/operations' +``` + +It expects two (optional) type arguments: + +1. `Input` + + The type of the `args` object (i.e., the Action's input payload). The default value is `never`. + +2. `Output` + + The type of the Action's return value (i.e., the Action's output payload). The default value is `unknown`. + +The defaults were chosen to make the type signature as permissive as possible. If don't want your Action to take/return anything, use `void` as a type argument. + + + +#### Example + + + + +The following Action: + +```wasp +action createFoo { + fn: import { createFoo } from "@src/actions.js" + entities: [Foo] +} +``` + +Expects to find a named export `createfoo` from the file `src/actions.js` + +```js title=actions.js +export const createFoo = (args, context) => { + // implementation +} +``` + + + + +The following Action: + +```wasp +action createFoo { + fn: import { createFoo } from "@src/actions.js" + entities: [Foo] +} +``` + +Expects to find a named export `createfoo` from the file `src/actions.js` + +You can use the generated type `CreateFoo` and specify the Action's inputs and outputs using its type arguments. + +```ts title=actions.ts +import { type CreateFoo } from 'wasp/server/operations' + +type Foo = // ... + +export const createFoo: CreateFoo<{ bar: string }, Foo> = (args, context) => { + // implementation +}; +``` + +In this case, the Action expects to receive an object with a `bar` field of type `string` (this is the type of `args`), and return a value of type `Foo` (this must match the type of the Action's return value). + + + + +### The `useAction` Hook and Optimistic Updates + +Make sure you understand how [Queries](../../data-model/operations/queries.md) and [Cache Invalidation](#cache-invalidation) work before reading this chapter. + +When using Actions in components, you can enhance them with the help of the `useAction` hook. This hook comes bundled with Wasp, and is used for decorating Wasp Actions. +In other words, the hook returns a function whose API matches the original Action while also doing something extra under the hood (depending on how you configure it). + +The `useAction` hook accepts two arguments: + +- `actionFn` + + The Wasp Action (i.e., the client-side Action function generated by Wasp based on a Action declaration) you wish to enhance. + +- `actionOptions` + + An object configuring the extra features you want to add to the given Action. While this argument is technically optional, there is no point in using the `useAction` hook without providing it (it would be the same as using the Action directly). The Action options object supports the following fields: + + - `optimisticUpdates` + + An array of objects where each object defines an [optimistic update](https://stackoverflow.com/a/33009713) to perform on the Query cache. To define an optimistic update, you must specify the following properties: + + - `getQuerySpecifier` + + A function returning the Query specifier (i.e., a value used to address the Query you want to update). A Query specifier is an array specifying the query function and arguments. For example, to optimistically update the Query used with `useQuery(fetchFilteredTasks, {isDone: true }]`, your `getQuerySpecifier` function would have to return the array `[fetchFilteredTasks, { isDone: true}]`. Wasp will forward the argument you pass into the decorated Action to this function (i.e., you can use the properties of the added/changed item to address the Query). + + - `updateQuery` + + The function used to perform the optimistic update. It should return the desired state of the cache. Wasp will call it with the following arguments: + + - `item` - The argument you pass into the decorated Action. + - `oldData` - The currently cached value for the Query identified by the specifier. + +:::caution +The `updateQuery` function must be a pure function. It must return the desired cache value identified by the `getQuerySpecifier` function and _must not_ perform any side effects. + +Also, make sure you only update the Query caches affected by your Action causing the optimistic update (Wasp cannot yet verify this). + +Finally, your implementation of the `updateQuery` function should work correctly regardless of the state of `oldData` (e.g., don't rely on array positioning). If you need to do something else during your optimistic update, you can directly use _react-query_'s lower-level API (read more about it [here](#advanced-usage)). +::: + +Here's an example showing how to configure the Action `markTaskAsDone` that toggles a task's `isDone` status to perform an optimistic update: + + + + +```jsx title=src/pages/Task.jsx +import React from 'react' +import { + useQuery, + useAction, + getTask, + markTaskAsDone, +} from 'wasp/client/operations' + +const TaskPage = ({ id }) => { + const { data: task } = useQuery(getTask, { id }) + // highlight-start + const markTaskAsDoneOptimistically = useAction(markTaskAsDone, { + optimisticUpdates: [ + { + getQuerySpecifier: ({ id }) => [getTask, { id }], + updateQuery: (_payload, oldData) => ({ ...oldData, isDone: true }), + }, + ], + }) + // highlight-end + + if (!task) { + return

    "Loading"

    + } + + const { description, isDone } = task + return ( +
    +

    + Description: + {description} +

    +

    + Is done: + {isDone ? 'Yes' : 'No'} +

    + {isDone || ( + + )} +
    + ) +} + +export default TaskPage +``` + +
    + + +```tsx title=src/pages/Task.tsx +import React from 'react' +import { + useQuery, + useAction, + type OptimisticUpdateDefinition, + getTask, + markTaskAsDone, +} from 'wasp/client/operations' + +type TaskPayload = Pick; + +const TaskPage = ({ id }: { id: number }) => { + const { data: task } = useQuery(getTask, { id }); + // highlight-start + const markTaskAsDoneOptimistically = useAction(markTaskAsDone, { + optimisticUpdates: [ + { + getQuerySpecifier: ({ id }) => [getTask, { id }], + updateQuery: (_payload, oldData) => ({ ...oldData, isDone: true }), + } as OptimisticUpdateDefinition, + ], + }); + // highlight-end + + if (!task) { + return

    "Loading"

    ; + } + + const { description, isDone } = task; + return ( +
    +

    + Description: + {description} +

    +

    + Is done: + {isDone ? "Yes" : "No"} +

    + {isDone || ( + + )} +
    + ); +}; + +export default TaskPage; +``` + +
    +
    + +#### Advanced usage + +The `useAction` hook currently only supports specifying optimistic updates. You can expect more features in future versions of Wasp. + +Wasp's optimistic update API is deliberately small and focuses exclusively on updating Query caches (as that's the most common use case). You might need an API that offers more options or a higher level of control. If that's the case, instead of using Wasp's `useAction` hook, you can use _react-query_'s `useMutation` hook and directly work with [their low-level API](https://tanstack.com/query/v4/docs/guides/optimistic-updates?from=reactQueryV3&original=https://react-query-v3.tanstack.com/guides/optimistic-updates). + +If you decide to use _react-query_'s API directly, you will need access to Query cache key. Wasp internally uses this key but abstracts it from the programmer. Still, you can easily obtain it by accessing the `queryCacheKey` property on any Query: + + + + +```js +import { getTasks } from 'wasp/client/operations' + +const queryKey = getTasks.queryCacheKey +``` + + + + +```ts +import { getTasks } from 'wasp/client/operations' + +const queryKey = getTasks.queryCacheKey +``` + + + diff --git a/web/versioned_docs/version-0.13.0/data-model/operations/overview.md b/web/versioned_docs/version-0.13.0/data-model/operations/overview.md new file mode 100644 index 0000000000..2bf1fa44d5 --- /dev/null +++ b/web/versioned_docs/version-0.13.0/data-model/operations/overview.md @@ -0,0 +1,12 @@ +--- +title: Overview +--- + +import { Required } from '@site/src/components/Tag'; + +While Entities enable help you define your app's data model and relationships, Operations are all about working with this data. + +There are two kinds of Operations: [Queries](../../data-model/operations/queries.md) and [Actions](../../data-model/operations/actions.md). As their names suggest, +Queries are meant for reading data, and Actions are meant for changing it (either by updating existing entries or creating new ones). + +Keep reading to find out all there is to know about Operations in Wasp. diff --git a/web/versioned_docs/version-0.13.0/data-model/operations/queries.md b/web/versioned_docs/version-0.13.0/data-model/operations/queries.md new file mode 100644 index 0000000000..0fa7149f14 --- /dev/null +++ b/web/versioned_docs/version-0.13.0/data-model/operations/queries.md @@ -0,0 +1,648 @@ +--- +title: Queries +--- + +import { Required } from '@site/src/components/Tag'; +import { ShowForTs } from '@site/src/components/TsJsHelpers'; +import SuperjsonNote from './\_superjson-note.md'; + +We'll explain what Queries are and how to use them. If you're looking for a detailed API specification, skip ahead to the [API Reference](#api-reference). + +You can use Queries to fetch data from the server. They shouldn't modify the server's state. +Fetching all comments on a blog post, a list of users that liked a video, information about a single product based on its ID... All of these are perfect use cases for a Query. + +:::tip +Queries are fairly similar to Actions in terms of their API. +Therefore, if you're already familiar with Actions, you might find reading the entire guide repetitive. + +We instead recommend skipping ahead and only reading [the differences between Queries and Actions](../../data-model/operations/actions#differences-between-queries-and-actions), and consulting the [API Reference](#api-reference) as needed. +::: + +## Working with Queries + +You declare queries in the `.wasp` file and implement them using NodeJS. Wasp not only runs these queries within the server's context but also creates code that enables you to call them from any part of your codebase, whether it's on the client or server side. + +This means you don't have to build an HTTP API for your query, manage server-side request handling, or even deal with client-side response handling and caching. +Instead, just concentrate on implementing the business logic inside your query, and let Wasp handle the rest! + +To create a Query, you must: + +1. Declare the Query in Wasp using the `query` declaration. +2. Define the Query's NodeJS implementation. + +After completing these two steps, you'll be able to use the Query from any point in your code. + +### Declaring Queries + +To create a Query in Wasp, we begin with a `query` declaration. + +Let's declare two Queries - one to fetch all tasks, and another to fetch tasks based on a filter, such as whether a task is done: + + + + +```wasp title="main.wasp" +// ... + +query getAllTasks { + fn: import { getAllTasks } from "@src/queries.js" +} + +query getFilteredTasks { + fn: import { getFilteredTasks } from "@src/queries.js" +} +``` + + + + +```wasp title="main.wasp" +// ... + +query getAllTasks { + fn: import { getAllTasks } from "@src/queries.js" +} + +query getFilteredTasks { + fn: import { getFilteredTasks } from "@src/queries.js" +} +``` + + + + + + +If you want to know about all supported options for the `query` declaration, take a look at the [API Reference](#api-reference). + + + +The names of Wasp Queries and their implementations don't need to match, but we'll keep them the same to avoid confusion. + +:::info +You might have noticed that we told Wasp to import Query implementations that don't yet exist. Don't worry about that for now. We'll write the implementations imported from `queries.{js,ts}` in the next section. + +It's a good idea to start with the high-level concept (i.e., the Query declaration in the Wasp file) and only then deal with the implementation details (i.e., the Query's implementation in JavaScript). +::: + +After declaring a Wasp Query, two important things happen: + +- Wasp **generates a server-side NodeJS function** that shares its name with the Query. + +- Wasp **generates a client-side JavaScript function** that shares its name with the Query (e.g., `getFilteredTasks`). + This function takes a single optional argument - an object containing any serializable data you wish to use inside the Query. + Wasp will send this object over the network and pass it into the Query's implementation as its first positional argument (more on this when we look at the implementations). + Such an abstraction works thanks to an HTTP API route handler Wasp generates on the server, which calls the Query's NodeJS implementation under the hood. + +Generating these two functions ensures a uniform calling interface across the entire app (both client and server). + +### Implementing Queries in Node + +Now that we've declared the Query, what remains is to implement it. +We've instructed Wasp to look for the Queries' implementations in the file `src/queries.{js,ts}`, so that's where we should export them from. + +Here's how you might implement the previously declared Queries `getAllTasks` and `getFilteredTasks`: + + + + +```js title="src/queries.js" +// our "database" +const tasks = [ + { id: 1, description: 'Buy some eggs', isDone: true }, + { id: 2, description: 'Make an omelette', isDone: false }, + { id: 3, description: 'Eat breakfast', isDone: false }, +] + +// You don't need to use the arguments if you don't need them +export const getAllTasks = () => { + return tasks +} + +// The 'args' object is something sent by the caller (most often from the client) +export const getFilteredTasks = (args) => { + const { isDone } = args + return tasks.filter((task) => task.isDone === isDone) +} +``` + + + + + + +```ts title="src/queries.ts" +import { type GetAllTasks, type GetFilteredTasks } from 'wasp/server/operations' + +type Task = { + id: number + description: string + isDone: boolean +} + +// our "database" +const tasks: Task[] = [ + { id: 1, description: 'Buy some eggs', isDone: true }, + { id: 2, description: 'Make an omelette', isDone: false }, + { id: 3, description: 'Eat breakfast', isDone: false }, +] + +// You don't need to use the arguments if you don't need them +export const getAllTasks: GetAllTasks = () => { + return tasks +} + +// The 'args' object is something sent by the caller (most often from the client) +export const getFilteredTasks: GetFilteredTasks< + Pick, + Task[] +> = (args) => { + const { isDone } = args + return tasks.filter((task) => task.isDone === isDone) +} +``` + +Wasp automatically generates the types `GetTasks` and `GetFilteredTasks` based on your Wasp file's declarations: + +- `GetTasks` is a generic type automatically generated by Wasp, based on the Query declaration for `getTasks`. +- `GetFilteredTasks` is also a generic type automatically generated by Wasp, based on the Query declaration for `getFilteredTasks`. + +You can utilize these types to define the input and output types for your Query. + +For example, the Query `getTasks` doesn't expect any arguments (its input type is `void`), but it does return a list of tasks (its output type is `Task[]`). + +On the other hand, the Query `getFilteredTasks` expects an object of type `{ isDone: boolean }`. This type is derived from the `Task` type. + +While annotating the Queries is optional, it's highly recommended. Doing so enables **full-stack type safety**. We'll explore what this means when we discuss calling the Query from the client. + + + + + + + + +For a detailed explanation of the Query definition API (i.e., arguments and return values), check the [API Reference](#api-reference). + + + +### Using Queries + +To use a Query, you can import it from `wasp/client/operations` and call it directly. As mentioned, the usage doesn't change depending on whether you're on the server or the client: + + + + +```js +import { getAllTasks, getFilteredTasks } from 'wasp/client/operations' + +// ... + +const allTasks = await getAllTasks() +const doneTasks = await getFilteredTasks({ isDone: true }) +``` + + + + +```ts +import { getAllTasks, getFilteredTasks } from 'wasp/client/operations' + +// TypeScript automatically infers the return values and type-checks +// the payloads. +const allTasks = await getAllTasks() +const doneTasks = await getFilteredTasks({ isDone: true }) +``` + + + + +#### The `useQuery` hook + +When using Queries on the client, you can make them reactive with the `useQuery` hook. +This hook comes bundled with Wasp and is a thin wrapper around the `useQuery` hook from [_react-query_](https://github.com/tannerlinsley/react-query). The only difference is that you don't need to supply the key - Wasp handles this for you automatically. + +Here's an example of calling the Queries using the `useQuery` hook: + + + + +```jsx title=src/MainPage.jsx +import React from 'react' +import { useQuery, getAllTasks, getFilteredTasks } from 'wasp/client/operations' + +const MainPage = () => { + const { data: allTasks, error: error1 } = useQuery(getAllTasks) + const { data: doneTasks, error: error2 } = useQuery(getFilteredTasks, { + isDone: true, + }) + + if (error1 !== null || error2 !== null) { + return
    There was an error
    + } + + return ( +
    +

    All Tasks

    + {allTasks && allTasks.length > 0 + ? allTasks.map((task) => ) + : 'No tasks'} + +

    Finished Tasks

    + {doneTasks && doneTasks.length > 0 + ? doneTasks.map((task) => ) + : 'No finished tasks'} +
    + ) +} + +const Task = ({ description, isDone }: Task) => { + return ( +
    +

    + Description: + {description} +

    +

    + Is done: + {isDone ? 'Yes' : 'No'} +

    +
    + ) +} + +export default MainPage +``` + +
    + + +```tsx title=src/MainPage.tsx +import React from 'react' +import { type Task } from 'wasp/entities' +import { useQuery, getAllTasks, getFilteredTasks } from 'wasp/client/operations' + +const MainPage = () => { + // TypeScript will automatically infer and type-check payload types. + const { data: allTasks, error: error1 } = useQuery(getAllTasks) + const { data: doneTasks, error: error2 } = useQuery(getFilteredTasks, { + isDone: true, + }) + + if (error1 !== null || error2 !== null) { + return
    There was an error
    + } + + return ( +
    +

    All Tasks

    + {allTasks && allTasks.length > 0 + ? allTasks.map((task) => ) + : 'No tasks'} + +

    Finished Tasks

    + {doneTasks && doneTasks.length > 0 + ? doneTasks.map((task) => ) + : 'No finished tasks'} +
    + ) +} + +const Task = ({ description, isDone }: Task) => { + return ( +
    +

    + Description: + {description} +

    +

    + Is done: + {isDone ? 'Yes' : 'No'} +

    +
    + ) +} + +export default MainPage +``` + +Notice how you don't need to annotate the Query's return value type. Wasp automatically infers the from the Query's backend implementation. This is **full-stack type safety**: the types on the client always match the types on the server. + +
    +
    + + + +For a detailed specification of the `useQuery` hook, check the [API Reference](#api-reference). + + + +### Error Handling + +For security reasons, all exceptions thrown in the Query's NodeJS implementation are sent to the client as responses with the HTTP status code `500`, with all other details removed. +Hiding error details by default helps against accidentally leaking possibly sensitive information over the network. + +If you do want to pass additional error information to the client, you can construct and throw an appropriate `HttpError` in your implementation: + + + + +```js title=src/queries.js +import { HttpError } from 'wasp/server' + +export const getAllTasks = async (args, context) => { + throw new HttpError( + 403, // status code + "You can't do this!", // message + { foo: 'bar' } // data + ) +} +``` + + + + +```ts title=src/queries.ts +import { type GetAllTasks } from 'wasp/server/operations' +import { HttpError } from 'wasp/server' + +export const getAllTasks: GetAllTasks = async (args, context) => { + throw new HttpError( + 403, // status code + "You can't do this!", // message + { foo: 'bar' } // data + ) +} +``` + + + + +If the status code is `4xx`, the client will receive a response object with the corresponding `message` and `data` fields, and it will rethrow the error (including these fields). +To prevent information leakage, the server won't forward these fields for any other HTTP status codes. + +### Using Entities in Queries + +In most cases, resources used in Queries will be [Entities](../../data-model/entities.md). +To use an Entity in your Query, add it to the `query` declaration in Wasp: + + + + +```wasp {4,9} title="main.wasp" + +query getAllTasks { + fn: import { getAllTasks } from "@src/queries.js", + entities: [Task] +} + +query getFilteredTasks { + fn: import { getFilteredTasks } from "@src/queries.js", + entities: [Task] +} +``` + + + + +```wasp {4,9} title="main.wasp" + +query getAllTasks { + fn: import { getAllTasks } from "@src/queries.js", + entities: [Task] +} + +query getFilteredTasks { + fn: import { getFilteredTasks } from "@src/queries.js", + entities: [Task] +} +``` + + + + +Wasp will inject the specified Entity into the Query's `context` argument, giving you access to the Entity's Prisma API: + + + + +```js title="src/queries.js" +export const getAllTasks = async (args, context) => { + return context.entities.Task.findMany({}) +} + +export const getFilteredTasks = async (args, context) => { + return context.entities.Task.findMany({ + where: { isDone: args.isDone }, + }) +} +``` + + + + +```ts title="src/queries.ts" +import { type Task } from 'wasp/entities' +import { type GetAllTasks, type GetFilteredTasks } from 'wasp/server/operations' + +export const getAllTasks: GetAllTasks = async (args, context) => { + return context.entities.Task.findMany({}) +} + +export const getFilteredTasks: GetFilteredTasks< + Pick, + Task[] +> = async (args, context) => { + return context.entities.Task.findMany({ + where: { isDone: args.isDone }, + }) +} +``` + +Again, annotating the Queries is optional, but greatly improves **full-stack type safety**. + + + + +The object `context.entities.Task` exposes `prisma.task` from [Prisma's CRUD API](https://www.prisma.io/docs/reference/tools-and-interfaces/prisma-client/crud). + +## API Reference + +### Declaring Queries + +The `query` declaration supports the following fields: + +- `fn: ExtImport` + + The import statement of the Query's NodeJs implementation. + +- `entities: [Entity]` + + A list of entities you wish to use inside your Query. + For instructions on using Entities in Queries, take a look at [the guide](#using-entities-in-queries). + +#### Example + + + + +Declaring the Query: + +```wasp +query getFoo { + fn: import { getFoo } from "@src/queries.js" + entities: [Foo] +} +``` + +Enables you to import and use it anywhere in your code (on the server or the client): + +```js +import { getFoo } from 'wasp/client/operations' +``` + + + + +Declaring the Query: + +```wasp +query getFoo { + fn: import { getFoo } from "@src/queries.js" + entities: [Foo] +} +``` + +Enables you to import and use it anywhere in your code (on the server or the client): + +```ts +// Use it on the client +import { getFoo } from 'wasp/client/operations' + +// Use it on the server +import { getFoo } from 'wasp/server/operations' +``` + +And also creates a type you can import on the server: + +```ts +import { type GetFoo } from 'wasp/server/operations' +``` + + + + +### Implementing Queries + +The Query's implementation is a NodeJS function that takes two arguments (it can be an `async` function if you need to use the `await` keyword). +Since both arguments are positional, you can name the parameters however you want, but we'll stick with `args` and `context`: + +1. `args` (type depends on the Query) + + An object containing the data **passed in when calling the query** (e.g., filtering conditions). + Check [the usage examples](#using-queries) to see how to pass this object to the Query. + +2. `context` (type depends on the Query) + + An additional context object **passed into the Query by Wasp**. This object contains user session information, as well as information about entities. Check the [section about using entities in Queries](#using-entities-in-queries) to see how to use the entities field on the `context` object, or the [auth section](../../auth/overview#using-the-contextuser-object) to see how to use the `user` object. + + + +Afer you [declare the query](#declaring-queries), Wasp generates a generic type you can use when defining its implementation. +For the Query declared as `getSomething`, the generated type is called `GetSomething`: + +```ts +import { type GetSomething } from 'wasp/server/operations' +``` + +It expects two (optional) type arguments: + +1. `Input` + + The type of the `args` object (i.e., the Query's input payload). The default value is `never`. + +2. `Output` + + The type of the Query's return value (i.e., the Query's output payload). The default value is `unknown`. + +The defaults were chosen to make the type signature as permissive as possible. If don't want your Query to take/return anything, use `void` as a type argument. + + + +#### Example + + + + +The following Query: + +```wasp +query getFoo { + fn: import { getFoo } from "@src/queries.js" + entities: [Foo] +} +``` + +Expects to find a named export `getFoo` from the file `src/queries.js` + +```js title=queries.js +export const getFoo = (args, context) => { + // implementation +} +``` + + + + +The following Query: + +```wasp +query getFoo { + fn: import { getFoo } from "@src/queries.js" + entities: [Foo] +} +``` + +Expects to find a named export `getFoo` from the file `src/queries.js` + +You can use the generated type `GetFoo` and specify the Query's inputs and outputs using its type arguments. + +```ts title=queries.ts +import { type GetFoo } from 'wasp/server/operations' + +type Foo = // ... + +export const getFoo: GetFoo<{ id: number }, Foo> = (args, context) => { + // implementation +}; +``` + +In this case, the Query expects to receive an object with an `id` field of type `number` (this is the type of `args`), and return a value of type `Foo` (this must match the type of the Query's return value). + + + + +### The `useQuery` Hook + +Wasp's `useQuery` hook is a thin wrapper around the `useQuery` hook from [_react-query_](https://github.com/tannerlinsley/react-query). +One key difference is that Wasp doesn't expect you to supply the cache key - it takes care of it under the hood. + +Wasp's `useQuery` hook accepts three arguments: + +- `queryFn` + + The client-side query function generated by Wasp based on a `query` declaration in your `.wasp` file. + +- `queryFnArgs` + + The arguments object (payload) you wish to pass into the Query. The Query's NodeJS implementation will receive this object as its first positional argument. + +- `options` + + A _react-query_ `options` object. Use this to change + [the default + behavior](https://react-query.tanstack.com/guides/important-defaults) for + this particular Query. If you want to change the global defaults, you can do + so in the [client setup function](../../project/client-config.md#overriding-default-behaviour-for-queries). + +For an example of usage, check [this section](#the-usequery-hook). diff --git a/web/versioned_docs/version-0.13.0/general/cli.md b/web/versioned_docs/version-0.13.0/general/cli.md new file mode 100644 index 0000000000..9288108957 --- /dev/null +++ b/web/versioned_docs/version-0.13.0/general/cli.md @@ -0,0 +1,188 @@ +--- +title: CLI Reference +--- +This guide provides an overview of the Wasp CLI commands, arguments, and options. + +## Overview + +Once [installed](../quick-start), you can use the wasp command from your command line. + +If you run the `wasp` command without any arguments, it will show you a list of available commands and their descriptions: + +``` +USAGE + wasp [command-args] + +COMMANDS + GENERAL + new [] [args] Creates a new Wasp project. Run it without arguments for interactive mode. + OPTIONS: + -t|--template + Check out the templates list here: https://github.com/wasp-lang/starters + + new:ai [] + Uses AI to create a new Wasp project just based on the app name and the description. + You can do the same thing with `wasp new` interactively. + Run `wasp new:ai` for more info. + + version Prints current version of CLI. + waspls Run Wasp Language Server. Add --help to get more info. + completion Prints help on bash completion. + uninstall Removes Wasp from your system. + IN PROJECT + start Runs Wasp app in development mode, watching for file changes. + start db Starts managed development database for you. + db [args] Executes a database command. Run 'wasp db' for more info. + clean Deletes all generated code, all cached artifacts, and the node_modules dir. + Wasp equivalent of 'have you tried closing and opening it again?'. + build Generates full web app code, ready for deployment. Use when deploying or ejecting. + deploy Deploys your Wasp app to cloud hosting providers. + telemetry Prints telemetry status. + deps Prints the dependencies that Wasp uses in your project. + dockerfile Prints the contents of the Wasp generated Dockerfile. + info Prints basic information about the current Wasp project. + test Executes tests in your project. + studio (experimental) GUI for inspecting your Wasp app. + +EXAMPLES + wasp new MyApp + wasp start + wasp db migrate-dev + +Docs: https://wasp-lang.dev/docs +Discord (chat): https://discord.gg/rzdnErX +Newsletter: https://wasp-lang.dev/#signup +``` + +## Commands + +### Creating a New Project + - Use `wasp new` to start the interactive mode for setting up a new Wasp project. + + This will prompt you to input the project name and to select a template. The chosen template will then be used to generate the project directory with the specified name. + + ``` + $ wasp new + Enter the project name (e.g. my-project) ▸ MyFirstProject + Choose a starter template + [1] basic (default) + Simple starter template with a single page. + [2] todo-ts + Simple but well-rounded Wasp app implemented with Typescript & full-stack type safety. + [3] saas + Everything a SaaS needs! Comes with Auth, ChatGPT API, Tailwind, Stripe payments and more. Check out https://opensaas.sh/ for more details. + [4] embeddings + Comes with code for generating vector embeddings and performing vector similarity search. + [5] ai-generated + 🤖 Describe an app in a couple of sentences and have Wasp AI generate initial code for you. (experimental) + ▸ 1 + + 🐝 --- Creating your project from the "basic" template... ------------------------- + + Created new Wasp app in ./MyFirstProject directory! + + To run your new app, do: + cd MyFirstProject + wasp db start + ``` + - To skip the interactive mode and create a new Wasp project with the default template, use `wasp new `. + + ``` + $ wasp new MyFirstProject + 🐝 --- Creating your project from the "basic" template... ------------------------- + + Created new Wasp app in ./MyFirstProject directory! + + To run your new app, do: + cd MyFirstProject + wasp db start + ``` +### Project Commands + - `wasp start` launches the Wasp app in development mode. It automatically opens a browser tab with your application running and watches for any changes to .wasp or files in `src/` to automatically reflect in the browser. It also shows messages from the web app, the server and the database on stdout/stderr. + - `wasp start db` starts the database for you. This can be very handy since you don't need to spin up your own database or provide its connection URL to the Wasp app. + - `wasp clean` removes all generated code and other cached artifacts. If using SQlite, it also deletes the SQlite database. Think of this as the Wasp version of the classic "turn it off and on again" solution. + + ``` + $ wasp clean + + 🐝 --- Deleting the .wasp/ directory... ------------------------------------------- + + ✅ --- Deleted the .wasp/ directory. ---------------------------------------------- + + 🐝 --- Deleting the node_modules/ directory... ------------------------------------ + + ✅ --- Deleted the node_modules/ directory. --------------------------------------- + ``` + + - `wasp build` generates the complete web app code, which is ready for [deployment](../advanced/deployment/overview). Use this command when you're deploying or ejecting. The generated code is stored in the `.wasp/build` folder. + + - `wasp deploy` makes it easy to get your app hosted on the web. + + Currently, Wasp offers support for [Fly.io](https://fly.io). If you prefer a different hosting provider, feel free to let us know on Discord or submit a PR by updating [this TypeScript app](https://github.com/wasp-lang/wasp/tree/main/waspc/packages/deploy). + + Read more about automatic deployment [here](../advanced/deployment/cli). + + - `wasp telemetry` displays the status of [telemetry](https://wasp-lang.dev/docs/telemetry). + + ``` + $ wasp telemetry + + Telemetry is currently: ENABLED + Telemetry cache directory: /home/user/.cache/wasp/telemetry/ + Last time telemetry data was sent for this project: 2021-05-27 09:21:16.79537226 UTC + Our telemetry is anonymized and very limited in its scope: check https://wasp-lang.dev/docs/telemetry for more details. + + ``` + - `wasp deps` lists the dependencies that Wasp uses in your project. + - `wasp info` provides basic details about the current Wasp project. + - `wasp studio` shows you an graphical overview of your application in a graph: pages, queries, actions, data model etc. + +### Database Commands +Wasp provides a suite of commands for managing the database. These commands all begin with `db` and primarily execute Prisma commands behind the scenes. + + - `wasp db migrate-dev` synchronizes the development database with the current state of the schema (entities). If there are any changes in the schema, it generates a new migration and applies any pending migrations to the database. + - The `--name foo` option allows you to specify a name for the migration, while the `--create-only` option lets you create an empty migration without applying it. + + - `wasp db studio` opens the GUI for inspecting your database. + + +### Bash Completion + +To set up Bash completion, run the `wasp completion` command and follow the instructions. + + +### Miscellaneous Commands + - `wasp version` displays the current version of the CLI. + + ``` + $ wasp version + + 0.12.0 + + If you wish to install/switch to the latest version of Wasp, do: + curl -sSL https://get.wasp-lang.dev/installer.sh | sh -s + + If you want specific x.y.z version of Wasp, do: + curl -sSL https://get.wasp-lang.dev/installer.sh | sh -s -- -v x.y.z + + Check https://github.com/wasp-lang/wasp/releases for the list of valid versions, including the latest one. + ``` + - `wasp uninstall` removes Wasp from your system. + + ``` + $ wasp uninstall + + 🐝 --- Uninstalling Wasp ... ------------------------------------------------------ + + We will remove the following directories: + {home}/.local/share/wasp-lang/ + {home}/.cache/wasp/ + + We will also remove the following files: + {home}/.local/bin/wasp + + Are you sure you want to continue? [y/N] + y + + ✅ --- Uninstalled Wasp ----------------------------------------------------------- + ``` diff --git a/web/versioned_docs/version-0.13.0/general/language.md b/web/versioned_docs/version-0.13.0/general/language.md new file mode 100644 index 0000000000..9f8c7c53e5 --- /dev/null +++ b/web/versioned_docs/version-0.13.0/general/language.md @@ -0,0 +1,88 @@ +--- +title: Wasp Language (.wasp) +--- + +Wasp language (what you write in .wasp files) is a declarative, statically typed, domain-specific language (DSL). + +It is a quite simple language, closer to JSON, CSS or SQL than to e.g. Javascript or Python, since it is not a general programming language, but more of a configuration language. + +It is pretty intuitive to learn (there isn't much to learn really!) and you can probably do just fine without reading this page and learning from the rest of the docs as you go, but if you want a bit more formal definition and deeper understanding of how it works, then read on! + +## Declarations + +The central point of Wasp language are **declarations**, and Wasp code is at the end just a bunch of declarations, each of them describing a part of your web app. + +```wasp +app MyApp { + title: "My app" +} + +route RootRoute { path: "/", to: DashboardPage } + +page DashboardPage { + component: import { DashboardPage } from "@src/Dashboard.jsx" +} +``` + +In the example above we described a web app via three declarations: `app MyApp { ... }`, `route RootRoute { ... }` and `page DashboardPage { ... }`. + +Syntax for writing a declaration is ` `, where: + +- `` is one of the declaration types offered by Wasp (`app`, `route`, ...) +- `` is an identifier chosen by you to name this specific declaration +- `` is the value/definition of the declaration itself, which has to match the specific declaration body type expected by the chosen declaration type. + +So, for `app` declaration above, we have: + +- declaration type `app` +- declaration name `MyApp` (we could have used any other identifier, like `foobar`, `foo_bar`, or `hi3Ho`) +- declaration body `{ title: "My app" }`, which is a dictionary with field `title` that has string value. + Type of this dictionary is in line with the declaration body type of the `app` declaration type. + If we provided something else, e.g. changed `title` to `little`, we would get a type error from Wasp compiler since that does not match the expected type of the declaration body for `app`. + +Each declaration has a meaning behind it that describes how your web app should behave and function. + +All the other types in Wasp language (primitive types (`string`, `number`), composite types (`dict`, `list`), enum types (`DbSystem`), ...) are used to define the declaration bodies. + +## Complete List of Wasp Types + +Wasp's type system can be divided into two main categories of types: **fundamental types** and **domain types**. + +While fundamental types are here to be basic building blocks of a a language, and are very similar to what you would see in other popular languages, domain types are what makes Wasp special, as they model the concepts of a web app like `page`, `route` and similar. + +- Fundamental types ([source of truth](https://github.com/wasp-lang/wasp/blob/main/waspc/src/Wasp/Analyzer/Type.hs)) + - Primitive types + - **string** (`"foo"`, `"they said: \"hi\""`) + - **bool** (`true`, `false`) + - **number** (`12`, `14.5`) + - **declaration reference** (name of existing declaration: `TaskPage`, `updateTask`) + - **ExtImport** (external import) (`import Foo from "@src/bar.js"`, `import { Smth } from "@src/a/b.js"`) + - The path has to start with "@src". The rest is relative to the `src` directory. + - Import has to be a default import `import Foo` or a single named import `import { Foo }`. + - **json** (`{=json { a: 5, b: ["hi"] } json=}`) + - **psl** (Prisma Schema Language) (`{=psl psl=}`) + - Check [Prisma docs](https://www.prisma.io/docs/concepts/components/prisma-schema/data-model) for the syntax of psl data model. + - Composite types + - **dict** (dictionary) (`{ a: 5, b: "foo" }`) + - **list** (`[1, 2, 3]`) + - **tuple** (`(1, "bar")`, `(2, 4, true)`) + - Tuples can be of size 2, 3 and 4. +- Domain types ([source of truth](https://github.com/wasp-lang/wasp/blob/main/waspc/src/Wasp/Analyzer/StdTypeDefinitions.hs)) + - Declaration types + - **action** + - **api** + - **apiNamespace** + - **app** + - **entity** + - **job** + - **page** + - **query** + - **route** + - **crud** + - Enum types + - **DbSystem** + - **HttpMethod** + - **JobExecutor** + - **EmailProvider** + +You can find more details about each of the domain types, both regarding their body types and what they mean, in the corresponding doc pages covering their features. diff --git a/web/versioned_docs/version-0.13.0/introduction/editor-setup.md b/web/versioned_docs/version-0.13.0/introduction/editor-setup.md new file mode 100644 index 0000000000..f025eccd32 --- /dev/null +++ b/web/versioned_docs/version-0.13.0/introduction/editor-setup.md @@ -0,0 +1,23 @@ +--- +title: Editor Setup +slug: /editor-setup +--- + +:::note +This page assumes you have already installed Wasp. If you do not have Wasp installed yet, check out the [Quick Start](./quick-start.md) guide. +::: + +Wasp comes with the Wasp language server, which gives supported editors powerful support and integration with the language. + +## VSCode + +Currently, Wasp only supports integration with VSCode. Install the [Wasp language extension](https://marketplace.visualstudio.com/items?itemName=wasp-lang.wasp) to get syntax highlighting and integration with the Wasp language server. + +The extension enables: +- syntax highlighting for `.wasp` files +- scaffolding of new project files +- code completion +- diagnostics (errors and warnings) +- go to definition + +and more! diff --git a/web/versioned_docs/version-0.13.0/introduction/introduction.md b/web/versioned_docs/version-0.13.0/introduction/introduction.md new file mode 100644 index 0000000000..f41f1b9168 --- /dev/null +++ b/web/versioned_docs/version-0.13.0/introduction/introduction.md @@ -0,0 +1,203 @@ +--- +title: Introduction +slug: / +--- + +import ImgWithCaption from '@site/blog/components/ImgWithCaption' + +:::note +If you are looking for the installation instructions, check out the [Quick Start](./quick-start.md) section. +::: + +We will give a brief overview of what Wasp is, how it works on a high level and when to use it. + +## Wasp is a tool to build modern web applications + +It is an opinionated way of building **full-stack web applications**. It takes care of all three +major parts of a web application: **client** (front-end), **server** (back-end) and **database**. + +### Works well with your existing stack +Wasp is not trying to do everything at once but rather focuses on the complexity +which arises from connecting all the parts of the stack (client, server, database, deployment) together. + +Wasp is using **React**, **Node.js** and **Prisma** under the hood and relies on them to define web components and server queries and actions. + +### Wasp's secret sauce + +At the core is the Wasp compiler which takes the Wasp config and your Javascript code and outputs the client app, server app and deployment code. + + + + + +The cool thing about having a compiler that understands your code is that it can do a lot of things for you. + +Define your app in the Wasp config and get: +- login and signup with Auth UI components, +- full-stack type safety, +- e-mail sending, +- async processing jobs, +- React Query powered data fetching, +- security best practices, +- and more. + +You don't need to write any code for these features, Wasp will take care of it for you 🤯 And what's even better, Wasp also maintains the code for you, so you don't have to worry about keeping up with the latest security best practices. As Wasp updates, so does your app. + +## So what does the code look like? + +Let's say you want to build a web app that allows users to **create and share their favorite recipes**. + +Let's start with the main.wasp file: it is the central file of your app, where you describe the app from the high level. + +Let's give our app a title and let's immediately turn on the full-stack authentication via username and password: +```wasp title="main.wasp" +app RecipeApp { + title: "My Recipes", + wasp: { version: "^0.13.0" }, + auth: { + methods: { usernameAndPassword: {} }, + onAuthFailedRedirectTo: "/login", + userEntity: User + } +} +``` + +Let's then add the data models for your recipes. We will want to have Users and Users can own Recipes: + +```wasp title="main.wasp" +... + +entity User {=psl // Data models are defined using Prisma Schema Language. + id Int @id @default(autoincrement()) + recipes Recipe[] +psl=} + +entity Recipe {=psl + id Int @id @default(autoincrement()) + title String + description String? + userId Int + user User @relation(fields: [userId], references: [id]) +psl=} +``` + +Next, let's define how to do something with these data models! + +We do that by defining Operations, in this case a Query `getRecipes` and Action `addRecipe`, +which are in their essence a Node.js functions that execute on server and can, thanks to Wasp, very easily be called from the client. + +First, we define these Operations in our main.wasp file, so Wasp knows about them and can "beef them up": +```wasp title="main.wasp" +// Queries have automatic cache invalidation and are type-safe. +query getRecipes { + fn: import { getRecipes } from "@src/recipe/operations.ts", + entities: [Recipe], +} + +// Actions are type-safe and can be used to perform side-effects. +action addRecipe { + fn: import { addRecipe } from "@src/recipe/operations.ts", + entities: [Recipe], +} +``` + +... and then implement them in our Javascript (or TypeScript) code (we show just the query here, using TypeScript): + +```ts title="src/recipe/operations.ts" +// Wasp generates the types for you. +import { type GetRecipes } from "wasp/server/operations"; +import { type Recipe } from "wasp/entities"; + +export const getRecipes: GetRecipes<{}, Recipe[]> = async (_args, context) => { + return context.entities.Recipe.findMany( // Prisma query + { where: { user: { id: context.user.id } } } + ); +}; + +export const addRecipe ... +``` + +Now we can very easily use these in our React components! + +For the end, let's create a home page of our app. + +First we define it in main.wasp: +```wasp title="main.wasp" +... + +route HomeRoute { path: "/", to: HomePage } +page HomePage { + component: import { HomePage } from "@src/pages/HomePage", + authRequired: true // Will send user to /login if not authenticated. +} +``` + +and then implement it as a React component in JS/TS (that calls the Operations we previously defined): + +```tsx title="src/pages/HomePage.tsx" +import { useQuery, getRecipes } from "wasp/client/operations"; +import { type User } from "wasp/entities"; + +export function HomePage({ user }: { user: User }) { + // Due to full-stack type safety, `recipes` will be of type `Recipe[]` here. + const { data: recipes, isLoading } = useQuery(getRecipes); // Calling our query here! + + if (isLoading) { + return
    Loading...
    ; + } + + return ( +
    +

    Recipes

    +
      + {recipes ? recipes.map((recipe) => ( +
    • +
      {recipe.title}
      +
      {recipe.description}
      +
    • + )) : 'No recipes defined yet!'} +
    +
    + ); +} +``` + +And voila! We are listing all the recipes in our app 🎉 + +This was just a quick example to give you a taste of what Wasp is. For step by step tour through the most important Wasp features, check out the [Todo app tutorial](../tutorial/01-create.md). + +:::note +Above we skipped defining `/login` and `/signup` pages to keep the example a bit shorter, but those are very simple to do by using Wasp's Auth UI feature. +::: + +## When to use Wasp +Wasp is addressing the same core problems that typical web app frameworks are addressing, and it in big part [looks, swims and quacks](https://en.wikipedia.org/wiki/Duck_test) like a web app framework. + +### Best used for +- building full-stack web apps (like e.g. Airbnb or Asana) +- quickly starting a web app with industry best practices +- to be used alongside modern web dev stack (currently supported React and Node) + +### Avoid using Wasp for +- building static/presentational websites +- to be used as a no-code solution +- to be a solve-it-all tool in a single language + +## Wasp is a DSL + +:::note +You don't need to know what a DSL is to use Wasp, but if you are curious, you can read more about it below. +::: + +Wasp does not match typical expectations of a web app framework: it is not a set of libraries, it is instead a simple programming language that understands your code and can do a lot of things for you. + +Wasp is a programming language, but a specific kind: it is specialized for a single purpose: **building modern web applications**. We call such languages *DSL*s (Domain Specific Language). + +Other examples of *DSL*s that are often used today are e.g. *SQL* for databases and *HTML* for web page layouts. +The main advantage and reason why *DSL*s exist is that they need to do only one task (e.g. database queries) +so they can do it well and provide the best possible experience for the developer. + +The same idea stands behind Wasp - a language that will allow developers to **build modern web applications with 10x less code and less stack-specific knowledge**. diff --git a/web/versioned_docs/version-0.13.0/introduction/quick-start.md b/web/versioned_docs/version-0.13.0/introduction/quick-start.md new file mode 100644 index 0000000000..e33552e164 --- /dev/null +++ b/web/versioned_docs/version-0.13.0/introduction/quick-start.md @@ -0,0 +1,150 @@ +--- +title: Quick Start +slug: /quick-start +--- + +import useBaseUrl from '@docusaurus/useBaseUrl'; + +## Installation + +Welcome, new Waspeteer 🐝! + +Let's create and run our first Wasp app in 3 short steps: + +1. **To install Wasp on Linux / OSX / WSL (Windows), open your terminal and run:** + + ```shell + curl -sSL https://get.wasp-lang.dev/installer.sh | sh + ``` + + ℹ️ Wasp requires Node.js and will warn you if it is missing: check below for [more details](#requirements). + +2. **Then, create a new app by running:** + + ```shell + wasp new + ``` + +3. **Finally, run the app:** + + ```shell + cd + wasp start + ``` + +That's it 🎉 You have successfully created and served a new full-stack web app at and Wasp is serving both frontend and backend for you. + +:::note Something Unclear? + Check [More Details](#more-details) section below if anything went wrong with the installation, or if you have additional questions. +::: + +:::tip Want an even faster start? + Try out [Wasp AI](../wasp-ai/creating-new-app.md) 🤖 to generate a new Wasp app in minutes just from a title and short description! +::: + +:::tip Try Wasp Without Installing 🤔? + Give Wasp a spin in the browser without any setup by running our [Wasp Template for Gitpod](https://github.com/wasp-lang/gitpod-template) +::: + + +### What next? + + - [ ] 👉 **Check out the [Todo App tutorial](../tutorial/01-create.md), which will take you through all the core features of Wasp!** 👈 + - [ ] [Setup your editor](./editor-setup.md) for working with Wasp. + - [ ] Join us on [Discord](https://discord.gg/rzdnErX)! Any feedback or questions you have, we are there for you. + - [ ] Follow Wasp development by subscribing to our newsletter: https://wasp-lang.dev/#signup . We usually send 1 per month, and [Matija](https://github.com/matijaSos) does his best to unleash his creativity to make them engaging and fun to read :D! + +------ + +## More details + +### Requirements + +You must have Node.js (and NPM) installed on your machine and available in `PATH`. +A version of Node.js must be >= 18. + +If you need it, we recommend using [nvm](https://github.com/nvm-sh/nvm) for managing your Node.js installation version(s). + +
    + + A quick guide on installing/using nvm + +
    + + Install nvm via your OS package manager (`apt`, `pacman`, `homebrew`, ...) or via the [nvm](https://github.com/nvm-sh/nvm#install--update-script) install script. + + Then, install a version of Node.js that you need: + ```shell + nvm install 20 + ``` + + Finally, whenever you need to ensure a specific version of Node.js is used, run: + ```shell + nvm use 20 + ``` + to set the Node.js version for the current shell session. + + You can run + ```shell + node -v + ``` + to check the version of Node.js currently being used in this shell session. + + Check NVM repo for more details: https://github.com/nvm-sh/nvm. + +
    +
    + + +### Installation + + + + +Open your terminal and run: + +```shell +curl -sSL https://get.wasp-lang.dev/installer.sh | sh +``` + +:::note Running Wasp on Mac with Mx chip (arm64) +**Experiencing the 'Bad CPU type in executable' issue on a device with arm64 (Apple Silicon)?** +Given that the wasp binary is built for x86 and not for arm64 (Apple Silicon), you'll need to install [Rosetta on your Mac](https://support.apple.com/en-us/HT211861) if you are using a Mac with Mx (M1, M2, ...). Rosetta is a translation process that enables users to run applications designed for x86 on arm64 (Apple Silicon). To install Rosetta, run the following command in your terminal +```bash +softwareupdate --install-rosetta +``` +Once Rosetta is installed, you should be able to run Wasp without any issues. +::: + + + + + +With Wasp for Windows, we are almost there: Wasp is successfully compiling and running on Windows but there is a bug or two stopping it from fully working. Check it out [here](https://github.com/wasp-lang/wasp/issues/48) if you are interested in helping. + +In the meantime, the best way to start using Wasp on Windows is by using [WSL](https://learn.microsoft.com/en-us/windows/wsl/install). Once you set up Ubuntu on WSL, just follow Linux instructions for installing Wasp. You can refer to this [article](https://wasp-lang.dev/blog/2023/11/21/guide-windows-development-wasp-wsl) if you prefer a step by step guide to using Wasp in WSL environment. If you need further help, reach out to us on [Discord](https://discord.gg/rzdnErX) - we have some community members using WSL that might be able to help you. +:::caution + If you are using WSL2, make sure that your Wasp project is not on the Windows file system, but instead on the Linux file system. Otherwise, Wasp won't be able to detect file changes, due to the [issue in WSL2](https://github.com/microsoft/WSL/issues/4739). +::: + + + + + +If the installer is not working for you or your OS is not supported, you can try building Wasp from the source. + +To install from source, you need to clone the [wasp repo](https://github.com/wasp-lang/wasp), install [Cabal](https://cabal.readthedocs.io/en/stable/getting-started.html) on your machine and then run `cabal install` from the `waspc/` dir. + +If you have never built Wasp before, this might take some time due to `cabal` downloading dependencies for the first time. + +Check [waspc/](https://github.com/wasp-lang/wasp/tree/main/waspc) for more details on building Wasp from the source. + + + diff --git a/web/versioned_docs/version-0.13.0/migrate-from-0-11-to-0-12.md b/web/versioned_docs/version-0.13.0/migrate-from-0-11-to-0-12.md new file mode 100644 index 0000000000..f9a6630508 --- /dev/null +++ b/web/versioned_docs/version-0.13.0/migrate-from-0-11-to-0-12.md @@ -0,0 +1,1375 @@ +--- +title: Migration from 0.11.X to 0.12.X +--- + +import { EmailPill, UsernameAndPasswordPill, GithubPill, GooglePill } from "./auth/Pills"; + +:::note The latest version of Wasp is 0.13.X + +To fully migrate from 0.11.X to the latest version of Wasp, you should first migrate to **0.12.X and then to 0.13.X**. + +Make sure to read the [migration guide from 0.12.X to 0.13.X](./migrate-from-0-12-to-0-13.md) after you finish this one. + +::: + +## What's new in Wasp 0.12.0? + +### New project structure + +Here's a file tree of a fresh Wasp project created with the previous version of Wasp. +More precisely, this is what you'll get if you run `wasp new myProject` using Wasp 0.11.x: + +``` +. +├── .gitignore +├── main.wasp +├── src +│   ├── client +│   │   ├── Main.css +│   │   ├── MainPage.jsx +│   │   ├── react-app-env.d.ts +│   │   ├── tsconfig.json +│   │   └── waspLogo.png +│   ├── server +│   │   └── tsconfig.json +│   ├── shared +│   │   └── tsconfig.json +│   └── .waspignore +└── .wasproot +``` + +Compare that with the file tree of a fresh Wasp project created with Wasp +0.12.0. In other words, this is what you will get by running `wasp new myProject` +from this point onwards: + +``` +. +├── .gitignore +├── main.wasp +├── package.json +├── public +│   └── .gitkeep +├── src +│   ├── Main.css +│   ├── MainPage.jsx +│   ├── queries.ts +│   ├── vite-env.d.ts +│   ├── .waspignore +│   └── waspLogo.png +├── tsconfig.json +├── vite.config.ts +└── .wasproot + +``` + +The main differences are: + +- The server/client code separation is no longer necessary. You can now organize + your code however you want, as long as it's inside the `src` directory. +- All external imports in your Wasp file must have paths starting with `@src` (e.g., `import foo from '@src/bar.js'`) + where `@src` refers to the `src` directory in your project root. The paths can + no longer start with `@server` or `@client`. +- Your project now features a top-level `public` dir. Wasp will publicly serve + all the files it finds in this directory. Read more about it + [here](https://wasp-lang.dev/docs/project/static-assets). + +Our [Overview docs](./tutorial/02-project-structure.md) explain the new +structure in detail, while this page provides a [quick guide](#migrating-your-project-to-the-new-structure) for migrating existing +projects. + +### New auth + +In Wasp 0.11.X, authentication was based on the `User` model which the developer needed to set up properly and take care of the auth fields like `email` or `password`. + +```wasp title="main.wasp" +app myApp { + wasp: { + version: "^0.11.0" + }, + title: "My App", + auth: { + userEntity: User, + externalAuthEntity: SocialLogin, + methods: { + gitHub: {} + }, + onAuthFailedRedirectTo: "/login" + }, +} + +entity User {=psl + id Int @id @default(autoincrement()) + // highlight-start + username String @unique + password String + externalAuthAssociations SocialLogin[] + // highlight-end +psl=} + + +// highlight-start +entity SocialLogin {=psl + id Int @id @default(autoincrement()) + provider String + providerId String + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + userId Int + createdAt DateTime @default(now()) + @@unique([provider, providerId, userId]) +psl=} +// highlight-end +``` + +From 0.12.X onwards, authentication is based on the auth models which are automatically set up by Wasp. You don't need to take care of the auth fields anymore. + +The `User` model is now just a business logic model and you use it for storing the data that is relevant for your app. + +```wasp title="main.wasp" +app myApp { + wasp: { + version: "^0.12.0" + }, + title: "My App", + auth: { + userEntity: User, + methods: { + gitHub: {} + }, + onAuthFailedRedirectTo: "/login" + }, +} + +entity User {=psl + id Int @id @default(autoincrement()) +psl=} +``` + +:::caution Regression Note: Multiple Auth Identities per User + +With our old auth implementation, if you were using both Google and email auth methods, your users could sign up with Google first and then, later on, reset their password and therefore also enable logging in with their email and password. This was the only way in which a single user could have multiple login methods at the same time (Google and email). + +This is not possible anymore. **The new auth system doesn't support multiple login methods per user at the moment**. We do plan to add this soon though, with the introduction of the [account merging feature](https://github.com/wasp-lang/wasp/issues/954). + +If you have any users that have both Google and email login credentials at the same time, you will have to pick only one of those for that user to keep when migrating them. + +::: + +:::caution Regression Note: `_waspCustomValidations` is deprecated + +Auth field customization is no longer possible using the `_waspCustomValidations` on the `User` entity. This is a part of auth refactoring that we are doing to make it easier to customize auth. We will be adding more customization options in the future. + +::: + +You can read more about the new auth system in the [Auth Entities](./auth/entities) section. + +## How to Migrate? + +These instructions are for migrating your app from Wasp `0.11.X` to Wasp `0.12.X`, meaning they will work for all minor releases that fit this pattern (e.g., the guide applies to `0.12.0`, `0.12.1`, ...). + +The guide consists of two big steps: +1. Migrating your Wasp project to the new structure. +2. Migrating to the new auth. + +If you get stuck at any point, don't hesitate to ask for help on [our Discord server](https://discord.gg/rzdnErX). + +### Migrating Your Project to the New Structure + +You can easily migrate your old Wasp project to the new structure by following a +series of steps. Assuming you have a project called `foo` inside the +directory `foo`, you should: + +0. **Install the `0.12.x` version** of Wasp. + ```bash + curl -sSL https://get.wasp-lang.dev/installer.sh | sh -s -- -v 0.12.4 + ``` +1. Make sure to **backup or save your project** before starting the procedure (e.g., + by committing it to source control or creating a copy). +2. **Position yourself in the terminal** in the directory that is a parent of your wasp project directory (so one level above: if you do `ls`, you should see your wasp project dir listed). +3. **Run the migration script** (replace `foo` at the end with the name of your Wasp project directory) and follow the instructions: + ``` + npx wasp-migrate foo + ``` + +
    + + In case the migration script doesn't work well for you, you can do the same steps manually, as described here: + +
    + +1. Rename your project's root directory to something like `foo_old`. +2. Create a new project by running `wasp new foo`. +3. Delete all files of `foo/src` except `vite-env.d.ts`. +4. If `foo_old/src/client/public` exists and contains any files, copy those files into + `foo/public`. +5. Copy the contents of `foo_old/src` into `foo/src`. + `foo/src` should now contain `vite-env.d.ts`, `.waspignore`, and three subdirectories (`server`, `client`, and `shared`). + Don't change anything about this structure yet. +6. Delete redundant files and folders from `foo/src`: + - `foo/src/.waspignore` - A new version of this file already exists at the top level. + - `foo/src/client/vite-env.d.ts` - A new version of this file already exists at the top level. + - `foo/src/client/tsconfig.json` - A new version of this file already exists at the top level. + - `foo/src/server/tsconfig.json` - A new version of this file already exists at the top level. + - `foo/src/shared/tsconfig.json` - A new version of this file already exists at the top level. + - `foo/src/client/public` - You've moved all the files from this directory in step 5. +7. Update all the `@wasp` imports in your JS(X)/TS(X) source files in the `src/` dir. + + For this, we prepared a special script that will rewrite these imports automatically for you. + + Before doing this step, as the script will modify your JS(X)/TS(X) files in place, we advise committing + all changes you have so far, so you can then both easily inspect the import rewrites that our + script did (with `git diff`) and also revert them if something went wrong. + + To run the import-rewriting script, make sure you are in the root dir of your wasp project, and then run + ``` + npx jscodeshift@0.15.1 -t https://raw.githubusercontent.com/wasp-lang/wasp-codemod/main/src/transforms/imports-from-0-11-to-0-12.ts --extensions=js,ts,jsx,tsx src/ + ``` + + Then, check the changes it did, in case some kind of manual intervention is needed (in which case you should see TODO comments generated by the script). + + Alternatively, you can find all the mappings of old imports to the new ones in [this table](https://docs.google.com/spreadsheets/d/1QW-_16KRGTOaKXx9NYUtjk6m2TQ0nUMOA74hBthTH3g/edit#gid=1725669920) and use it to fix some/all of them manually. +8. Replace the Wasp file in `foo` (i.e., `main.wasp`) with the Wasp file from `foo_old` +9. Change the Wasp version field in your Wasp file (now residing in `foo`) to `"^0.12.0"`. +10. Correct external imports in your Wasp file (now residing in `foo`). + imports. You can do this by running search-and-replace inside the file: + + - Change all occurrences of `@server` to `@src/server` + - Change all occurrences of `@client` to `@src/client` + + For example, if you previously had something like: + + ```js + page LoginPage { + // highlight-next-line + // This previously resolved to src/client/LoginPage.js + // highlight-next-line + component: import Login from "@client/LoginPage" + } + + // ... + + query getTasks { + // highlight-next-line + // This previously resolved to src/server/queries.js + // highlight-next-line + fn: import { getTasks } from "@server/queries.js", + } + ``` + + You should change it to: + + ```js + page LoginPage { + // highlight-next-line + // This now resolves to src/client/LoginPage.js + // highlight-next-line + component: import Login from "@src/client/LoginPage" + } + + // ... + + query getTasks { + // highlight-next-line + // This now resolves to src/server/queries.js + // highlight-next-line + fn: import { getTasks } from "@src/server/queries.js", + } + ``` + + Do this for all external imports in your `.wasp` file. After you're done, there shouldn't be any occurrences of strings `"@server"` or `"@client"` + +11. Take all the dependencies from `app.dependencies` declaration in + `foo/main.wasp` and move them to `foo/package.json`. Make sure to remove the `app.dependencies` field from `foo/main.wasp`. + + For example, if `foo_old/main.wasp` had: + + ```css + app Foo { + // ... + dependencies: [ ('redux', '^4.0.5'), ('reacjt-redux', '^7.1.3')]; + } + ``` + + Your `package.json` in `foo` should now list these dependencies (Wasp already generated most of the file, you just have to list additional dependencies). + + ```json + { + "name": "foo", + "dependencies": { + "wasp": "file:.wasp/out/sdk/wasp", + "react": "^18.2.0", + // highlight-next-line + "redux": "^4.0.5", + // highlight-next-line + "reactjs-redux": "^7.1.3" + }, + "devDependencies": { + "typescript": "^5.1.0", + "vite": "^4.3.9", + "@types/react": "^18.0.37", + "prisma": "4.16.2" + } + } + ``` + +12. Copy all lines you might have added to `foo_old/.gitignore` into + `foo/.gitignore` +13. Copy the rest of the top-level files and folders (all of them except for `.gitignore`, `main.wasp` and `src/`) + in `foo_old/` into `foo/` (overwrite the existing files in `foo`). +14. Run `wasp clean` in `foo`. +15. Delete the `foo_old` directory. + +
    +
    + +That's it! You now have a properly structured Wasp 0.12.0 project in the `foo` directory. +Your app probably doesn't quite work yet due to some other changes in Wasp 0.12.0, but we'll get to that in the next sections. + +### Migrating declaration names +Wasp 0.12.0 adds a casing constraints when naming Queries, Actions, Jobs, and Entities in the `main.wasp` file. + +The following casing conventions have now become mandatory: +- Operation (i.e., Query and Action) names must begin with a lowercase letter: `query getTasks {...}`, `action createTask {...}`. +- Job names must begin with a lowercase letter: `job sendReport {...}`. +- Entity names must start with an uppercase letter: `entity Task {...}`. + +### Migrating the Tailwind Setup + +:::note +If you don't use Tailwind in your project, you can skip this section. +::: + +There is a small change in how the `tailwind.config.cjs` needs to be defined in Wasp 0.12.0. + +You'll need to wrap all your paths in the `content` field with the `resolveProjectPath` function. This makes sure that the paths are resolved correctly when generating your CSS. + +Here's how you can do it: + + + + +```js title="tailwind.config.cjs" +/** @type {import('tailwindcss').Config} */ +module.exports = { + content: [ + // highlight-next-line + './src/**/*.{js,jsx,ts,tsx}', + ], + theme: { + extend: {}, + }, + plugins: [], +} +``` + + + + +```js title="tailwind.config.cjs" +// highlight-next-line +const { resolveProjectPath } = require('wasp/dev') + +/** @type {import('tailwindcss').Config} */ +module.exports = { + content: [ + // highlight-next-line + resolveProjectPath('./src/**/*.{js,jsx,ts,tsx}'), + ], + theme: { + extend: {}, + }, + plugins: [], +} +``` + + + +### Default Server Dockerfile Changed +:::note +If you didn't customize your Dockerfile or had a custom build process for the Wasp server, you can skip this section. +::: + +Between Wasp 0.11.X and 0.12.X, the Dockerfile that Wasp generates for you for deploying the server has changed. If you defined a custom Dockerfile in your project root dir or in any other way relied on its contents, you'll need to update it to incorporate the changes that Wasp 0.12.X made. + +We suggest that you temporarily move your custom Dockerfile to a different location, then run `wasp start` to generate the new Dockerfile. +Check out the `.wasp/out/Dockerfile` to see the new Dockerfile and what changes you need to make. You'll probably need to copy some of the changes from the new Dockerfile to your custom one to make your app work with Wasp 0.12.X. + +### Migrating to the New Auth +As shown in [the previous section](#new-auth), Wasp significantly changed how authentication works in version 0.12.0. +This section leads you through migrating your app from Wasp 0.11.X to Wasp 0.12.X. + +Migrating your existing app to the new auth system is a two-step process: + +1. Migrate to the new auth system +1. Clean up the old auth system + +:::info Migrating a deployed app + +While going through these steps, we will focus first on doing the changes locally (including your local development database). + +Once we confirm everything works well locally, we will apply the same changes to the deployed app (including your production database). + +**We'll put extra info for migrating a deployed app in a box like this one.** +::: + +#### 1. Migrate to the New Auth System + +You can follow these steps to migrate to the new auth system (assuming you already migrated the project structure to 0.12, as described [above](#migrating-your-project-to-the-new-structure)): + +1. **Migrate `getUserFields` and/or `additionalSignupFields` in the `main.wasp` file to the new `userSignupFields` field.** + + If you are not using them, you can skip this step. + + In Wasp 0.11.X, you could define a `getUserFieldsFn` to specify extra fields that would get saved to the `User` when using Google or GitHub to sign up. + + You could also define `additionalSignupFields` to specify extra fields for the Email or Username & Password signup. + + In 0.12.X, we unified these two concepts into the `userSignupFields` field. + +
    + Migration for and + + First, move the value of `auth.signup.additionalFields` to `auth.methods.{method}.userSignupFields` in the `main.wasp` file. + + `{method}` depends on the auth method you are using. For example, if you are using the email auth method, you should move the `auth.signup.additionalFields` to `auth.methods.email.userSignupFields`. + + To finish, update the JS/TS implementation to use the `defineUserSignupFields` from `wasp/server/auth` instead of `defineAdditionalSignupFields` from `@wasp/auth/index.js`. + + + + + ```wasp title="main.wasp" + app crudTesting { + // ... + auth: { + userEntity: User, + methods: { + email: {}, + }, + onAuthFailedRedirectTo: "/login", + // highlight-start + signup: { + additionalFields: import { fields } from "@server/auth/signup.js", + }, + // highlight-end + }, + } + ``` + + ```ts title="src/server/auth/signup.ts" + // highlight-next-line + import { defineAdditionalSignupFields } from '@wasp/auth/index.js' + + // highlight-next-line + export const fields = defineAdditionalSignupFields({ + address: async (data) => { + const address = data.address + if (typeof address !== 'string') { + throw new Error('Address is required') + } + if (address.length < 5) { + throw new Error('Address must be at least 5 characters long') + } + return address + }, + }) + ``` + + + + + + ```wasp title="main.wasp" + app crudTesting { + // ... + auth: { + userEntity: User, + methods: { + email: { + // highlight-next-line + userSignupFields: import { fields } from "@src/server/auth/signup.js", + }, + }, + onAuthFailedRedirectTo: "/login", + }, + } + ``` + + ```ts title="src/server/auth/signup.ts" + // highlight-next-line + import { defineUserSignupFields } from 'wasp/server/auth' + + // highlight-next-line + export const fields = defineUserSignupFields({ + address: async (data) => { + const address = data.address; + if (typeof address !== 'string') { + throw new Error('Address is required'); + } + if (address.length < 5) { + throw new Error('Address must be at least 5 characters long'); + } + return address; + }, + }) + ``` + + Read more about the `userSignupFields` function [here](/auth/overview.md#1-defining-extra-fields). + + + + +
    + +
    + Migration for and + + First, move the value of `auth.methods.{method}.getUserFieldsFn` to `auth.methods.{method}.userSignupFields` in the `main.wasp` file. + + `{method}` depends on the auth method you are using. For example, if you are using Google auth, you should move the `auth.methods.google.getUserFieldsFn` to `auth.methods.google.userSignupFields`. + + To finish, update the JS/TS implementation to use the `defineUserSignupFields` from `wasp/server/auth` and modify the code to return the fields in the format that `defineUserSignupFields` expects. + + + + + ```wasp title="main.wasp" + app crudTesting { + // ... + auth: { + userEntity: User, + methods: { + google: { + // highlight-next-line + getUserFieldsFn: import { getUserFields } from "@server/auth/google.js" + }, + }, + onAuthFailedRedirectTo: "/login", + }, + } + ``` + + ```ts title="src/server/auth/google.ts" + // highlight-next-line + import type { GetUserFieldsFn } from '@wasp/types' + + // highlight-start + export const getUserFields: GetUserFieldsFn = async (_context, args) => { + const displayName = args.profile.displayName + return { displayName } + } + // highlight-end + ``` + + + + + + ```wasp title="main.wasp" + app crudTesting { + // ... + auth: { + userEntity: User, + methods: { + google: { + // highlight-next-line + userSignupFields: import { fields } from "@src/server/auth/google.js", + }, + }, + onAuthFailedRedirectTo: "/login", + }, + } + ``` + + ```ts title="src/server/auth/signup.ts" + // highlight-next-line + import { defineUserSignupFields } from 'wasp/server/auth' + + // highlight-start + export const fields = defineUserSignupFields({ + displayName: async (data) => { + const profile: any = data.profile; + if (!profile?.displayName) { throw new Error('Display name is not available'); } + return profile.displayName; + }, + }) + // highlight-end + ``` + + If you want to properly type the `profile` object, we recommend you use a validation library like Zod to define the shape of the `profile` object. + + Read more about this and the `defineUserSignupFields` function in the [Auth Overview - Defining Extra Fields](./auth/overview.md#1-defining-extra-fields) section. + + + + +
    + +1. **Remove the `auth.methods.email.allowUnverifiedLogin` field** from your `main.wasp` file. + + In Wasp 0.12.X we removed the `auth.methods.email.allowUnverifiedLogin` field to make our Email auth implementation easier to reason about. If you were using it, you should remove it from your `main.wasp` file. + +1. Ensure your **local development database is running**. +1. **Do the schema migration** (create the new auth tables in the database) by running: + ```bash + wasp db migrate-dev + ``` +You should see the new `Auth`, `AuthIdentity` and `Session` tables in your database. You can use the `wasp db studio` command to open the database in a GUI and verify the tables are there. At the moment, they will be empty. +1. **Do the data migration** (move existing users from the old auth system to the new one by filling the new auth tables in the database with their data): + + 1. **Implement your data migration function(s)** in e.g. `src/migrateToNewAuth.ts`. + + Below we prepared [examples of migration functions](#example-data-migration-functions) for each of the auth methods, for you to use as a starting point. + They should be fine to use as-is, meaning you can just copy them and they are likely to work out of the box for typical use cases, but you can also modify them for your needs. + + We recommend you create one function per each auth method that you use in your app. + + 1. **Define custom API endpoints for each migration function** you implemented. + + With each data migration function below, we provided a relevant `api` declaration that you should add to your `main.wasp` file. + + 1. **Run the data migration function(s)** on the local development database by calling the API endpoints you defined in the previous step. + + You can call the endpoint by visiting the URL in your browser, or by using a tool like `curl` or Postman. + + For example, if you defined the API endpoint at `/migrate-username-and-password`, you can call it by visiting `http://localhost:3001/migrate-username-and-password` in your browser. + + This should be it, you can now run `wasp db studio` again and verify that there is now relevant data in the new auth tables (`Auth` and `AuthIdentity`; `Session` should still be empty for now). + +1. **Verify that the basic auth functionality works** by running `wasp start` and successfully signing up / logging in with each of the auth methods. +1. **Update your JS/TS code** to work correctly with the new auth. + + You might want to use the new auth helper functions to get the `email` or `username` from a user object. For example, `user.username` might not work anymore for you, since the `username` obtained by the Username & Password auth method isn't stored on the `User` entity anymore (unless you are explicitly storing something into `user.username`, e.g. via `userSignupFields` for a social auth method like Github). Same goes for `email` from Email auth method. + + Instead, you can now use `getUsername(user)` to get the username obtained from Username & Password auth method, or `getEmail(user)` to get the email obtained from Email auth method. + + Read more about the helpers in the [Auth Entities - Accessing the Auth Fields](auth/entities#accessing-the-auth-fields) section. +1. Finally, **check that your app now fully works as it worked before**. If all the above steps were done correctly, everything should be working now. + + :::info Migrating a deployed app + + After successfully performing migration locally so far, and verifying that your app works as expected, it is time to also migrate our deployed app. + + Before migrating your production (deployed) app, we advise you to back up your production database in case something goes wrong. Also, besides testing it in development, it's good to test the migration in a staging environment if you have one. + + We will perform the production migration in 2 steps: + - Deploying the new code to production (client and server). + - Migrating the production database data. + + --- + + Between these two steps, so after successfully deploying the new code to production and before migrating the production database data, your app will not be working completely: new users will be able to sign up, but existing users won't be able to log in, and already logged in users will be logged out. Once you do the second step, migrating the production database data, it will all be back to normal. You will likely want to keep the time between the two steps as short as you can. + + --- + + - **First step: deploy the new code** (client and server), either via `wasp deploy` (i.e. `wasp deploy fly deploy`) or manually. + + Check our [Deployment docs](advanced/deployment/overview.md) for more details. + + - **Second step: run the data migration functions** on the production database. + + You can do this by calling the API endpoints you defined in the previous step, just like you did locally. You can call the endpoint by visiting the URL in your browser, or by using a tool like `curl` or Postman. + + For example, if you defined the API endpoint at `/migrate-username-and-password`, you can call it by visiting `https://your-server-url.com/migrate-username-and-password` in your browser. + + Your deployed app should be working normally now, with the new auth system. + ::: + + +#### 2. Cleanup the Old Auth System + +Your app should be working correctly and using new auth, but to finish the migration, we need to clean up the old auth system: + +1. In `main.wasp` file, **delete auth-related fields from the `User` entity**, since with 0.12 they got moved to the internal Wasp entity `AuthIdentity`. + + - This means any fields that were required by Wasp for authentication, like `email`, `password`, `isEmailVerified`, `emailVerificationSentAt`, `passwordResetSentAt`, `username`, etc. + - There are situations in which you might want to keep some of them, e.g. `email` and/or `username`, if they are still relevant for you due to your custom logic (e.g. you are populating them with `userSignupFields` upon social signup in order to have this info easily available on the `User` entity). Note that they won't be used by Wasp Auth anymore, they are here just for your business logic. + +1. In `main.wasp` file, **remove the `externalAuthEntity` field from the `app.auth`** and also **remove the whole `SocialLogin` entity** if you used Google or GitHub auth. +1. **Delete the data migration function(s)** you implemented earlier (e.g. in `src/migrateToNewAuth.ts`) and also the corresponding API endpoints from the `main.wasp` file. +1. **Run `wasp db migrate-dev`** again to apply these changes and remove the redundant fields from the database. + +:::info Migrating a deployed app + + After doing the steps above successfully locally and making sure everything is working, it is time to push these changes to the deployed app again. + + _Deploy the app again_, either via `wasp deploy` or manually. Check our [Deployment docs](advanced/deployment/overview.md) for more details. + + The database migrations will automatically run on successful deployment of the server and delete the now redundant auth-related `User` columns from the database. + + Your app is now fully migrated to the new auth system. + +::: + +### Next Steps + +If you made it this far, you've completed all the necessary steps to get your +Wasp app working with Wasp 0.12.x. Nice work! + +Finally, since Wasp no longer requires you to separate your client source files +(previously in `src/client`) from server source files (previously in +`src/server`), you are now free to reorganize your project however you think is best, +as long as you keep all the source files in the `src/` directory. + +This section is optional, but if you didn't like the server/client +separation, now's the perfect time to change it. + +For example, if your `src` dir looked like this: + +``` +src +│ +├── client +│   ├── Dashboard.tsx +│   ├── Login.tsx +│   ├── MainPage.tsx +│   ├── Register.tsx +│   ├── Task.css +│   ├── TaskLisk.tsx +│   ├── Task.tsx +│   └── User.tsx +├── server +│   ├── taskActions.ts +│   ├── taskQueries.ts +│   ├── userActions.ts +│   └── userQueries.ts +└── shared + └── utils.ts +``` + +you can now change it to a feature-based structure (which we recommend for any project that is not very small): + +``` +src +│ +├── task +│   ├── actions.ts -- former taskActions.ts +│   ├── queries.ts -- former taskQueries.ts +│   ├── Task.css +│   ├── TaskLisk.tsx +│   └── Task.tsx +├── user +│   ├── actions.ts -- former userActions.ts +│   ├── Dashboard.tsx +│   ├── Login.tsx +│   ├── queries.ts -- former userQueries.ts +│   ├── Register.tsx +│   └── User.tsx +├── MainPage.tsx +└── utils.ts +``` + + +## Appendix + +### Example Data Migration Functions + +The migration functions provided below are written with the typical use cases in mind and you can use them as-is. If your setup requires additional logic, you can use them as a good starting point and modify them to your needs. + +Note that all of the functions below are written to be idempotent, meaning that running a function multiple times can't hurt. This allows executing a function again in case only a part of the previous execution succeeded and also means that accidentally running it one time too much won't have any negative effects. **We recommend you keep your data migration functions idempotent**. + +#### Username & Password + +To successfully migrate the users using the Username & Password auth method, you will need to do two things: +1. Migrate the user data + +
    + Username & Password data migration function + + ```wasp title="main.wasp" + api migrateUsernameAndPassword { + httpRoute: (GET, "/migrate-username-and-password"), + fn: import { migrateUsernameAndPasswordHandler } from "@src/migrateToNewAuth", + entities: [] + } + ``` + + ```ts title="src/migrateToNewAuth.ts" + import { prisma } from "wasp/server"; + import { type ProviderName, type UsernameProviderData } from "wasp/server/auth"; + import { MigrateUsernameAndPassword } from "wasp/server/api"; + + export const migrateUsernameAndPasswordHandler: MigrateUsernameAndPassword = + async (_req, res) => { + const result = await migrateUsernameAuth(); + + res.status(200).json({ message: "Migrated users to the new auth", result }); + }; + + async function migrateUsernameAuth(): Promise<{ + numUsersAlreadyMigrated: number; + numUsersNotUsingThisAuthMethod: number; + numUsersMigratedSuccessfully: number; + }> { + const users = await prisma.user.findMany({ + include: { + auth: true, + }, + }); + + const result = { + numUsersAlreadyMigrated: 0, + numUsersNotUsingThisAuthMethod: 0, + numUsersMigratedSuccessfully: 0, + }; + + for (const user of users) { + if (user.auth) { + result.numUsersAlreadyMigrated++; + console.log("Skipping user (already migrated) with id:", user.id); + continue; + } + + if (!user.username || !user.password) { + result.numUsersNotUsingThisAuthMethod++; + console.log("Skipping user (not using username auth) with id:", user.id); + continue; + } + + const providerData: UsernameProviderData = { + hashedPassword: user.password, + }; + const providerName: ProviderName = "username"; + + await prisma.auth.create({ + data: { + identities: { + create: { + providerName, + providerUserId: user.username.toLowerCase(), + providerData: JSON.stringify(providerData), + }, + }, + user: { + connect: { + id: user.id, + }, + }, + }, + }); + result.numUsersMigratedSuccessfully++; + } + + return result; + } + ``` + +
    + +2. Provide a way for users to migrate their password + + There is a **breaking change between the old and the new auth in the way the password is hashed**. This means that users will need to migrate their password after the migration, as the old password will no longer work. + + Since the only way users using username and password as a login method can verify their identity is by providing both their username and password (there is no email or any other info, unless you asked for it and stored it explicitly), we need to provide them a way to **exchange their old password for a new password**. One way to handle this is to inform them about the need to migrate their password (on the login page) and provide a custom page to migrate the password. + +
    + + Steps to create a custom page for migrating the password + + + 1. You will need to install the `secure-password` and `sodium-native` packages to use the old hashing algorithm: + + ```bash + npm install secure-password@4.0.0 sodium-native@3.3.0 --save-exact + ``` + + Make sure to save the exact versions of the packages. + + 2. Then you'll need to create a new page in your app where users can migrate their password. You can use the following code as a starting point: + + + + +```wasp title="main.wasp" +route MigratePasswordRoute { path: "/migrate-password", to: MigratePassword } +page MigratePassword { + component: import { MigratePasswordPage } from "@src/pages/MigratePassword" +} +``` + +```jsx title="src/pages/MigratePassword.jsx" +import { + FormItemGroup, + FormLabel, + FormInput, + FormError, +} from "wasp/client/auth"; +import { useForm } from "react-hook-form"; +import { migratePassword } from "wasp/client/operations"; +import { useState } from "react"; + +export function MigratePasswordPage() { + const [successMessage, setSuccessMessage] = useState(null); + const [errorMessage, setErrorMessage] = useState(null); + const form = useForm(); + + const onSubmit = form.handleSubmit(async (data) => { + try { + const result = await migratePassword(data); + setSuccessMessage(result.message); + } catch (e) { + console.error(e); + if (e instanceof Error) { + setErrorMessage(e.message); + } + } + }); + + return ( +
    +

    Migrate your password

    +

    + If you have an account on the old version of the website, you can + migrate your password to the new version. +

    + {successMessage &&
    {successMessage}
    } + {errorMessage && {errorMessage}} +
    + + Username + + {form.formState.errors.username?.message} + + + Password + + {form.formState.errors.password?.message} + + +
    +
    + ); +} +``` + +
    + + +```wasp title="main.wasp" +route MigratePasswordRoute { path: "/migrate-password", to: MigratePassword } +page MigratePassword { + component: import { MigratePasswordPage } from "@src/pages/MigratePassword" +} +``` + +```tsx title="src/pages/MigratePassword.tsx" +import { + FormItemGroup, + FormLabel, + FormInput, + FormError, +} from "wasp/client/auth"; +import { useForm } from "react-hook-form"; +import { migratePassword } from "wasp/client/operations"; +import { useState } from "react"; + +export function MigratePasswordPage() { + const [successMessage, setSuccessMessage] = useState(null); + const [errorMessage, setErrorMessage] = useState(null); + const form = useForm<{ + username: string; + password: string; + }>(); + + const onSubmit = form.handleSubmit(async (data) => { + try { + const result = await migratePassword(data); + setSuccessMessage(result.message); + } catch (e: unknown) { + console.error(e); + if (e instanceof Error) { + setErrorMessage(e.message); + } + } + }); + + return ( +
    +

    Migrate your password

    +

    + If you have an account on the old version of the website, you can + migrate your password to the new version. +

    + {successMessage &&
    {successMessage}
    } + {errorMessage && {errorMessage}} +
    + + Username + + {form.formState.errors.username?.message} + + + Password + + {form.formState.errors.password?.message} + + +
    +
    + ); +} +``` + +
    +
    + + 3. Finally, you will need to create a new operation in your app to handle the password migration. You can use the following code as a starting point: + + + + + +```wasp title="main.wasp" +action migratePassword { + fn: import { migratePassword } from "@src/auth", + entities: [] +} +``` + +```js title="src/auth.js" +import SecurePassword from "secure-password"; +import { HttpError } from "wasp/server"; +import { + createProviderId, + deserializeAndSanitizeProviderData, + findAuthIdentity, + updateAuthIdentityProviderData, +} from "wasp/server/auth"; + +export const migratePassword = async ({ password, username }, _context) => { + const providerId = createProviderId("username", username); + const authIdentity = await findAuthIdentity(providerId); + + if (!authIdentity) { + throw new HttpError(400, "Something went wrong"); + } + + const providerData = deserializeAndSanitizeProviderData( + authIdentity.providerData + ); + + try { + const SP = new SecurePassword(); + + // This will verify the password using the old algorithm + const result = await SP.verify( + Buffer.from(password), + Buffer.from(providerData.hashedPassword, "base64") + ); + + if (result !== SecurePassword.VALID) { + throw new HttpError(400, "Something went wrong"); + } + + // This will hash the password using the new algorithm and update the + // provider data in the database. + await updateAuthIdentityProviderData(providerId, providerData, { + hashedPassword: password, + }); + } catch (e) { + throw new HttpError(400, "Something went wrong"); + } + + return { + message: "Password migrated successfully.", + }; +}; +``` + + + + +```wasp title="main.wasp" +action migratePassword { + fn: import { migratePassword } from "@src/auth", + entities: [] +} +``` + +```ts title="src/auth.ts" +import SecurePassword from "secure-password"; +import { HttpError } from "wasp/server"; +import { + createProviderId, + deserializeAndSanitizeProviderData, + findAuthIdentity, + updateAuthIdentityProviderData, +} from "wasp/server/auth"; +import { MigratePassword } from "wasp/server/operations"; + +type MigratePasswordInput = { + username: string; + password: string; +}; +type MigratePasswordOutput = { + message: string; +}; + +export const migratePassword: MigratePassword< + MigratePasswordInput, + MigratePasswordOutput +> = async ({ password, username }, _context) => { + const providerId = createProviderId("username", username); + const authIdentity = await findAuthIdentity(providerId); + + if (!authIdentity) { + throw new HttpError(400, "Something went wrong"); + } + + const providerData = deserializeAndSanitizeProviderData<"username">( + authIdentity.providerData + ); + + try { + const SP = new SecurePassword(); + + // This will verify the password using the old algorithm + const result = await SP.verify( + Buffer.from(password), + Buffer.from(providerData.hashedPassword, "base64") + ); + + if (result !== SecurePassword.VALID) { + throw new HttpError(400, "Something went wrong"); + } + + // This will hash the password using the new algorithm and update the + // provider data in the database. + await updateAuthIdentityProviderData<"username">(providerId, providerData, { + hashedPassword: password, + }); + } catch (e) { + throw new HttpError(400, "Something went wrong"); + } + + return { + message: "Password migrated successfully.", + }; +}; +``` + + + + +
    + + +#### Email + +To successfully migrate the users using the Email auth method, you will need to do two things: +1. Migrate the user data + +
    + Email data migration function + + ```wasp title="main.wasp" + api migrateEmail { + httpRoute: (GET, "/migrate-email"), + fn: import { migrateEmailHandler } from "@src/migrateToNewAuth", + entities: [] + } + ``` + + ```ts title="src/migrateToNewAuth.ts" + import { prisma } from "wasp/server"; + import { type ProviderName, type EmailProviderData } from "wasp/server/auth"; + import { MigrateEmail } from "wasp/server/api"; + + export const migrateEmailHandler: MigrateEmail = + async (_req, res) => { + const result = await migrateEmailAuth(); + + res.status(200).json({ message: "Migrated users to the new auth", result }); + }; + + async function migrateEmailAuth(): Promise<{ + numUsersAlreadyMigrated: number; + numUsersNotUsingThisAuthMethod: number; + numUsersMigratedSuccessfully: number; + }> { + const users = await prisma.user.findMany({ + include: { + auth: true, + }, + }); + + const result = { + numUsersAlreadyMigrated: 0, + numUsersNotUsingThisAuthMethod: 0, + numUsersMigratedSuccessfully: 0, + }; + + for (const user of users) { + if (user.auth) { + result.numUsersAlreadyMigrated++; + console.log("Skipping user (already migrated) with id:", user.id); + continue; + } + + if (!user.email || !user.password) { + result.numUsersNotUsingThisAuthMethod++; + console.log("Skipping user (not using email auth) with id:", user.id); + continue; + } + + const providerData: EmailProviderData = { + isEmailVerified: user.isEmailVerified, + emailVerificationSentAt: + user.emailVerificationSentAt?.toISOString() ?? null, + passwordResetSentAt: user.passwordResetSentAt?.toISOString() ?? null, + hashedPassword: user.password, + }; + const providerName: ProviderName = "email"; + + await prisma.auth.create({ + data: { + identities: { + create: { + providerName, + providerUserId: user.email, + providerData: JSON.stringify(providerData), + }, + }, + user: { + connect: { + id: user.id, + }, + }, + }, + }); + result.numUsersMigratedSuccessfully++; + } + + return result; + } + ``` + +
    + +2. Ask the users to reset their password + + There is a **breaking change between the old and the new auth in the way the password is hashed**. This means that users will need to reset their password after the migration, as the old password will no longer work. + + It would be best to notify your users about this change and put a notice on your login page to **request a password reset**. + +#### Google & GitHub + +
    +Google & GitHub data migration functions + +```wasp title="main.wasp" +api migrateGoogle { + httpRoute: (GET, "/migrate-google"), + fn: import { migrateGoogleHandler } from "@src/migrateToNewAuth", + entities: [] +} + +api migrateGithub { + httpRoute: (GET, "/migrate-github"), + fn: import { migrateGithubHandler } from "@src/migrateToNewAuth", + entities: [] +} +``` + +```ts title="src/migrateToNewAuth.ts" +import { prisma } from "wasp/server"; +import { MigrateGoogle, MigrateGithub } from "wasp/server/api"; + +export const migrateGoogleHandler: MigrateGoogle = + async (_req, res) => { + const result = await createSocialLoginMigration("google"); + + res.status(200).json({ message: "Migrated users to the new auth", result }); + }; + +export const migrateGithubHandler: MigrateGithub = + async (_req, res) => { + const result = await createSocialLoginMigration("github"); + + res.status(200).json({ message: "Migrated users to the new auth", result }); + }; + +async function createSocialLoginMigration( + providerName: "google" | "github" +): Promise<{ + numUsersAlreadyMigrated: number; + numUsersNotUsingThisAuthMethod: number; + numUsersMigratedSuccessfully: number; +}> { + const users = await prisma.user.findMany({ + include: { + auth: true, + externalAuthAssociations: true, + }, + }); + + const result = { + numUsersAlreadyMigrated: 0, + numUsersNotUsingThisAuthMethod: 0, + numUsersMigratedSuccessfully: 0, + }; + + for (const user of users) { + if (user.auth) { + result.numUsersAlreadyMigrated++; + console.log("Skipping user (already migrated) with id:", user.id); + continue; + } + + const provider = user.externalAuthAssociations.find( + (provider) => provider.provider === providerName + ); + + if (!provider) { + result.numUsersNotUsingThisAuthMethod++; + console.log(`Skipping user (not using ${providerName} auth) with id:`, user.id); + continue; + } + + await prisma.auth.create({ + data: { + identities: { + create: { + providerName, + providerUserId: provider.providerId, + providerData: JSON.stringify({}), + }, + }, + user: { + connect: { + id: user.id, + }, + }, + }, + }); + result.numUsersMigratedSuccessfully++; + } + + return result; +} +``` + +
    diff --git a/web/versioned_docs/version-0.13.0/migrate-from-0-12-to-0-13.md b/web/versioned_docs/version-0.13.0/migrate-from-0-12-to-0-13.md new file mode 100644 index 0000000000..fb7e5d8270 --- /dev/null +++ b/web/versioned_docs/version-0.13.0/migrate-from-0-12-to-0-13.md @@ -0,0 +1,134 @@ +--- +title: Migration from 0.12.X to 0.13.X +--- + +:::note Are you on 0.11.X or earlier? + +This guide only covers the migration from **0.12.X to 0.13.X**. If you are migrating from 0.11.X or earlier, please read the [migration guide from 0.11.X to 0.12.X](./migrate-from-0-11-to-0-12.md) first. + +::: + +## What's new in 0.13.0? + +### OAuth providers got an overhaul + +Wasp 0.13.0 switches away from using Passport for our OAuth providers in favor of [Arctic](https://arctic.js.org/) from the [Lucia](https://lucia-auth.com/) ecosystem. This change simplifies the codebase and makes it easier to add new OAuth providers in the future. + +### We added Keycloak as an OAuth provider + +Wasp now supports using [Keycloak](https://www.keycloak.org/) as an OAuth provider. + +## How to migrate? + +### Migrate your OAuth setup + +We had to make some breaking changes to upgrade the OAuth setup to the new Arctic lib. + +Follow the steps below to migrate: + +1. **Define the `WASP_SERVER_URL` server env variable** + + In 0.13.0 Wasp introduces a new server env variable `WASP_SERVER_URL` that you need to define. This is the URL of your Wasp server and it's used to generate the redirect URL for the OAuth providers. + + ```bash title="Server env variables" + WASP_SERVER_URL=https://your-wasp-server-url.com + ``` + + In development, Wasp sets the `WASP_SERVER_URL` to `http://localhost:3001` by default. + + :::info Migrating a deployed app + + If you are migrating a deployed app, you will need to define the `WASP_SERVER_URL` server env variable in your deployment environment. + + Read more about setting env variables in production [here](./project/env-vars#defining-env-vars-in-production). + ::: + +2. **Update the redirect URLs** for the OAuth providers + + The redirect URL for the OAuth providers has changed. You will need to update the redirect URL for the OAuth providers in the provider's dashboard. + + + + + ``` + {clientUrl}/auth/login/{provider} + ``` + + + + ``` + {serverUrl}/auth/{provider}/callback + ``` + + + + Check the new redirect URLs for [Google](./auth/social-auth/google.md#3-creating-a-google-oauth-app) and [GitHub](./auth/social-auth/github.md#3-creating-a-github-oauth-app) in Wasp's docs. + +3. **Update the `configFn`** for the OAuth providers + + If you didn't use the `configFn` option, you can skip this step. + + If you used the `configFn` to configure the `scope` for the OAuth providers, you will need to rename the `scope` property to `scopes`. + + Also, the object returned from `configFn` no longer needs to include the Client ID and the Client Secret. You can remove them from the object that `configFn` returns. + + + + + ```ts title="google.ts" + export function getConfig() { + return { + clientID: process.env.GOOGLE_CLIENT_ID, + clientSecret: process.env.GOOGLE_CLIENT_SECRET, + scope: ['profile', 'email'], + } + } + ``` + + + + + ```ts title="google.ts" + export function getConfig() { + return { + scopes: ['profile', 'email'], + } + } + ``` + + + +4. **Update the `userSignupFields` fields** to use the new `profile` format + + If you didn't use the `userSignupFields` option, you can skip this step. + + The data format for the `profile` that you receive from the OAuth providers has changed. You will need to update your code to reflect this change. + + + + + ```ts title="google.ts" + import { defineUserSignupFields } from 'wasp/server/auth' + + export const userSignupFields = defineUserSignupFields({ + displayName: (data: any) => data.profile.displayName, + }) + ``` + + + + ```ts title="google.ts" + import { defineUserSignupFields } from 'wasp/server/auth' + + export const userSignupFields = defineUserSignupFields({ + displayName: (data: any) => data.profile.name, + }) + ``` + + + + Wasp now directly forwards what it receives from the OAuth providers. You can check the data format for [Google](./auth/social-auth/google.md#data-received-from-google) and [GitHub](./auth/social-auth/github.md#data-received-from-github) in Wasp's docs. + +That's it! + +You should now be able to run your app with the new Wasp 0.13.0. \ No newline at end of file diff --git a/web/versioned_docs/version-0.13.0/project/_baseDirEnvNote.md b/web/versioned_docs/version-0.13.0/project/_baseDirEnvNote.md new file mode 100644 index 0000000000..472263cc6a --- /dev/null +++ b/web/versioned_docs/version-0.13.0/project/_baseDirEnvNote.md @@ -0,0 +1,6 @@ +:::caution Setting the correct env variable + +If you set the `baseDir` option, make sure that the `WASP_WEB_CLIENT_URL` env variable also includes that base directory. + +For example, if you are serving your app from `https://example.com/my-app`, the `WASP_WEB_CLIENT_URL` should be also set to `https://example.com/my-app`, and not just `https://example.com`. +::: \ No newline at end of file diff --git a/web/versioned_docs/version-0.13.0/project/client-config.md b/web/versioned_docs/version-0.13.0/project/client-config.md new file mode 100644 index 0000000000..abb5272e3a --- /dev/null +++ b/web/versioned_docs/version-0.13.0/project/client-config.md @@ -0,0 +1,449 @@ +--- +title: Client Config +--- + +import BaseDirEnvNote from './_baseDirEnvNote.md' + +import { ShowForTs, ShowForJs } from '@site/src/components/TsJsHelpers' + +You can configure the client using the `client` field inside the `app` declaration: + + + + +```wasp title="main.wasp" +app MyApp { + title: "My app", + // ... + client: { + rootComponent: import Root from "@src/Root.jsx", + setupFn: import mySetupFunction from "@src/myClientSetupCode.js" + } +} +``` + + + + +```wasp title="main.wasp" +app MyApp { + title: "My app", + // ... + client: { + rootComponent: import Root from "@src/Root.tsx", + setupFn: import mySetupFunction from "@src/myClientSetupCode.ts" + } +} +``` + + + + +## Root Component + +Wasp gives you the option to define a "wrapper" component for your React app. + +It can be used for a variety of purposes, but the most common ones are: + +- Defining a common layout for your application. +- Setting up various providers that your application needs. + +### Defining a Common Layout + +Let's define a common layout for your application: + + + + +```wasp title="main.wasp" +app MyApp { + title: "My app", + // ... + client: { + rootComponent: import Root from "@src/Root.jsx", + } +} +``` + +```jsx title="src/Root.jsx" +export default function Root({ children }) { + return ( +
    +
    +

    My App

    +
    + {children} +
    +

    My App footer

    +
    +
    + ) +} +``` + +
    + + +```wasp title="main.wasp" +app MyApp { + title: "My app", + // ... + client: { + rootComponent: import Root from "@src/Root.tsx", + } +} +``` + +```tsx title="src/Root.tsx" +export default function Root({ children }: { children: React.ReactNode }) { + return ( +
    +
    +

    My App

    +
    + {children} +
    +

    My App footer

    +
    +
    + ) +} +``` + +
    +
    + +### Setting up a Provider + +This is how to set up various providers that your application needs: + + + + +```wasp title="main.wasp" +app MyApp { + title: "My app", + // ... + client: { + rootComponent: import Root from "@src/Root.jsx", + } +} +``` + +```jsx title="src/Root.jsx" +import store from './store' +import { Provider } from 'react-redux' + +export default function Root({ children }) { + return {children} +} +``` + + + + +```wasp title="main.wasp" +app MyApp { + title: "My app", + // ... + client: { + rootComponent: import Root from "@src/Root.tsx", + } +} +``` + +```tsx title="src/Root.tsx" +import store from './store' +import { Provider } from 'react-redux' + +export default function Root({ children }: { children: React.ReactNode }) { + return {children} +} +``` + + + + +As long as you render the children, you can do whatever you want in your root +component. + +Read more about the root component in the [API Reference](#rootcomponent-extimport). + +## Setup Function + +`setupFn` declares a TypescriptJavaScript function that Wasp executes on the client before everything else. + +### Running Some Code + +We can run any code we want in the setup function. + +For example, here's a setup function that logs a message every hour: + + + + +```js title="src/myClientSetupCode.js" +export default async function mySetupFunction() { + let count = 1 + setInterval( + () => console.log(`You have been online for ${count++} hours.`), + 1000 * 60 * 60 + ) +} +``` + + + + +```ts title="src/myClientSetupCode.ts" +export default async function mySetupFunction(): Promise { + let count = 1 + setInterval( + () => console.log(`You have been online for ${count++} hours.`), + 1000 * 60 * 60 + ) +} +``` + + + + +### Overriding Default Behaviour for Queries + +:::info +You can change the options for a **single** Query using the `options` object, as described [here](../data-model/operations/queries#the-usequery-hook-1). +::: + +Wasp's `useQuery` hook uses `react-query`'s `useQuery` hook under the hood. Since `react-query` comes configured with aggressive but sane default options, you most likely won't have to change those defaults for all Queries. + +If you do need to change the global defaults, you can do so inside the client setup function. + +Wasp exposes a `configureQueryClient` hook that lets you configure _react-query_'s `QueryClient` object: + + + + +```js title="src/myClientSetupCode.js" +import { configureQueryClient } from 'wasp/client/operations' + +export default async function mySetupFunction() { + // ... some setup + configureQueryClient({ + defaultOptions: { + queries: { + staleTime: Infinity, + }, + }, + }) + // ... some more setup +} +``` + + + + +```ts title="src/myClientSetupCode.ts" +import { configureQueryClient } from 'wasp/client/operations' + +export default async function mySetupFunction(): Promise { + // ... some setup + configureQueryClient({ + defaultOptions: { + queries: { + staleTime: Infinity, + }, + }, + }) + // ... some more setup +} +``` + + + + +Make sure to pass in an object expected by the `QueryClient`'s constructor, as +explained in +[react-query's docs](https://tanstack.com/query/v4/docs/react/reference/QueryClient). + +Read more about the setup function in the [API Reference](#setupfn-extimport). + +## Base Directory + +If you need to serve the client from a subdirectory, you can use the `baseDir` option: + +```wasp title="main.wasp" +app MyApp { + title: "My app", + // ... + client: { + baseDir: "/my-app", + } +} +``` + +This means that if you serve your app from `https://example.com/my-app`, the +router will work correctly, and all the assets will be served from +`https://example.com/my-app`. + + + +## API Reference + + + + +```wasp title="main.wasp" +app MyApp { + title: "My app", + // ... + client: { + rootComponent: import Root from "@src/Root.jsx", + setupFn: import mySetupFunction from "@src/myClientSetupCode.js" + } +} +``` + + + + +```wasp title="main.wasp" +app MyApp { + title: "My app", + // ... + client: { + rootComponent: import Root from "@src/Root.tsx", + setupFn: import mySetupFunction from "@src/myClientSetupCode.ts", + baseDir: "/my-app", + } +} +``` + + + + +Client has the following options: + +- #### `rootComponent: ExtImport` + + `rootComponent` defines the root component of your client application. It is + expected to be a React component, and Wasp will use it to wrap your entire app. + It must render its children, which are the actual pages of your application. + + Here's an example of a root component that both sets up a provider and + renders a custom layout: + + + + + ```jsx title="src/Root.jsx" + import store from './store' + import { Provider } from 'react-redux' + + export default function Root({ children }) { + return ( + + {children} + + ) + } + + function Layout({ children }) { + return ( +
    +
    +

    My App

    +
    + {children} +
    +

    My App footer

    +
    +
    + ) + } + ``` + +
    + + + ```tsx title="src/Root.tsx" + import store from './store' + import { Provider } from 'react-redux' + + export default function Root({ children }: { children: React.ReactNode }) { + return ( + + {children} + + ) + } + + function Layout({ children }: { children: React.ReactNode }) { + return ( +
    +
    +

    My App

    +
    + {children} +
    +

    My App footer

    +
    +
    + ) + } + ``` + +
    +
    + +- #### `setupFn: ExtImport` + + + + `setupFn` declares a Typescript function that Wasp executes on the client + before everything else. It is expected to be asynchronous, and + Wasp will await its completion before rendering the page. The function takes no + arguments, and its return value is ignored. + + + + + `setupFn` declares a JavaScript function that Wasp executes on the client + before everything else. It is expected to be asynchronous, and + Wasp will await its completion before rendering the page. The function takes no + arguments, and its return value is ignored. + + + You can use this function to perform any custom setup (e.g., setting up + client-side periodic jobs). + + + + + ```js title="src/myClientSetupCode.js" + export default async function mySetupFunction() { + // Run some code + } + ``` + + + + + ```ts title="src/myClientSetupCode.ts" + export default async function mySetupFunction(): Promise { + // Run some code + } + ``` + + + + +- #### `baseDir: String` + + If you need to serve the client from a subdirectory, you can use the `baseDir` option. + + If you set `baseDir` to `/my-app` for example, that will make Wasp set the `basename` prop of the `Router` to + `/my-app`. It will also set the `base` option of the Vite config to `/my-app`. + + This means that if you serve your app from `https://example.com/my-app`, the router will work correctly, and all the assets will be served from `https://example.com/my-app`. + + diff --git a/web/versioned_docs/version-0.13.0/project/css-frameworks.md b/web/versioned_docs/version-0.13.0/project/css-frameworks.md new file mode 100644 index 0000000000..48c150809d --- /dev/null +++ b/web/versioned_docs/version-0.13.0/project/css-frameworks.md @@ -0,0 +1,110 @@ +--- +title: CSS Frameworks +--- + +import useBaseUrl from '@docusaurus/useBaseUrl'; + +## Tailwind + +To enable support for Tailwind in your project, you need to add two config files — [`tailwind.config.cjs`](https://tailwindcss.com/docs/configuration#configuration-options) and `postcss.config.cjs` — to the root directory. + +With these files present, Wasp installs the necessary dependencies and copies your configuration to the generated project. You can then use [Tailwind CSS directives](https://tailwindcss.com/docs/functions-and-directives#directives) in your CSS and Tailwind classes on your React components. + +```bash title="tree ." +. +├── main.wasp +├── package.json +├── src +│   ├── Main.css +│   ├── MainPage.jsx +│   ├── vite-env.d.ts +│   └── waspLogo.png +├── public +├── tsconfig.json +├── vite.config.ts +# highlight-start +├── postcss.config.cjs +└── tailwind.config.cjs +# highlight-end +``` + +:::tip Tailwind not working? +If you can not use Tailwind after adding the required config files, make sure to restart `wasp start`. This is sometimes needed to ensure that Wasp picks up the changes and enables Tailwind integration. +::: + +### Enabling Tailwind Step-by-Step + +:::caution +Make sure to use the `.cjs` extension for these config files, if you name them with a `.js` extension, Wasp will not detect them. +::: + +1. Add `./tailwind.config.cjs`. + + ```js title="./tailwind.config.cjs" + const { resolveProjectPath } = require('wasp/dev') + + /** @type {import('tailwindcss').Config} */ + module.exports = { + content: [resolveProjectPath('./src/**/*.{js,jsx,ts,tsx}')], + theme: { + extend: {}, + }, + plugins: [], + } + ``` + +2. Add `./postcss.config.cjs`. + + ```js title="./postcss.config.cjs" + module.exports = { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, + } + ``` + +3. Import Tailwind into your CSS file. For example, in a new project you might import Tailwind into `Main.css`. + + ```css title="./src/Main.css" {1-3} + @tailwind base; + @tailwind components; + @tailwind utilities; + + /* ... */ + ``` + +4. Start using Tailwind 🥳 + + ```jsx title="./src/MainPage.jsx" + // ... + +

    + Hello world! +

    + + // ... + ``` + +### Adding Tailwind Plugins + +To add Tailwind plugins, install them as npm development [dependencies](../project/dependencies) and add them to the plugins list in your `tailwind.config.cjs` file: + +```shell +npm install -D @tailwindcss/forms +npm install -D @tailwindcss/typography +``` + +and also + +```js title="./tailwind.config.cjs" {5-6} +/** @type {import('tailwindcss').Config} */ +module.exports = { + // ... + plugins: [ + require('@tailwindcss/forms'), + require('@tailwindcss/typography'), + ], + // ... +} +``` diff --git a/web/versioned_docs/version-0.13.0/project/custom-vite-config.md b/web/versioned_docs/version-0.13.0/project/custom-vite-config.md new file mode 100644 index 0000000000..8b61322ace --- /dev/null +++ b/web/versioned_docs/version-0.13.0/project/custom-vite-config.md @@ -0,0 +1,122 @@ +--- +title: Custom Vite Config +--- + +import { ShowForTs, ShowForJs } from '@site/src/components/TsJsHelpers' + +Wasp uses [Vite](https://vitejs.dev/) to serve the client during development and bundling it for production. If you want to customize the Vite config, you can do that by editing the `vite.config.{js,ts}` file in your project root directory. + +Wasp will use your config and **merge** it with the default Wasp's Vite config. + +Vite config customization can be useful for things like: + +- Adding custom Vite plugins. +- Customising the dev server. +- Customising the build process. + +Be careful with making changes to the Vite config, as it can break the Wasp's client build process. Check out the default Vite config [here](https://github.com/wasp-lang/wasp/blob/release/waspc/data/Generator/templates/react-app/vite.config.ts) to see what you can change. + +## Examples + +Below are some examples of how you can customize the Vite config. + +### Changing the Dev Server Behaviour + +If you want to stop Vite from opening the browser automatically when you run `wasp start`, you can do that by customizing the `open` option. + + + + +```js title="vite.config.js" +export default { + server: { + open: false, + }, +} +``` + + + + +```ts title="vite.config.ts" +import { defineConfig } from 'vite' + +export default defineConfig({ + server: { + open: false, + }, +}) +``` + + + + +### Custom Dev Server Port + +You have access to all of the [Vite dev server options](https://vitejs.dev/config/server-options.html) in your custom Vite config. You can change the dev server port by setting the `port` option. + + + + +```js title="vite.config.js" +export default { + server: { + port: 4000, + }, +} +``` + +```env title=".env.server" +WASP_WEB_CLIENT_URL=http://localhost:4000 +``` + + + + +```ts title="vite.config.ts" +import { defineConfig } from 'vite' + +export default defineConfig({ + server: { + port: 4000, + }, +}) +``` + +```env title=".env.server" +WASP_WEB_CLIENT_URL=http://localhost:4000 +``` + + + + +:::warning Changing the dev server port +⚠️ Be careful when changing the dev server port, you'll need to update the `WASP_WEB_CLIENT_URL` env var in your `.env.server` file. +::: + +### Customising the Base Path + +If you, for example, want to serve the client from a different path than `/`, you can do that by customizing the `base` option. + + + + +```js title="vite.config.js" +export default { + base: '/my-app/', +} +``` + + + + +```ts title="vite.config.ts" +import { defineConfig } from 'vite' + +export default defineConfig({ + base: '/my-app/', +}) +``` + + + diff --git a/web/versioned_docs/version-0.13.0/project/customizing-app.md b/web/versioned_docs/version-0.13.0/project/customizing-app.md new file mode 100644 index 0000000000..1d569a4329 --- /dev/null +++ b/web/versioned_docs/version-0.13.0/project/customizing-app.md @@ -0,0 +1,133 @@ +--- +title: Customizing the App +--- + +import { Required } from '@site/src/components/Tag'; + +Each Wasp project can have only one `app` type declaration. It is used to configure your app and its components. + +```wasp +app todoApp { + wasp: { + version: "^0.13.0" + }, + title: "ToDo App", + head: [ + "" + ] +} +``` + +We'll go through some common customizations you might want to do to your app. For more details on each of the fields, check out the [API Reference](#api-reference). + +### Changing the App Title + +You may want to change the title of your app, which appears in the browser tab, next to the favicon. You can change it by changing the `title` field of your `app` declaration: + +```wasp +app myApp { + wasp: { + version: "^0.13.0" + }, + title: "BookFace" +} +``` + +### Adding Additional Lines to the Head + +If you are looking to add additional style sheets or scripts to your app, you can do so by adding them to the `head` field of your `app` declaration. + +An example of adding extra style sheets and scripts: + +```wasp +app myApp { + wasp: { + version: "^0.13.0" + }, + title: "My App", + head: [ // optional + "", + "", + "" + ] +} +``` + +## API Reference + +```wasp +app todoApp { + wasp: { + version: "^0.13.0" + }, + title: "ToDo App", + head: [ + "" + ], + auth: { + // ... + }, + client: { + // ... + }, + server: { + // ... + }, + db: { + // ... + }, + emailSender: { + // ... + }, + webSocket: { + // ... + } +} +``` + +The `app` declaration has the following fields: + +- `wasp: dict` + Wasp compiler configuration. It is a dictionary with a single field: + + - `version: string` + + The version specifies which versions of Wasp are compatible with the app. It should contain a valid [SemVer range](https://github.com/npm/node-semver#ranges) + + :::info + For now, the version field only supports caret ranges (i.e., `^x.y.z`). Support for the full specification will come in a future version of Wasp + ::: + +- `title: string` + + Title of your app. It will appear in the browser tab, next to the favicon. + +- `head: [string]` + + List of additional lines (e.g. `` or `