mirror of
https://github.com/wasp-lang/wasp.git
synced 2024-09-11 15:26:19 +03:00
Fix build for 0.12.0 (#1773)
This commit is contained in:
parent
87e576d66d
commit
5cd5130534
@ -7,11 +7,6 @@ import Control.Monad (when)
|
||||
import Control.Monad.Except (throwError)
|
||||
import Control.Monad.IO.Class (liftIO)
|
||||
import StrongPath (Abs, Dir, Path', (</>))
|
||||
import qualified StrongPath as SP
|
||||
import System.Directory
|
||||
( doesDirectoryExist,
|
||||
removeDirectoryRecursive,
|
||||
)
|
||||
import Wasp.Cli.Command (Command, CommandError (..))
|
||||
import Wasp.Cli.Command.Compile (compileIOWithOptions, printCompilationResult)
|
||||
import Wasp.Cli.Command.Message (cliSendMessageC)
|
||||
@ -20,9 +15,11 @@ import Wasp.Cli.Message (cliSendMessage)
|
||||
import Wasp.CompileOptions (CompileOptions (..))
|
||||
import qualified Wasp.Generator
|
||||
import Wasp.Generator.Monad (GeneratorWarning (GeneratorNeedsMigrationWarning))
|
||||
import Wasp.Generator.SdkGenerator.Common (sdkRootDirInProjectRootDir)
|
||||
import qualified Wasp.Message as Msg
|
||||
import Wasp.Project (CompileError, CompileWarning, WaspProjectDir)
|
||||
import Wasp.Project.Common (buildDirInDotWaspDir, dotWaspDirInWaspProjectDir)
|
||||
import Wasp.Project.Common (buildDirInDotWaspDir, dotWaspDirInWaspProjectDir, generatedCodeDirInDotWaspDir)
|
||||
import Wasp.Util.IO (doesDirectoryExist, removeDirectory)
|
||||
|
||||
-- | Builds Wasp project that the current working directory is part of.
|
||||
-- Does all the steps, from analysis to generation, and at the end writes generated code
|
||||
@ -37,14 +34,22 @@ build = do
|
||||
let buildDir =
|
||||
waspProjectDir </> dotWaspDirInWaspProjectDir
|
||||
</> buildDirInDotWaspDir
|
||||
buildDirFilePath = SP.fromAbsDir buildDir
|
||||
|
||||
doesBuildDirExist <- liftIO $ doesDirectoryExist buildDirFilePath
|
||||
doesBuildDirExist <- liftIO $ doesDirectoryExist buildDir
|
||||
when doesBuildDirExist $ do
|
||||
cliSendMessageC $ Msg.Start "Clearing the content of the .wasp/build directory..."
|
||||
liftIO $ removeDirectoryRecursive buildDirFilePath
|
||||
liftIO $ removeDirectory buildDir
|
||||
cliSendMessageC $ Msg.Success "Successfully cleared the contents of the .wasp/build directory."
|
||||
|
||||
-- We are using the same SDK location for both build and start. Read this issue
|
||||
-- for the full story: https://github.com/wasp-lang/wasp/issues/1769
|
||||
let sdkDir = waspProjectDir </> dotWaspDirInWaspProjectDir </> generatedCodeDirInDotWaspDir </> sdkRootDirInProjectRootDir
|
||||
doesSdkDirExist <- liftIO $ doesDirectoryExist sdkDir
|
||||
when doesSdkDirExist $ do
|
||||
cliSendMessageC $ Msg.Start "Clearing the content of the .wasp/out/sdk directory..."
|
||||
liftIO $ removeDirectory sdkDir
|
||||
cliSendMessageC $ Msg.Success "Successfully cleared the contents of the .wasp/out/sdk directory."
|
||||
|
||||
cliSendMessageC $ Msg.Start "Building wasp project..."
|
||||
(warnings, errors) <- liftIO $ buildIO waspProjectDir buildDir
|
||||
|
||||
|
@ -23,8 +23,8 @@ import Wasp.Project.Common (dotWaspDirInWaspProjectDir, generatedCodeDirInDotWas
|
||||
-- It also listens for any file changes and recompiles and restarts generated project accordingly.
|
||||
start :: Command ()
|
||||
start = do
|
||||
InWaspProject waspRoot <- require
|
||||
let outDir = waspRoot </> dotWaspDirInWaspProjectDir </> generatedCodeDirInDotWaspDir
|
||||
InWaspProject waspProjectDir <- require
|
||||
let outDir = waspProjectDir </> dotWaspDirInWaspProjectDir </> generatedCodeDirInDotWaspDir
|
||||
|
||||
cliSendMessageC $ Msg.Start "Starting compilation and setup phase. Hold tight..."
|
||||
|
||||
@ -42,7 +42,7 @@ start = do
|
||||
-- This way we can show newest Wasp compile warnings and errors (produced by recompilation from
|
||||
-- 'watch') once jobs from 'start' quiet down a bit.
|
||||
ongoingCompilationResultMVar <- newMVar (warnings, [])
|
||||
let watchWaspProjectSource = watch waspRoot outDir ongoingCompilationResultMVar
|
||||
let watchWaspProjectSource = watch waspProjectDir outDir ongoingCompilationResultMVar
|
||||
let startGeneratedWebApp = Wasp.Generator.start outDir (onJobsQuietDown ongoingCompilationResultMVar)
|
||||
-- In parallel:
|
||||
-- 1. watch for any changes in the Wasp project, be it users wasp code or users JS/HTML/...
|
||||
|
@ -3,7 +3,7 @@
|
||||
# Because if not, we had situations where it would use the different version
|
||||
# locally and on Github CI. This way we ensure exact version is used,
|
||||
# and also have control over updating it (instead of update surprising us).
|
||||
FROM node:{= nodeMajorVersion =}-alpine3.17 AS node
|
||||
FROM node:{= nodeVersion =}-alpine3.17 AS node
|
||||
|
||||
|
||||
# We split Dockerfile into base, server-builder and server-production.
|
||||
@ -18,18 +18,31 @@ FROM node AS base
|
||||
RUN apk --no-cache -U upgrade # To ensure any potential security patches are applied.
|
||||
|
||||
|
||||
# Todo: The 'server-builder' image stays on disk under <none>:<none> and is
|
||||
# relatively large (~900 MB), should we remove it? Or is it useful for future
|
||||
# builds?
|
||||
FROM base AS server-builder
|
||||
RUN apk add --no-cache build-base libtool autoconf automake
|
||||
# Building the Docker image on Apple's Silicon Mac fails without python3 (the build
|
||||
# throws `node-gyp` errors when it tries to compile native deps. Installing
|
||||
# `python3` fixes the issue.
|
||||
RUN apk add --no-cache python3 build-base libtool autoconf automake
|
||||
WORKDIR /app
|
||||
COPY server/ ./server/
|
||||
# Since the framwork code in /.wasp/build/server imports the user code in /src
|
||||
# using relative imports, we must mirror the same directory structure in the
|
||||
# Docker image.
|
||||
COPY src ./src
|
||||
COPY package.json .
|
||||
COPY package-lock.json .
|
||||
COPY .wasp/build/server .wasp/build/server
|
||||
COPY .wasp/out/sdk .wasp/out/sdk
|
||||
# Install npm packages, resulting in node_modules/.
|
||||
RUN cd server && npm install
|
||||
RUN npm install && cd .wasp/build/server && npm install
|
||||
{=# usingPrisma =}
|
||||
COPY db/schema.prisma ./db/
|
||||
RUN cd server && npx prisma generate --schema='{= dbSchemaFileFromServerDir =}'
|
||||
COPY .wasp/build/db/schema.prisma .wasp/build/db/
|
||||
RUN cd .wasp/build/server && npx prisma generate --schema='{= dbSchemaFileFromServerDir =}'
|
||||
{=/ usingPrisma =}
|
||||
# Building the server should come after Prisma generation.
|
||||
RUN cd server && npm run bundle
|
||||
RUN cd .wasp/build/server && npm run bundle
|
||||
|
||||
|
||||
# TODO: Use pm2?
|
||||
@ -39,13 +52,21 @@ FROM base AS server-production
|
||||
RUN apk add --no-cache python3
|
||||
ENV NODE_ENV production
|
||||
WORKDIR /app
|
||||
COPY --from=server-builder /app/server/node_modules ./server/node_modules
|
||||
COPY --from=server-builder /app/server/dist ./server/dist
|
||||
COPY --from=server-builder /app/server/package*.json ./server/
|
||||
COPY --from=server-builder /app/server/scripts ./server/scripts
|
||||
COPY db/ ./db/
|
||||
# Copying the top level 'node_modules' because it contains the Prisma packages
|
||||
# necessary for migrating the database.
|
||||
COPY --from=server-builder /app/node_modules ./node_modules
|
||||
# Copying the SDK because 'validate-env.mjs' executes independent of the bundle
|
||||
# and references the 'wasp' package.
|
||||
COPY --from=server-builder /app/.wasp/out/sdk .wasp/out/sdk
|
||||
# Copying 'server/node_modules' because 'validate-env.mjs' executes independent
|
||||
# of the bundle and references the dotenv package.
|
||||
COPY --from=server-builder /app/.wasp/build/server/node_modules .wasp/build/server/node_modules
|
||||
COPY --from=server-builder /app/.wasp/build/server/bundle .wasp/build/server/bundle
|
||||
COPY --from=server-builder /app/.wasp/build/server/package*.json .wasp/build/server/
|
||||
COPY --from=server-builder /app/.wasp/build/server/scripts .wasp/build/server/scripts
|
||||
COPY .wasp/build/db/ .wasp/build/db/
|
||||
EXPOSE ${PORT}
|
||||
WORKDIR /app/server
|
||||
WORKDIR /app/.wasp/build/server
|
||||
ENTRYPOINT ["npm", "run", "start-production"]
|
||||
|
||||
|
||||
|
@ -29,6 +29,12 @@ const defaultViteConfig = {
|
||||
build: {
|
||||
outDir: "build",
|
||||
},
|
||||
resolve: {
|
||||
// These packages rely on a single instance per page. Not dedpuing them
|
||||
// causes runtime errors (e.g., hook rule violation in react, QueryClient
|
||||
// instance error in react-query, Invariant Error in react-router-dom).
|
||||
dedupe: ["react", "react-dom", "@tanstack/react-query", "react-router-dom"]
|
||||
},
|
||||
test: {
|
||||
globals: true,
|
||||
environment: "jsdom",
|
||||
|
@ -1,5 +1,5 @@
|
||||
{{={= =}=}}
|
||||
import { createContext, useState, useEffect } from 'react'
|
||||
import { createContext, useState, useEffect, Context } from 'react'
|
||||
import { io, Socket } from 'socket.io-client'
|
||||
|
||||
import { getSessionId } from 'wasp/client/api'
|
||||
@ -8,6 +8,11 @@ import config from 'wasp/core/config'
|
||||
|
||||
import type { ClientToServerEvents, ServerToClientEvents } from 'wasp/server/webSocket';
|
||||
|
||||
export type WebSocketContextValue = {
|
||||
socket: typeof socket
|
||||
isConnected: boolean
|
||||
}
|
||||
|
||||
// PRIVATE API
|
||||
// TODO: In the future, it would be nice if users could pass more
|
||||
// options to `io`, likely via some `configFn`.
|
||||
@ -31,7 +36,7 @@ apiEventsEmitter.on('sessionId.set', refreshAuthToken)
|
||||
apiEventsEmitter.on('sessionId.clear', refreshAuthToken)
|
||||
|
||||
// PRIVATE API
|
||||
export const WebSocketContext = createContext({
|
||||
export const WebSocketContext: Context<WebSocketContextValue> = createContext({
|
||||
socket,
|
||||
isConnected: false,
|
||||
});
|
||||
|
@ -97,6 +97,7 @@
|
||||
{=! Public: { type WebSocketDefinition, type WaspSocketData } =}
|
||||
{=! Private: [server, sdk] =}
|
||||
"./server/webSocket": "./dist/server/webSocket/index.js",
|
||||
"./entities": "./dist/entities/index.js",
|
||||
"./auth": "./dist/auth/index.js",
|
||||
"./client/auth": "./dist/client/auth/index.js",
|
||||
"./client/operations": "./dist/client/operations/index.js",
|
||||
|
@ -18,7 +18,7 @@ export interface JSONObject {
|
||||
|
||||
type PrimitiveJSONValue = string | number | boolean | undefined | null
|
||||
|
||||
interface JSONArray extends Array<JSONValue> {}
|
||||
export interface JSONArray extends Array<JSONValue> {}
|
||||
|
||||
type SerializableJSONValue =
|
||||
| Symbol
|
||||
|
@ -8,6 +8,7 @@
|
||||
"dom",
|
||||
"DOM.Iterable"
|
||||
],
|
||||
"declaration": true,
|
||||
"strict": false,
|
||||
// Overriding this because we want to use top-level await
|
||||
"module": "esnext",
|
||||
|
@ -7,33 +7,33 @@ app TodoTypescript {
|
||||
auth: {
|
||||
userEntity: User,
|
||||
methods: {
|
||||
// usernameAndPassword: {
|
||||
// userSignupFields: import { userSignupFields } from "@src/user/userSignupFields.js"
|
||||
// },
|
||||
usernameAndPassword: {
|
||||
userSignupFields: import { userSignupFields } from "@src/user/userSignupFields.js"
|
||||
},
|
||||
// google: {
|
||||
// userSignupFields: import { googleUserSignupFields } from "@src/user/userSignupFields.js"
|
||||
// },
|
||||
// gitHub: {
|
||||
// userSignupFields: import { githubUserSignupFields } from "@src/user/userSignupFields.js"
|
||||
// },
|
||||
email: {
|
||||
userSignupFields: import { userSignupFields } from "@src/user/userSignupFields.js",
|
||||
fromField: {
|
||||
email: "waspy@app.com"
|
||||
},
|
||||
emailVerification: {
|
||||
clientRoute: EmailVerificationRoute,
|
||||
},
|
||||
passwordReset: {
|
||||
clientRoute: PasswordResetRoute,
|
||||
}
|
||||
} // https://wasp-lang.dev/docs/guides/email-auth
|
||||
// email: {
|
||||
// userSignupFields: import { userSignupFields } from "@src/user/userSignupFields.js",
|
||||
// fromField: {
|
||||
// email: "waspy@app.com"
|
||||
// },
|
||||
// emailVerification: {
|
||||
// clientRoute: EmailVerificationRoute,
|
||||
// },
|
||||
// passwordReset: {
|
||||
// clientRoute: PasswordResetRoute,
|
||||
// }
|
||||
// } // https://wasp-lang.dev/docs/guides/email-auth
|
||||
},
|
||||
onAuthFailedRedirectTo: "/login",
|
||||
},
|
||||
emailSender: {
|
||||
provider: Dummy
|
||||
},
|
||||
// emailSender: {
|
||||
// provider: Dummy
|
||||
// },
|
||||
db: {
|
||||
seeds: [
|
||||
import { seedMyDb } from "@src/db/seeds.js"
|
||||
@ -100,10 +100,10 @@ page SignupPage {
|
||||
component: import { SignupPage } from "@src/user/auth.tsx"
|
||||
}
|
||||
|
||||
route EmailVerificationRoute { path: "/email-verify", to: EmailVerification }
|
||||
page EmailVerification {
|
||||
component: import { EmailVerificationPage } from "@src/user/auth.tsx"
|
||||
}
|
||||
// route EmailVerificationRoute { path: "/email-verify", to: EmailVerification }
|
||||
// page EmailVerification {
|
||||
// component: import { EmailVerificationPage } from "@src/user/auth.tsx"
|
||||
// }
|
||||
|
||||
route ChatRoute { path: "/chat", to: Chat }
|
||||
page Chat {
|
||||
@ -115,16 +115,16 @@ page Chat {
|
||||
// component: import { EmailVerificationPage } from "@src/user/auth.tsx"
|
||||
// }
|
||||
|
||||
route RequestPasswordResetRoute { path: "/request-password-reset", to: RequestPasswordReset }
|
||||
page RequestPasswordReset {
|
||||
component: import { RequestPasswordResetPage } from "@src/user/auth.tsx"
|
||||
}
|
||||
// route RequestPasswordResetRoute { path: "/request-password-reset", to: RequestPasswordReset }
|
||||
// page RequestPasswordReset {
|
||||
// component: import { RequestPasswordResetPage } from "@src/user/auth.tsx"
|
||||
// }
|
||||
|
||||
|
||||
route PasswordResetRoute { path: "/password-reset", to: PasswordReset }
|
||||
page PasswordReset {
|
||||
component: import { PasswordResetPage } from "@src/user/auth.tsx"
|
||||
}
|
||||
// route PasswordResetRoute { path: "/password-reset", to: PasswordReset }
|
||||
// page PasswordReset {
|
||||
// component: import { PasswordResetPage } from "@src/user/auth.tsx"
|
||||
// }
|
||||
|
||||
query getTasks {
|
||||
fn: import { getTasks } from "@src/task/queries",
|
||||
@ -175,7 +175,7 @@ apiNamespace fooBarNamespace {
|
||||
path: "/foo/bar"
|
||||
}
|
||||
|
||||
action customEmailSending {
|
||||
fn: import { send } from "@src/user/customEmailSending",
|
||||
entities: [User]
|
||||
}
|
||||
// action customEmailSending {
|
||||
// fn: import { send } from "@src/user/customEmailSending",
|
||||
// entities: [User]
|
||||
// }
|
||||
|
2693
waspc/examples/todo-typescript/package-lock.json
generated
2693
waspc/examples/todo-typescript/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -2,7 +2,7 @@ import './Main.css'
|
||||
import React, { useEffect, FormEventHandler, FormEvent } from 'react'
|
||||
import {
|
||||
createTask,
|
||||
customEmailSending,
|
||||
// customEmailSending,
|
||||
deleteTasks,
|
||||
getTasks,
|
||||
useQuery,
|
||||
@ -34,9 +34,9 @@ export const MainPage = ({ user }: { user: AuthUser }) => {
|
||||
return (
|
||||
<main>
|
||||
<img src={waspLogo} alt="wasp logo" />
|
||||
<button onClick={() => customEmailSending(undefined)}>
|
||||
{/* <button onClick={() => customEmailSending(undefined)}>
|
||||
customEmailSending
|
||||
</button>
|
||||
</button> */}
|
||||
<Link to="/chat">Wonna chat?</Link>
|
||||
{user && (
|
||||
<h1>
|
||||
|
@ -5,7 +5,7 @@ import type {
|
||||
DeleteTasks,
|
||||
} from 'wasp/server/operations'
|
||||
import type { Task } from 'wasp/entities'
|
||||
import { emailSender } from 'wasp/server/email'
|
||||
// import { emailSender } from 'wasp/server/email'
|
||||
import { printTimeAndNumberOfTasks } from 'wasp/server/jobs'
|
||||
|
||||
type CreateArgs = Pick<Task, 'description'>
|
||||
@ -21,16 +21,16 @@ export const createTask: CreateTask<CreateArgs, Task> = async (
|
||||
console.log("Executing 'printTimeAndNumberOfTasks' task.")
|
||||
await printTimeAndNumberOfTasks.submit({})
|
||||
|
||||
emailSender.send({
|
||||
to: 'test@example.com',
|
||||
from: {
|
||||
name: 'Test',
|
||||
email: 'test@example.com',
|
||||
},
|
||||
subject: 'Test email',
|
||||
text: 'Thank you for using our app!',
|
||||
html: '<h1>Thank you for using our app!</h1>',
|
||||
})
|
||||
// emailSender.send({
|
||||
// to: 'test@example.com',
|
||||
// from: {
|
||||
// name: 'Test',
|
||||
// email: 'test@example.com',
|
||||
// },
|
||||
// subject: 'Test email',
|
||||
// text: 'Thank you for using our app!',
|
||||
// html: '<h1>Thank you for using our app!</h1>',
|
||||
// })
|
||||
|
||||
return context.entities.Task.create({
|
||||
data: {
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { HttpError } from 'wasp/server'
|
||||
import type { GetTasks, GetTotalNumberOfTasks } from 'wasp/server/operations'
|
||||
import type { Task } from 'wasp/entities'
|
||||
import { ensureValidEmail, createProviderId } from 'wasp/server/auth'
|
||||
// import { ensureValidEmail, createProviderId } from 'wasp/server/auth'
|
||||
|
||||
//Using TypeScript's new 'satisfies' keyword, it will infer the types of the arguments and return value
|
||||
export const getTasks = ((_args, context) => {
|
||||
@ -9,8 +9,8 @@ export const getTasks = ((_args, context) => {
|
||||
throw new HttpError(401)
|
||||
}
|
||||
|
||||
console.log(createProviderId)
|
||||
ensureValidEmail({ email: 'wasp@gmail.com' })
|
||||
// console.log(createProviderId)
|
||||
// ensureValidEmail({ email: 'wasp@gmail.com' })
|
||||
|
||||
return context.entities.Task.findMany({
|
||||
where: { user: { id: context.user.id } },
|
||||
|
@ -1,9 +1,9 @@
|
||||
import {
|
||||
LoginForm,
|
||||
SignupForm,
|
||||
VerifyEmailForm,
|
||||
ResetPasswordForm,
|
||||
ForgotPasswordForm,
|
||||
// VerifyEmailForm,
|
||||
// ResetPasswordForm,
|
||||
// ForgotPasswordForm,
|
||||
FormError,
|
||||
FormInput,
|
||||
FormItemGroup,
|
||||
@ -74,14 +74,14 @@ export function LoginPage() {
|
||||
)
|
||||
}
|
||||
|
||||
export function RequestPasswordResetPage() {
|
||||
return <ForgotPasswordForm />
|
||||
}
|
||||
// export function RequestPasswordResetPage() {
|
||||
// return <ForgotPasswordForm />
|
||||
// }
|
||||
|
||||
export function PasswordResetPage() {
|
||||
return <ResetPasswordForm />
|
||||
}
|
||||
// export function PasswordResetPage() {
|
||||
// return <ResetPasswordForm />
|
||||
// }
|
||||
|
||||
export function EmailVerificationPage() {
|
||||
return <VerifyEmailForm />
|
||||
}
|
||||
// export function EmailVerificationPage() {
|
||||
// return <VerifyEmailForm />
|
||||
// }
|
||||
|
@ -1,43 +1,43 @@
|
||||
import {
|
||||
createPasswordResetLink,
|
||||
createEmailVerificationLink,
|
||||
sendEmailVerificationEmail,
|
||||
sendPasswordResetEmail,
|
||||
} from 'wasp/server/auth'
|
||||
// import {
|
||||
// createPasswordResetLink,
|
||||
// createEmailVerificationLink,
|
||||
// sendEmailVerificationEmail,
|
||||
// sendPasswordResetEmail,
|
||||
// } from 'wasp/server/auth'
|
||||
|
||||
export async function send() {
|
||||
const userEmail = 'mihovil@ilakovac.com'
|
||||
// export async function send() {
|
||||
// const userEmail = 'mihovil@ilakovac.com'
|
||||
|
||||
const link = await createPasswordResetLink(
|
||||
userEmail,
|
||||
'/password-reset'
|
||||
)
|
||||
const secondLink = await createEmailVerificationLink(
|
||||
userEmail,
|
||||
'/email-verify'
|
||||
)
|
||||
// const link = await createPasswordResetLink(
|
||||
// userEmail,
|
||||
// '/password-reset'
|
||||
// )
|
||||
// const secondLink = await createEmailVerificationLink(
|
||||
// userEmail,
|
||||
// '/email-verify'
|
||||
// )
|
||||
|
||||
// Send email verification email.
|
||||
await sendEmailVerificationEmail(userEmail, {
|
||||
from: {
|
||||
name: 'Wasp',
|
||||
email: userEmail,
|
||||
},
|
||||
to: userEmail,
|
||||
subject: 'Email verification',
|
||||
text: 'Click on the link to verify your email. ' + secondLink,
|
||||
html: `<a href="${secondLink}">Click here to verify your email.</a>`,
|
||||
})
|
||||
// // Send email verification email.
|
||||
// await sendEmailVerificationEmail(userEmail, {
|
||||
// from: {
|
||||
// name: 'Wasp',
|
||||
// email: userEmail,
|
||||
// },
|
||||
// to: userEmail,
|
||||
// subject: 'Email verification',
|
||||
// text: 'Click on the link to verify your email. ' + secondLink,
|
||||
// html: `<a href="${secondLink}">Click here to verify your email.</a>`,
|
||||
// })
|
||||
|
||||
// Send password reset email.
|
||||
await sendPasswordResetEmail(userEmail, {
|
||||
from: {
|
||||
name: 'Wasp',
|
||||
email: userEmail,
|
||||
},
|
||||
to: userEmail,
|
||||
subject: 'Password reset',
|
||||
text: 'Click on the link to reset your password.' + link,
|
||||
html: `<a href="${link}">Click here to reset your password.</a>`,
|
||||
})
|
||||
}
|
||||
// // Send password reset email.
|
||||
// await sendPasswordResetEmail(userEmail, {
|
||||
// from: {
|
||||
// name: 'Wasp',
|
||||
// email: userEmail,
|
||||
// },
|
||||
// to: userEmail,
|
||||
// subject: 'Password reset',
|
||||
// text: 'Click on the link to reset your password.' + link,
|
||||
// html: `<a href="${link}">Click here to reset your password.</a>`,
|
||||
// })
|
||||
// }
|
||||
|
@ -165,6 +165,10 @@ runPrismaCommandAsJobFromWaspServerDir :: Path' Abs (Dir ProjectRootDir) -> [Str
|
||||
runPrismaCommandAsJobFromWaspServerDir projectRootDir cmdArgs =
|
||||
runPrismaCommandAsJobWithExtraEnv serverDir [] projectRootDir cmdArgs
|
||||
where
|
||||
-- We must run our Prisma commands from the server dir for Prisma
|
||||
-- to pick up our .env file there like before. In the future, we might want
|
||||
-- to reconsider how Prisma and the server env vars interact and change
|
||||
-- this. Text copied from: https://github.com/wasp-lang/wasp/pull/1662
|
||||
serverDir = projectRootDir </> serverRootDirInProjectRootDir
|
||||
|
||||
runPrismaCommandAsJobWithExtraEnv ::
|
||||
|
@ -29,7 +29,6 @@ import Wasp.Generator.FileDraft (FileDraft (..), createTemplateFileDraft)
|
||||
import qualified Wasp.Generator.FileDraft.TemplateFileDraft as TmplFD
|
||||
import Wasp.Generator.Monad (Generator, GeneratorError, runGenerator)
|
||||
import Wasp.Generator.Templates (TemplatesDir, compileAndRenderTemplate)
|
||||
import qualified Wasp.SemanticVersion as SV
|
||||
|
||||
genDockerFiles :: AppSpec -> Generator [FileDraft]
|
||||
genDockerFiles spec = sequence [genDockerfile spec, genDockerignore spec]
|
||||
@ -46,7 +45,7 @@ genDockerfile spec = do
|
||||
object
|
||||
[ "usingPrisma" .= not (null $ AS.getDecls @AS.Entity.Entity spec),
|
||||
"dbSchemaFileFromServerDir" .= SP.fromRelFile dbSchemaFileFromServerDir,
|
||||
"nodeMajorVersion" .= show (SV.major $ getLowestNodeVersionUserAllows spec),
|
||||
"nodeVersion" .= show (getLowestNodeVersionUserAllows spec),
|
||||
"userDockerfile" .= fromMaybe "" (AS.userDockerfileContents spec)
|
||||
]
|
||||
)
|
||||
|
@ -212,6 +212,20 @@ npmDepsForSdk spec =
|
||||
("react-router-dom", "^5.3.3"),
|
||||
("react-hook-form", "^7.45.4"),
|
||||
("secure-password", "^4.0.0"),
|
||||
-- Secure-password 4.0.0. defaults to using sodium-native 3.4.1.,
|
||||
-- which segfaults on on Alpine:
|
||||
-- https://github.com/sodium-friends/sodium-native/issues/160
|
||||
--
|
||||
-- Before 0.12.0 (i.e., restructuring), we made Wasp use
|
||||
-- sodium-native 3.3.0. with package.json overrides in our web-app/package.json:
|
||||
-- https://github.com/wasp-lang/wasp/pull/729
|
||||
--
|
||||
-- Because our code that uses secure-password now lives in the SDK,
|
||||
-- and NPM apparently ignores package.json overrides for
|
||||
-- dependencies (no reference, found out by trying it out), the only
|
||||
-- way to force NPM to install sodium-native 3.3.0 is by listing it
|
||||
-- as a direct dependency.
|
||||
("sodium-native", "3.3.0"),
|
||||
("superjson", "^1.12.2"),
|
||||
("@types/express-serve-static-core", "^4.17.13")
|
||||
]
|
||||
|
@ -8,6 +8,7 @@ import Wasp.Generator.Common (ProjectRootDir)
|
||||
import Wasp.Generator.ExternalCodeGenerator.Common (GeneratedExternalCodeDir)
|
||||
import Wasp.Generator.FileDraft (FileDraft, createTemplateFileDraft)
|
||||
import Wasp.Generator.Templates (TemplatesDir)
|
||||
import Wasp.Project.Common (generatedCodeDirInDotWaspDir)
|
||||
|
||||
data SdkRootDir
|
||||
|
||||
@ -45,8 +46,13 @@ mkTmplFdWithData relSrcPath tmplData = mkTmplFdWithDstAndData relSrcPath relDstP
|
||||
mkTmplFd :: Path' (Rel SdkTemplatesDir) File' -> FileDraft
|
||||
mkTmplFd path = mkTmplFdWithDst path (SP.castRel path)
|
||||
|
||||
-- To understand what's going on here, read this issue:
|
||||
-- https://github.com/wasp-lang/wasp/issues/1769
|
||||
sdkRootDirInProjectRootDir :: Path' (Rel ProjectRootDir) (Dir SdkRootDir)
|
||||
sdkRootDirInProjectRootDir = [reldir|sdk/wasp|]
|
||||
sdkRootDirInProjectRootDir =
|
||||
[reldir|../|]
|
||||
</> basename generatedCodeDirInDotWaspDir
|
||||
</> [reldir|sdk/wasp|]
|
||||
|
||||
sdkTemplatesDirInTemplatesDir :: Path' (Rel TemplatesDir) (Dir SdkTemplatesDir)
|
||||
sdkTemplatesDirInTemplatesDir = [reldir|sdk|]
|
||||
|
@ -128,7 +128,6 @@ genPackageJson spec waspDependencies = do
|
||||
.= ( (if hasEntities then "npm run db-migrate-prod && " else "")
|
||||
++ "NODE_ENV=production npm run start"
|
||||
),
|
||||
"overrides" .= getPackageJsonOverrides,
|
||||
"prisma" .= ByteStringLazyUTF8.toString (Aeson.encode $ getPackageJsonPrismaField spec)
|
||||
]
|
||||
)
|
||||
@ -256,35 +255,6 @@ genRoutesIndex spec =
|
||||
operationsRouteInRootRouter :: String
|
||||
operationsRouteInRootRouter = "operations"
|
||||
|
||||
-- Allows us to make specific changes to dependencies of our dependencies.
|
||||
-- This is helpful if something broke in later versions, etc.
|
||||
-- Ref: https://docs.npmjs.com/cli/v8/configuring-npm/package-json#overrides
|
||||
getPackageJsonOverrides :: [Aeson.Value]
|
||||
getPackageJsonOverrides = map buildOverrideData (designateLastElement overrides)
|
||||
where
|
||||
overrides :: [(String, String, String)]
|
||||
overrides =
|
||||
[ -- sodium-native > 3.3.0 broke deploying on Heroku.
|
||||
-- Ref: https://github.com/sodium-friends/sodium-native/issues/160
|
||||
("secure-password", "sodium-native", "3.3.0")
|
||||
]
|
||||
|
||||
-- NOTE: We must designate the last element so the JSON template can omit the final comma.
|
||||
buildOverrideData :: (String, String, String, Bool) -> Aeson.Value
|
||||
buildOverrideData (packageName, dependencyName, dependencyVersion, lastElement) =
|
||||
object
|
||||
[ "packageName" .= packageName,
|
||||
"dependencyName" .= dependencyName,
|
||||
"dependencyVersion" .= dependencyVersion,
|
||||
"last" .= lastElement
|
||||
]
|
||||
|
||||
designateLastElement :: [(String, String, String)] -> [(String, String, String, Bool)]
|
||||
designateLastElement [] = []
|
||||
designateLastElement l =
|
||||
map (\(x1, x2, x3) -> (x1, x2, x3, False)) (init l)
|
||||
++ map (\(x1, x2, x3) -> (x1, x2, x3, True)) [last l]
|
||||
|
||||
genEnvValidationScript :: Generator [FileDraft]
|
||||
genEnvValidationScript =
|
||||
return
|
||||
|
@ -25,7 +25,7 @@ import Wasp.Util (indent)
|
||||
-- - /waspc/.nvmrc
|
||||
-- - /web/docs/introduction/getting-started.md -> "Requirements" section.
|
||||
oldestWaspSupportedNodeVersion :: SV.Version
|
||||
oldestWaspSupportedNodeVersion = SV.Version 18 0 0
|
||||
oldestWaspSupportedNodeVersion = SV.Version 18 18 0
|
||||
|
||||
isRangeInWaspSupportedRange :: SV.Range -> Bool
|
||||
isRangeInWaspSupportedRange range =
|
||||
|
Loading…
Reference in New Issue
Block a user