alepha 0.15.2 → 0.15.4
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/README.md +68 -80
- package/dist/api/audits/index.d.ts.map +1 -1
- package/dist/api/audits/index.js +8 -0
- package/dist/api/audits/index.js.map +1 -1
- package/dist/api/files/index.d.ts +170 -170
- package/dist/api/files/index.d.ts.map +1 -1
- package/dist/api/files/index.js +1 -0
- package/dist/api/files/index.js.map +1 -1
- package/dist/api/jobs/index.d.ts.map +1 -1
- package/dist/api/jobs/index.js +3 -0
- package/dist/api/jobs/index.js.map +1 -1
- package/dist/api/notifications/index.browser.js +1 -0
- package/dist/api/notifications/index.browser.js.map +1 -1
- package/dist/api/notifications/index.js +1 -0
- package/dist/api/notifications/index.js.map +1 -1
- package/dist/api/parameters/index.d.ts +260 -260
- package/dist/api/parameters/index.d.ts.map +1 -1
- package/dist/api/parameters/index.js +10 -0
- package/dist/api/parameters/index.js.map +1 -1
- package/dist/api/users/index.d.ts +12 -1
- package/dist/api/users/index.d.ts.map +1 -1
- package/dist/api/users/index.js +18 -2
- package/dist/api/users/index.js.map +1 -1
- package/dist/batch/index.d.ts +4 -4
- package/dist/bucket/index.d.ts +8 -0
- package/dist/bucket/index.d.ts.map +1 -1
- package/dist/bucket/index.js +7 -2
- package/dist/bucket/index.js.map +1 -1
- package/dist/cli/index.d.ts +196 -74
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +234 -50
- package/dist/cli/index.js.map +1 -1
- package/dist/command/index.d.ts +10 -0
- package/dist/command/index.d.ts.map +1 -1
- package/dist/command/index.js +67 -13
- package/dist/command/index.js.map +1 -1
- package/dist/core/index.browser.js +28 -21
- package/dist/core/index.browser.js.map +1 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +28 -21
- package/dist/core/index.js.map +1 -1
- package/dist/core/index.native.js +28 -21
- package/dist/core/index.native.js.map +1 -1
- package/dist/email/index.d.ts +21 -13
- package/dist/email/index.d.ts.map +1 -1
- package/dist/email/index.js +10561 -4
- package/dist/email/index.js.map +1 -1
- package/dist/lock/core/index.d.ts +6 -1
- package/dist/lock/core/index.d.ts.map +1 -1
- package/dist/lock/core/index.js +9 -1
- package/dist/lock/core/index.js.map +1 -1
- package/dist/mcp/index.d.ts +5 -5
- package/dist/orm/index.bun.js +32 -16
- package/dist/orm/index.bun.js.map +1 -1
- package/dist/orm/index.d.ts +4 -1
- package/dist/orm/index.d.ts.map +1 -1
- package/dist/orm/index.js +34 -22
- package/dist/orm/index.js.map +1 -1
- package/dist/react/auth/index.browser.js +2 -1
- package/dist/react/auth/index.browser.js.map +1 -1
- package/dist/react/auth/index.js +2 -1
- package/dist/react/auth/index.js.map +1 -1
- package/dist/react/core/index.d.ts +3 -3
- package/dist/react/router/index.browser.js +9 -15
- package/dist/react/router/index.browser.js.map +1 -1
- package/dist/react/router/index.d.ts +305 -407
- package/dist/react/router/index.d.ts.map +1 -1
- package/dist/react/router/index.js +581 -781
- package/dist/react/router/index.js.map +1 -1
- package/dist/scheduler/index.d.ts +13 -1
- package/dist/scheduler/index.d.ts.map +1 -1
- package/dist/scheduler/index.js +42 -4
- package/dist/scheduler/index.js.map +1 -1
- package/dist/security/index.d.ts +42 -42
- package/dist/security/index.d.ts.map +1 -1
- package/dist/security/index.js +8 -7
- package/dist/security/index.js.map +1 -1
- package/dist/server/auth/index.d.ts +167 -167
- package/dist/server/compress/index.d.ts.map +1 -1
- package/dist/server/compress/index.js +1 -0
- package/dist/server/compress/index.js.map +1 -1
- package/dist/server/health/index.d.ts +17 -17
- package/dist/server/links/index.d.ts +39 -39
- package/dist/server/links/index.js +1 -1
- package/dist/server/links/index.js.map +1 -1
- package/dist/server/static/index.js +7 -2
- package/dist/server/static/index.js.map +1 -1
- package/dist/server/swagger/index.d.ts +8 -0
- package/dist/server/swagger/index.d.ts.map +1 -1
- package/dist/server/swagger/index.js +7 -2
- package/dist/server/swagger/index.js.map +1 -1
- package/dist/sms/index.d.ts +8 -0
- package/dist/sms/index.d.ts.map +1 -1
- package/dist/sms/index.js +7 -2
- package/dist/sms/index.js.map +1 -1
- package/dist/system/index.browser.js +734 -12
- package/dist/system/index.browser.js.map +1 -1
- package/dist/system/index.d.ts +8 -0
- package/dist/system/index.d.ts.map +1 -1
- package/dist/system/index.js +7 -2
- package/dist/system/index.js.map +1 -1
- package/dist/vite/index.d.ts +3 -2
- package/dist/vite/index.d.ts.map +1 -1
- package/dist/vite/index.js +42 -8
- package/dist/vite/index.js.map +1 -1
- package/dist/websocket/index.d.ts +34 -34
- package/dist/websocket/index.d.ts.map +1 -1
- package/package.json +9 -4
- package/src/api/audits/controllers/AdminAuditController.ts +8 -0
- package/src/api/files/controllers/AdminFileStatsController.ts +1 -0
- package/src/api/jobs/controllers/AdminJobController.ts +3 -0
- package/src/api/logs/TODO.md +13 -10
- package/src/api/notifications/controllers/AdminNotificationController.ts +1 -0
- package/src/api/parameters/controllers/AdminConfigController.ts +10 -0
- package/src/api/users/controllers/AdminIdentityController.ts +3 -0
- package/src/api/users/controllers/AdminSessionController.ts +3 -0
- package/src/api/users/controllers/AdminUserController.ts +5 -0
- package/src/cli/apps/AlephaPackageBuilderCli.ts +9 -0
- package/src/cli/atoms/buildOptions.ts +99 -9
- package/src/cli/commands/build.ts +150 -32
- package/src/cli/commands/db.ts +5 -7
- package/src/cli/commands/init.spec.ts +50 -6
- package/src/cli/commands/init.ts +28 -5
- package/src/cli/providers/ViteDevServerProvider.ts +31 -9
- package/src/cli/services/AlephaCliUtils.ts +16 -0
- package/src/cli/services/PackageManagerUtils.ts +2 -0
- package/src/cli/services/ProjectScaffolder.spec.ts +97 -0
- package/src/cli/services/ProjectScaffolder.ts +28 -6
- package/src/cli/templates/agentMd.ts +6 -1
- package/src/cli/templates/apiAppSecurityTs.ts +11 -0
- package/src/cli/templates/apiIndexTs.ts +18 -4
- package/src/cli/templates/webAppRouterTs.ts +25 -1
- package/src/cli/templates/webHelloComponentTsx.ts +15 -5
- package/src/command/helpers/Runner.spec.ts +135 -0
- package/src/command/helpers/Runner.ts +4 -1
- package/src/command/providers/CliProvider.spec.ts +325 -0
- package/src/command/providers/CliProvider.ts +117 -7
- package/src/core/Alepha.ts +32 -25
- package/src/email/index.workerd.ts +36 -0
- package/src/email/providers/WorkermailerEmailProvider.ts +221 -0
- package/src/lock/core/primitives/$lock.ts +13 -1
- package/src/orm/index.bun.ts +1 -1
- package/src/orm/index.ts +2 -6
- package/src/orm/providers/drivers/BunSqliteProvider.ts +4 -1
- package/src/orm/providers/drivers/CloudflareD1Provider.ts +57 -30
- package/src/orm/providers/drivers/DatabaseProvider.ts +9 -1
- package/src/orm/providers/drivers/NodeSqliteProvider.ts +4 -1
- package/src/react/auth/services/ReactAuth.ts +3 -1
- package/src/react/router/atoms/ssrManifestAtom.ts +7 -0
- package/src/react/router/hooks/useActive.ts +1 -1
- package/src/react/router/hooks/useRouter.ts +1 -1
- package/src/react/router/index.ts +4 -0
- package/src/react/router/primitives/$page.browser.spec.tsx +24 -24
- package/src/react/router/primitives/$page.spec.tsx +0 -32
- package/src/react/router/primitives/$page.ts +6 -14
- package/src/react/router/providers/ReactBrowserProvider.ts +6 -3
- package/src/react/router/providers/ReactPageProvider.ts +1 -1
- package/src/react/router/providers/ReactPreloadProvider.spec.ts +142 -0
- package/src/react/router/providers/ReactPreloadProvider.ts +85 -0
- package/src/react/router/providers/ReactServerProvider.ts +21 -82
- package/src/react/router/providers/ReactServerTemplateProvider.spec.ts +210 -0
- package/src/react/router/providers/ReactServerTemplateProvider.ts +228 -665
- package/src/react/router/providers/SSRManifestProvider.ts +7 -0
- package/src/react/router/services/ReactRouter.ts +13 -13
- package/src/scheduler/index.workerd.ts +43 -0
- package/src/scheduler/providers/CronProvider.ts +53 -6
- package/src/scheduler/providers/WorkerdCronProvider.ts +102 -0
- package/src/security/__tests__/ServerSecurityProvider.spec.ts +77 -0
- package/src/security/providers/ServerSecurityProvider.ts +30 -22
- package/src/server/compress/providers/ServerCompressProvider.ts +6 -0
- package/src/server/core/providers/NodeHttpServerProvider.spec.ts +9 -3
- package/src/server/links/providers/ServerLinksProvider.spec.ts +332 -0
- package/src/server/links/providers/ServerLinksProvider.ts +1 -1
- package/src/system/index.browser.ts +25 -0
- package/src/system/index.workerd.ts +1 -0
- package/src/system/providers/FileSystemProvider.ts +8 -0
- package/src/system/providers/NodeFileSystemProvider.ts +11 -2
- package/src/vite/tasks/buildServer.ts +2 -12
- package/src/vite/tasks/generateCloudflare.ts +47 -8
- package/src/vite/tasks/generateDocker.ts +4 -0
package/dist/cli/index.js
CHANGED
|
@@ -1370,8 +1370,13 @@ var NodeFileSystemProvider = class {
|
|
|
1370
1370
|
* await fs.mkdir("/tmp/mydir", { mode: 0o755 });
|
|
1371
1371
|
* ```
|
|
1372
1372
|
*/
|
|
1373
|
-
async mkdir(path, options) {
|
|
1374
|
-
|
|
1373
|
+
async mkdir(path, options = {}) {
|
|
1374
|
+
const p = mkdir(path, {
|
|
1375
|
+
recursive: options.recursive ?? true,
|
|
1376
|
+
mode: options.mode
|
|
1377
|
+
});
|
|
1378
|
+
if (options.force === false) await p;
|
|
1379
|
+
else await p.catch(() => {});
|
|
1375
1380
|
}
|
|
1376
1381
|
/**
|
|
1377
1382
|
* Lists files in a directory.
|
|
@@ -1912,13 +1917,24 @@ $atom$1[KIND] = "atom";
|
|
|
1912
1917
|
* Build options atom for CLI build command.
|
|
1913
1918
|
*
|
|
1914
1919
|
* Defines the available build configuration options with their defaults.
|
|
1915
|
-
* Options can be overridden via
|
|
1920
|
+
* Options can be overridden via alepha.config.ts or CLI flags.
|
|
1916
1921
|
*/
|
|
1917
1922
|
const buildOptions = $atom$1({
|
|
1918
1923
|
name: "alepha.cli.build.options",
|
|
1919
1924
|
description: "Build configuration options",
|
|
1920
1925
|
schema: t.object({
|
|
1921
1926
|
stats: t.optional(t.boolean({ default: false })),
|
|
1927
|
+
target: t.optional(t.enum([
|
|
1928
|
+
"bare",
|
|
1929
|
+
"docker",
|
|
1930
|
+
"vercel",
|
|
1931
|
+
"cloudflare"
|
|
1932
|
+
])),
|
|
1933
|
+
runtime: t.optional(t.enum([
|
|
1934
|
+
"node",
|
|
1935
|
+
"bun",
|
|
1936
|
+
"workerd"
|
|
1937
|
+
])),
|
|
1922
1938
|
vercel: t.optional(t.object({
|
|
1923
1939
|
projectName: t.optional(t.string()),
|
|
1924
1940
|
orgId: t.optional(t.string()),
|
|
@@ -1930,8 +1946,13 @@ const buildOptions = $atom$1({
|
|
|
1930
1946
|
})),
|
|
1931
1947
|
cloudflare: t.optional(t.object({ config: t.optional(t.json()) })),
|
|
1932
1948
|
docker: t.optional(t.object({
|
|
1933
|
-
|
|
1934
|
-
command: t.optional(t.string(
|
|
1949
|
+
from: t.optional(t.string()),
|
|
1950
|
+
command: t.optional(t.string()),
|
|
1951
|
+
image: t.optional(t.object({
|
|
1952
|
+
tag: t.string(),
|
|
1953
|
+
args: t.optional(t.string()),
|
|
1954
|
+
oci: t.optional(t.boolean())
|
|
1955
|
+
}))
|
|
1935
1956
|
})),
|
|
1936
1957
|
sitemap: t.optional(t.object({ hostname: t.string() }))
|
|
1937
1958
|
}),
|
|
@@ -2205,6 +2226,18 @@ ${models.map((it) => `export const ${it} = models["${it}"];`).join("\n")}
|
|
|
2205
2226
|
isInstalledAsync(cmd) {
|
|
2206
2227
|
return this.shell.isInstalled(cmd);
|
|
2207
2228
|
}
|
|
2229
|
+
/**
|
|
2230
|
+
* Get the current git revision (commit SHA).
|
|
2231
|
+
*
|
|
2232
|
+
* @returns The short commit SHA or "unknown" if not in a git repo
|
|
2233
|
+
*/
|
|
2234
|
+
async getGitRevision() {
|
|
2235
|
+
try {
|
|
2236
|
+
return (await this.shell.run("git rev-parse --short HEAD", { capture: true })).trim();
|
|
2237
|
+
} catch {
|
|
2238
|
+
return "unknown";
|
|
2239
|
+
}
|
|
2240
|
+
}
|
|
2208
2241
|
};
|
|
2209
2242
|
|
|
2210
2243
|
//#endregion
|
|
@@ -2220,16 +2253,19 @@ var devDependencies = {
|
|
|
2220
2253
|
"@types/react": "^19.2.10",
|
|
2221
2254
|
"@types/react-dom": "^19.2.3",
|
|
2222
2255
|
"@types/ws": "^8.18.1",
|
|
2256
|
+
"@vitejs/plugin-react": "^5.1.2",
|
|
2223
2257
|
"cron-schedule": "^6.0.0",
|
|
2224
2258
|
"jose": "^6.1.3",
|
|
2225
2259
|
"jsdom": "^27.4.0",
|
|
2260
|
+
"nodemailer": "^7.0.13",
|
|
2226
2261
|
"openid-client": "^6.8.1",
|
|
2227
2262
|
"prom-client": "^15.1.3",
|
|
2228
2263
|
"react": "^19.2.4",
|
|
2229
2264
|
"react-dom": "^19.2.4",
|
|
2230
2265
|
"swagger-ui-dist": "^5.31.0",
|
|
2231
2266
|
"tsdown": "^0.20.1",
|
|
2232
|
-
"vitest": "^4.0.18"
|
|
2267
|
+
"vitest": "^4.0.18",
|
|
2268
|
+
"worker-mailer": "^1.2.1"
|
|
2233
2269
|
};
|
|
2234
2270
|
|
|
2235
2271
|
//#endregion
|
|
@@ -2477,6 +2513,7 @@ var PackageManagerUtils = class {
|
|
|
2477
2513
|
if (modes.react) {
|
|
2478
2514
|
dependencies.react = alephaDeps.react;
|
|
2479
2515
|
dependencies["react-dom"] = alephaDeps["react-dom"];
|
|
2516
|
+
devDependencies$1["@vitejs/plugin-react"] = alephaDeps["@vitejs/plugin-react"];
|
|
2480
2517
|
devDependencies$1["@types/react"] = alephaDeps["@types/react"];
|
|
2481
2518
|
}
|
|
2482
2519
|
return {
|
|
@@ -2783,7 +2820,26 @@ alepha build # Build the project
|
|
|
2783
2820
|
## Source Code Access
|
|
2784
2821
|
|
|
2785
2822
|
Full framework source available at \`node_modules/alepha/src/\`.
|
|
2786
|
-
|
|
2823
|
+
|
|
2824
|
+
**IMPORTANT:** When answering questions about Alepha primitives, APIs, or internals:
|
|
2825
|
+
1. ALWAYS read the local source code first at \`node_modules/alepha/src/\` or \`node_modules/@alepha/ui/src/\` for UI-related questions
|
|
2826
|
+
2. Use \`Glob\` to find relevant files: \`node_modules/alepha/src/**/primitives/$<name>.ts\`
|
|
2827
|
+
3. Read the implementation AND the \`.spec.ts\` test files for usage examples
|
|
2828
|
+
4. Use external documentation as a fallback if source code is insufficient
|
|
2829
|
+
`.trim();
|
|
2830
|
+
};
|
|
2831
|
+
|
|
2832
|
+
//#endregion
|
|
2833
|
+
//#region ../../src/cli/templates/apiAppSecurityTs.ts
|
|
2834
|
+
const apiAppSecurityTs = () => {
|
|
2835
|
+
return `
|
|
2836
|
+
import { $realm } from "alepha/api/users";
|
|
2837
|
+
|
|
2838
|
+
export class AppSecurity {
|
|
2839
|
+
users = $realm({
|
|
2840
|
+
// configure your realm here
|
|
2841
|
+
});
|
|
2842
|
+
}
|
|
2787
2843
|
`.trim();
|
|
2788
2844
|
};
|
|
2789
2845
|
|
|
@@ -2811,14 +2867,21 @@ export class HelloController {
|
|
|
2811
2867
|
//#endregion
|
|
2812
2868
|
//#region ../../src/cli/templates/apiIndexTs.ts
|
|
2813
2869
|
const apiIndexTs = (options = {}) => {
|
|
2814
|
-
const { appName = "app" } = options;
|
|
2870
|
+
const { appName = "app", auth = false } = options;
|
|
2871
|
+
const imports = ["import { $module } from \"alepha\";"];
|
|
2872
|
+
const services = [];
|
|
2873
|
+
if (auth) {
|
|
2874
|
+
imports.push("import { AppSecurity } from \"./AppSecurity.ts\";");
|
|
2875
|
+
services.push("AppSecurity");
|
|
2876
|
+
}
|
|
2877
|
+
imports.push("import { HelloController } from \"./controllers/HelloController.ts\";");
|
|
2878
|
+
services.push("HelloController");
|
|
2815
2879
|
return `
|
|
2816
|
-
|
|
2817
|
-
import { HelloController } from "./controllers/HelloController.ts";
|
|
2880
|
+
${imports.join("\n")}
|
|
2818
2881
|
|
|
2819
2882
|
export const ApiModule = $module({
|
|
2820
2883
|
name: "${appName}.api",
|
|
2821
|
-
services: [
|
|
2884
|
+
services: [${services.join(", ")}],
|
|
2822
2885
|
});
|
|
2823
2886
|
`.trim();
|
|
2824
2887
|
};
|
|
@@ -3006,6 +3069,8 @@ const webAppRouterTs = (options) => {
|
|
|
3006
3069
|
const imports = [];
|
|
3007
3070
|
const classMembers = [];
|
|
3008
3071
|
if (options.ui) imports.push("import { $ui } from \"@alepha/ui\";");
|
|
3072
|
+
if (options.auth) imports.push("import { $uiAuth } from \"@alepha/ui/auth\";");
|
|
3073
|
+
if (options.admin) imports.push("import { $uiAdmin } from \"@alepha/ui/admin\";");
|
|
3009
3074
|
imports.push("import { $page } from \"alepha/react/router\";");
|
|
3010
3075
|
if (options.api) {
|
|
3011
3076
|
imports.push("import { $client } from \"alepha/server/links\";");
|
|
@@ -3014,6 +3079,8 @@ const webAppRouterTs = (options) => {
|
|
|
3014
3079
|
}
|
|
3015
3080
|
if (options.ui) {
|
|
3016
3081
|
classMembers.push(" ui = $ui();");
|
|
3082
|
+
if (options.auth) classMembers.push(" uiAuth = $uiAuth();");
|
|
3083
|
+
if (options.admin) classMembers.push(" uiAdmin = $uiAdmin();");
|
|
3017
3084
|
classMembers.push(` layout = $page({
|
|
3018
3085
|
parent: this.ui.root,
|
|
3019
3086
|
children: () => [this.home],
|
|
@@ -3037,7 +3104,12 @@ ${classMembers.join("\n\n")}
|
|
|
3037
3104
|
|
|
3038
3105
|
//#endregion
|
|
3039
3106
|
//#region ../../src/cli/templates/webHelloComponentTsx.ts
|
|
3040
|
-
const webHelloComponentTsx = (
|
|
3107
|
+
const webHelloComponentTsx = (options = {}) => {
|
|
3108
|
+
const imports = [];
|
|
3109
|
+
if (options.auth) imports.push("import { UserButton } from \"@alepha/ui/auth\";");
|
|
3110
|
+
imports.push("import { useState } from \"react\";");
|
|
3111
|
+
const userButton = options.auth ? "\n <UserButton />" : "";
|
|
3112
|
+
return `${imports.join("\n")}
|
|
3041
3113
|
|
|
3042
3114
|
interface Props {
|
|
3043
3115
|
message?: string;
|
|
@@ -3048,14 +3120,15 @@ const Hello = (props: Props) => {
|
|
|
3048
3120
|
return (
|
|
3049
3121
|
<div>
|
|
3050
3122
|
<h1>{message}</h1>
|
|
3051
|
-
<input value={message} onChange={e => setMessage(e.target.value)} />
|
|
3052
|
-
<p>Edit this component in src/web/components/Hello.tsx</p
|
|
3123
|
+
<input value={message} onChange={(e) => setMessage(e.target.value)} />
|
|
3124
|
+
<p>Edit this component in src/web/components/Hello.tsx</p>${userButton}
|
|
3053
3125
|
</div>
|
|
3054
3126
|
);
|
|
3055
3127
|
};
|
|
3056
3128
|
|
|
3057
3129
|
export default Hello;
|
|
3058
|
-
|
|
3130
|
+
`;
|
|
3131
|
+
};
|
|
3059
3132
|
|
|
3060
3133
|
//#endregion
|
|
3061
3134
|
//#region ../../src/cli/templates/webIndexTs.ts
|
|
@@ -3097,7 +3170,7 @@ var ProjectScaffolder = class {
|
|
|
3097
3170
|
* - Falls back to "app" if empty
|
|
3098
3171
|
*/
|
|
3099
3172
|
getAppName(root) {
|
|
3100
|
-
return basename(root).toLowerCase().replace(/[\s\-_]/g, "") || "app";
|
|
3173
|
+
return basename(root).toLowerCase().replace(/[\s\-_.\d]/g, "") || "app";
|
|
3101
3174
|
}
|
|
3102
3175
|
/**
|
|
3103
3176
|
* Ensure all configuration files exist.
|
|
@@ -3175,8 +3248,12 @@ var ProjectScaffolder = class {
|
|
|
3175
3248
|
async ensureApiProject(root, opts = {}) {
|
|
3176
3249
|
const appName = this.getAppName(root);
|
|
3177
3250
|
await this.fs.mkdir(this.fs.join(root, "src/api/controllers"), { recursive: true });
|
|
3178
|
-
await this.ensureFile(root, "src/api/index.ts", apiIndexTs({
|
|
3251
|
+
await this.ensureFile(root, "src/api/index.ts", apiIndexTs({
|
|
3252
|
+
appName,
|
|
3253
|
+
auth: opts.auth
|
|
3254
|
+
}), opts.force);
|
|
3179
3255
|
await this.ensureFile(root, "src/api/controllers/HelloController.ts", apiHelloControllerTs(), opts.force);
|
|
3256
|
+
if (opts.auth) await this.ensureFile(root, "src/api/AppSecurity.ts", apiAppSecurityTs(), opts.force);
|
|
3180
3257
|
}
|
|
3181
3258
|
/**
|
|
3182
3259
|
* Ensure web/React project structure exists.
|
|
@@ -3193,9 +3270,11 @@ var ProjectScaffolder = class {
|
|
|
3193
3270
|
await this.ensureFile(root, "src/web/index.ts", webIndexTs({ appName }), opts.force);
|
|
3194
3271
|
await this.ensureFile(root, "src/web/AppRouter.ts", webAppRouterTs({
|
|
3195
3272
|
api: opts.api,
|
|
3196
|
-
ui: opts.ui
|
|
3273
|
+
ui: opts.ui,
|
|
3274
|
+
auth: opts.auth,
|
|
3275
|
+
admin: opts.admin
|
|
3197
3276
|
}), opts.force);
|
|
3198
|
-
await this.ensureFile(root, "src/web/components/Hello.tsx", webHelloComponentTsx(), opts.force);
|
|
3277
|
+
await this.ensureFile(root, "src/web/components/Hello.tsx", webHelloComponentTsx({ auth: opts.auth }), opts.force);
|
|
3199
3278
|
await this.ensureFile(root, "src/main.browser.ts", mainBrowserTs(), opts.force);
|
|
3200
3279
|
}
|
|
3201
3280
|
/**
|
|
@@ -3243,17 +3322,55 @@ var BuildCommand = class {
|
|
|
3243
3322
|
boot = $inject(AppEntryProvider);
|
|
3244
3323
|
viteBuildProvider = $inject(ViteBuildProvider);
|
|
3245
3324
|
options = $use(buildOptions);
|
|
3325
|
+
/**
|
|
3326
|
+
* Resolve the effective runtime based on target and explicit runtime flag.
|
|
3327
|
+
*
|
|
3328
|
+
* Some targets force a specific runtime:
|
|
3329
|
+
* - `cloudflare` always uses `workerd`
|
|
3330
|
+
* - `vercel` always uses `node`
|
|
3331
|
+
* - `docker` and bare deployments respect the runtime flag
|
|
3332
|
+
*
|
|
3333
|
+
* @throws {AlephaError} If an incompatible runtime is specified for a target
|
|
3334
|
+
*/
|
|
3335
|
+
resolveRuntime(target, runtime) {
|
|
3336
|
+
if (target === "cloudflare") {
|
|
3337
|
+
if (runtime && runtime !== "workerd") throw new AlephaError(`Target 'cloudflare' requires 'workerd' runtime, got '${runtime}'`);
|
|
3338
|
+
return "workerd";
|
|
3339
|
+
}
|
|
3340
|
+
if (target === "vercel") {
|
|
3341
|
+
if (runtime && runtime !== "node") throw new AlephaError(`Target 'vercel' requires 'node' runtime, got '${runtime}'`);
|
|
3342
|
+
return "node";
|
|
3343
|
+
}
|
|
3344
|
+
return runtime ?? "node";
|
|
3345
|
+
}
|
|
3246
3346
|
build = $command({
|
|
3247
3347
|
name: "build",
|
|
3248
3348
|
mode: "production",
|
|
3249
3349
|
description: "Build the project for production",
|
|
3250
3350
|
flags: t.object({
|
|
3251
3351
|
stats: t.optional(t.boolean({ description: "Generate build stats report" })),
|
|
3252
|
-
|
|
3253
|
-
|
|
3254
|
-
|
|
3255
|
-
|
|
3256
|
-
|
|
3352
|
+
target: t.optional(t.enum([
|
|
3353
|
+
"bare",
|
|
3354
|
+
"docker",
|
|
3355
|
+
"vercel",
|
|
3356
|
+
"cloudflare"
|
|
3357
|
+
], {
|
|
3358
|
+
aliases: ["t"],
|
|
3359
|
+
description: "Deployment target"
|
|
3360
|
+
})),
|
|
3361
|
+
runtime: t.optional(t.enum([
|
|
3362
|
+
"node",
|
|
3363
|
+
"bun",
|
|
3364
|
+
"workerd"
|
|
3365
|
+
], {
|
|
3366
|
+
aliases: ["r"],
|
|
3367
|
+
description: "JavaScript runtime"
|
|
3368
|
+
})),
|
|
3369
|
+
image: t.optional(t.union([t.boolean(), t.text()], {
|
|
3370
|
+
aliases: ["i"],
|
|
3371
|
+
description: "Build Docker image. Use -i for latest, -i=<version> for specific version"
|
|
3372
|
+
})),
|
|
3373
|
+
sitemap: t.optional(t.text({ description: "Generate sitemap.xml with base URL" }))
|
|
3257
3374
|
}),
|
|
3258
3375
|
handler: async ({ flags, run, root }) => {
|
|
3259
3376
|
process.env.NODE_ENV = "production";
|
|
@@ -3266,6 +3383,13 @@ var BuildCommand = class {
|
|
|
3266
3383
|
await run.rm("dist", { alias: "clean dist" });
|
|
3267
3384
|
const options = this.options;
|
|
3268
3385
|
await this.utils.loadEnv(root, [".env", ".env.production"]);
|
|
3386
|
+
const target = flags.target ?? options.target;
|
|
3387
|
+
const runtime = this.resolveRuntime(target, flags.runtime ?? options.runtime);
|
|
3388
|
+
if (flags.image && target !== "docker") throw new AlephaError(`Flag '--image' requires '--target=docker', got '${target ?? "bare"}'`);
|
|
3389
|
+
this.log.trace("Build configuration", {
|
|
3390
|
+
target,
|
|
3391
|
+
runtime
|
|
3392
|
+
});
|
|
3269
3393
|
const stats = flags.stats ?? options.stats ?? false;
|
|
3270
3394
|
let template = "";
|
|
3271
3395
|
let hasClient = false;
|
|
@@ -3303,8 +3427,8 @@ var BuildCommand = class {
|
|
|
3303
3427
|
const clientIndexPath = `${distDir}/${publicDir}/index.html`;
|
|
3304
3428
|
const clientBuilt = await this.fs.exists(clientIndexPath);
|
|
3305
3429
|
const conditions = [];
|
|
3306
|
-
if (
|
|
3307
|
-
if (
|
|
3430
|
+
if (runtime === "bun") conditions.push("bun");
|
|
3431
|
+
else if (runtime === "workerd") conditions.push("workerd");
|
|
3308
3432
|
await buildServer({
|
|
3309
3433
|
silent: true,
|
|
3310
3434
|
entry: entry.server,
|
|
@@ -3339,7 +3463,7 @@ var BuildCommand = class {
|
|
|
3339
3463
|
run
|
|
3340
3464
|
});
|
|
3341
3465
|
}
|
|
3342
|
-
if (
|
|
3466
|
+
if (target === "vercel") await run({
|
|
3343
3467
|
name: "add Vercel config",
|
|
3344
3468
|
handler: () => generateVercel({
|
|
3345
3469
|
distDir,
|
|
@@ -3347,20 +3471,57 @@ var BuildCommand = class {
|
|
|
3347
3471
|
config: options.vercel
|
|
3348
3472
|
})
|
|
3349
3473
|
});
|
|
3350
|
-
if (
|
|
3474
|
+
if (target === "cloudflare") await run({
|
|
3351
3475
|
name: "add Cloudflare config",
|
|
3352
3476
|
handler: () => generateCloudflare({
|
|
3353
3477
|
distDir,
|
|
3354
|
-
config: options.cloudflare?.config
|
|
3355
|
-
|
|
3356
|
-
});
|
|
3357
|
-
if (flags.docker || options.docker) await run({
|
|
3358
|
-
name: "add Docker config",
|
|
3359
|
-
handler: () => generateDocker({
|
|
3360
|
-
distDir,
|
|
3361
|
-
...options.docker
|
|
3478
|
+
config: options.cloudflare?.config,
|
|
3479
|
+
alepha
|
|
3362
3480
|
})
|
|
3363
3481
|
});
|
|
3482
|
+
if (target === "docker") {
|
|
3483
|
+
const dockerFrom = options.docker?.from ?? (runtime === "bun" ? "oven/bun:alpine" : "node:24-alpine");
|
|
3484
|
+
const dockerCommand = options.docker?.command ?? (runtime === "bun" ? "bun" : "node");
|
|
3485
|
+
await run({
|
|
3486
|
+
name: "add Docker config",
|
|
3487
|
+
handler: () => generateDocker({
|
|
3488
|
+
distDir,
|
|
3489
|
+
image: dockerFrom,
|
|
3490
|
+
command: dockerCommand
|
|
3491
|
+
})
|
|
3492
|
+
});
|
|
3493
|
+
if (flags.image) {
|
|
3494
|
+
const imageConfig = options.docker?.image;
|
|
3495
|
+
const flagValue = typeof flags.image === "string" ? flags.image : null;
|
|
3496
|
+
let imageTag;
|
|
3497
|
+
let version;
|
|
3498
|
+
if (!flagValue) {
|
|
3499
|
+
if (!imageConfig?.tag) throw new AlephaError("Flag '--image' requires 'build.docker.image.tag' in config");
|
|
3500
|
+
version = "latest";
|
|
3501
|
+
imageTag = `${imageConfig.tag}:${version}`;
|
|
3502
|
+
} else if (flagValue.startsWith(":")) {
|
|
3503
|
+
if (!imageConfig?.tag) throw new AlephaError("Flag '--image=:version' requires 'build.docker.image.tag' in config");
|
|
3504
|
+
version = flagValue.slice(1);
|
|
3505
|
+
imageTag = `${imageConfig.tag}:${version}`;
|
|
3506
|
+
} else if (flagValue.includes(":")) {
|
|
3507
|
+
imageTag = flagValue;
|
|
3508
|
+
version = flagValue.split(":")[1];
|
|
3509
|
+
} else {
|
|
3510
|
+
imageTag = `${flagValue}:latest`;
|
|
3511
|
+
version = "latest";
|
|
3512
|
+
}
|
|
3513
|
+
const args = [];
|
|
3514
|
+
if (imageConfig?.args) args.push(imageConfig.args);
|
|
3515
|
+
if (imageConfig?.oci) {
|
|
3516
|
+
const revision = await this.utils.getGitRevision();
|
|
3517
|
+
const created = (/* @__PURE__ */ new Date()).toISOString();
|
|
3518
|
+
args.push(`--label "org.opencontainers.image.revision=${revision}"`);
|
|
3519
|
+
args.push(`--label "org.opencontainers.image.created=${created}"`);
|
|
3520
|
+
args.push(`--label "org.opencontainers.image.version=${version}"`);
|
|
3521
|
+
}
|
|
3522
|
+
await run(`docker build ${args.length > 0 ? `${args.join(" ")} ` : ""}-t ${imageTag} ${distDir}`, { alias: `docker build ${imageTag}` });
|
|
3523
|
+
}
|
|
3524
|
+
}
|
|
3364
3525
|
}
|
|
3365
3526
|
});
|
|
3366
3527
|
};
|
|
@@ -3629,9 +3790,9 @@ var DbCommand = class {
|
|
|
3629
3790
|
const accountId = process.env.CLOUDFLARE_ACCOUNT_ID;
|
|
3630
3791
|
if (!accountId) throw new AlephaError("CLOUDFLARE_ACCOUNT_ID environment variable is not set. https://orm.drizzle.team/docs/guides/d1-http-with-drizzle-kit");
|
|
3631
3792
|
const url = options.providerUrl;
|
|
3632
|
-
if (!url.startsWith("
|
|
3633
|
-
const [, databaseId] = url.replace("
|
|
3634
|
-
if (!databaseId) throw new AlephaError("Database ID is missing in the D1 provider URL. Cloudflare D1 URL format:
|
|
3793
|
+
if (!url.startsWith("d1://")) throw new AlephaError("D1 provider URL must start with 'd1://'.");
|
|
3794
|
+
const [, databaseId] = url.replace("d1://", "").replace("d1:", "").split(":");
|
|
3795
|
+
if (!databaseId) throw new AlephaError("Database ID is missing in the D1 provider URL. Cloudflare D1 URL format: d1://<database_name>:<database_id>");
|
|
3635
3796
|
config.dbCredentials = {
|
|
3636
3797
|
accountId,
|
|
3637
3798
|
databaseId,
|
|
@@ -3763,7 +3924,6 @@ var DeployCommand = class {
|
|
|
3763
3924
|
var ViteDevServerProvider = class {
|
|
3764
3925
|
log = $logger();
|
|
3765
3926
|
fs = $inject(FileSystemProvider);
|
|
3766
|
-
templateProvider = $inject(ViteUtils);
|
|
3767
3927
|
server;
|
|
3768
3928
|
options;
|
|
3769
3929
|
alepha = null;
|
|
@@ -3905,12 +4065,12 @@ var ViteDevServerProvider = class {
|
|
|
3905
4065
|
}
|
|
3906
4066
|
}
|
|
3907
4067
|
/**
|
|
3908
|
-
* Setup Alepha instance with Vite middleware
|
|
4068
|
+
* Setup Alepha instance with Vite middleware.
|
|
3909
4069
|
*/
|
|
3910
4070
|
async setupAlepha() {
|
|
3911
4071
|
if (!this.alepha || !this.hasReact()) return;
|
|
3912
|
-
const
|
|
3913
|
-
this.alepha.store.set("alepha.react.
|
|
4072
|
+
const devHead = await this.generateDevHead();
|
|
4073
|
+
this.alepha.store.set("alepha.react.ssr.manifest", { devHead });
|
|
3914
4074
|
this.alepha.events.on("server:onRequest", {
|
|
3915
4075
|
priority: "first",
|
|
3916
4076
|
callback: async ({ request }) => {
|
|
@@ -3924,6 +4084,18 @@ var ViteDevServerProvider = class {
|
|
|
3924
4084
|
});
|
|
3925
4085
|
}
|
|
3926
4086
|
/**
|
|
4087
|
+
* Generate dev head content by transforming a minimal HTML through Vite.
|
|
4088
|
+
* This lets Vite and all plugins inject their scripts (HMR client, React Fast Refresh, etc.).
|
|
4089
|
+
*/
|
|
4090
|
+
async generateDevHead() {
|
|
4091
|
+
const { browser, style } = this.options.entry;
|
|
4092
|
+
const scripts = [];
|
|
4093
|
+
if (style) scripts.push(`<link rel="stylesheet" href="/${style}">`);
|
|
4094
|
+
if (browser) scripts.push(`<script type="module" src="/${browser}"><\/script>`);
|
|
4095
|
+
const minimalHtml = `<!DOCTYPE html><html><head>${scripts.join("\n")}</head><body></body></html>`;
|
|
4096
|
+
return (await this.server.transformIndexHtml("/", minimalHtml)).match(/<head>([\s\S]*?)<\/head>/i)?.[1]?.trim() ?? "";
|
|
4097
|
+
}
|
|
4098
|
+
/**
|
|
3927
4099
|
* Check if request is for an HTML page (not an asset).
|
|
3928
4100
|
*/
|
|
3929
4101
|
isPageRequest(req) {
|
|
@@ -4350,10 +4522,7 @@ var InitCommand = class {
|
|
|
4350
4522
|
lowercase: true
|
|
4351
4523
|
})),
|
|
4352
4524
|
flags: t.object({
|
|
4353
|
-
|
|
4354
|
-
aliases: ["a"],
|
|
4355
|
-
description: "Add AI agent instructions (CLAUDE.md if claude CLI installed, else AGENTS.md)"
|
|
4356
|
-
})),
|
|
4525
|
+
ai: t.optional(t.boolean({ description: "Add AI agent instructions (CLAUDE.md if claude CLI installed, else AGENTS.md)" })),
|
|
4357
4526
|
pm: t.optional(t.enum([
|
|
4358
4527
|
"yarn",
|
|
4359
4528
|
"npm",
|
|
@@ -4366,6 +4535,8 @@ var InitCommand = class {
|
|
|
4366
4535
|
description: "Include React dependencies and web module (src/web/)"
|
|
4367
4536
|
})),
|
|
4368
4537
|
ui: t.optional(t.boolean({ description: "Include @alepha/ui (components, auth portal, admin portal)" })),
|
|
4538
|
+
auth: t.optional(t.boolean({ description: "Include authentication (AppSecurity, $uiAuth). Implies --api --ui --react" })),
|
|
4539
|
+
admin: t.optional(t.boolean({ description: "Include admin portal ($uiAdmin). Implies --auth" })),
|
|
4369
4540
|
test: t.optional(t.boolean({ description: "Include Vitest and create test directory" })),
|
|
4370
4541
|
force: t.optional(t.boolean({
|
|
4371
4542
|
aliases: ["f"],
|
|
@@ -4375,12 +4546,17 @@ var InitCommand = class {
|
|
|
4375
4546
|
handler: async ({ run, flags, root, args }) => {
|
|
4376
4547
|
if (args) {
|
|
4377
4548
|
root = this.fs.join(root, args);
|
|
4378
|
-
await this.fs.mkdir(root);
|
|
4549
|
+
await this.fs.mkdir(root, { force: true });
|
|
4550
|
+
}
|
|
4551
|
+
if (flags.admin) flags.auth = true;
|
|
4552
|
+
if (flags.auth) {
|
|
4553
|
+
flags.api = true;
|
|
4554
|
+
flags.ui = true;
|
|
4379
4555
|
}
|
|
4380
4556
|
if (flags.ui) flags.react = true;
|
|
4381
4557
|
const workspace = await this.pm.getWorkspaceContext(root);
|
|
4382
4558
|
let agentType = false;
|
|
4383
|
-
if (flags.
|
|
4559
|
+
if (flags.ai) agentType = await this.utils.isInstalledAsync("claude") ? "claude" : "agents";
|
|
4384
4560
|
const isExpo = await this.pm.hasExpo(root);
|
|
4385
4561
|
const force = !!flags.force;
|
|
4386
4562
|
await run({
|
|
@@ -4406,10 +4582,15 @@ var InitCommand = class {
|
|
|
4406
4582
|
react: !!flags.react && !isExpo,
|
|
4407
4583
|
force
|
|
4408
4584
|
});
|
|
4409
|
-
if (flags.api) await this.scaffolder.ensureApiProject(root, {
|
|
4585
|
+
if (flags.api) await this.scaffolder.ensureApiProject(root, {
|
|
4586
|
+
auth: !!flags.auth,
|
|
4587
|
+
force
|
|
4588
|
+
});
|
|
4410
4589
|
if (flags.react && !isExpo) await this.scaffolder.ensureWebProject(root, {
|
|
4411
4590
|
api: !!flags.api,
|
|
4412
4591
|
ui: !!flags.ui,
|
|
4592
|
+
auth: !!flags.auth,
|
|
4593
|
+
admin: !!flags.admin,
|
|
4413
4594
|
force
|
|
4414
4595
|
});
|
|
4415
4596
|
}
|
|
@@ -4648,6 +4829,7 @@ var AlephaPackageBuilderCli = class {
|
|
|
4648
4829
|
pkgData.exports[path].types = `./src/${item.name}/index.ts`;
|
|
4649
4830
|
if (item.native) pkgData.exports[path]["react-native"] = `./src/${item.name}/index.native.ts`;
|
|
4650
4831
|
else if (item.browser) pkgData.exports[path]["react-native"] = `./src/${item.name}/index.browser.ts`;
|
|
4832
|
+
if (item.workerd) pkgData.exports[path].workerd = `./src/${item.name}/index.workerd.ts`;
|
|
4651
4833
|
if (item.browser) pkgData.exports[path].browser = `./src/${item.name}/index.browser.ts`;
|
|
4652
4834
|
if (item.bun) pkgData.exports[path].bun = `./src/${item.name}/index.bun.ts`;
|
|
4653
4835
|
pkgData.exports[path].import = `./src/${item.name}/index.ts`;
|
|
@@ -4804,6 +4986,7 @@ async function analyzeModules(srcDir, packageName) {
|
|
|
4804
4986
|
const hasNative = await fileExists(join(modulePath, "index.native.ts"));
|
|
4805
4987
|
const hasBun = await fileExists(join(modulePath, "index.bun.ts"));
|
|
4806
4988
|
const hasNode = await fileExists(join(modulePath, "index.node.ts"));
|
|
4989
|
+
const hasEdge = await fileExists(join(modulePath, "index.workerd.ts"));
|
|
4807
4990
|
const files = await getAllFiles(modulePath);
|
|
4808
4991
|
for (const file of files) {
|
|
4809
4992
|
const deps = extractAlephaDependencies(await readFile(file, "utf-8"), packageName, moduleName);
|
|
@@ -4818,6 +5001,7 @@ async function analyzeModules(srcDir, packageName) {
|
|
|
4818
5001
|
dependencies: Array.from(dependencies)
|
|
4819
5002
|
};
|
|
4820
5003
|
if (hasNative) module.native = true;
|
|
5004
|
+
if (hasEdge) module.workerd = true;
|
|
4821
5005
|
if (hasBrowser) module.browser = true;
|
|
4822
5006
|
if (hasBun) module.bun = true;
|
|
4823
5007
|
if (hasNode) module.node = true;
|