alepha 0.15.2 → 0.15.3
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 +332 -332
- package/dist/api/audits/index.d.ts.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/jobs/index.d.ts +151 -151
- package/dist/api/keys/index.d.ts +195 -195
- package/dist/api/keys/index.d.ts.map +1 -1
- package/dist/api/parameters/index.d.ts +260 -260
- package/dist/api/users/index.d.ts +22 -11
- package/dist/api/users/index.d.ts.map +1 -1
- package/dist/api/users/index.js +7 -2
- package/dist/api/users/index.js.map +1 -1
- package/dist/api/verifications/index.d.ts +128 -128
- package/dist/api/verifications/index.d.ts.map +1 -1
- 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 +191 -74
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +215 -48
- 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 +8 -0
- package/dist/email/index.d.ts.map +1 -1
- package/dist/email/index.js +7 -2
- package/dist/email/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/router/index.browser.js +9 -15
- package/dist/react/router/index.browser.js.map +1 -1
- package/dist/react/router/index.d.ts +295 -407
- package/dist/react/router/index.d.ts.map +1 -1
- package/dist/react/router/index.js +566 -776
- package/dist/react/router/index.js.map +1 -1
- package/dist/redis/index.d.ts +19 -19
- 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/core/index.d.ts +9 -9
- package/dist/server/health/index.d.ts +17 -17
- package/dist/server/links/index.d.ts +39 -39
- 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 +1 -1
- package/dist/vite/index.js +15 -7
- package/dist/vite/index.js.map +1 -1
- package/package.json +4 -2
- package/src/api/logs/TODO.md +13 -10
- package/src/cli/apps/AlephaPackageBuilderCli.ts +9 -0
- package/src/cli/atoms/buildOptions.ts +99 -9
- package/src/cli/commands/build.ts +149 -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 +1 -10
- 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/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/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 +7 -78
- package/src/react/router/providers/ReactServerTemplateProvider.spec.ts +210 -0
- package/src/react/router/providers/ReactServerTemplateProvider.ts +228 -665
- package/src/react/router/services/ReactRouter.ts +13 -13
- package/src/security/__tests__/ServerSecurityProvider.spec.ts +77 -0
- package/src/security/providers/ServerSecurityProvider.ts +30 -22
- package/src/server/core/providers/NodeHttpServerProvider.spec.ts +9 -3
- 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 +10 -7
- 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,6 +2253,7 @@ 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",
|
|
@@ -2477,6 +2511,7 @@ var PackageManagerUtils = class {
|
|
|
2477
2511
|
if (modes.react) {
|
|
2478
2512
|
dependencies.react = alephaDeps.react;
|
|
2479
2513
|
dependencies["react-dom"] = alephaDeps["react-dom"];
|
|
2514
|
+
devDependencies$1["@vitejs/plugin-react"] = alephaDeps["@vitejs/plugin-react"];
|
|
2480
2515
|
devDependencies$1["@types/react"] = alephaDeps["@types/react"];
|
|
2481
2516
|
}
|
|
2482
2517
|
return {
|
|
@@ -2783,7 +2818,26 @@ alepha build # Build the project
|
|
|
2783
2818
|
## Source Code Access
|
|
2784
2819
|
|
|
2785
2820
|
Full framework source available at \`node_modules/alepha/src/\`.
|
|
2786
|
-
|
|
2821
|
+
|
|
2822
|
+
**IMPORTANT:** When answering questions about Alepha primitives, APIs, or internals:
|
|
2823
|
+
1. ALWAYS read the local source code first at \`node_modules/alepha/src/\` or \`node_modules/@alepha/ui/src/\` for UI-related questions
|
|
2824
|
+
2. Use \`Glob\` to find relevant files: \`node_modules/alepha/src/**/primitives/$<name>.ts\`
|
|
2825
|
+
3. Read the implementation AND the \`.spec.ts\` test files for usage examples
|
|
2826
|
+
4. Use external documentation as a fallback if source code is insufficient
|
|
2827
|
+
`.trim();
|
|
2828
|
+
};
|
|
2829
|
+
|
|
2830
|
+
//#endregion
|
|
2831
|
+
//#region ../../src/cli/templates/apiAppSecurityTs.ts
|
|
2832
|
+
const apiAppSecurityTs = () => {
|
|
2833
|
+
return `
|
|
2834
|
+
import { $realm } from "alepha/api/users";
|
|
2835
|
+
|
|
2836
|
+
export class AppSecurity {
|
|
2837
|
+
users = $realm({
|
|
2838
|
+
// configure your realm here
|
|
2839
|
+
});
|
|
2840
|
+
}
|
|
2787
2841
|
`.trim();
|
|
2788
2842
|
};
|
|
2789
2843
|
|
|
@@ -2811,14 +2865,21 @@ export class HelloController {
|
|
|
2811
2865
|
//#endregion
|
|
2812
2866
|
//#region ../../src/cli/templates/apiIndexTs.ts
|
|
2813
2867
|
const apiIndexTs = (options = {}) => {
|
|
2814
|
-
const { appName = "app" } = options;
|
|
2868
|
+
const { appName = "app", auth = false } = options;
|
|
2869
|
+
const imports = ["import { $module } from \"alepha\";"];
|
|
2870
|
+
const services = [];
|
|
2871
|
+
if (auth) {
|
|
2872
|
+
imports.push("import { AppSecurity } from \"./AppSecurity.ts\";");
|
|
2873
|
+
services.push("AppSecurity");
|
|
2874
|
+
}
|
|
2875
|
+
imports.push("import { HelloController } from \"./controllers/HelloController.ts\";");
|
|
2876
|
+
services.push("HelloController");
|
|
2815
2877
|
return `
|
|
2816
|
-
|
|
2817
|
-
import { HelloController } from "./controllers/HelloController.ts";
|
|
2878
|
+
${imports.join("\n")}
|
|
2818
2879
|
|
|
2819
2880
|
export const ApiModule = $module({
|
|
2820
2881
|
name: "${appName}.api",
|
|
2821
|
-
services: [
|
|
2882
|
+
services: [${services.join(", ")}],
|
|
2822
2883
|
});
|
|
2823
2884
|
`.trim();
|
|
2824
2885
|
};
|
|
@@ -3006,6 +3067,8 @@ const webAppRouterTs = (options) => {
|
|
|
3006
3067
|
const imports = [];
|
|
3007
3068
|
const classMembers = [];
|
|
3008
3069
|
if (options.ui) imports.push("import { $ui } from \"@alepha/ui\";");
|
|
3070
|
+
if (options.auth) imports.push("import { $uiAuth } from \"@alepha/ui/auth\";");
|
|
3071
|
+
if (options.admin) imports.push("import { $uiAdmin } from \"@alepha/ui/admin\";");
|
|
3009
3072
|
imports.push("import { $page } from \"alepha/react/router\";");
|
|
3010
3073
|
if (options.api) {
|
|
3011
3074
|
imports.push("import { $client } from \"alepha/server/links\";");
|
|
@@ -3014,6 +3077,8 @@ const webAppRouterTs = (options) => {
|
|
|
3014
3077
|
}
|
|
3015
3078
|
if (options.ui) {
|
|
3016
3079
|
classMembers.push(" ui = $ui();");
|
|
3080
|
+
if (options.auth) classMembers.push(" uiAuth = $uiAuth();");
|
|
3081
|
+
if (options.admin) classMembers.push(" uiAdmin = $uiAdmin();");
|
|
3017
3082
|
classMembers.push(` layout = $page({
|
|
3018
3083
|
parent: this.ui.root,
|
|
3019
3084
|
children: () => [this.home],
|
|
@@ -3037,7 +3102,12 @@ ${classMembers.join("\n\n")}
|
|
|
3037
3102
|
|
|
3038
3103
|
//#endregion
|
|
3039
3104
|
//#region ../../src/cli/templates/webHelloComponentTsx.ts
|
|
3040
|
-
const webHelloComponentTsx = (
|
|
3105
|
+
const webHelloComponentTsx = (options = {}) => {
|
|
3106
|
+
const imports = [];
|
|
3107
|
+
if (options.auth) imports.push("import { UserButton } from \"@alepha/ui/auth\";");
|
|
3108
|
+
imports.push("import { useState } from \"react\";");
|
|
3109
|
+
const userButton = options.auth ? "\n <UserButton />" : "";
|
|
3110
|
+
return `${imports.join("\n")}
|
|
3041
3111
|
|
|
3042
3112
|
interface Props {
|
|
3043
3113
|
message?: string;
|
|
@@ -3048,14 +3118,15 @@ const Hello = (props: Props) => {
|
|
|
3048
3118
|
return (
|
|
3049
3119
|
<div>
|
|
3050
3120
|
<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
|
|
3121
|
+
<input value={message} onChange={(e) => setMessage(e.target.value)} />
|
|
3122
|
+
<p>Edit this component in src/web/components/Hello.tsx</p>${userButton}
|
|
3053
3123
|
</div>
|
|
3054
3124
|
);
|
|
3055
3125
|
};
|
|
3056
3126
|
|
|
3057
3127
|
export default Hello;
|
|
3058
|
-
|
|
3128
|
+
`;
|
|
3129
|
+
};
|
|
3059
3130
|
|
|
3060
3131
|
//#endregion
|
|
3061
3132
|
//#region ../../src/cli/templates/webIndexTs.ts
|
|
@@ -3097,7 +3168,7 @@ var ProjectScaffolder = class {
|
|
|
3097
3168
|
* - Falls back to "app" if empty
|
|
3098
3169
|
*/
|
|
3099
3170
|
getAppName(root) {
|
|
3100
|
-
return basename(root).toLowerCase().replace(/[\s\-_]/g, "") || "app";
|
|
3171
|
+
return basename(root).toLowerCase().replace(/[\s\-_.\d]/g, "") || "app";
|
|
3101
3172
|
}
|
|
3102
3173
|
/**
|
|
3103
3174
|
* Ensure all configuration files exist.
|
|
@@ -3175,8 +3246,12 @@ var ProjectScaffolder = class {
|
|
|
3175
3246
|
async ensureApiProject(root, opts = {}) {
|
|
3176
3247
|
const appName = this.getAppName(root);
|
|
3177
3248
|
await this.fs.mkdir(this.fs.join(root, "src/api/controllers"), { recursive: true });
|
|
3178
|
-
await this.ensureFile(root, "src/api/index.ts", apiIndexTs({
|
|
3249
|
+
await this.ensureFile(root, "src/api/index.ts", apiIndexTs({
|
|
3250
|
+
appName,
|
|
3251
|
+
auth: opts.auth
|
|
3252
|
+
}), opts.force);
|
|
3179
3253
|
await this.ensureFile(root, "src/api/controllers/HelloController.ts", apiHelloControllerTs(), opts.force);
|
|
3254
|
+
if (opts.auth) await this.ensureFile(root, "src/api/AppSecurity.ts", apiAppSecurityTs(), opts.force);
|
|
3180
3255
|
}
|
|
3181
3256
|
/**
|
|
3182
3257
|
* Ensure web/React project structure exists.
|
|
@@ -3193,9 +3268,11 @@ var ProjectScaffolder = class {
|
|
|
3193
3268
|
await this.ensureFile(root, "src/web/index.ts", webIndexTs({ appName }), opts.force);
|
|
3194
3269
|
await this.ensureFile(root, "src/web/AppRouter.ts", webAppRouterTs({
|
|
3195
3270
|
api: opts.api,
|
|
3196
|
-
ui: opts.ui
|
|
3271
|
+
ui: opts.ui,
|
|
3272
|
+
auth: opts.auth,
|
|
3273
|
+
admin: opts.admin
|
|
3197
3274
|
}), opts.force);
|
|
3198
|
-
await this.ensureFile(root, "src/web/components/Hello.tsx", webHelloComponentTsx(), opts.force);
|
|
3275
|
+
await this.ensureFile(root, "src/web/components/Hello.tsx", webHelloComponentTsx({ auth: opts.auth }), opts.force);
|
|
3199
3276
|
await this.ensureFile(root, "src/main.browser.ts", mainBrowserTs(), opts.force);
|
|
3200
3277
|
}
|
|
3201
3278
|
/**
|
|
@@ -3243,17 +3320,55 @@ var BuildCommand = class {
|
|
|
3243
3320
|
boot = $inject(AppEntryProvider);
|
|
3244
3321
|
viteBuildProvider = $inject(ViteBuildProvider);
|
|
3245
3322
|
options = $use(buildOptions);
|
|
3323
|
+
/**
|
|
3324
|
+
* Resolve the effective runtime based on target and explicit runtime flag.
|
|
3325
|
+
*
|
|
3326
|
+
* Some targets force a specific runtime:
|
|
3327
|
+
* - `cloudflare` always uses `workerd`
|
|
3328
|
+
* - `vercel` always uses `node`
|
|
3329
|
+
* - `docker` and bare deployments respect the runtime flag
|
|
3330
|
+
*
|
|
3331
|
+
* @throws {AlephaError} If an incompatible runtime is specified for a target
|
|
3332
|
+
*/
|
|
3333
|
+
resolveRuntime(target, runtime) {
|
|
3334
|
+
if (target === "cloudflare") {
|
|
3335
|
+
if (runtime && runtime !== "workerd") throw new AlephaError(`Target 'cloudflare' requires 'workerd' runtime, got '${runtime}'`);
|
|
3336
|
+
return "workerd";
|
|
3337
|
+
}
|
|
3338
|
+
if (target === "vercel") {
|
|
3339
|
+
if (runtime && runtime !== "node") throw new AlephaError(`Target 'vercel' requires 'node' runtime, got '${runtime}'`);
|
|
3340
|
+
return "node";
|
|
3341
|
+
}
|
|
3342
|
+
return runtime ?? "node";
|
|
3343
|
+
}
|
|
3246
3344
|
build = $command({
|
|
3247
3345
|
name: "build",
|
|
3248
3346
|
mode: "production",
|
|
3249
3347
|
description: "Build the project for production",
|
|
3250
3348
|
flags: t.object({
|
|
3251
3349
|
stats: t.optional(t.boolean({ description: "Generate build stats report" })),
|
|
3252
|
-
|
|
3253
|
-
|
|
3254
|
-
|
|
3255
|
-
|
|
3256
|
-
|
|
3350
|
+
target: t.optional(t.enum([
|
|
3351
|
+
"bare",
|
|
3352
|
+
"docker",
|
|
3353
|
+
"vercel",
|
|
3354
|
+
"cloudflare"
|
|
3355
|
+
], {
|
|
3356
|
+
aliases: ["t"],
|
|
3357
|
+
description: "Deployment target"
|
|
3358
|
+
})),
|
|
3359
|
+
runtime: t.optional(t.enum([
|
|
3360
|
+
"node",
|
|
3361
|
+
"bun",
|
|
3362
|
+
"workerd"
|
|
3363
|
+
], {
|
|
3364
|
+
aliases: ["r"],
|
|
3365
|
+
description: "JavaScript runtime"
|
|
3366
|
+
})),
|
|
3367
|
+
image: t.optional(t.union([t.boolean(), t.text()], {
|
|
3368
|
+
aliases: ["i"],
|
|
3369
|
+
description: "Build Docker image. Use -i for latest, -i=<version> for specific version"
|
|
3370
|
+
})),
|
|
3371
|
+
sitemap: t.optional(t.text({ description: "Generate sitemap.xml with base URL" }))
|
|
3257
3372
|
}),
|
|
3258
3373
|
handler: async ({ flags, run, root }) => {
|
|
3259
3374
|
process.env.NODE_ENV = "production";
|
|
@@ -3266,6 +3381,13 @@ var BuildCommand = class {
|
|
|
3266
3381
|
await run.rm("dist", { alias: "clean dist" });
|
|
3267
3382
|
const options = this.options;
|
|
3268
3383
|
await this.utils.loadEnv(root, [".env", ".env.production"]);
|
|
3384
|
+
const target = flags.target ?? options.target;
|
|
3385
|
+
const runtime = this.resolveRuntime(target, flags.runtime ?? options.runtime);
|
|
3386
|
+
if (flags.image && target !== "docker") throw new AlephaError(`Flag '--image' requires '--target=docker', got '${target ?? "bare"}'`);
|
|
3387
|
+
this.log.trace("Build configuration", {
|
|
3388
|
+
target,
|
|
3389
|
+
runtime
|
|
3390
|
+
});
|
|
3269
3391
|
const stats = flags.stats ?? options.stats ?? false;
|
|
3270
3392
|
let template = "";
|
|
3271
3393
|
let hasClient = false;
|
|
@@ -3303,8 +3425,8 @@ var BuildCommand = class {
|
|
|
3303
3425
|
const clientIndexPath = `${distDir}/${publicDir}/index.html`;
|
|
3304
3426
|
const clientBuilt = await this.fs.exists(clientIndexPath);
|
|
3305
3427
|
const conditions = [];
|
|
3306
|
-
if (
|
|
3307
|
-
if (
|
|
3428
|
+
if (runtime === "bun") conditions.push("bun");
|
|
3429
|
+
else if (runtime === "workerd") conditions.push("workerd");
|
|
3308
3430
|
await buildServer({
|
|
3309
3431
|
silent: true,
|
|
3310
3432
|
entry: entry.server,
|
|
@@ -3339,7 +3461,7 @@ var BuildCommand = class {
|
|
|
3339
3461
|
run
|
|
3340
3462
|
});
|
|
3341
3463
|
}
|
|
3342
|
-
if (
|
|
3464
|
+
if (target === "vercel") await run({
|
|
3343
3465
|
name: "add Vercel config",
|
|
3344
3466
|
handler: () => generateVercel({
|
|
3345
3467
|
distDir,
|
|
@@ -3347,20 +3469,56 @@ var BuildCommand = class {
|
|
|
3347
3469
|
config: options.vercel
|
|
3348
3470
|
})
|
|
3349
3471
|
});
|
|
3350
|
-
if (
|
|
3472
|
+
if (target === "cloudflare") await run({
|
|
3351
3473
|
name: "add Cloudflare config",
|
|
3352
3474
|
handler: () => generateCloudflare({
|
|
3353
3475
|
distDir,
|
|
3354
3476
|
config: options.cloudflare?.config
|
|
3355
3477
|
})
|
|
3356
3478
|
});
|
|
3357
|
-
if (
|
|
3358
|
-
|
|
3359
|
-
|
|
3360
|
-
|
|
3361
|
-
|
|
3362
|
-
|
|
3363
|
-
|
|
3479
|
+
if (target === "docker") {
|
|
3480
|
+
const dockerFrom = options.docker?.from ?? (runtime === "bun" ? "oven/bun:alpine" : "node:24-alpine");
|
|
3481
|
+
const dockerCommand = options.docker?.command ?? (runtime === "bun" ? "bun" : "node");
|
|
3482
|
+
await run({
|
|
3483
|
+
name: "add Docker config",
|
|
3484
|
+
handler: () => generateDocker({
|
|
3485
|
+
distDir,
|
|
3486
|
+
image: dockerFrom,
|
|
3487
|
+
command: dockerCommand
|
|
3488
|
+
})
|
|
3489
|
+
});
|
|
3490
|
+
if (flags.image) {
|
|
3491
|
+
const imageConfig = options.docker?.image;
|
|
3492
|
+
const flagValue = typeof flags.image === "string" ? flags.image : null;
|
|
3493
|
+
let imageTag;
|
|
3494
|
+
let version;
|
|
3495
|
+
if (!flagValue) {
|
|
3496
|
+
if (!imageConfig?.tag) throw new AlephaError("Flag '--image' requires 'build.docker.image.tag' in config");
|
|
3497
|
+
version = "latest";
|
|
3498
|
+
imageTag = `${imageConfig.tag}:${version}`;
|
|
3499
|
+
} else if (flagValue.startsWith(":")) {
|
|
3500
|
+
if (!imageConfig?.tag) throw new AlephaError("Flag '--image=:version' requires 'build.docker.image.tag' in config");
|
|
3501
|
+
version = flagValue.slice(1);
|
|
3502
|
+
imageTag = `${imageConfig.tag}:${version}`;
|
|
3503
|
+
} else if (flagValue.includes(":")) {
|
|
3504
|
+
imageTag = flagValue;
|
|
3505
|
+
version = flagValue.split(":")[1];
|
|
3506
|
+
} else {
|
|
3507
|
+
imageTag = `${flagValue}:latest`;
|
|
3508
|
+
version = "latest";
|
|
3509
|
+
}
|
|
3510
|
+
const args = [];
|
|
3511
|
+
if (imageConfig?.args) args.push(imageConfig.args);
|
|
3512
|
+
if (imageConfig?.oci) {
|
|
3513
|
+
const revision = await this.utils.getGitRevision();
|
|
3514
|
+
const created = (/* @__PURE__ */ new Date()).toISOString();
|
|
3515
|
+
args.push(`--label "org.opencontainers.image.revision=${revision}"`);
|
|
3516
|
+
args.push(`--label "org.opencontainers.image.created=${created}"`);
|
|
3517
|
+
args.push(`--label "org.opencontainers.image.version=${version}"`);
|
|
3518
|
+
}
|
|
3519
|
+
await run(`docker build ${args.length > 0 ? `${args.join(" ")} ` : ""}-t ${imageTag} ${distDir}`, { alias: `docker build ${imageTag}` });
|
|
3520
|
+
}
|
|
3521
|
+
}
|
|
3364
3522
|
}
|
|
3365
3523
|
});
|
|
3366
3524
|
};
|
|
@@ -3629,9 +3787,9 @@ var DbCommand = class {
|
|
|
3629
3787
|
const accountId = process.env.CLOUDFLARE_ACCOUNT_ID;
|
|
3630
3788
|
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
3789
|
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:
|
|
3790
|
+
if (!url.startsWith("d1://")) throw new AlephaError("D1 provider URL must start with 'd1://'.");
|
|
3791
|
+
const [, databaseId] = url.replace("d1://", "").replace("d1:", "").split(":");
|
|
3792
|
+
if (!databaseId) throw new AlephaError("Database ID is missing in the D1 provider URL. Cloudflare D1 URL format: d1://<database_name>:<database_id>");
|
|
3635
3793
|
config.dbCredentials = {
|
|
3636
3794
|
accountId,
|
|
3637
3795
|
databaseId,
|
|
@@ -3763,7 +3921,6 @@ var DeployCommand = class {
|
|
|
3763
3921
|
var ViteDevServerProvider = class {
|
|
3764
3922
|
log = $logger();
|
|
3765
3923
|
fs = $inject(FileSystemProvider);
|
|
3766
|
-
templateProvider = $inject(ViteUtils);
|
|
3767
3924
|
server;
|
|
3768
3925
|
options;
|
|
3769
3926
|
alepha = null;
|
|
@@ -3905,12 +4062,10 @@ var ViteDevServerProvider = class {
|
|
|
3905
4062
|
}
|
|
3906
4063
|
}
|
|
3907
4064
|
/**
|
|
3908
|
-
* Setup Alepha instance with Vite middleware
|
|
4065
|
+
* Setup Alepha instance with Vite middleware.
|
|
3909
4066
|
*/
|
|
3910
4067
|
async setupAlepha() {
|
|
3911
4068
|
if (!this.alepha || !this.hasReact()) return;
|
|
3912
|
-
const template = await this.server.transformIndexHtml("/", this.templateProvider.generateIndexHtml(this.options.entry));
|
|
3913
|
-
this.alepha.store.set("alepha.react.server.template", template);
|
|
3914
4069
|
this.alepha.events.on("server:onRequest", {
|
|
3915
4070
|
priority: "first",
|
|
3916
4071
|
callback: async ({ request }) => {
|
|
@@ -4350,10 +4505,7 @@ var InitCommand = class {
|
|
|
4350
4505
|
lowercase: true
|
|
4351
4506
|
})),
|
|
4352
4507
|
flags: t.object({
|
|
4353
|
-
|
|
4354
|
-
aliases: ["a"],
|
|
4355
|
-
description: "Add AI agent instructions (CLAUDE.md if claude CLI installed, else AGENTS.md)"
|
|
4356
|
-
})),
|
|
4508
|
+
ai: t.optional(t.boolean({ description: "Add AI agent instructions (CLAUDE.md if claude CLI installed, else AGENTS.md)" })),
|
|
4357
4509
|
pm: t.optional(t.enum([
|
|
4358
4510
|
"yarn",
|
|
4359
4511
|
"npm",
|
|
@@ -4366,6 +4518,8 @@ var InitCommand = class {
|
|
|
4366
4518
|
description: "Include React dependencies and web module (src/web/)"
|
|
4367
4519
|
})),
|
|
4368
4520
|
ui: t.optional(t.boolean({ description: "Include @alepha/ui (components, auth portal, admin portal)" })),
|
|
4521
|
+
auth: t.optional(t.boolean({ description: "Include authentication (AppSecurity, $uiAuth). Implies --api --ui --react" })),
|
|
4522
|
+
admin: t.optional(t.boolean({ description: "Include admin portal ($uiAdmin). Implies --auth" })),
|
|
4369
4523
|
test: t.optional(t.boolean({ description: "Include Vitest and create test directory" })),
|
|
4370
4524
|
force: t.optional(t.boolean({
|
|
4371
4525
|
aliases: ["f"],
|
|
@@ -4375,12 +4529,17 @@ var InitCommand = class {
|
|
|
4375
4529
|
handler: async ({ run, flags, root, args }) => {
|
|
4376
4530
|
if (args) {
|
|
4377
4531
|
root = this.fs.join(root, args);
|
|
4378
|
-
await this.fs.mkdir(root);
|
|
4532
|
+
await this.fs.mkdir(root, { force: true });
|
|
4533
|
+
}
|
|
4534
|
+
if (flags.admin) flags.auth = true;
|
|
4535
|
+
if (flags.auth) {
|
|
4536
|
+
flags.api = true;
|
|
4537
|
+
flags.ui = true;
|
|
4379
4538
|
}
|
|
4380
4539
|
if (flags.ui) flags.react = true;
|
|
4381
4540
|
const workspace = await this.pm.getWorkspaceContext(root);
|
|
4382
4541
|
let agentType = false;
|
|
4383
|
-
if (flags.
|
|
4542
|
+
if (flags.ai) agentType = await this.utils.isInstalledAsync("claude") ? "claude" : "agents";
|
|
4384
4543
|
const isExpo = await this.pm.hasExpo(root);
|
|
4385
4544
|
const force = !!flags.force;
|
|
4386
4545
|
await run({
|
|
@@ -4406,10 +4565,15 @@ var InitCommand = class {
|
|
|
4406
4565
|
react: !!flags.react && !isExpo,
|
|
4407
4566
|
force
|
|
4408
4567
|
});
|
|
4409
|
-
if (flags.api) await this.scaffolder.ensureApiProject(root, {
|
|
4568
|
+
if (flags.api) await this.scaffolder.ensureApiProject(root, {
|
|
4569
|
+
auth: !!flags.auth,
|
|
4570
|
+
force
|
|
4571
|
+
});
|
|
4410
4572
|
if (flags.react && !isExpo) await this.scaffolder.ensureWebProject(root, {
|
|
4411
4573
|
api: !!flags.api,
|
|
4412
4574
|
ui: !!flags.ui,
|
|
4575
|
+
auth: !!flags.auth,
|
|
4576
|
+
admin: !!flags.admin,
|
|
4413
4577
|
force
|
|
4414
4578
|
});
|
|
4415
4579
|
}
|
|
@@ -4648,6 +4812,7 @@ var AlephaPackageBuilderCli = class {
|
|
|
4648
4812
|
pkgData.exports[path].types = `./src/${item.name}/index.ts`;
|
|
4649
4813
|
if (item.native) pkgData.exports[path]["react-native"] = `./src/${item.name}/index.native.ts`;
|
|
4650
4814
|
else if (item.browser) pkgData.exports[path]["react-native"] = `./src/${item.name}/index.browser.ts`;
|
|
4815
|
+
if (item.workerd) pkgData.exports[path].workerd = `./src/${item.name}/index.workerd.ts`;
|
|
4651
4816
|
if (item.browser) pkgData.exports[path].browser = `./src/${item.name}/index.browser.ts`;
|
|
4652
4817
|
if (item.bun) pkgData.exports[path].bun = `./src/${item.name}/index.bun.ts`;
|
|
4653
4818
|
pkgData.exports[path].import = `./src/${item.name}/index.ts`;
|
|
@@ -4804,6 +4969,7 @@ async function analyzeModules(srcDir, packageName) {
|
|
|
4804
4969
|
const hasNative = await fileExists(join(modulePath, "index.native.ts"));
|
|
4805
4970
|
const hasBun = await fileExists(join(modulePath, "index.bun.ts"));
|
|
4806
4971
|
const hasNode = await fileExists(join(modulePath, "index.node.ts"));
|
|
4972
|
+
const hasEdge = await fileExists(join(modulePath, "index.workerd.ts"));
|
|
4807
4973
|
const files = await getAllFiles(modulePath);
|
|
4808
4974
|
for (const file of files) {
|
|
4809
4975
|
const deps = extractAlephaDependencies(await readFile(file, "utf-8"), packageName, moduleName);
|
|
@@ -4818,6 +4984,7 @@ async function analyzeModules(srcDir, packageName) {
|
|
|
4818
4984
|
dependencies: Array.from(dependencies)
|
|
4819
4985
|
};
|
|
4820
4986
|
if (hasNative) module.native = true;
|
|
4987
|
+
if (hasEdge) module.workerd = true;
|
|
4821
4988
|
if (hasBrowser) module.browser = true;
|
|
4822
4989
|
if (hasBun) module.bun = true;
|
|
4823
4990
|
if (hasNode) module.node = true;
|