@wasp.sh/wasp-cli-darwin-arm64-unknown 0.20.2 → 0.21.0-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/data/Cli/starters/basic/README.md +1 -1
- package/data/Cli/starters/basic/package.json +10 -7
- package/data/Cli/starters/basic/src/App.css +30 -12
- package/data/Cli/starters/basic/src/App.tsx +1 -1
- package/data/Cli/starters/basic/src/auth/AuthLayout.tsx +3 -1
- package/data/Cli/starters/basic/src/auth/email/EmailVerificationPage.tsx +2 -2
- package/data/Cli/starters/basic/src/auth/email/LoginPage.tsx +3 -3
- package/data/Cli/starters/basic/src/auth/email/PasswordResetPage.tsx +2 -2
- package/data/Cli/starters/basic/src/auth/email/SignupPage.tsx +2 -2
- package/data/Cli/starters/basic/src/shared/components/Button.tsx +3 -2
- package/data/Cli/starters/basic/src/shared/components/Dialog.tsx +23 -41
- package/data/Cli/starters/basic/src/shared/components/Header.tsx +2 -2
- package/data/Cli/starters/basic/src/shared/components/Input.tsx +25 -28
- package/data/Cli/starters/basic/src/tags/components/ColorRadioButton.tsx +8 -9
- package/data/Cli/starters/basic/src/tags/components/CreateTagDialog.tsx +29 -29
- package/data/Cli/starters/basic/src/tags/components/CreateTagForm.tsx +6 -8
- package/data/Cli/starters/basic/src/tasks/components/CreateTaskForm.tsx +2 -2
- package/data/Cli/starters/basic/src/tasks/components/TaskListItem.tsx +3 -2
- package/data/Cli/starters/basic/vite.config.ts +3 -0
- package/data/Cli/starters/minimal/package.json +2 -3
- package/data/Cli/starters/minimal/vite.config.ts +2 -0
- package/data/Cli/starters/skeleton/src/vite-env.d.ts +2 -6
- package/data/Generator/libs/auth/wasp.sh-lib-auth-0.21.0.tgz +0 -0
- package/data/Generator/templates/Dockerfile +13 -12
- package/data/Generator/templates/sdk/wasp/auth/forms/Auth.tsx +2 -11
- package/data/Generator/templates/sdk/wasp/auth/forms/internal/common/LoginSignupForm.tsx +10 -4
- package/data/Generator/templates/sdk/wasp/auth/forms/internal/email/ForgotPasswordForm.tsx +4 -3
- package/data/Generator/templates/sdk/wasp/auth/forms/internal/email/ResetPasswordForm.tsx +4 -4
- package/data/Generator/templates/sdk/wasp/auth/forms/internal/email/VerifyEmailForm.tsx +3 -4
- package/data/Generator/templates/sdk/wasp/auth/forms/internal/social/SocialIcons.tsx +11 -0
- package/data/Generator/templates/sdk/wasp/auth/forms/types.ts +0 -6
- package/data/Generator/templates/sdk/wasp/auth/jwt.ts +9 -16
- package/data/Generator/templates/sdk/wasp/auth/password.ts +1 -36
- package/data/Generator/templates/sdk/wasp/auth/utils.ts +2 -0
- package/data/Generator/templates/{react-app/src → sdk/wasp/client/app}/components/DefaultRootErrorBoundary.tsx +1 -1
- package/data/Generator/templates/sdk/wasp/client/app/components/WaspApp.tsx +45 -0
- package/data/Generator/templates/sdk/wasp/client/app/index.tsx +26 -0
- package/data/Generator/templates/{react-app/src/auth → sdk/wasp/client/app}/pages/OAuthCallback.tsx +9 -8
- package/data/Generator/templates/{react-app/src/auth → sdk/wasp/client/app}/pages/createAuthRequiredPage.jsx +7 -9
- package/data/Generator/templates/sdk/wasp/client/app/router/router.tsx +47 -0
- package/data/Generator/templates/sdk/wasp/client/auth/index.ts +3 -0
- package/data/Generator/templates/sdk/wasp/client/auth/microsoft.ts +2 -0
- package/data/Generator/templates/sdk/wasp/client/auth/ui.ts +3 -0
- package/data/Generator/templates/sdk/wasp/client/router/Link.tsx +2 -2
- package/data/Generator/templates/sdk/wasp/client/test/vitest/helpers.tsx +10 -12
- package/data/Generator/templates/sdk/wasp/client/vite/index.ts +1 -0
- package/data/Generator/templates/sdk/wasp/client/vite/plugins/detectServerImports.ts +50 -0
- package/data/Generator/templates/sdk/wasp/client/vite/plugins/envFile.ts +112 -0
- package/data/Generator/templates/sdk/wasp/client/vite/plugins/html/build.ts +38 -0
- package/data/Generator/templates/sdk/wasp/client/vite/plugins/html/dev.ts +35 -0
- package/data/Generator/templates/sdk/wasp/client/vite/plugins/typescriptCheck.ts +32 -0
- package/data/Generator/templates/{react-app/vite → sdk/wasp/client/vite/plugins}/validateEnv.ts +17 -7
- package/data/Generator/templates/sdk/wasp/client/vite/plugins/virtualModules.ts +29 -0
- package/data/Generator/templates/sdk/wasp/client/vite/plugins/wasp.ts +36 -0
- package/data/Generator/templates/sdk/wasp/client/vite/plugins/waspConfig.ts +56 -0
- package/data/Generator/templates/{react-app → sdk/wasp/client/vite/virtual-files/files}/index.html +1 -2
- package/data/Generator/templates/sdk/wasp/client/vite/virtual-files/files/index.tsx +34 -0
- package/data/Generator/templates/sdk/wasp/client/vite/virtual-files/files/routes.tsx +17 -0
- package/data/Generator/templates/sdk/wasp/client/vite/virtual-files/index.ts +20 -0
- package/data/Generator/templates/sdk/wasp/client/vite/virtual-files/resolver.ts +28 -0
- package/data/Generator/templates/sdk/wasp/package.json +6 -4
- package/data/Generator/templates/sdk/wasp/scripts/copy-assets.js +67 -7
- package/data/Generator/templates/sdk/wasp/server/auth/hooks.ts +3 -0
- package/data/Generator/templates/sdk/wasp/server/auth/oauth/index.ts +4 -0
- package/data/Generator/templates/sdk/wasp/server/auth/oauth/providers/microsoft.ts +23 -0
- package/data/Generator/templates/sdk/wasp/server/auth/user.ts +6 -0
- package/data/Generator/templates/sdk/wasp/server/env.ts +11 -0
- package/data/Generator/templates/sdk/wasp/tsconfig.json +5 -1
- package/data/Generator/templates/server/src/auth/providers/config/microsoft.ts +65 -0
- package/data/Generator/templates/server/src/auth/providers/oauth/cookies.ts +1 -1
- package/data/packages/deploy/dist/common/clientApp.js +4 -11
- package/data/packages/deploy/dist/common/terminal.js +7 -0
- package/data/packages/deploy/dist/common/waspProject.js +11 -7
- package/data/packages/deploy/dist/providers/fly/CommonOps.js +3 -3
- package/data/packages/deploy/dist/providers/fly/commands/cmd/cmd.js +1 -1
- package/data/packages/deploy/dist/providers/fly/commands/deploy/deploy.js +6 -5
- package/data/packages/deploy/dist/providers/fly/commands/setup/setup.js +3 -3
- package/data/packages/deploy/dist/providers/fly/index.js +5 -0
- package/data/packages/deploy/dist/providers/railway/commands/deploy/client.js +2 -1
- package/data/packages/deploy/dist/providers/railway/commands/setup/setup.js +21 -10
- package/data/packages/deploy/dist/providers/railway/index.js +5 -0
- package/data/packages/deploy/dist/providers/railway/jsonOutputSchemas.js +9 -3
- package/data/packages/deploy/dist/providers/railway/railwayService/url.js +8 -1
- package/data/packages/studio/dist/public/assets/Flow-_d98T2dd.js +26 -0
- package/data/packages/studio/dist/public/assets/index-B6X8EdJH.js +21 -0
- package/data/packages/studio/dist/public/assets/index-CXlD_bzV.js +1 -0
- package/data/packages/studio/dist/public/assets/index-IWX3d-Jz.css +1 -0
- package/data/packages/studio/dist/public/index.html +2 -3
- package/package.json +1 -1
- package/wasp-bin +0 -0
- package/data/Cli/starters/basic/postcss.config.js +0 -6
- package/data/Cli/starters/basic/src/shared/components/Portal.tsx +0 -26
- package/data/Cli/starters/basic/tailwind.config.js +0 -30
- package/data/Generator/templates/react-app/README.md +0 -21
- package/data/Generator/templates/react-app/gitignore +0 -23
- package/data/Generator/templates/react-app/netlify.toml +0 -8
- package/data/Generator/templates/react-app/npmrc +0 -1
- package/data/Generator/templates/react-app/package.json +0 -31
- package/data/Generator/templates/react-app/public/manifest.json +0 -15
- package/data/Generator/templates/react-app/src/index.tsx +0 -47
- package/data/Generator/templates/react-app/src/logo.png +0 -0
- package/data/Generator/templates/react-app/src/router.tsx +0 -59
- package/data/Generator/templates/react-app/src/utils.js +0 -3
- package/data/Generator/templates/react-app/src/vite-env.d.ts +0 -1
- package/data/Generator/templates/react-app/tsconfig.app.json +0 -28
- package/data/Generator/templates/react-app/tsconfig.json +0 -11
- package/data/Generator/templates/react-app/tsconfig.vite.json +0 -16
- package/data/Generator/templates/react-app/vite/detectServerImports.ts +0 -53
- package/data/Generator/templates/react-app/vite.config.ts +0 -74
- package/data/Generator/templates/sdk/wasp/dev/index.ts +0 -19
- package/data/packages/studio/dist/public/assets/Flow-b5112d3d.js +0 -26
- package/data/packages/studio/dist/public/assets/index-17ce6ed4.css +0 -1
- package/data/packages/studio/dist/public/assets/index-62a9d21a.js +0 -120
- /package/data/Generator/templates/{react-app/src → sdk/wasp/client/app}/components/FullPageWrapper.tsx +0 -0
- /package/data/Generator/templates/{react-app/src → sdk/wasp/client/app}/components/Loader.module.css +0 -0
- /package/data/Generator/templates/{react-app/src → sdk/wasp/client/app}/components/Loader.tsx +0 -0
- /package/data/Generator/templates/{react-app/src → sdk/wasp/client/app}/components/Message.tsx +0 -0
- /package/data/Generator/templates/{react-app/src/test/vitest → sdk/wasp/client/test}/setup.ts +0 -0
|
@@ -29,27 +29,28 @@ FROM base AS server-builder
|
|
|
29
29
|
# `python3` fixes the issue.
|
|
30
30
|
RUN apk add --no-cache python3 build-base libtool autoconf automake
|
|
31
31
|
WORKDIR /app
|
|
32
|
-
# Since the framwork code in /.wasp/
|
|
32
|
+
# Since the framwork code in /.wasp/out/server imports the user code in /src
|
|
33
33
|
# using relative imports, we must mirror the same directory structure in the
|
|
34
34
|
# Docker image.
|
|
35
35
|
COPY src ./src
|
|
36
36
|
COPY package.json .
|
|
37
37
|
COPY package-lock.json .
|
|
38
38
|
COPY tsconfig*.json .
|
|
39
|
-
COPY server .wasp/
|
|
39
|
+
COPY server .wasp/out/server
|
|
40
40
|
COPY sdk .wasp/out/sdk
|
|
41
|
+
COPY libs .wasp/out/libs
|
|
41
42
|
# Install npm packages, resulting in node_modules/.
|
|
42
|
-
RUN npm install && cd .wasp/
|
|
43
|
+
RUN npm install && cd .wasp/out/server && npm install
|
|
43
44
|
{=# usingPrisma =}
|
|
44
|
-
COPY db/schema.prisma .wasp/
|
|
45
|
-
RUN cd .wasp/
|
|
45
|
+
COPY db/schema.prisma .wasp/out/db/
|
|
46
|
+
RUN cd .wasp/out/server && npx prisma generate --schema='{= dbSchemaFileFromServerDir =}'
|
|
46
47
|
{=/ usingPrisma =}
|
|
47
48
|
# Building the server should come after Prisma generation.
|
|
48
|
-
RUN cd .wasp/
|
|
49
|
+
RUN cd .wasp/out/server && npm run bundle
|
|
49
50
|
|
|
50
51
|
# Depending on `npm`'s dependency resolution, this folder may or may not exist.
|
|
51
52
|
# We ensure they are created so that the COPY instruction later does not fail.
|
|
52
|
-
RUN mkdir -p ./.wasp/
|
|
53
|
+
RUN mkdir -p ./.wasp/out/server/node_modules
|
|
53
54
|
|
|
54
55
|
|
|
55
56
|
# TODO: Use pm2?
|
|
@@ -65,12 +66,12 @@ COPY --from=server-builder /app/node_modules ./node_modules
|
|
|
65
66
|
# Copying 'server/node_modules' because we require dotenv package to
|
|
66
67
|
# load environment variables
|
|
67
68
|
# TODO: replace dotenv with native Node.js environment variable loading
|
|
68
|
-
COPY --from=server-builder /app/.wasp/
|
|
69
|
-
COPY --from=server-builder /app/.wasp/
|
|
70
|
-
COPY --from=server-builder /app/.wasp/
|
|
71
|
-
COPY db/ .wasp/
|
|
69
|
+
COPY --from=server-builder /app/.wasp/out/server/node_modules .wasp/out/server/node_modules
|
|
70
|
+
COPY --from=server-builder /app/.wasp/out/server/bundle .wasp/out/server/bundle
|
|
71
|
+
COPY --from=server-builder /app/.wasp/out/server/package*.json .wasp/out/server/
|
|
72
|
+
COPY db/ .wasp/out/db/
|
|
72
73
|
EXPOSE ${PORT}
|
|
73
|
-
WORKDIR /app/.wasp/
|
|
74
|
+
WORKDIR /app/.wasp/out/server
|
|
74
75
|
ENTRYPOINT ["npm", "run", "start-production"]
|
|
75
76
|
|
|
76
77
|
|
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
{{={= =}=}}
|
|
2
|
-
import { useState,
|
|
2
|
+
import { useState, useMemo } from 'react'
|
|
3
|
+
import { AuthContext, type ErrorMessage } from '@wasp.sh/lib-auth/browser'
|
|
3
4
|
import styles from './Auth.module.css'
|
|
4
5
|
import './internal/auth-styles.css'
|
|
5
6
|
import { tokenObjToCSSVars } from "./internal/util"
|
|
6
|
-
import { CSSProperties } from "react"
|
|
7
7
|
|
|
8
8
|
import {
|
|
9
9
|
type State,
|
|
10
10
|
type CustomizationOptions,
|
|
11
|
-
type ErrorMessage,
|
|
12
11
|
type AdditionalSignupFields,
|
|
13
12
|
} from './types'
|
|
14
13
|
import { LoginSignupForm } from './internal/common/LoginSignupForm'
|
|
@@ -24,14 +23,6 @@ const logoStyle = {
|
|
|
24
23
|
}
|
|
25
24
|
|
|
26
25
|
|
|
27
|
-
// PRIVATE API
|
|
28
|
-
export const AuthContext = createContext({
|
|
29
|
-
isLoading: false,
|
|
30
|
-
setIsLoading: (isLoading: boolean) => {},
|
|
31
|
-
setErrorMessage: (errorMessage: ErrorMessage | null) => {},
|
|
32
|
-
setSuccessMessage: (successMessage: string | null) => {},
|
|
33
|
-
})
|
|
34
|
-
|
|
35
26
|
function Auth ({ state, appearance, logo, socialLayout = 'horizontal', additionalSignupFields }: {
|
|
36
27
|
state: State;
|
|
37
28
|
} & CustomizationOptions & {
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
{{={= =}=}}
|
|
2
|
-
import { useContext } from 'react'
|
|
3
2
|
import { useForm, UseFormReturn } from 'react-hook-form'
|
|
4
3
|
import styles from './LoginSignupForm.module.css'
|
|
5
4
|
import '../auth-styles.css'
|
|
6
5
|
import { config } from 'wasp/client'
|
|
7
6
|
import { clsx } from '../util'
|
|
8
7
|
|
|
9
|
-
import {
|
|
8
|
+
import { useAuthContext } from '@wasp.sh/lib-auth/browser'
|
|
10
9
|
import {
|
|
11
10
|
Form,
|
|
12
11
|
FormInput,
|
|
@@ -27,7 +26,7 @@ import * as SocialIcons from '../social/SocialIcons'
|
|
|
27
26
|
import { SocialButton } from '../social/SocialButton'
|
|
28
27
|
{=/ isSocialAuthEnabled =}
|
|
29
28
|
{=# isAnyPasswordBasedAuthEnabled =}
|
|
30
|
-
import { useNavigate } from 'react-router
|
|
29
|
+
import { useNavigate } from 'react-router'
|
|
31
30
|
{=/ isAnyPasswordBasedAuthEnabled =}
|
|
32
31
|
{=# enabledProviders.isUsernameAndPasswordAuthEnabled =}
|
|
33
32
|
import { useUsernameAndPassword } from '../usernameAndPassword/useUsernameAndPassword'
|
|
@@ -55,6 +54,9 @@ const keycloakSignInUrl = `${config.apiUrl}{= keycloakSignInPath =}`
|
|
|
55
54
|
{=# enabledProviders.isGitHubAuthEnabled =}
|
|
56
55
|
const gitHubSignInUrl = `${config.apiUrl}{= gitHubSignInPath =}`
|
|
57
56
|
{=/ enabledProviders.isGitHubAuthEnabled =}
|
|
57
|
+
{=# enabledProviders.isMicrosoftAuthEnabled =}
|
|
58
|
+
const microsoftSignInUrl = `${config.apiUrl}{= microsoftSignInPath =}`
|
|
59
|
+
{=/ enabledProviders.isMicrosoftAuthEnabled =}
|
|
58
60
|
|
|
59
61
|
{=!
|
|
60
62
|
// Since we allow users to add additional fields to the signup form, we don't
|
|
@@ -81,7 +83,7 @@ export const LoginSignupForm = ({
|
|
|
81
83
|
setErrorMessage,
|
|
82
84
|
setSuccessMessage,
|
|
83
85
|
setIsLoading,
|
|
84
|
-
} =
|
|
86
|
+
} = useAuthContext();
|
|
85
87
|
const isLogin = state === 'login'
|
|
86
88
|
const cta = isLogin ? 'Log in' : 'Sign up';
|
|
87
89
|
{=# isAnyPasswordBasedAuthEnabled =}
|
|
@@ -151,6 +153,10 @@ export const LoginSignupForm = ({
|
|
|
151
153
|
{=# enabledProviders.isGitHubAuthEnabled =}
|
|
152
154
|
<SocialButton href={gitHubSignInUrl}><SocialIcons.GitHub/></SocialButton>
|
|
153
155
|
{=/ enabledProviders.isGitHubAuthEnabled =}
|
|
156
|
+
|
|
157
|
+
{=# enabledProviders.isMicrosoftAuthEnabled =}
|
|
158
|
+
<SocialButton href={microsoftSignInUrl}><SocialIcons.Microsoft/></SocialButton>
|
|
159
|
+
{=/ enabledProviders.isMicrosoftAuthEnabled =}
|
|
154
160
|
</div>
|
|
155
161
|
</div>
|
|
156
162
|
{=/ isSocialAuthEnabled =}
|
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
import { useContext } from 'react'
|
|
2
1
|
import { useForm } from 'react-hook-form'
|
|
2
|
+
import { useAuthContext } from '@wasp.sh/lib-auth/browser'
|
|
3
|
+
|
|
3
4
|
import { requestPasswordReset } from '../../../email/actions/passwordReset.js'
|
|
4
5
|
import { Form, FormItemGroup, FormLabel, FormInput, SubmitButton, FormError } from '../Form'
|
|
5
|
-
|
|
6
|
+
|
|
6
7
|
|
|
7
8
|
// PRIVATE API
|
|
8
9
|
export const ForgotPasswordForm = () => {
|
|
9
10
|
const { register, handleSubmit, reset, formState: { errors } } = useForm<{ email: string }>()
|
|
10
|
-
const { isLoading, setErrorMessage, setSuccessMessage, setIsLoading } =
|
|
11
|
+
const { isLoading, setErrorMessage, setSuccessMessage, setIsLoading } = useAuthContext()
|
|
11
12
|
|
|
12
13
|
const onSubmit = async (data) => {
|
|
13
14
|
setIsLoading(true)
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import { useContext } from 'react'
|
|
2
1
|
import { useForm } from 'react-hook-form'
|
|
2
|
+
import { useLocation } from 'react-router'
|
|
3
|
+
import { useAuthContext } from '@wasp.sh/lib-auth/browser'
|
|
4
|
+
|
|
3
5
|
import { resetPassword } from '../../../email/actions/passwordReset.js'
|
|
4
|
-
import { useLocation } from 'react-router-dom'
|
|
5
6
|
import { Form, FormItemGroup, FormLabel, FormInput, SubmitButton, FormError } from '../Form'
|
|
6
|
-
import { AuthContext } from '../../Auth'
|
|
7
7
|
|
|
8
8
|
// PRIVATE API
|
|
9
9
|
export const ResetPasswordForm = () => {
|
|
10
10
|
const { register, handleSubmit, reset, formState: { errors } } = useForm<{ password: string; passwordConfirmation: string }>()
|
|
11
|
-
const { isLoading, setErrorMessage, setSuccessMessage, setIsLoading } =
|
|
11
|
+
const { isLoading, setErrorMessage, setSuccessMessage, setIsLoading } = useAuthContext()
|
|
12
12
|
const location = useLocation()
|
|
13
13
|
const token = new URLSearchParams(location.search).get('token')
|
|
14
14
|
const onSubmit = async (data) => {
|
|
@@ -1,13 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { useLocation } from 'react-router'
|
|
2
|
+
import { useAuthContext } from '@wasp.sh/lib-auth/browser'
|
|
3
3
|
import { verifyEmail } from '../../../email/actions/verifyEmail.js'
|
|
4
4
|
import { Message } from '../Message'
|
|
5
|
-
import { AuthContext } from '../../Auth'
|
|
6
5
|
import { useEffectOnce } from '../../../../client/hooks.js'
|
|
7
6
|
|
|
8
7
|
// PRIVATE API
|
|
9
8
|
export const VerifyEmailForm = () => {
|
|
10
|
-
const { isLoading, setErrorMessage, setSuccessMessage, setIsLoading } =
|
|
9
|
+
const { isLoading, setErrorMessage, setSuccessMessage, setIsLoading } = useAuthContext()
|
|
11
10
|
const location = useLocation()
|
|
12
11
|
const token = new URLSearchParams(location.search).get('token')
|
|
13
12
|
|
|
@@ -72,3 +72,14 @@ export const Slack = () => (
|
|
|
72
72
|
<path d="M13 10C13 11.1046 13.8954 12 15 12C16.1046 12 17 11.1046 17 10V5C17 3.89543 16.1046 3 15 3C13.8954 3 13 3.89543 13 5V10ZM5 8C3.89543 8 3 8.89543 3 10C3 11.1046 3.89543 12 5 12H10C11.1046 12 12 11.1046 12 10C12 8.89543 11.1046 8 10 8H5ZM15 13C13.8954 13 13 13.8954 13 15C13 16.1046 13.8954 17 15 17H20C21.1046 17 22 16.1046 22 15C22 13.8954 21.1046 13 20 13H15ZM10 22C8.89543 22 8 21.1046 8 20L8 15C8 13.8954 8.89543 13 10 13C11.1046 13 12 13.8954 12 15V20C12 21.1046 11.1046 22 10 22ZM8 5C8 3.89543 8.89543 3 10 3C11.1046 3 12 3.89543 12 5V7H10C8.89543 7 8 6.10457 8 5ZM3 15C3 16.1046 3.89543 17 5 17C6.10457 17 7 16.1046 7 15V13H5C3.89543 13 3 13.8954 3 15ZM17 20C17 21.1046 16.1046 22 15 22C13.8954 22 13 21.1046 13 20V18H15C16.1046 18 17 18.8954 17 20ZM22 10C22 8.89543 21.1046 8 20 8C18.8954 8 18 8.89543 18 10V12H20C21.1046 12 22 11.1046 22 10Z" />
|
|
73
73
|
</svg>
|
|
74
74
|
)
|
|
75
|
+
|
|
76
|
+
export const Microsoft = () => (
|
|
77
|
+
<svg
|
|
78
|
+
className={styles.icon}
|
|
79
|
+
aria-hidden="true"
|
|
80
|
+
fill="currentColor"
|
|
81
|
+
viewBox="0 0 24 24"
|
|
82
|
+
>
|
|
83
|
+
<path d="M2 3h9v9H2zm9 19H2v-9h9zM21 3v9h-9V3zm0 19h-9v-9h9z" />
|
|
84
|
+
</svg>
|
|
85
|
+
)
|
|
@@ -1,22 +1,15 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { config } from 'wasp/server'
|
|
1
|
+
import { createJWTHelpers } from "@wasp.sh/lib-auth/node";
|
|
3
2
|
|
|
4
|
-
|
|
5
|
-
const JWT_ALGORITHM = 'HS256'
|
|
3
|
+
import { config } from "wasp/server";
|
|
6
4
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
data: Parameters<typeof jwt.createJWT>[2],
|
|
10
|
-
options: Parameters<typeof jwt.createJWT>[3],
|
|
11
|
-
): Promise<string> {
|
|
12
|
-
return jwt.createJWT(JWT_ALGORITHM, JWT_SECRET, data, options)
|
|
13
|
-
}
|
|
5
|
+
const JWT_SECRET = new TextEncoder().encode(config.auth.jwtSecret);
|
|
6
|
+
const JWT_ALGORITHM = "HS256";
|
|
14
7
|
|
|
15
8
|
// PRIVATE API
|
|
16
|
-
export
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
9
|
+
export const { createJWT, validateJWT } = createJWTHelpers(
|
|
10
|
+
JWT_SECRET,
|
|
11
|
+
JWT_ALGORITHM,
|
|
12
|
+
);
|
|
20
13
|
|
|
21
14
|
// PRIVATE API
|
|
22
|
-
export { TimeSpan } from
|
|
15
|
+
export { TimeSpan } from "@wasp.sh/lib-auth/node";
|
|
@@ -1,36 +1 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
// The options are the same as the ones used in the oslo/password library
|
|
4
|
-
const hashingOptions: Options = {
|
|
5
|
-
memoryCost: 19456,
|
|
6
|
-
timeCost: 2,
|
|
7
|
-
outputLen: 32,
|
|
8
|
-
parallelism: 1,
|
|
9
|
-
version: Version.V0x13,
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
// PRIVATE API
|
|
13
|
-
export async function hashPassword(password: string): Promise<string> {
|
|
14
|
-
return hash(normalizePassword(password), hashingOptions);
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
// PRIVATE API
|
|
18
|
-
export async function verifyPassword(
|
|
19
|
-
hashedPassword: string,
|
|
20
|
-
password: string
|
|
21
|
-
): Promise<void> {
|
|
22
|
-
const validPassword = await verify(
|
|
23
|
-
hashedPassword,
|
|
24
|
-
normalizePassword(password),
|
|
25
|
-
hashingOptions
|
|
26
|
-
);
|
|
27
|
-
if (!validPassword) {
|
|
28
|
-
throw new Error("Invalid password");
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
// We are normalising the password to ensure that the password is always hashed in the same way
|
|
33
|
-
// We have the same normalising process as oslo/password did in the past
|
|
34
|
-
function normalizePassword(password: string): string {
|
|
35
|
-
return password.normalize("NFKC");
|
|
36
|
-
}
|
|
1
|
+
export { hashPassword, verifyPassword } from "@wasp.sh/lib-auth/node";
|
|
@@ -45,6 +45,7 @@ export type PossibleProviderData = {
|
|
|
45
45
|
google: OAuthProviderData;
|
|
46
46
|
keycloak: OAuthProviderData;
|
|
47
47
|
github: OAuthProviderData;
|
|
48
|
+
microsoft: OAuthProviderData;
|
|
48
49
|
}
|
|
49
50
|
|
|
50
51
|
// PUBLIC API
|
|
@@ -97,6 +98,7 @@ export function normalizeProviderUserId(providerName: ProviderName, providerUser
|
|
|
97
98
|
case 'discord':
|
|
98
99
|
case 'keycloak':
|
|
99
100
|
case 'slack':
|
|
101
|
+
case 'microsoft':
|
|
100
102
|
return providerUserId;
|
|
101
103
|
/*
|
|
102
104
|
Why the default case?
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{{={= =}=}}
|
|
2
|
+
import * as React from 'react'
|
|
3
|
+
import { QueryClientProvider } from '@tanstack/react-query'
|
|
4
|
+
|
|
5
|
+
import { getRouter } from '../router/router'
|
|
6
|
+
import { queryClientInitialized } from '../../operations/index'
|
|
7
|
+
|
|
8
|
+
{=# areWebSocketsUsed =}
|
|
9
|
+
import { WebSocketProvider } from '../../webSocket/WebSocketProvider'
|
|
10
|
+
{=/ areWebSocketsUsed =}
|
|
11
|
+
|
|
12
|
+
export type WaspAppProps = {
|
|
13
|
+
rootElement?: React.ReactNode;
|
|
14
|
+
routesMapping: Record<string, React.ComponentType>;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function WaspApp({ rootElement, routesMapping }: Required<WaspAppProps>) {
|
|
18
|
+
const [queryClient, setQueryClient] = React.useState<any>(null)
|
|
19
|
+
|
|
20
|
+
React.useEffect(() => {
|
|
21
|
+
queryClientInitialized.then(setQueryClient)
|
|
22
|
+
}, [])
|
|
23
|
+
|
|
24
|
+
if (!queryClient) {
|
|
25
|
+
return null
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const router = getRouter({
|
|
29
|
+
rootElement,
|
|
30
|
+
routesMapping,
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
return (
|
|
34
|
+
<QueryClientProvider client={queryClient}>
|
|
35
|
+
{=# areWebSocketsUsed =}
|
|
36
|
+
<WebSocketProvider>
|
|
37
|
+
{router}
|
|
38
|
+
</WebSocketProvider>
|
|
39
|
+
{=/ areWebSocketsUsed =}
|
|
40
|
+
{=^ areWebSocketsUsed =}
|
|
41
|
+
{router}
|
|
42
|
+
{=/ areWebSocketsUsed =}
|
|
43
|
+
</QueryClientProvider>
|
|
44
|
+
)
|
|
45
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{{={= =}=}}
|
|
2
|
+
import { Outlet } from 'react-router'
|
|
3
|
+
import { initializeQueryClient } from '../operations'
|
|
4
|
+
import { WaspApp, type WaspAppProps } from './components/WaspApp'
|
|
5
|
+
|
|
6
|
+
const DefaultRootComponent = () => <Outlet />
|
|
7
|
+
|
|
8
|
+
let isAppInitialized = false
|
|
9
|
+
|
|
10
|
+
// PRIVATE API (web-app)
|
|
11
|
+
export function getWaspApp({
|
|
12
|
+
rootElement = <DefaultRootComponent />,
|
|
13
|
+
routesMapping,
|
|
14
|
+
}: WaspAppProps): React.ReactNode {
|
|
15
|
+
if (!isAppInitialized) {
|
|
16
|
+
initializeQueryClient()
|
|
17
|
+
isAppInitialized = true
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return <WaspApp rootElement={rootElement} routesMapping={routesMapping} />
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
{=# isAuthEnabled =}
|
|
24
|
+
// PRIVATE API (web-app)
|
|
25
|
+
export { createAuthRequiredPage } from './pages/createAuthRequiredPage'
|
|
26
|
+
{=/ isAuthEnabled =}
|
package/data/Generator/templates/{react-app/src/auth → sdk/wasp/client/app}/pages/OAuthCallback.tsx
RENAMED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{{={= =}=}}
|
|
2
2
|
import { useState } from "react";
|
|
3
3
|
import { type AxiosResponse } from "axios";
|
|
4
|
-
import { Navigate, useLocation } from 'react-router
|
|
5
|
-
import { useAuth } from
|
|
6
|
-
import { api } from
|
|
7
|
-
import { initSession } from
|
|
8
|
-
import { useEffectOnce } from
|
|
9
|
-
import { MessageLoading, MessageError } from "
|
|
10
|
-
import { FullPageWrapper } from "
|
|
4
|
+
import { Navigate, useLocation } from 'react-router'
|
|
5
|
+
import { useAuth } from "../../auth";
|
|
6
|
+
import { api } from "../../../api";
|
|
7
|
+
import { initSession } from "../../../auth/helpers/user";
|
|
8
|
+
import { useEffectOnce } from "../../hooks";
|
|
9
|
+
import { MessageLoading, MessageError } from "../components/Message";
|
|
10
|
+
import { FullPageWrapper } from "../components/FullPageWrapper";
|
|
11
11
|
|
|
12
12
|
const oAuthCallbackWrapperClassName = "wasp-oauth-callback-wrapper";
|
|
13
13
|
|
|
@@ -89,5 +89,6 @@ async function exchangeOAuthCodeForToken(data: {
|
|
|
89
89
|
function isResponseWithSessionId(
|
|
90
90
|
response: AxiosResponse<unknown>
|
|
91
91
|
): response is AxiosResponse<{ sessionId: string }> {
|
|
92
|
-
|
|
92
|
+
const data = response.data as any;
|
|
93
|
+
return !!data && typeof data.sessionId === 'string'
|
|
93
94
|
}
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
{{={= =}=}}
|
|
2
|
-
import React from 'react'
|
|
2
|
+
import * as React from 'react'
|
|
3
3
|
|
|
4
|
-
import { Navigate } from 'react-router
|
|
5
|
-
import { useAuth } from '
|
|
4
|
+
import { Navigate } from 'react-router'
|
|
5
|
+
import { useAuth } from '../../auth'
|
|
6
6
|
|
|
7
|
-
import { Loader } from '
|
|
8
|
-
import { MessageError } from '
|
|
9
|
-
import { FullPageWrapper } from '
|
|
7
|
+
import { Loader } from '../components/Loader'
|
|
8
|
+
import { MessageError } from '../components/Message'
|
|
9
|
+
import { FullPageWrapper } from '../components/FullPageWrapper'
|
|
10
10
|
|
|
11
|
-
const createAuthRequiredPage = (Page) => {
|
|
11
|
+
export const createAuthRequiredPage = (Page) => {
|
|
12
12
|
return (props) => {
|
|
13
13
|
const { data: user, status, error } = useAuth()
|
|
14
14
|
|
|
@@ -36,5 +36,3 @@ const createAuthRequiredPage = (Page) => {
|
|
|
36
36
|
}
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
|
-
|
|
40
|
-
export default createAuthRequiredPage
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{{={= =}=}}
|
|
2
|
+
import * as React from 'react'
|
|
3
|
+
import { createBrowserRouter, RouterProvider } from 'react-router'
|
|
4
|
+
|
|
5
|
+
{=# isExternalAuthEnabled =}
|
|
6
|
+
import { OAuthCallbackPage } from "../pages/OAuthCallback"
|
|
7
|
+
{=/ isExternalAuthEnabled =}
|
|
8
|
+
|
|
9
|
+
import { DefaultRootErrorBoundary } from '../components/DefaultRootErrorBoundary'
|
|
10
|
+
|
|
11
|
+
import { routes } from '../../router/index'
|
|
12
|
+
|
|
13
|
+
export function getRouter({
|
|
14
|
+
routesMapping,
|
|
15
|
+
rootElement,
|
|
16
|
+
}: {
|
|
17
|
+
routesMapping: Record<string, React.ComponentType>,
|
|
18
|
+
rootElement: React.ReactNode,
|
|
19
|
+
}) {
|
|
20
|
+
const waspDefinedRoutes = [
|
|
21
|
+
{=# isExternalAuthEnabled =}
|
|
22
|
+
{
|
|
23
|
+
path: "{= oAuthCallbackPath =}",
|
|
24
|
+
Component: OAuthCallbackPage,
|
|
25
|
+
},
|
|
26
|
+
{=/ isExternalAuthEnabled =}
|
|
27
|
+
]
|
|
28
|
+
const userDefinedRoutes = Object.entries(routes).map(([routeKey, route]) => {
|
|
29
|
+
return {
|
|
30
|
+
path: route.to,
|
|
31
|
+
Component: routesMapping[routeKey],
|
|
32
|
+
}
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
const browserRouter = createBrowserRouter([{
|
|
36
|
+
path: '/',
|
|
37
|
+
element: rootElement,
|
|
38
|
+
ErrorBoundary: DefaultRootErrorBoundary,
|
|
39
|
+
children: [
|
|
40
|
+
...waspDefinedRoutes,
|
|
41
|
+
...userDefinedRoutes,
|
|
42
|
+
],
|
|
43
|
+
}], {
|
|
44
|
+
basename: '{= baseDir =}',
|
|
45
|
+
})
|
|
46
|
+
return <RouterProvider router={browserRouter} />;
|
|
47
|
+
}
|
|
@@ -23,6 +23,9 @@ export { SignInButton as KeycloakSignInButton } from '../../auth/helpers/Keycloa
|
|
|
23
23
|
{=# isGitHubAuthEnabled =}
|
|
24
24
|
export { SignInButton as GitHubSignInButton } from '../../auth/helpers/GitHub'
|
|
25
25
|
{=/ isGitHubAuthEnabled =}
|
|
26
|
+
{=# isMicrosoftAuthEnabled =}
|
|
27
|
+
export { SignInButton as MicrosoftSignInButton } from '../../auth/helpers/Microsoft'
|
|
28
|
+
{=/ isMicrosoftAuthEnabled =}
|
|
26
29
|
export {
|
|
27
30
|
FormError,
|
|
28
31
|
FormInput,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useMemo } from 'react'
|
|
2
|
-
import { Link as RouterLink } from 'react-router
|
|
2
|
+
import { Link as RouterLink } from 'react-router'
|
|
3
3
|
import { interpolatePath } from './linkHelpers'
|
|
4
4
|
import { type Routes } from './index'
|
|
5
5
|
|
|
@@ -16,6 +16,6 @@ export function Link(
|
|
|
16
16
|
): React.JSX.Element {
|
|
17
17
|
const toPropWithParams = useMemo(() => {
|
|
18
18
|
return interpolatePath(to, params, search, hash)
|
|
19
|
-
}, [to, params])
|
|
19
|
+
}, [to, params, search, hash])
|
|
20
20
|
return <RouterLink to={toPropWithParams} {...restOfProps} />
|
|
21
21
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ReactElement, ReactNode } from 'react'
|
|
2
|
-
import {
|
|
2
|
+
import { http, type HttpResponseResolver, type RequestHandler } from 'msw'
|
|
3
3
|
import { setupServer, type SetupServer } from 'msw/node'
|
|
4
|
-
import { BrowserRouter as Router } from 'react-router
|
|
4
|
+
import { BrowserRouter as Router } from 'react-router'
|
|
5
5
|
import { render, RenderResult, cleanup } from '@testing-library/react'
|
|
6
6
|
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
|
|
7
7
|
import { beforeAll, afterEach, afterAll } from 'vitest'
|
|
@@ -57,13 +57,11 @@ export function mockServer(): {
|
|
|
57
57
|
|
|
58
58
|
const mockQuery: MockQuery = (query, mockData) => {
|
|
59
59
|
const route = (query as unknown as { route: Route }).route
|
|
60
|
-
mockRoute(server, route, (
|
|
61
|
-
res(ctx.json(serialize(mockData)))
|
|
62
|
-
)
|
|
60
|
+
mockRoute(server, route, () => Response.json(serialize(mockData)))
|
|
63
61
|
}
|
|
64
62
|
|
|
65
63
|
const mockApi: MockApi = (route, mockData) => {
|
|
66
|
-
mockRoute(server, route, (
|
|
64
|
+
mockRoute(server, route, () => Response.json(mockData))
|
|
67
65
|
}
|
|
68
66
|
|
|
69
67
|
return { server, mockQuery, mockApi }
|
|
@@ -72,7 +70,7 @@ export function mockServer(): {
|
|
|
72
70
|
function mockRoute(
|
|
73
71
|
server: SetupServer,
|
|
74
72
|
route: Route,
|
|
75
|
-
responseHandler:
|
|
73
|
+
responseHandler: HttpResponseResolver
|
|
76
74
|
) {
|
|
77
75
|
if (!Object.values(HttpMethod).includes(route.method)) {
|
|
78
76
|
throw new Error(
|
|
@@ -84,11 +82,11 @@ function mockRoute(
|
|
|
84
82
|
|
|
85
83
|
const url = `${config.apiUrl}${route.path}`
|
|
86
84
|
|
|
87
|
-
const handlers: Record<HttpMethod,
|
|
88
|
-
[HttpMethod.Get]:
|
|
89
|
-
[HttpMethod.Post]:
|
|
90
|
-
[HttpMethod.Put]:
|
|
91
|
-
[HttpMethod.Delete]:
|
|
85
|
+
const handlers: Record<HttpMethod, RequestHandler> = {
|
|
86
|
+
[HttpMethod.Get]: http.get(url, responseHandler),
|
|
87
|
+
[HttpMethod.Post]: http.post(url, responseHandler),
|
|
88
|
+
[HttpMethod.Put]: http.put(url, responseHandler),
|
|
89
|
+
[HttpMethod.Delete]: http.delete(url, responseHandler),
|
|
92
90
|
}
|
|
93
91
|
|
|
94
92
|
server.use(handlers[route.method])
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { type WaspPluginOptions, wasp } from "./plugins/wasp.js";
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{{={= =}=}}
|
|
2
|
+
import { type Plugin } from 'vite'
|
|
3
|
+
import path from 'path'
|
|
4
|
+
|
|
5
|
+
export function detectServerImports(): Plugin {
|
|
6
|
+
let parsePathToUserCode!: ParsePathToUserCodeFn
|
|
7
|
+
return {
|
|
8
|
+
name: 'wasp:detect-server-imports',
|
|
9
|
+
enforce: 'pre',
|
|
10
|
+
configResolved(config) {
|
|
11
|
+
parsePathToUserCode = createPathToUserCodeParser(config.root)
|
|
12
|
+
},
|
|
13
|
+
resolveId(source, importer) {
|
|
14
|
+
if (!importer) {
|
|
15
|
+
return
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const pathToUserCode = parsePathToUserCode(importer)
|
|
19
|
+
if (!pathToUserCode) {
|
|
20
|
+
return
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (isServerImport(source)) {
|
|
24
|
+
throw new Error(
|
|
25
|
+
`Server code cannot be imported in the client code. Import from "${source}" in "${pathToUserCode}" is not allowed.`
|
|
26
|
+
)
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function isServerImport(moduleName: string): boolean {
|
|
33
|
+
return moduleName.startsWith('wasp/server')
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
type RelativePathToUserCode = string & { _brand: 'relativePathToUserCode' }
|
|
37
|
+
|
|
38
|
+
type ParsePathToUserCodeFn = (importerPath: string) => RelativePathToUserCode | null;
|
|
39
|
+
|
|
40
|
+
function createPathToUserCodeParser(waspProjectDirPath: string): ParsePathToUserCodeFn {
|
|
41
|
+
return (importerPath: string): RelativePathToUserCode | null => {
|
|
42
|
+
const importerPathRelativeToWaspProjectDir = path.relative(
|
|
43
|
+
waspProjectDirPath,
|
|
44
|
+
importerPath
|
|
45
|
+
)
|
|
46
|
+
return importerPathRelativeToWaspProjectDir.startsWith('{= srcDirInWaspProjectDir =}')
|
|
47
|
+
? (importerPathRelativeToWaspProjectDir as RelativePathToUserCode)
|
|
48
|
+
: null
|
|
49
|
+
}
|
|
50
|
+
}
|