@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
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
{{={= =}=}}
|
|
2
|
+
import { type Plugin, type UserConfig } from 'vite'
|
|
3
|
+
import { resolve } from 'node:path'
|
|
4
|
+
import { readFile, access, constants } from 'node:fs/promises'
|
|
5
|
+
import { parse as parseDotenv } from 'dotenv'
|
|
6
|
+
import { expand, type DotenvPopulateInput } from 'dotenv-expand'
|
|
7
|
+
|
|
8
|
+
const envFileName = '{= clientEnvFileName =}'
|
|
9
|
+
|
|
10
|
+
export function envFile(): Plugin {
|
|
11
|
+
let envFilePath!: string
|
|
12
|
+
return {
|
|
13
|
+
name: 'wasp:env-file',
|
|
14
|
+
enforce: 'pre',
|
|
15
|
+
async config(config, env) {
|
|
16
|
+
const rootDir = config.root || process.cwd()
|
|
17
|
+
const envVars = await loadEnvVars({
|
|
18
|
+
rootDir,
|
|
19
|
+
// We are sure that `envPrefix` is defined because
|
|
20
|
+
// we defined it in an earlier plugin.
|
|
21
|
+
envPrefix: config.envPrefix!,
|
|
22
|
+
// We load the env file variables only in development,
|
|
23
|
+
// when building for production, users are expected to
|
|
24
|
+
// provide the environment variables inline.
|
|
25
|
+
loadDotEnvFile: env.command === 'serve',
|
|
26
|
+
})
|
|
27
|
+
envFilePath = resolve(rootDir, envFileName)
|
|
28
|
+
|
|
29
|
+
const prefixedVars = Object.entries(envVars)
|
|
30
|
+
.reduce((acc, [key, value]) => {
|
|
31
|
+
acc[`import.meta.env.${key}`] = JSON.stringify(value)
|
|
32
|
+
return acc
|
|
33
|
+
}, {} as Record<string, string>)
|
|
34
|
+
|
|
35
|
+
return {
|
|
36
|
+
// Disable Vite's default .env loading.
|
|
37
|
+
envDir: false,
|
|
38
|
+
define: prefixedVars,
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
configureServer(server) {
|
|
42
|
+
const reloadServerOnEnvFileEvent = (path: string) => {
|
|
43
|
+
if (path === envFilePath) {
|
|
44
|
+
server.restart()
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
server.watcher.on('add', reloadServerOnEnvFileEvent)
|
|
49
|
+
server.watcher.on('change', reloadServerOnEnvFileEvent)
|
|
50
|
+
server.watcher.on('unlink', reloadServerOnEnvFileEvent)
|
|
51
|
+
},
|
|
52
|
+
async buildStart() {
|
|
53
|
+
this.addWatchFile(envFilePath)
|
|
54
|
+
},
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Based on: https://github.com/vitejs/vite/blob/8bb32036792a6f522f5c947112f3d688add755a0/packages/vite/src/node/env.ts
|
|
59
|
+
export async function loadEnvVars({
|
|
60
|
+
rootDir,
|
|
61
|
+
envPrefix,
|
|
62
|
+
loadDotEnvFile,
|
|
63
|
+
}: {
|
|
64
|
+
rootDir: string
|
|
65
|
+
envPrefix: NonNullable<UserConfig['envPrefix']>
|
|
66
|
+
loadDotEnvFile: boolean
|
|
67
|
+
}): Promise<Record<string, string>> {
|
|
68
|
+
const envPrefixNormalized = Array.isArray(envPrefix) ? envPrefix : [envPrefix]
|
|
69
|
+
const env: Record<string, string> = {}
|
|
70
|
+
|
|
71
|
+
if (loadDotEnvFile) {
|
|
72
|
+
const envFilePath = resolve(rootDir, envFileName)
|
|
73
|
+
const parsed = await parseEnvFile(envFilePath)
|
|
74
|
+
|
|
75
|
+
// Let environment variables use each other. Make a copy of `process.env` so that `dotenv-expand`
|
|
76
|
+
// doesn't re-assign the expanded values to the global `process.env`.
|
|
77
|
+
const processEnv = { ...process.env } as DotenvPopulateInput
|
|
78
|
+
expand({ parsed, processEnv })
|
|
79
|
+
|
|
80
|
+
// Only keys that start with prefix are exposed to client.
|
|
81
|
+
for (const [key, value] of Object.entries(parsed)) {
|
|
82
|
+
if (envPrefixNormalized.some(prefix => key.startsWith(prefix))) {
|
|
83
|
+
env[key] = value
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Make sure that inline env variables are prioritized over env file variables.
|
|
89
|
+
// Follows the logic Vite uses for env variables.
|
|
90
|
+
for (const key in process.env) {
|
|
91
|
+
if (envPrefixNormalized.some(prefix => key.startsWith(prefix))) {
|
|
92
|
+
env[key] = process.env[key] as string
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return env
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
async function parseEnvFile(envFilePath: string): Promise<Record<string, string>> {
|
|
100
|
+
try {
|
|
101
|
+
await access(envFilePath, constants.R_OK)
|
|
102
|
+
} catch {
|
|
103
|
+
return {}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
try {
|
|
107
|
+
return parseDotenv(await readFile(envFilePath, 'utf-8'))
|
|
108
|
+
} catch (error) {
|
|
109
|
+
console.error(`Error parsing ${envFileName}:`, error)
|
|
110
|
+
throw error
|
|
111
|
+
}
|
|
112
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { Plugin } from "vite";
|
|
2
|
+
import { getIndexHtmlContent } from "../../virtual-files/index.js";
|
|
3
|
+
import { makeVirtualFilesResolver, type VirtualFiles } from "../../virtual-files/resolver.js";
|
|
4
|
+
|
|
5
|
+
const INDEX_HTML_FILE_NAME = "index.html";
|
|
6
|
+
|
|
7
|
+
const resolveVirtualFiles = makeVirtualFilesResolver([
|
|
8
|
+
{ id: INDEX_HTML_FILE_NAME, load: getIndexHtmlContent },
|
|
9
|
+
]);
|
|
10
|
+
|
|
11
|
+
export function waspHtmlBuild(): Plugin {
|
|
12
|
+
let virtualFiles!: VirtualFiles;
|
|
13
|
+
|
|
14
|
+
return {
|
|
15
|
+
name: "wasp:html-build",
|
|
16
|
+
apply: "build",
|
|
17
|
+
config() {
|
|
18
|
+
return {
|
|
19
|
+
build: {
|
|
20
|
+
rollupOptions: {
|
|
21
|
+
// Vite tries to find the entry file on disk (which doesn't exist)
|
|
22
|
+
// so the build fails. We tell Vite/Rollup to use `index.html` even
|
|
23
|
+
// though it doesn't exist on the disk.
|
|
24
|
+
input: INDEX_HTML_FILE_NAME,
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
},
|
|
29
|
+
configResolved(config) {
|
|
30
|
+
virtualFiles = resolveVirtualFiles(config.root);
|
|
31
|
+
},
|
|
32
|
+
resolveId: (id) => virtualFiles.ids.get(id),
|
|
33
|
+
load(id) {
|
|
34
|
+
const loader = virtualFiles.loaders.get(id);
|
|
35
|
+
return loader?.();
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { Plugin } from "vite";
|
|
2
|
+
import { getIndexHtmlContent } from "../../virtual-files/index.js";
|
|
3
|
+
|
|
4
|
+
export function waspHtmlDev(): Plugin {
|
|
5
|
+
return {
|
|
6
|
+
name: "wasp:html-dev",
|
|
7
|
+
apply: "serve",
|
|
8
|
+
configureServer(server) {
|
|
9
|
+
return () => {
|
|
10
|
+
// Post middleware: runs after Vite's built-in SPA fallback
|
|
11
|
+
// middleware which resolves routes to `/index.html` which
|
|
12
|
+
// we pick up here and return the virtual `index.html` content.
|
|
13
|
+
server.middlewares.use(async (req, res, next) => {
|
|
14
|
+
if (req.url === "/" || req.url === `/index.html`) {
|
|
15
|
+
try {
|
|
16
|
+
const html = getIndexHtmlContent();
|
|
17
|
+
const transformedHtml = await server.transformIndexHtml(
|
|
18
|
+
req.url,
|
|
19
|
+
html
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
res.setHeader("Content-Type", "text/html");
|
|
23
|
+
res.end(transformedHtml);
|
|
24
|
+
return;
|
|
25
|
+
} catch (e) {
|
|
26
|
+
return next(e);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
next();
|
|
31
|
+
});
|
|
32
|
+
};
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { type Plugin } from 'vite'
|
|
2
|
+
import { spawn } from 'node:child_process'
|
|
3
|
+
|
|
4
|
+
export function typescriptCheck(): Plugin {
|
|
5
|
+
return {
|
|
6
|
+
name: 'wasp:typescript-check',
|
|
7
|
+
apply: 'build',
|
|
8
|
+
async buildStart() {
|
|
9
|
+
await runTsc()
|
|
10
|
+
},
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function runTsc(): Promise<void> {
|
|
15
|
+
return new Promise((resolve, reject) => {
|
|
16
|
+
const child = spawn(
|
|
17
|
+
'tsc',
|
|
18
|
+
['--build', '--noEmit'],
|
|
19
|
+
{
|
|
20
|
+
stdio: 'inherit',
|
|
21
|
+
shell: process.platform === 'win32',
|
|
22
|
+
}
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
child.once('error', reject)
|
|
26
|
+
child.once('close', (code) =>
|
|
27
|
+
code === 0
|
|
28
|
+
? resolve()
|
|
29
|
+
: reject(new Error(`TypeScript check failed (exit ${code})`))
|
|
30
|
+
)
|
|
31
|
+
})
|
|
32
|
+
}
|
package/data/Generator/templates/{react-app/vite → sdk/wasp/client/vite/plugins}/validateEnv.ts
RENAMED
|
@@ -1,20 +1,30 @@
|
|
|
1
|
-
import { type Plugin
|
|
1
|
+
import { type Plugin } from 'vite'
|
|
2
2
|
|
|
3
|
+
import { loadEnvVars } from './envFile.js'
|
|
3
4
|
import {
|
|
4
5
|
getValidatedEnvOrError,
|
|
5
6
|
formatZodEnvErrors,
|
|
6
|
-
} from '
|
|
7
|
-
import { clientEnvSchema } from '
|
|
8
|
-
import { getColorizedConsoleFormatString } from '
|
|
7
|
+
} from '../../../env/validation.js'
|
|
8
|
+
import { clientEnvSchema } from '../../env/schema.js'
|
|
9
|
+
import { getColorizedConsoleFormatString } from '../../../universal/ansiColors.js'
|
|
9
10
|
|
|
10
11
|
const redColorFormatString = getColorizedConsoleFormatString('red');
|
|
11
12
|
|
|
12
13
|
export function validateEnv(): Plugin {
|
|
13
14
|
let validationResult: ReturnType<typeof getValidatedEnvOrError> | null = null
|
|
14
15
|
return {
|
|
15
|
-
name: 'wasp
|
|
16
|
-
configResolved
|
|
17
|
-
const env =
|
|
16
|
+
name: 'wasp:validate-env',
|
|
17
|
+
async configResolved(config) {
|
|
18
|
+
const env = await loadEnvVars({
|
|
19
|
+
rootDir: config.root,
|
|
20
|
+
// We are sure that `envPrefix` is defined because
|
|
21
|
+
// we defined it in an earlier plugin.
|
|
22
|
+
envPrefix: config.envPrefix!,
|
|
23
|
+
// We load the env file variables only in development,
|
|
24
|
+
// when building for production, users are expected to
|
|
25
|
+
// provide the environment variables inline.
|
|
26
|
+
loadDotEnvFile: config.command === 'serve',
|
|
27
|
+
})
|
|
18
28
|
validationResult = getValidatedEnvOrError(env, clientEnvSchema)
|
|
19
29
|
|
|
20
30
|
// Exit if we are in build mode, because we can't show the error in the browser.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{{={= =}=}}
|
|
2
|
+
import { type Plugin } from "vite";
|
|
3
|
+
import {
|
|
4
|
+
getIndexTsxContent,
|
|
5
|
+
getRoutesTsxContent,
|
|
6
|
+
} from "../virtual-files/index.js";
|
|
7
|
+
import { makeVirtualFilesResolver, type VirtualFiles } from "../virtual-files/resolver.js";
|
|
8
|
+
|
|
9
|
+
const resolveVirtualFiles = makeVirtualFilesResolver([
|
|
10
|
+
{ id: "{= clientEntryPointPath =}", load: getIndexTsxContent },
|
|
11
|
+
{ id: "{= routesEntryPointPath =}", load: getRoutesTsxContent },
|
|
12
|
+
]);
|
|
13
|
+
|
|
14
|
+
export function waspVirtualModules(): Plugin {
|
|
15
|
+
let virtualFiles!: VirtualFiles;
|
|
16
|
+
|
|
17
|
+
return {
|
|
18
|
+
name: "wasp:virtual-modules",
|
|
19
|
+
enforce: "pre",
|
|
20
|
+
configResolved(config) {
|
|
21
|
+
virtualFiles = resolveVirtualFiles(config.root);
|
|
22
|
+
},
|
|
23
|
+
resolveId: (id) => virtualFiles.ids.get(id),
|
|
24
|
+
load(id) {
|
|
25
|
+
const loader = virtualFiles.loaders.get(id);
|
|
26
|
+
return loader?.();
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { type PluginOption } from "vite";
|
|
2
|
+
import react, { type Options as ReactOptions } from "@vitejs/plugin-react";
|
|
3
|
+
import { validateEnv } from "./validateEnv.js";
|
|
4
|
+
import { envFile } from "./envFile.js";
|
|
5
|
+
import { detectServerImports } from "./detectServerImports.js";
|
|
6
|
+
import { waspVirtualModules } from "./virtualModules.js";
|
|
7
|
+
import { waspHtmlDev } from "./html/dev.js";
|
|
8
|
+
import { waspHtmlBuild } from "./html/build.js";
|
|
9
|
+
import { typescriptCheck } from "./typescriptCheck.js";
|
|
10
|
+
import { waspConfig } from "./waspConfig.js";
|
|
11
|
+
|
|
12
|
+
export interface WaspPluginOptions {
|
|
13
|
+
reactOptions?: ReactOptions;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function wasp(options?: WaspPluginOptions): PluginOption {
|
|
17
|
+
return [
|
|
18
|
+
/**
|
|
19
|
+
* Plugins running before core plugins (enforce: 'pre').
|
|
20
|
+
*/
|
|
21
|
+
// The `wasp:config` plugin must come first because
|
|
22
|
+
// other plugins may depend on its configuration.
|
|
23
|
+
waspConfig(),
|
|
24
|
+
waspVirtualModules(),
|
|
25
|
+
envFile(),
|
|
26
|
+
detectServerImports(),
|
|
27
|
+
/**
|
|
28
|
+
* Plugins running after core Vite plugins.
|
|
29
|
+
*/
|
|
30
|
+
typescriptCheck(),
|
|
31
|
+
waspHtmlDev(),
|
|
32
|
+
waspHtmlBuild(),
|
|
33
|
+
validateEnv(),
|
|
34
|
+
react(options?.reactOptions),
|
|
35
|
+
];
|
|
36
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{{={= =}=}}
|
|
2
|
+
import { type PluginOption, mergeConfig } from "vite";
|
|
3
|
+
import { defaultExclude } from "vitest/config"
|
|
4
|
+
|
|
5
|
+
export function waspConfig(): PluginOption {
|
|
6
|
+
return {
|
|
7
|
+
name: "wasp:config",
|
|
8
|
+
enforce: 'pre',
|
|
9
|
+
config(config) {
|
|
10
|
+
return mergeConfig({
|
|
11
|
+
base: "{= baseDir =}",
|
|
12
|
+
optimizeDeps: {
|
|
13
|
+
exclude: {=& depsExcludedFromOptimization =}
|
|
14
|
+
},
|
|
15
|
+
server: {
|
|
16
|
+
port: {= defaultClientPort =},
|
|
17
|
+
host: "0.0.0.0",
|
|
18
|
+
open: true,
|
|
19
|
+
},
|
|
20
|
+
envPrefix: "REACT_APP_",
|
|
21
|
+
build: {
|
|
22
|
+
outDir: "{= clientBuildDirPath =}",
|
|
23
|
+
},
|
|
24
|
+
resolve: {
|
|
25
|
+
// These packages rely on a single instance per page. Not deduping them
|
|
26
|
+
// causes runtime errors (e.g., hook rule violation in react, QueryClient
|
|
27
|
+
// instance error in react-query, Invariant Error in react-router).
|
|
28
|
+
dedupe: ["react", "react-dom", "@tanstack/react-query", "react-router"],
|
|
29
|
+
alias: [
|
|
30
|
+
{
|
|
31
|
+
// Vite doesn't look for `.prisma/client` imports in the `node_modules`
|
|
32
|
+
// folder. We point it to the correct place here.
|
|
33
|
+
// TODO: Check if we can remove when updating Prisma (#2504)
|
|
34
|
+
find: /^\.prisma\/client\/(.+)$/,
|
|
35
|
+
replacement: "node_modules/.prisma/client/$1.js",
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
// Handle bare .prisma/client import
|
|
39
|
+
find: /^\.prisma\/client$/,
|
|
40
|
+
replacement: "node_modules/.prisma/client",
|
|
41
|
+
},
|
|
42
|
+
],
|
|
43
|
+
},
|
|
44
|
+
test: {
|
|
45
|
+
globals: true,
|
|
46
|
+
environment: "jsdom",
|
|
47
|
+
setupFiles: {=& vitest.setupFilesArray =},
|
|
48
|
+
exclude: [
|
|
49
|
+
...defaultExclude,
|
|
50
|
+
"{= vitest.excludeWaspArtefactsPattern =}",
|
|
51
|
+
]
|
|
52
|
+
},
|
|
53
|
+
}, config);
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
}
|
package/data/Generator/templates/{react-app → sdk/wasp/client/vite/virtual-files/files}/index.html
RENAMED
|
@@ -7,7 +7,6 @@
|
|
|
7
7
|
name="viewport"
|
|
8
8
|
content="minimum-scale=1, initial-scale=1, width=device-width, shrink-to-fit=no"
|
|
9
9
|
/>
|
|
10
|
-
<link rel="manifest" href="/manifest.json" />
|
|
11
10
|
|
|
12
11
|
{=& head =}
|
|
13
12
|
|
|
@@ -17,6 +16,6 @@
|
|
|
17
16
|
<body>
|
|
18
17
|
<noscript>You need to enable JavaScript to run this app.</noscript>
|
|
19
18
|
<div id="root"></div>
|
|
20
|
-
<script type="module" src="
|
|
19
|
+
<script type="module" src="{= clientEntryPointPath =}"></script>
|
|
21
20
|
</body>
|
|
22
21
|
</html>
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{{={= =}=}}
|
|
2
|
+
// @ts-nocheck
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import * as ReactDOM from "react-dom/client";
|
|
5
|
+
import { getWaspApp } from "wasp/client/app";
|
|
6
|
+
{=!
|
|
7
|
+
// NOTE: We are not inlining routes mapping into this file becuase once we
|
|
8
|
+
// allow users to override the `index.tsx` entry point they can use the existing
|
|
9
|
+
// routes mapping.
|
|
10
|
+
=}
|
|
11
|
+
{=& routesMapping.importStatement =}
|
|
12
|
+
|
|
13
|
+
{=# rootComponent.isDefined =}
|
|
14
|
+
{=& rootComponent.importStatement =}
|
|
15
|
+
{=/ rootComponent.isDefined =}
|
|
16
|
+
|
|
17
|
+
{=# setupFn.isDefined =}
|
|
18
|
+
{=& setupFn.importStatement =}
|
|
19
|
+
{=/ setupFn.isDefined =}
|
|
20
|
+
|
|
21
|
+
{=# setupFn.isDefined =}
|
|
22
|
+
await {= setupFn.importIdentifier =}()
|
|
23
|
+
{=/ setupFn.isDefined =}
|
|
24
|
+
|
|
25
|
+
const app = getWaspApp({
|
|
26
|
+
{=# rootComponent.isDefined =}
|
|
27
|
+
rootElement: <{= rootComponent.importIdentifier =} />,
|
|
28
|
+
{=/ rootComponent.isDefined =}
|
|
29
|
+
routesMapping: {= routesMapping.importIdentifier =},
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
ReactDOM.createRoot(document.getElementById("root")!).render(
|
|
33
|
+
<React.StrictMode>{app}</React.StrictMode>,
|
|
34
|
+
);
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{{={= =}=}}
|
|
2
|
+
// @ts-nocheck
|
|
3
|
+
{=# isAuthEnabled =}
|
|
4
|
+
import { createAuthRequiredPage } from "wasp/client/app"
|
|
5
|
+
{=/ isAuthEnabled =}
|
|
6
|
+
|
|
7
|
+
// These files are used from user-land and the import paths below are relative to the
|
|
8
|
+
// user's project dir, and not the SDK:
|
|
9
|
+
{=# pagesToImport =}
|
|
10
|
+
{=& importStatement =}
|
|
11
|
+
{=/ pagesToImport =}
|
|
12
|
+
|
|
13
|
+
export const routesMapping = {
|
|
14
|
+
{=# routes =}
|
|
15
|
+
{= name =}: {= targetComponent =},
|
|
16
|
+
{=/ routes =}
|
|
17
|
+
} as const;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
|
|
3
|
+
export function getIndexTsxContent(): string {
|
|
4
|
+
return getFileContentFromRelativePath("./files/index.tsx");
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export function getRoutesTsxContent(): string {
|
|
8
|
+
return getFileContentFromRelativePath("./files/routes.tsx");
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function getIndexHtmlContent(): string {
|
|
12
|
+
return getFileContentFromRelativePath("./files/index.html");
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function getFileContentFromRelativePath(relativePath: string): string {
|
|
16
|
+
return fs.readFileSync(
|
|
17
|
+
new URL(relativePath, import.meta.url),
|
|
18
|
+
"utf-8"
|
|
19
|
+
);
|
|
20
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import * as path from "node:path";
|
|
2
|
+
|
|
3
|
+
export type VirtualFiles = {
|
|
4
|
+
ids: ReadonlyMap<string, string>;
|
|
5
|
+
loaders: ReadonlyMap<string, () => Promise<string> | string>;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
type VirtualFilesDefinition = {
|
|
9
|
+
id: string;
|
|
10
|
+
load: () => Promise<string> | string;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export const makeVirtualFilesResolver =
|
|
14
|
+
(files: VirtualFilesDefinition[]) =>
|
|
15
|
+
(rootPath: string): VirtualFiles => {
|
|
16
|
+
const filesWithAbsPath = files.map((d) => ({
|
|
17
|
+
...d,
|
|
18
|
+
absPath: path.resolve(rootPath, path.basename(d.id)),
|
|
19
|
+
}));
|
|
20
|
+
|
|
21
|
+
const ids = new Map(filesWithAbsPath.map((d) => [d.id, d.absPath]));
|
|
22
|
+
|
|
23
|
+
const loaders = new Map(
|
|
24
|
+
filesWithAbsPath.map((d) => [d.absPath, d.load]),
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
return { ids, loaders };
|
|
28
|
+
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{{={= =}=}}
|
|
2
2
|
{
|
|
3
|
-
"name": "
|
|
3
|
+
"name": "{= sdkPackageName =}",
|
|
4
4
|
"version": "1.0.0",
|
|
5
5
|
"private": true,
|
|
6
6
|
"type": "module",
|
|
@@ -64,8 +64,6 @@
|
|
|
64
64
|
{=! Used by our code, undocumented (but accessible) for users. =}
|
|
65
65
|
"./server/auth/email": "./dist/server/auth/email/index.js",
|
|
66
66
|
{=! Used by our code, undocumented (but accessible) for users. =}
|
|
67
|
-
"./client/test/*": "./dist/client/test/*.js",
|
|
68
|
-
{=! Used by our code, undocumented (but accessible) for users. =}
|
|
69
67
|
"./server/crud/*": "./dist/server/crud/*.js",
|
|
70
68
|
{=! Used by our code, undocumented (but accessible) for users. =}
|
|
71
69
|
"./server/email/core/types": "./dist/server/email/core/types.js",
|
|
@@ -113,14 +111,18 @@
|
|
|
113
111
|
"./server/operations": "./dist/server/operations/index.js",
|
|
114
112
|
"./client/router": "./dist/client/router/index.js",
|
|
115
113
|
"./client/test": "./dist/client/test/index.js",
|
|
114
|
+
"./client/test/setup": "./dist/client/test/setup.js",
|
|
116
115
|
"./client/hooks": "./dist/client/hooks.js",
|
|
117
116
|
"./client": "./dist/client/index.js",
|
|
118
|
-
"./dev": "./dist/dev/index.js",
|
|
119
117
|
"./env": "./dist/env/index.js",
|
|
120
118
|
{=! Private: [client] =}
|
|
121
119
|
"./env/validation": "./dist/env/validation.js",
|
|
122
120
|
{=! Private: [client, sdk] =}
|
|
123
121
|
"./client/env/schema": "./dist/client/env/schema.js",
|
|
122
|
+
{=! Private: [client] =}
|
|
123
|
+
"./client/app": "./dist/client/app/index.jsx",
|
|
124
|
+
{=! Private: [client] =}
|
|
125
|
+
"./client/vite": "./dist/client/vite/index.js",
|
|
124
126
|
|
|
125
127
|
{=! todo(filip): Fixes below are for type errors in 0.13.1, remove ASAP =}
|
|
126
128
|
{=! Used by our code (SDK for full-stack type safety), undocumented (but accessible) for users. =}
|
|
@@ -1,14 +1,74 @@
|
|
|
1
1
|
import * as fs from "node:fs/promises"
|
|
2
2
|
import * as path from "node:path"
|
|
3
3
|
|
|
4
|
-
const base = path.resolve(import.meta.dirname, "..")
|
|
4
|
+
const base = path.resolve(import.meta.dirname, "..")
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
await copyAssets([
|
|
7
|
+
"./auth/forms/**/*.css",
|
|
8
|
+
"./client/app/components/**/*.css",
|
|
9
|
+
"./client/vite/virtual-files/files/**/*.*",
|
|
10
|
+
])
|
|
7
11
|
|
|
8
|
-
|
|
9
|
-
const
|
|
10
|
-
const
|
|
12
|
+
async function copyAssets(globs) {
|
|
13
|
+
const sourceFiles = await Array.fromAsync(fs.glob(globs, { cwd: base }))
|
|
14
|
+
const { copied, skipped } = await copyChangedFiles(sourceFiles)
|
|
15
|
+
console.log(`[copy-assets] ${copied} copied, ${skipped} skipped`)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
async function copyChangedFiles(sourceFiles) {
|
|
19
|
+
let copied = 0
|
|
20
|
+
let skipped = 0
|
|
21
|
+
|
|
22
|
+
for (const file of sourceFiles) {
|
|
23
|
+
const sourcePath = getSourcePath(file)
|
|
24
|
+
const destPath = getDestinationPath(file)
|
|
25
|
+
try {
|
|
26
|
+
if (await shouldCopyFile(sourcePath, destPath)) {
|
|
27
|
+
await copyFile(sourcePath, destPath)
|
|
28
|
+
copied++
|
|
29
|
+
} else {
|
|
30
|
+
skipped++
|
|
31
|
+
}
|
|
32
|
+
} catch (error) {
|
|
33
|
+
console.error(`[copy-assets] Error processing ${file}:`, error.message)
|
|
34
|
+
throw error
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return { copied, skipped }
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* File should be copied if:
|
|
43
|
+
* - It doesn't exist in the destination directory.
|
|
44
|
+
* - Its modification time is newer than the destination file.
|
|
45
|
+
*
|
|
46
|
+
* We want to avoid needless copying of files to avoid triggering
|
|
47
|
+
* Vite's file watcher which can cause full page reloads when not
|
|
48
|
+
* necessary.
|
|
49
|
+
*/
|
|
50
|
+
async function shouldCopyFile(sourcePath, destPath) {
|
|
51
|
+
try {
|
|
52
|
+
const [sourceStat, destStat] = await Promise.all([
|
|
53
|
+
fs.stat(sourcePath),
|
|
54
|
+
fs.stat(destPath),
|
|
55
|
+
])
|
|
56
|
+
return sourceStat.mtimeMs > destStat.mtimeMs
|
|
57
|
+
} catch {
|
|
58
|
+
// Most likely the destination doesn't exist, so we should copy the file.
|
|
59
|
+
return true
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
async function copyFile(sourcePath, destPath) {
|
|
64
|
+
await fs.mkdir(path.dirname(destPath), { recursive: true })
|
|
65
|
+
await fs.copyFile(sourcePath, destPath)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function getSourcePath(file) {
|
|
69
|
+
return path.join(base, file)
|
|
70
|
+
}
|
|
11
71
|
|
|
12
|
-
|
|
13
|
-
|
|
72
|
+
function getDestinationPath(file) {
|
|
73
|
+
return path.join(base, "dist", file)
|
|
14
74
|
}
|
|
@@ -184,5 +184,8 @@ export type OAuthData = {
|
|
|
184
184
|
{=# enabledProviders.isKeycloakAuthEnabled =}
|
|
185
185
|
| { providerName: 'keycloak'; tokens: import('arctic').KeycloakTokens }
|
|
186
186
|
{=/ enabledProviders.isKeycloakAuthEnabled =}
|
|
187
|
+
{=# enabledProviders.isMicrosoftAuthEnabled =}
|
|
188
|
+
| { providerName: 'microsoft'; tokens: import('arctic').MicrosoftEntraIdTokens }
|
|
189
|
+
{=/ enabledProviders.isMicrosoftAuthEnabled =}
|
|
187
190
|
| never
|
|
188
191
|
)
|
|
@@ -22,6 +22,10 @@ export { github } from './providers/github.js';
|
|
|
22
22
|
// PUBLIC API
|
|
23
23
|
export { keycloak } from './providers/keycloak.js';
|
|
24
24
|
{=/ enabledProviders.isKeycloakAuthEnabled =}
|
|
25
|
+
{=# enabledProviders.isMicrosoftAuthEnabled =}
|
|
26
|
+
// PUBLIC API
|
|
27
|
+
export { microsoft } from './providers/microsoft.js';
|
|
28
|
+
{=/ enabledProviders.isMicrosoftAuthEnabled =}
|
|
25
29
|
|
|
26
30
|
// PRIVATE API
|
|
27
31
|
export {
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{{={= =}=}}
|
|
2
|
+
import { MicrosoftEntraId } from 'arctic';
|
|
3
|
+
|
|
4
|
+
import { getRedirectUriForCallback } from '../redirect.js';
|
|
5
|
+
import { defineProvider } from '../provider.js';
|
|
6
|
+
import { env } from '../../../env.js';
|
|
7
|
+
|
|
8
|
+
const id = '{= providerId =}';
|
|
9
|
+
const displayName = '{= displayName =}';
|
|
10
|
+
|
|
11
|
+
const oAuthClient = new MicrosoftEntraId(
|
|
12
|
+
env.MICROSOFT_TENANT_ID,
|
|
13
|
+
env.MICROSOFT_CLIENT_ID,
|
|
14
|
+
env.MICROSOFT_CLIENT_SECRET,
|
|
15
|
+
getRedirectUriForCallback(id).toString(),
|
|
16
|
+
);
|
|
17
|
+
|
|
18
|
+
// PUBLIC API
|
|
19
|
+
export const microsoft = defineProvider({
|
|
20
|
+
id,
|
|
21
|
+
displayName,
|
|
22
|
+
oAuthClient,
|
|
23
|
+
});
|