alepha 0.20.2 → 0.20.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 +0 -1
- package/assets/swagger-ui/swagger-ui-bundle.js +1 -1
- package/assets/swagger-ui/swagger-ui.css +1 -1
- package/dist/api/audits/index.browser.js +49 -0
- package/dist/api/audits/index.browser.js.map +1 -1
- package/dist/api/audits/index.js +49 -0
- package/dist/api/audits/index.js.map +1 -1
- package/dist/api/files/index.js.map +1 -1
- package/dist/api/jobs/index.d.ts +2 -61
- package/dist/api/jobs/index.d.ts.map +1 -1
- package/dist/api/jobs/index.js.map +1 -1
- package/dist/api/keys/index.d.ts +4 -4
- package/dist/api/keys/index.js.map +1 -1
- package/dist/api/notifications/index.d.ts +1 -10
- package/dist/api/notifications/index.d.ts.map +1 -1
- package/dist/api/parameters/index.browser.js +37 -0
- package/dist/api/parameters/index.browser.js.map +1 -1
- package/dist/api/parameters/index.d.ts +12 -68
- package/dist/api/parameters/index.d.ts.map +1 -1
- package/dist/api/parameters/index.js +57 -4
- package/dist/api/parameters/index.js.map +1 -1
- package/dist/api/payments/index.js.map +1 -1
- package/dist/api/users/index.browser.js +6 -0
- package/dist/api/users/index.browser.js.map +1 -1
- package/dist/api/users/index.d.ts +148 -227
- package/dist/api/users/index.d.ts.map +1 -1
- package/dist/api/users/index.js +60 -14
- package/dist/api/users/index.js.map +1 -1
- package/dist/api/verifications/index.d.ts.map +1 -1
- package/dist/api/verifications/index.js +2 -1
- package/dist/api/verifications/index.js.map +1 -1
- package/dist/bucket/index.d.ts +77 -107
- package/dist/bucket/index.d.ts.map +1 -1
- package/dist/bucket/index.js +153 -5
- package/dist/bucket/index.js.map +1 -1
- package/dist/bucket/index.workerd.js +12 -2
- package/dist/bucket/index.workerd.js.map +1 -1
- package/dist/cache/core/index.d.ts +26 -0
- package/dist/cache/core/index.d.ts.map +1 -1
- package/dist/cache/core/index.js +11 -1
- package/dist/cache/core/index.js.map +1 -1
- package/dist/cache/core/index.workerd.js +11 -1
- package/dist/cache/core/index.workerd.js.map +1 -1
- package/dist/captcha/index.js.map +1 -1
- package/dist/cli/config/index.d.ts +7 -5
- package/dist/cli/config/index.d.ts.map +1 -1
- package/dist/cli/config/index.js +2 -3
- package/dist/cli/config/index.js.map +1 -1
- package/dist/cli/core/index.d.ts +637 -11660
- package/dist/cli/core/index.d.ts.map +1 -1
- package/dist/cli/core/index.js +707 -532
- package/dist/cli/core/index.js.map +1 -1
- package/dist/cli/devtools/index.d.ts +4 -8
- package/dist/cli/devtools/index.d.ts.map +1 -1
- package/dist/cli/devtools/index.js +20 -16
- package/dist/cli/devtools/index.js.map +1 -1
- package/dist/cli/platform/index.d.ts +51 -77
- package/dist/cli/platform/index.d.ts.map +1 -1
- package/dist/cli/platform/index.js +65 -15
- package/dist/cli/platform/index.js.map +1 -1
- package/dist/cli/vendor/index.d.ts +10 -13
- package/dist/cli/vendor/index.d.ts.map +1 -1
- package/dist/cli/vendor/index.js +30 -12
- package/dist/cli/vendor/index.js.map +1 -1
- package/dist/command/index.js +1 -1
- package/dist/command/index.js.map +1 -1
- package/dist/core/index.browser.js +27 -3
- package/dist/core/index.browser.js.map +1 -1
- package/dist/core/index.d.ts +8 -11
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +27 -3
- package/dist/core/index.js.map +1 -1
- package/dist/core/index.native.js +27 -3
- package/dist/core/index.native.js.map +1 -1
- package/dist/core/index.workerd.js +27 -3
- package/dist/core/index.workerd.js.map +1 -1
- package/dist/crypto/index.js.map +1 -1
- package/dist/datetime/index.d.ts +69 -10
- package/dist/datetime/index.d.ts.map +1 -1
- package/dist/datetime/index.js +135 -13
- package/dist/datetime/index.js.map +1 -1
- package/dist/email/core/index.js.map +1 -1
- package/dist/email/smtp/index.js +130 -16
- package/dist/email/smtp/index.js.map +1 -1
- package/dist/fake/index.js.map +1 -1
- package/dist/lock/core/index.d.ts +30 -2
- package/dist/lock/core/index.d.ts.map +1 -1
- package/dist/lock/core/index.js +35 -12
- package/dist/lock/core/index.js.map +1 -1
- package/dist/lock/redis/index.js.map +1 -1
- package/dist/logger/index.js +32 -1
- package/dist/logger/index.js.map +1 -1
- package/dist/mcp/index.d.ts +238 -31
- package/dist/mcp/index.d.ts.map +1 -1
- package/dist/mcp/index.js +198 -67
- package/dist/mcp/index.js.map +1 -1
- package/dist/orm/core/index.browser.js +2 -362
- package/dist/orm/core/index.browser.js.map +1 -1
- package/dist/orm/core/index.bun.js +18 -409
- package/dist/orm/core/index.bun.js.map +1 -1
- package/dist/orm/core/index.d.ts +41 -194
- package/dist/orm/core/index.d.ts.map +1 -1
- package/dist/orm/core/index.js +27 -422
- package/dist/orm/core/index.js.map +1 -1
- package/dist/orm/postgres/index.bun.js +17 -20
- package/dist/orm/postgres/index.bun.js.map +1 -1
- package/dist/orm/postgres/index.d.ts +1 -5
- package/dist/orm/postgres/index.d.ts.map +1 -1
- package/dist/orm/postgres/index.js +17 -20
- package/dist/orm/postgres/index.js.map +1 -1
- package/dist/react/core/index.d.ts +102 -1
- package/dist/react/core/index.d.ts.map +1 -1
- package/dist/react/core/index.js +65 -1
- package/dist/react/core/index.js.map +1 -1
- package/dist/react/form/index.d.ts +6 -0
- package/dist/react/form/index.d.ts.map +1 -1
- package/dist/react/form/index.js +7 -7
- package/dist/react/form/index.js.map +1 -1
- package/dist/react/i18n/index.d.ts +7 -1
- package/dist/react/i18n/index.d.ts.map +1 -1
- package/dist/react/i18n/index.js +6 -0
- package/dist/react/i18n/index.js.map +1 -1
- package/dist/react/intro/index.js +22 -17
- package/dist/react/intro/index.js.map +1 -1
- package/dist/react/router/index.browser.js +98 -4
- package/dist/react/router/index.browser.js.map +1 -1
- package/dist/react/router/index.d.ts +58 -5
- package/dist/react/router/index.d.ts.map +1 -1
- package/dist/react/router/index.js +122 -6
- package/dist/react/router/index.js.map +1 -1
- package/dist/react/testing/{chunk-DBEY4PJZ.js → chunk-6Ep1yQYe.js} +1 -1
- package/dist/react/testing/index.js +1 -1
- package/dist/react/testing/index.js.map +1 -1
- package/dist/react/ui/index.d.ts +195 -1
- package/dist/react/ui/index.d.ts.map +1 -1
- package/dist/react/ui/index.js +64 -1
- package/dist/react/ui/index.js.map +1 -1
- package/dist/react/websocket/index.js.map +1 -1
- package/dist/redis/index.js.map +1 -1
- package/dist/scheduler/index.d.ts +1 -2
- package/dist/scheduler/index.d.ts.map +1 -1
- package/dist/scheduler/index.js +1 -1
- package/dist/scheduler/index.js.map +1 -1
- package/dist/scheduler/index.workerd.js +1 -1
- package/dist/scheduler/index.workerd.js.map +1 -1
- package/dist/security/index.browser.js.map +1 -1
- package/dist/security/index.d.ts.map +1 -1
- package/dist/security/index.js +2 -2
- package/dist/security/index.js.map +1 -1
- package/dist/server/auth/index.d.ts.map +1 -1
- package/dist/server/auth/index.js +24 -10
- package/dist/server/auth/index.js.map +1 -1
- package/dist/server/cookies/index.js.map +1 -1
- package/dist/server/core/index.browser.js +10 -3
- package/dist/server/core/index.browser.js.map +1 -1
- package/dist/server/core/index.d.ts +1 -4
- package/dist/server/core/index.d.ts.map +1 -1
- package/dist/server/core/index.js +47 -9
- package/dist/server/core/index.js.map +1 -1
- package/dist/server/links/index.browser.js.map +1 -1
- package/dist/server/links/index.js.map +1 -1
- package/dist/server/metrics/index.js +19 -1
- package/dist/server/metrics/index.js.map +1 -1
- package/dist/server/rate-limit/index.js.map +1 -1
- package/dist/server/static/index.js.map +1 -1
- package/dist/server/swagger/index.d.ts.map +1 -1
- package/dist/server/swagger/index.js +4 -5
- package/dist/server/swagger/index.js.map +1 -1
- package/dist/sms/index.js.map +1 -1
- package/dist/system/index.browser.js.map +1 -1
- package/dist/system/index.js.map +1 -1
- package/dist/system/index.workerd.js.map +1 -1
- package/dist/topic/core/index.js.map +1 -1
- package/dist/websocket/index.browser.js +32 -5
- package/dist/websocket/index.browser.js.map +1 -1
- package/dist/websocket/index.d.ts +3 -1
- package/dist/websocket/index.d.ts.map +1 -1
- package/dist/websocket/index.js +42 -6
- package/dist/websocket/index.js.map +1 -1
- package/package.json +685 -274
- package/src/api/files/__tests__/FileController.spec.ts +1 -1
- package/src/api/jobs/__tests__/$job.spec.ts +5 -1
- package/src/api/parameters/services/ParameterProvider.ts +21 -4
- package/src/api/users/__tests__/SessionService.spec.ts +99 -0
- package/src/api/users/__tests__/UserJobs.spec.ts +67 -0
- package/src/api/users/atoms/realmAuthSettingsAtom.ts +15 -0
- package/src/api/users/entities/sessions.ts +6 -0
- package/src/api/users/jobs/UserJobs.ts +44 -17
- package/src/api/users/providers/RealmProvider.ts +4 -0
- package/src/api/users/schemas/userQuerySchema.ts +0 -1
- package/src/api/users/services/SessionService.ts +27 -0
- package/src/api/users/services/UserService.ts +1 -5
- package/src/api/verifications/__tests__/CodeVerification.spec.ts +14 -0
- package/src/api/verifications/__tests__/LinkVerification.spec.ts +14 -0
- package/src/api/verifications/services/VerificationService.ts +1 -0
- package/src/bucket/__tests__/NodeS3BucketProvider.spec.ts +74 -0
- package/src/bucket/index.ts +19 -2
- package/src/bucket/primitives/$bucket.ts +9 -1
- package/src/bucket/providers/CloudflareR2Provider.ts +2 -137
- package/src/bucket/providers/NodeS3BucketProvider.ts +218 -0
- package/src/cache/core/index.ts +29 -0
- package/src/cache/core/primitives/$cache.ts +14 -1
- package/src/cli/config/defineConfig.ts +13 -15
- package/src/cli/core/__tests__/init.spec.ts +214 -7
- package/src/cli/core/commands/init.ts +12 -0
- package/src/cli/core/services/PackageManagerUtils.ts +23 -6
- package/src/cli/core/services/ProjectScaffolder.ts +315 -33
- package/src/cli/core/tasks/BuildCloudflareTask.ts +5 -0
- package/src/cli/core/tasks/BuildDockerTask.ts +9 -10
- package/src/cli/core/tasks/BuildServerTask.ts +8 -0
- package/src/cli/core/templates/agentMd.ts +2 -10
- package/src/cli/core/templates/apiIndexTs.ts +23 -1
- package/src/cli/core/templates/componentsJsonTs.ts +39 -0
- package/src/cli/core/templates/mainCss.ts +1 -0
- package/src/cli/core/templates/saasAdminLayoutTsx.ts +77 -0
- package/src/cli/core/templates/saasAdminPagesTsx.ts +26 -0
- package/src/cli/core/templates/saasAuthLayoutTsx.ts +20 -0
- package/src/cli/core/templates/saasAuthPagesTsx.ts +62 -0
- package/src/cli/core/templates/saasRealmProviderTs.ts +46 -0
- package/src/cli/core/templates/webAppRouterTs.ts +104 -1
- package/src/cli/core/templates/webIndexTs.ts +23 -1
- package/src/cli/devtools/index.ts +12 -26
- package/src/cli/platform/__tests__/SecretsCommand.spec.ts +2 -0
- package/src/cli/platform/index.ts +15 -24
- package/src/cli/vendor/atoms/vendorOptions.ts +1 -1
- package/src/cli/vendor/index.ts +14 -23
- package/src/command/providers/CliProvider.ts +1 -1
- package/src/core/Alepha.ts +11 -1
- package/src/core/helpers/ref.ts +18 -0
- package/src/core/index.shared.ts +1 -0
- package/src/core/interfaces/Service.ts +3 -1
- package/src/core/providers/SchemaValidator.ts +9 -1
- package/src/core/providers/TypeProvider.ts +2 -3
- package/src/datetime/REFACTORING.md +118 -0
- package/src/datetime/providers/DateTimeProvider.ts +203 -24
- package/src/lock/core/index.ts +31 -0
- package/src/lock/core/primitives/$lock.ts +14 -1
- package/src/logger/services/Logger.ts +1 -1
- package/src/mcp/__tests__/$resource.spec.ts +1 -1
- package/src/mcp/__tests__/$tool.spec.ts +1 -1
- package/src/mcp/__tests__/McpServerProvider.spec.ts +1 -1
- package/src/mcp/__tests__/jsonrpc.spec.ts +1 -1
- package/src/mcp/helpers/jsonrpc.ts +26 -1
- package/src/mcp/index.ts +10 -5
- package/src/mcp/interfaces/McpTypes.ts +83 -6
- package/src/mcp/primitives/$prompt.ts +18 -1
- package/src/mcp/primitives/$resource.ts +18 -1
- package/src/mcp/primitives/$tool.ts +83 -7
- package/src/mcp/providers/McpServerProvider.ts +74 -16
- package/src/mcp/transports/StreamableHttpMcpTransport.ts +226 -0
- package/src/orm/REFACTORING.md +330 -0
- package/src/orm/__tests__/$repository-tests.ts +1 -0
- package/src/orm/__tests__/orm-next-tests.ts +2 -67
- package/src/orm/__tests__/orm-next.spec.ts +0 -21
- package/src/orm/core/index.shared.ts +0 -2
- package/src/orm/core/index.ts +1 -2
- package/src/orm/core/primitives/$repository.ts +3 -6
- package/src/orm/core/primitives/$transactional.ts +11 -0
- package/src/orm/core/providers/drivers/DatabaseProvider.ts +0 -5
- package/src/orm/core/providers/drivers/NodeSqliteProvider.ts +11 -13
- package/src/orm/core/schemas/updateSchema.ts +1 -1
- package/src/orm/core/services/ModelBuilder.ts +1 -13
- package/src/orm/core/services/PgRelationManager.ts +4 -2
- package/src/orm/core/services/Repository.ts +1 -42
- package/src/orm/core/services/SqliteModelBuilder.ts +2 -33
- package/src/orm/postgres/services/PostgresModelBuilder.ts +10 -45
- package/src/react/core/__tests__/useQuery.browser.spec.tsx +86 -0
- package/src/react/core/hooks/useQuery.ts +153 -0
- package/src/react/core/index.ts +1 -0
- package/src/react/form/services/FormModel.ts +15 -6
- package/src/react/form/services/parseField.ts +8 -0
- package/src/react/i18n/providers/I18nProvider.ts +8 -2
- package/src/react/intro/components/GettingStartedAuthSlide.tsx +11 -4
- package/src/react/router/__tests__/$page.spec.tsx +0 -16
- package/src/react/router/__tests__/ReactBrowserProvider.browser.spec.ts +213 -2
- package/src/react/router/__tests__/ssr.spec.tsx +339 -0
- package/src/react/router/primitives/$page.ts +28 -4
- package/src/react/router/providers/ReactBrowserProvider.ts +73 -0
- package/src/react/router/providers/ReactBrowserRouterProvider.ts +1 -1
- package/src/react/router/providers/ReactPageProvider.ts +27 -9
- package/src/react/router/providers/ReactPreloadProvider.ts +1 -1
- package/src/react/router/providers/ReactServerProvider.ts +1 -0
- package/src/react/ui/atoms/uiThemeListAtom.ts +36 -0
- package/src/react/ui/index.ts +6 -0
- package/src/react/ui/services/SchemaControl.ts +209 -0
- package/src/scheduler/providers/CronProvider.ts +1 -1
- package/src/security/primitives/$basicAuth.ts +1 -1
- package/src/security/primitives/$issuer.ts +6 -3
- package/src/server/auth/providers/ServerAuthProvider.ts +5 -1
- package/src/server/core/__tests__/ServerRouterProvider-serializationError.spec.ts +75 -0
- package/src/server/core/__tests__/ServerRouterProvider-validationError.spec.ts +306 -0
- package/src/server/core/errors/ValidationError.ts +13 -1
- package/src/server/core/interfaces/ServerRequest.ts +1 -0
- package/src/server/core/primitives/$action.ts +16 -5
- package/src/server/core/providers/ServerProvider.ts +1 -1
- package/src/server/core/providers/ServerRouterProvider.ts +28 -6
- package/src/server/core/services/HttpClient.ts +1 -1
- package/src/server/swagger/providers/ServerSwaggerProvider.ts +6 -8
- package/src/websocket/providers/NodeWebSocketServerProvider.ts +10 -4
- package/src/websocket/services/WebSocketClient.ts +11 -5
- package/src/mcp/transports/SseMcpTransport.ts +0 -182
- package/src/orm/core/__tests__/parseQueryString.spec.ts +0 -196
- package/src/orm/core/helpers/parseQueryString.ts +0 -502
- package/src/orm/core/primitives/$view.ts +0 -88
|
@@ -2,13 +2,14 @@ import { basename, dirname } from "node:path";
|
|
|
2
2
|
import { $inject, AlephaError } from "alepha";
|
|
3
3
|
import type { RunnerMethod } from "alepha/command";
|
|
4
4
|
import { $logger, ConsoleColorProvider } from "alepha/logger";
|
|
5
|
-
import { FileSystemProvider } from "alepha/system";
|
|
6
|
-
import {
|
|
5
|
+
import { FileSystemProvider, ShellProvider } from "alepha/system";
|
|
6
|
+
import { agentMd } from "../templates/agentMd.ts";
|
|
7
7
|
import { alephaConfigTs } from "../templates/alephaConfigTs.ts";
|
|
8
8
|
import { apiHelloControllerTs } from "../templates/apiHelloControllerTs.ts";
|
|
9
9
|
import { apiHelloResponseSchemaTs } from "../templates/apiHelloResponseSchemaTs.ts";
|
|
10
10
|
import { apiIndexTs } from "../templates/apiIndexTs.ts";
|
|
11
11
|
import { biomeJson } from "../templates/biomeJson.ts";
|
|
12
|
+
import { componentsJsonTs } from "../templates/componentsJsonTs.ts";
|
|
12
13
|
import { dummySpecTs } from "../templates/dummySpecTs.ts";
|
|
13
14
|
import { editorconfig } from "../templates/editorconfig.ts";
|
|
14
15
|
import { gitignore } from "../templates/gitignore.ts";
|
|
@@ -16,6 +17,19 @@ import { logoSvg } from "../templates/logoSvg.ts";
|
|
|
16
17
|
import { mainBrowserTs } from "../templates/mainBrowserTs.ts";
|
|
17
18
|
import { mainCss } from "../templates/mainCss.ts";
|
|
18
19
|
import { mainServerTs } from "../templates/mainServerTs.ts";
|
|
20
|
+
import { saasAdminLayoutTsx } from "../templates/saasAdminLayoutTsx.ts";
|
|
21
|
+
import {
|
|
22
|
+
saasAdminSessionsTsx,
|
|
23
|
+
saasAdminUsersTsx,
|
|
24
|
+
} from "../templates/saasAdminPagesTsx.ts";
|
|
25
|
+
import { saasAuthLayoutTsx } from "../templates/saasAuthLayoutTsx.ts";
|
|
26
|
+
import {
|
|
27
|
+
saasAuthLoginTsx,
|
|
28
|
+
saasAuthRegisterTsx,
|
|
29
|
+
saasAuthResetPasswordTsx,
|
|
30
|
+
saasAuthVerifyEmailTsx,
|
|
31
|
+
} from "../templates/saasAuthPagesTsx.ts";
|
|
32
|
+
import { saasRealmProviderTs } from "../templates/saasRealmProviderTs.ts";
|
|
19
33
|
import { tsconfigJson } from "../templates/tsconfigJson.ts";
|
|
20
34
|
import { viteConfigTs } from "../templates/viteConfigTs.ts";
|
|
21
35
|
import { vitestConfigTs } from "../templates/vitestConfigTs.ts";
|
|
@@ -41,6 +55,7 @@ export class ProjectScaffolder {
|
|
|
41
55
|
protected readonly log = $logger();
|
|
42
56
|
protected readonly colors = $inject(ConsoleColorProvider);
|
|
43
57
|
protected readonly fs = $inject(FileSystemProvider);
|
|
58
|
+
protected readonly shell = $inject(ShellProvider);
|
|
44
59
|
protected readonly pm = $inject(PackageManagerUtils);
|
|
45
60
|
protected readonly utils = $inject(AlephaCliUtils);
|
|
46
61
|
|
|
@@ -70,10 +85,16 @@ export class ProjectScaffolder {
|
|
|
70
85
|
*/
|
|
71
86
|
checkWorkspace?: boolean;
|
|
72
87
|
packageJson?: boolean | DependencyModes;
|
|
73
|
-
|
|
88
|
+
/**
|
|
89
|
+
* `true` writes a tsconfig.json if one doesn't already exist (parent
|
|
90
|
+
* dirs included). `"local"` writes one when none exists *in this
|
|
91
|
+
* directory* — used by shadcn since the CLI reads the local
|
|
92
|
+
* tsconfig directly for import-alias detection.
|
|
93
|
+
*/
|
|
94
|
+
tsconfigJson?: boolean | "local";
|
|
74
95
|
biomeJson?: boolean;
|
|
75
96
|
editorconfig?: boolean;
|
|
76
|
-
agentMd?:
|
|
97
|
+
agentMd?: boolean;
|
|
77
98
|
},
|
|
78
99
|
): Promise<void> {
|
|
79
100
|
const tasks: Promise<void>[] = [];
|
|
@@ -91,7 +112,12 @@ export class ProjectScaffolder {
|
|
|
91
112
|
);
|
|
92
113
|
}
|
|
93
114
|
if (opts.tsconfigJson) {
|
|
94
|
-
tasks.push(
|
|
115
|
+
tasks.push(
|
|
116
|
+
this.ensureTsConfig(root, {
|
|
117
|
+
force,
|
|
118
|
+
localOnly: opts.tsconfigJson === "local",
|
|
119
|
+
}),
|
|
120
|
+
);
|
|
95
121
|
}
|
|
96
122
|
if (opts.biomeJson) {
|
|
97
123
|
tasks.push(this.ensureBiomeConfig(root, { force, checkWorkspace }));
|
|
@@ -100,7 +126,7 @@ export class ProjectScaffolder {
|
|
|
100
126
|
tasks.push(this.ensureEditorConfig(root, { force, checkWorkspace }));
|
|
101
127
|
}
|
|
102
128
|
if (opts.agentMd) {
|
|
103
|
-
tasks.push(this.ensureAgentMd(root, {
|
|
129
|
+
tasks.push(this.ensureAgentMd(root, { force }));
|
|
104
130
|
}
|
|
105
131
|
|
|
106
132
|
await Promise.all(tasks);
|
|
@@ -112,10 +138,15 @@ export class ProjectScaffolder {
|
|
|
112
138
|
|
|
113
139
|
public async ensureTsConfig(
|
|
114
140
|
root: string,
|
|
115
|
-
opts: { force?: boolean } = {},
|
|
141
|
+
opts: { force?: boolean; localOnly?: boolean } = {},
|
|
116
142
|
): Promise<void> {
|
|
117
|
-
// Check if tsconfig.json exists in current or parent directories
|
|
118
|
-
|
|
143
|
+
// Check if tsconfig.json exists in current or parent directories.
|
|
144
|
+
// `localOnly: true` skips the parent walk — needed when a tool reads the
|
|
145
|
+
// local tsconfig directly (shadcn does this for import-alias detection).
|
|
146
|
+
const exists = opts.localOnly
|
|
147
|
+
? await this.fs.exists(this.fs.join(root, "tsconfig.json"))
|
|
148
|
+
: await this.existsInParents(root, "tsconfig.json");
|
|
149
|
+
if (!opts.force && exists) {
|
|
119
150
|
return;
|
|
120
151
|
}
|
|
121
152
|
await this.fs.writeFile(
|
|
@@ -183,12 +214,19 @@ export class ProjectScaffolder {
|
|
|
183
214
|
return true;
|
|
184
215
|
}
|
|
185
216
|
|
|
217
|
+
/**
|
|
218
|
+
* Ensure AGENTS.md (cross-tool standard, canonical source) exists, with a
|
|
219
|
+
* CLAUDE.md stub that imports it via Claude Code's `@` syntax. Single
|
|
220
|
+
* source of truth, cross-platform, no symlink needed.
|
|
221
|
+
*/
|
|
186
222
|
public async ensureAgentMd(
|
|
187
223
|
root: string,
|
|
188
|
-
options:
|
|
224
|
+
options: { force?: boolean } = {},
|
|
189
225
|
): Promise<void> {
|
|
190
|
-
|
|
191
|
-
|
|
226
|
+
await Promise.all([
|
|
227
|
+
this.ensureFile(root, "AGENTS.md", agentMd(), options.force),
|
|
228
|
+
this.ensureFile(root, "CLAUDE.md", "@AGENTS.md\n", options.force),
|
|
229
|
+
]);
|
|
192
230
|
}
|
|
193
231
|
|
|
194
232
|
/**
|
|
@@ -240,7 +278,7 @@ export class ProjectScaffolder {
|
|
|
240
278
|
*/
|
|
241
279
|
public async ensureApiProject(
|
|
242
280
|
root: string,
|
|
243
|
-
opts: { force?: boolean } = {},
|
|
281
|
+
opts: { saas?: boolean; force?: boolean } = {},
|
|
244
282
|
): Promise<void> {
|
|
245
283
|
const appName = this.getAppName(root);
|
|
246
284
|
|
|
@@ -256,7 +294,7 @@ export class ProjectScaffolder {
|
|
|
256
294
|
await this.ensureFile(
|
|
257
295
|
root,
|
|
258
296
|
"src/api/index.ts",
|
|
259
|
-
apiIndexTs({ appName }),
|
|
297
|
+
apiIndexTs({ appName, saas: opts.saas }),
|
|
260
298
|
opts.force,
|
|
261
299
|
);
|
|
262
300
|
await this.ensureFile(
|
|
@@ -271,6 +309,38 @@ export class ProjectScaffolder {
|
|
|
271
309
|
apiHelloResponseSchemaTs(),
|
|
272
310
|
opts.force,
|
|
273
311
|
);
|
|
312
|
+
|
|
313
|
+
if (opts.saas) {
|
|
314
|
+
await this.fs.mkdir(this.fs.join(root, "src/api/providers"), {
|
|
315
|
+
recursive: true,
|
|
316
|
+
});
|
|
317
|
+
const adminEmail = await this.detectGitEmail();
|
|
318
|
+
await this.ensureFile(
|
|
319
|
+
root,
|
|
320
|
+
"src/api/providers/RealmProvider.ts",
|
|
321
|
+
saasRealmProviderTs({ adminEmail }),
|
|
322
|
+
opts.force,
|
|
323
|
+
);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* Best-effort lookup for the developer's git email (used as the seeded
|
|
329
|
+
* `adminEmails` entry in the SaaS realm). Returns undefined if git isn't
|
|
330
|
+
* available or if `user.email` isn't configured — the template falls back
|
|
331
|
+
* to `admin@example.com` in that case.
|
|
332
|
+
*/
|
|
333
|
+
protected async detectGitEmail(): Promise<string | undefined> {
|
|
334
|
+
try {
|
|
335
|
+
const stdout = (await this.shell.run("git config --get user.email", {
|
|
336
|
+
capture: true,
|
|
337
|
+
})) as unknown as string;
|
|
338
|
+
const email = (stdout ?? "").trim();
|
|
339
|
+
if (!email || !email.includes("@")) return undefined;
|
|
340
|
+
return email;
|
|
341
|
+
} catch {
|
|
342
|
+
return undefined;
|
|
343
|
+
}
|
|
274
344
|
}
|
|
275
345
|
|
|
276
346
|
// ===========================================
|
|
@@ -290,6 +360,8 @@ export class ProjectScaffolder {
|
|
|
290
360
|
opts: {
|
|
291
361
|
api?: boolean;
|
|
292
362
|
tailwind?: boolean;
|
|
363
|
+
shadcn?: boolean;
|
|
364
|
+
saas?: boolean;
|
|
293
365
|
force?: boolean;
|
|
294
366
|
} = {},
|
|
295
367
|
): Promise<void> {
|
|
@@ -300,6 +372,15 @@ export class ProjectScaffolder {
|
|
|
300
372
|
recursive: true,
|
|
301
373
|
});
|
|
302
374
|
|
|
375
|
+
if (opts.saas) {
|
|
376
|
+
await this.fs.mkdir(this.fs.join(root, "src/web/components/auth"), {
|
|
377
|
+
recursive: true,
|
|
378
|
+
});
|
|
379
|
+
await this.fs.mkdir(this.fs.join(root, "src/web/components/admin"), {
|
|
380
|
+
recursive: true,
|
|
381
|
+
});
|
|
382
|
+
}
|
|
383
|
+
|
|
303
384
|
// public/favicon.svg
|
|
304
385
|
await this.fs.mkdir(this.fs.join(root, "public"), { recursive: true });
|
|
305
386
|
await this.ensureFile(root, "public/favicon.svg", logoSvg, opts.force);
|
|
@@ -317,17 +398,32 @@ export class ProjectScaffolder {
|
|
|
317
398
|
await this.ensureFile(root, "vite.config.ts", viteConfigTs(), opts.force);
|
|
318
399
|
}
|
|
319
400
|
|
|
401
|
+
// shadcn/ui: write components.json before running `shadcn init` — the
|
|
402
|
+
// CLI respects an existing config and skips its interactive prompts,
|
|
403
|
+
// which lets us pin our aliases (`@/web/*`) and the `@alepha` registry.
|
|
404
|
+
// The CLI itself writes the cn() helper, theme tokens, and installs
|
|
405
|
+
// runtime deps (clsx, tailwind-merge, class-variance-authority,
|
|
406
|
+
// lucide-react, tw-animate-css) — see runShadcnInit below.
|
|
407
|
+
if (opts.shadcn) {
|
|
408
|
+
await this.ensureFile(
|
|
409
|
+
root,
|
|
410
|
+
"components.json",
|
|
411
|
+
componentsJsonTs(),
|
|
412
|
+
opts.force,
|
|
413
|
+
);
|
|
414
|
+
}
|
|
415
|
+
|
|
320
416
|
// Web structure
|
|
321
417
|
await this.ensureFile(
|
|
322
418
|
root,
|
|
323
419
|
"src/web/index.ts",
|
|
324
|
-
webIndexTs({ appName }),
|
|
420
|
+
webIndexTs({ appName, saas: opts.saas }),
|
|
325
421
|
opts.force,
|
|
326
422
|
);
|
|
327
423
|
await this.ensureFile(
|
|
328
424
|
root,
|
|
329
425
|
"src/web/AppRouter.ts",
|
|
330
|
-
webAppRouterTs({ api: opts.api }),
|
|
426
|
+
webAppRouterTs({ api: opts.api, saas: opts.saas }),
|
|
331
427
|
opts.force,
|
|
332
428
|
);
|
|
333
429
|
await this.ensureFile(
|
|
@@ -342,6 +438,62 @@ export class ProjectScaffolder {
|
|
|
342
438
|
mainBrowserTs(),
|
|
343
439
|
opts.force,
|
|
344
440
|
);
|
|
441
|
+
|
|
442
|
+
if (opts.saas) {
|
|
443
|
+
// Auth — layout + 4 pages, each a thin wrapper around the registry
|
|
444
|
+
// component that `shadcn add @alepha/auth-*` drops at
|
|
445
|
+
// src/web/components/auth-*.tsx.
|
|
446
|
+
await this.ensureFile(
|
|
447
|
+
root,
|
|
448
|
+
"src/web/components/auth/AuthLayout.tsx",
|
|
449
|
+
saasAuthLayoutTsx(),
|
|
450
|
+
opts.force,
|
|
451
|
+
);
|
|
452
|
+
await this.ensureFile(
|
|
453
|
+
root,
|
|
454
|
+
"src/web/components/auth/Login.tsx",
|
|
455
|
+
saasAuthLoginTsx(),
|
|
456
|
+
opts.force,
|
|
457
|
+
);
|
|
458
|
+
await this.ensureFile(
|
|
459
|
+
root,
|
|
460
|
+
"src/web/components/auth/Register.tsx",
|
|
461
|
+
saasAuthRegisterTsx(),
|
|
462
|
+
opts.force,
|
|
463
|
+
);
|
|
464
|
+
await this.ensureFile(
|
|
465
|
+
root,
|
|
466
|
+
"src/web/components/auth/ResetPassword.tsx",
|
|
467
|
+
saasAuthResetPasswordTsx(),
|
|
468
|
+
opts.force,
|
|
469
|
+
);
|
|
470
|
+
await this.ensureFile(
|
|
471
|
+
root,
|
|
472
|
+
"src/web/components/auth/VerifyEmail.tsx",
|
|
473
|
+
saasAuthVerifyEmailTsx(),
|
|
474
|
+
opts.force,
|
|
475
|
+
);
|
|
476
|
+
|
|
477
|
+
// Admin — AppShell layout + 5 admin-* pages
|
|
478
|
+
await this.ensureFile(
|
|
479
|
+
root,
|
|
480
|
+
"src/web/components/admin/AdminLayout.tsx",
|
|
481
|
+
saasAdminLayoutTsx(),
|
|
482
|
+
opts.force,
|
|
483
|
+
);
|
|
484
|
+
await this.ensureFile(
|
|
485
|
+
root,
|
|
486
|
+
"src/web/components/admin/Users.tsx",
|
|
487
|
+
saasAdminUsersTsx(),
|
|
488
|
+
opts.force,
|
|
489
|
+
);
|
|
490
|
+
await this.ensureFile(
|
|
491
|
+
root,
|
|
492
|
+
"src/web/components/admin/Sessions.tsx",
|
|
493
|
+
saasAdminSessionsTsx(),
|
|
494
|
+
opts.force,
|
|
495
|
+
);
|
|
496
|
+
}
|
|
345
497
|
}
|
|
346
498
|
|
|
347
499
|
// ===========================================
|
|
@@ -394,6 +546,10 @@ export class ProjectScaffolder {
|
|
|
394
546
|
api?: boolean;
|
|
395
547
|
react?: boolean;
|
|
396
548
|
tailwind?: boolean;
|
|
549
|
+
/** boolean toggle, or a string preset id (default `b0` when bare). */
|
|
550
|
+
shadcn?: boolean | string;
|
|
551
|
+
/** boolean toggle, or a string preset id (default `b0` when bare). */
|
|
552
|
+
saas?: boolean | string;
|
|
397
553
|
test?: boolean;
|
|
398
554
|
force?: boolean;
|
|
399
555
|
};
|
|
@@ -404,13 +560,41 @@ export class ProjectScaffolder {
|
|
|
404
560
|
await this.fs.mkdir(root, { force: true });
|
|
405
561
|
}
|
|
406
562
|
|
|
407
|
-
//
|
|
563
|
+
// `--shadcn` / `--saas` are union flags: bare → true, string → preset.
|
|
564
|
+
// Capture the preset string (default `b0`), then normalize both flags
|
|
565
|
+
// to plain booleans so the rest of the pipeline keeps its boolean
|
|
566
|
+
// contract with PackageManagerUtils + ensureWebProject etc.
|
|
567
|
+
const shadcnPreset =
|
|
568
|
+
(typeof flags.saas === "string" && flags.saas) ||
|
|
569
|
+
(typeof flags.shadcn === "string" && flags.shadcn) ||
|
|
570
|
+
"b0";
|
|
571
|
+
|
|
572
|
+
// Cast to a narrower view so downstream sees pure booleans.
|
|
573
|
+
const f = flags as Omit<typeof flags, "shadcn" | "saas"> & {
|
|
574
|
+
shadcn?: boolean;
|
|
575
|
+
saas?: boolean;
|
|
576
|
+
};
|
|
577
|
+
f.shadcn = !!flags.shadcn;
|
|
578
|
+
f.saas = !!flags.saas;
|
|
579
|
+
|
|
580
|
+
// Flag cascading:
|
|
581
|
+
// --saas → --shadcn + --api
|
|
582
|
+
// --shadcn → --tailwind
|
|
583
|
+
// --tailwind→ --react
|
|
584
|
+
if (f.saas) {
|
|
585
|
+
f.shadcn = true;
|
|
586
|
+
f.api = true;
|
|
587
|
+
}
|
|
588
|
+
if (f.shadcn) {
|
|
589
|
+
f.tailwind = true;
|
|
590
|
+
}
|
|
408
591
|
if (flags.tailwind) {
|
|
409
592
|
flags.react = true;
|
|
410
593
|
}
|
|
411
594
|
|
|
412
595
|
// When codegen flags are set, target directory must be empty (unless --force)
|
|
413
|
-
const hasCodegenFlags =
|
|
596
|
+
const hasCodegenFlags =
|
|
597
|
+
flags.api || flags.react || flags.tailwind || flags.shadcn || flags.saas;
|
|
414
598
|
if (hasCodegenFlags && !flags.force) {
|
|
415
599
|
const files = await this.fs.ls(root);
|
|
416
600
|
// Allow a directory that only has package.json (common for monorepo packages)
|
|
@@ -425,12 +609,9 @@ export class ProjectScaffolder {
|
|
|
425
609
|
// Detect workspace context (are we inside packages/ or apps/ of a monorepo?)
|
|
426
610
|
const workspace = await this.pm.getWorkspaceContext(root);
|
|
427
611
|
|
|
428
|
-
//
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
const hasClaudeCli = await this.utils.isInstalledAsync("claude");
|
|
432
|
-
agentType = hasClaudeCli ? "claude" : "agents";
|
|
433
|
-
}
|
|
612
|
+
// Always emit both AGENTS.md and CLAUDE.md at project roots (skip for
|
|
613
|
+
// monorepo sub-packages where agent files live at workspace root).
|
|
614
|
+
const writeAgentMd = !workspace.isPackage;
|
|
434
615
|
|
|
435
616
|
const isExpo = await this.pm.hasExpo(root);
|
|
436
617
|
|
|
@@ -441,12 +622,15 @@ export class ProjectScaffolder {
|
|
|
441
622
|
handler: async () => {
|
|
442
623
|
await this.ensureConfig(root, {
|
|
443
624
|
force,
|
|
444
|
-
packageJson: { ...
|
|
445
|
-
// Skip workspace-level configs if they exist at workspace root
|
|
446
|
-
|
|
625
|
+
packageJson: { ...f, isPackage: workspace.isPackage },
|
|
626
|
+
// Skip workspace-level configs if they exist at workspace root —
|
|
627
|
+
// unless --shadcn is set: the shadcn CLI reads the local
|
|
628
|
+
// tsconfig.json directly to detect import aliases (it doesn't
|
|
629
|
+
// follow `extends`), so we must ensure one exists in the package.
|
|
630
|
+
tsconfigJson: f.shadcn ? "local" : !workspace.config.tsconfigJson,
|
|
447
631
|
biomeJson: true,
|
|
448
632
|
editorconfig: !workspace.config.editorconfig,
|
|
449
|
-
agentMd:
|
|
633
|
+
agentMd: writeAgentMd,
|
|
450
634
|
});
|
|
451
635
|
|
|
452
636
|
// Create alepha.config.ts with documented options
|
|
@@ -459,12 +643,14 @@ export class ProjectScaffolder {
|
|
|
459
643
|
force,
|
|
460
644
|
});
|
|
461
645
|
if (flags.api) {
|
|
462
|
-
await this.ensureApiProject(root, { force });
|
|
646
|
+
await this.ensureApiProject(root, { saas: !!flags.saas, force });
|
|
463
647
|
}
|
|
464
648
|
if (flags.react && !isExpo) {
|
|
465
649
|
await this.ensureWebProject(root, {
|
|
466
650
|
api: !!flags.api,
|
|
467
651
|
tailwind: !!flags.tailwind,
|
|
652
|
+
shadcn: !!flags.shadcn,
|
|
653
|
+
saas: !!flags.saas,
|
|
468
654
|
force,
|
|
469
655
|
});
|
|
470
656
|
}
|
|
@@ -503,10 +689,76 @@ export class ProjectScaffolder {
|
|
|
503
689
|
await this.ensureTestDir(root);
|
|
504
690
|
}
|
|
505
691
|
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
692
|
+
// shadcn/ui: run `<pm> shadcn init` against the components.json we wrote
|
|
693
|
+
// earlier. shadcn detects the existing config, respects our aliases,
|
|
694
|
+
// injects theme tokens into src/main.css, writes src/web/lib/utils.ts,
|
|
695
|
+
// and installs runtime deps (clsx, tailwind-merge, etc.).
|
|
696
|
+
//
|
|
697
|
+
// Flags chosen to keep this fully non-interactive:
|
|
698
|
+
// --yes skip confirmation prompts (default in shadcn v4 but
|
|
699
|
+
// passed explicitly so older versions also behave)
|
|
700
|
+
// --no-monorepo skip the monorepo prompt — we ship a single-app
|
|
701
|
+
// layout; users opt into monorepo via `--monorepo`
|
|
702
|
+
// on the alepha side later
|
|
703
|
+
// --silent suppress shadcn's own progress output; alepha's
|
|
704
|
+
// runner already prints a status line
|
|
705
|
+
//
|
|
706
|
+
// We deliberately do NOT pass `--defaults` (would force Next.js +
|
|
707
|
+
// base-nova preset) or `--template` (only applies to scratch projects;
|
|
708
|
+
// ours already has main.server.ts / main.browser.ts).
|
|
709
|
+
// Each PM has a different way to exec a project-local binary.
|
|
710
|
+
const exec = pmExecPrefix(pmName);
|
|
711
|
+
|
|
712
|
+
if (flags.shadcn) {
|
|
713
|
+
// Fully non-interactive shadcn init. The `--preset` arg is what makes
|
|
714
|
+
// this work — without it shadcn falls back to interactive prompts even
|
|
715
|
+
// with --yes/--force. Defaults: vite template + radix base + reinstall
|
|
716
|
+
// (so the components.json we pre-wrote stays canonical).
|
|
717
|
+
await run(
|
|
718
|
+
`${exec} shadcn init --no-monorepo --base radix -t vite --yes --force --reinstall --preset ${escapeShellArg(shadcnPreset)}`,
|
|
719
|
+
{ alias: `running shadcn init (preset ${shadcnPreset})`, root },
|
|
720
|
+
);
|
|
721
|
+
// Re-pin our aliases + alepha registry — `shadcn init --force`
|
|
722
|
+
// overwrites components.json with the template defaults.
|
|
723
|
+
await this.fs.writeFile(
|
|
724
|
+
this.fs.join(root, "components.json"),
|
|
725
|
+
componentsJsonTs(),
|
|
726
|
+
);
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
// SaaS preset: pull in the auth + admin registry components from the
|
|
730
|
+
// public alepha registry (already wired via components.json's
|
|
731
|
+
// `registries: { "@alepha": "https://alepha.dev/r/{name}.json" }`).
|
|
732
|
+
// Each `shadcn add` writes the component into src/web/components/* and
|
|
733
|
+
// pulls its peer primitives + dependencies (sonner, etc.).
|
|
734
|
+
if (flags.saas) {
|
|
735
|
+
// Pull the public SaaS bundle in one shot — it aggregates control,
|
|
736
|
+
// auto-form, alepha-table, use-dialog, app-shell, every auth-*, and
|
|
737
|
+
// every admin-* block. Definition lives at
|
|
738
|
+
// https://alepha.dev/r/saas.json (see @alepha/ui-registry).
|
|
739
|
+
// `--yes --overwrite` is the only combo that works non-interactively
|
|
740
|
+
// when registry items would replace files we pre-wrote (auth-login etc.
|
|
741
|
+
// overlap with shadcn primitives like button/input).
|
|
742
|
+
await run(`${exec} shadcn add @alepha/saas --yes --overwrite`, {
|
|
743
|
+
alias: "adding alepha saas registry bundle",
|
|
744
|
+
root,
|
|
745
|
+
});
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
// Best-effort lint: shadcn-imported registry components occasionally
|
|
749
|
+
// trip biome rules (e.g. noArrayIndexKey on a Fragment loop). The user
|
|
750
|
+
// can fix or silence these later — don't block the whole init.
|
|
751
|
+
try {
|
|
752
|
+
await run(`${pmName} run lint`, {
|
|
753
|
+
alias: "running linter",
|
|
754
|
+
root,
|
|
755
|
+
});
|
|
756
|
+
} catch (err) {
|
|
757
|
+
this.log.warn(
|
|
758
|
+
"Linter reported issues during init — continuing. Run `lint` again later to inspect.",
|
|
759
|
+
{ error: err instanceof Error ? err.message : String(err) },
|
|
760
|
+
);
|
|
761
|
+
}
|
|
510
762
|
|
|
511
763
|
// Initialize git repository if not in a workspace package
|
|
512
764
|
if (!workspace.isPackage) {
|
|
@@ -587,3 +839,33 @@ export class ProjectScaffolder {
|
|
|
587
839
|
}
|
|
588
840
|
}
|
|
589
841
|
}
|
|
842
|
+
|
|
843
|
+
/**
|
|
844
|
+
* Map a package manager name to the command that runs a project-local binary.
|
|
845
|
+
*
|
|
846
|
+
* - npm: `npx`
|
|
847
|
+
* - yarn: `yarn` (yarn auto-resolves binary names; `yarn shadcn ...` works)
|
|
848
|
+
* - pnpm: `pnpm exec`
|
|
849
|
+
* - bun: `bunx`
|
|
850
|
+
*
|
|
851
|
+
* Used to invoke `shadcn init` / `shadcn add` regardless of the user's PM —
|
|
852
|
+
* `npm shadcn ...` is invalid (it tries to run a script named `shadcn`).
|
|
853
|
+
*/
|
|
854
|
+
/** Quote a value so it survives shell parsing. */
|
|
855
|
+
const escapeShellArg = (value: string): string => {
|
|
856
|
+
if (/^[A-Za-z0-9_./@:-]+$/.test(value)) return value;
|
|
857
|
+
return `'${value.replace(/'/g, "'\\''")}'`;
|
|
858
|
+
};
|
|
859
|
+
|
|
860
|
+
const pmExecPrefix = (pmName: string): string => {
|
|
861
|
+
switch (pmName) {
|
|
862
|
+
case "npm":
|
|
863
|
+
return "npx";
|
|
864
|
+
case "pnpm":
|
|
865
|
+
return "pnpm exec";
|
|
866
|
+
case "bun":
|
|
867
|
+
return "bunx";
|
|
868
|
+
default:
|
|
869
|
+
return "yarn";
|
|
870
|
+
}
|
|
871
|
+
};
|
|
@@ -73,6 +73,11 @@ export class BuildCloudflareTask extends BuildTask {
|
|
|
73
73
|
};
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
+
wrangler.observability ??= {
|
|
77
|
+
enabled: true,
|
|
78
|
+
head_sampling_rate: 1,
|
|
79
|
+
};
|
|
80
|
+
|
|
76
81
|
this.enhanceDomain(wrangler);
|
|
77
82
|
this.enhanceCron(ctx, wrangler);
|
|
78
83
|
this.enhanceDatabase(wrangler);
|
|
@@ -8,7 +8,7 @@ import { BuildTask, type BuildTaskContext } from "./BuildTask.ts";
|
|
|
8
8
|
*
|
|
9
9
|
* Creates:
|
|
10
10
|
* - Dockerfile with configurable base image
|
|
11
|
-
* - Copies
|
|
11
|
+
* - Copies migrations directory if it exists
|
|
12
12
|
* - Builds Docker image when `--image` flag is provided
|
|
13
13
|
*/
|
|
14
14
|
export class BuildDockerTask extends BuildTask {
|
|
@@ -32,7 +32,7 @@ export class BuildDockerTask extends BuildTask {
|
|
|
32
32
|
await ctx.run({
|
|
33
33
|
name: "generate deploy config (docker)",
|
|
34
34
|
handler: async () => {
|
|
35
|
-
await this.
|
|
35
|
+
await this.copyMigrations(ctx.root, distDir);
|
|
36
36
|
await this.writeDockerfile(
|
|
37
37
|
ctx.root,
|
|
38
38
|
distDir,
|
|
@@ -47,14 +47,13 @@ export class BuildDockerTask extends BuildTask {
|
|
|
47
47
|
}
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
protected async
|
|
51
|
-
root
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
await this.fs.cp(drizzleDir, this.fs.join(root, distDir, "drizzle"));
|
|
50
|
+
protected async copyMigrations(root: string, distDir: string): Promise<void> {
|
|
51
|
+
const migrationsDir = this.fs.join(root, "migrations");
|
|
52
|
+
if (await this.fs.exists(migrationsDir)) {
|
|
53
|
+
await this.fs.cp(
|
|
54
|
+
migrationsDir,
|
|
55
|
+
this.fs.join(root, distDir, "migrations"),
|
|
56
|
+
);
|
|
58
57
|
}
|
|
59
58
|
}
|
|
60
59
|
|
|
@@ -135,6 +135,14 @@ export class BuildServerTask extends BuildTask {
|
|
|
135
135
|
chunkFileNames: "[hash].js",
|
|
136
136
|
assetFileNames: "[hash][extname]",
|
|
137
137
|
format: "esm",
|
|
138
|
+
codeSplitting: {
|
|
139
|
+
groups: [
|
|
140
|
+
{
|
|
141
|
+
name: "react",
|
|
142
|
+
test: /node_modules\/react(\/|-dom\/)/,
|
|
143
|
+
},
|
|
144
|
+
],
|
|
145
|
+
},
|
|
138
146
|
// Rolldown/Oxc minifier: preserve class and function names
|
|
139
147
|
minify: {
|
|
140
148
|
mangle: { keepNames: true },
|
|
@@ -1,13 +1,5 @@
|
|
|
1
|
-
export
|
|
2
|
-
|
|
3
|
-
export interface AgentMdOptions {
|
|
4
|
-
type: AgentMdType;
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
export const agentMd = (options: AgentMdOptions): string => {
|
|
8
|
-
const header = options.type === "claude" ? `# CLAUDE.md` : `# AGENTS.md`;
|
|
9
|
-
|
|
10
|
-
return `${header}
|
|
1
|
+
export const agentMd = (): string => {
|
|
2
|
+
return `# AGENTS.md
|
|
11
3
|
|
|
12
4
|
This is an **Alepha** project.
|
|
13
5
|
|
|
@@ -1,9 +1,31 @@
|
|
|
1
1
|
export interface ApiIndexTsOptions {
|
|
2
2
|
appName?: string;
|
|
3
|
+
/**
|
|
4
|
+
* Include `AlephaApiUsers` (realms, sessions, registration, identities,
|
|
5
|
+
* password reset, email verification, admin endpoints) plus the local
|
|
6
|
+
* `RealmProvider` that declares `$realm({ ... })`.
|
|
7
|
+
*/
|
|
8
|
+
saas?: boolean;
|
|
3
9
|
}
|
|
4
10
|
|
|
5
11
|
export const apiIndexTs = (options: ApiIndexTsOptions = {}) => {
|
|
6
|
-
const { appName = "app" } = options;
|
|
12
|
+
const { appName = "app", saas = false } = options;
|
|
13
|
+
|
|
14
|
+
if (saas) {
|
|
15
|
+
return `
|
|
16
|
+
import { $module } from "alepha";
|
|
17
|
+
import { AlephaApiUsers } from "alepha/api/users";
|
|
18
|
+
import { HelloController } from "./controllers/HelloController.ts";
|
|
19
|
+
import { RealmProvider } from "./providers/RealmProvider.ts";
|
|
20
|
+
|
|
21
|
+
export const ApiModule = $module({
|
|
22
|
+
name: "${appName}.api",
|
|
23
|
+
services: [HelloController, RealmProvider],
|
|
24
|
+
imports: [AlephaApiUsers],
|
|
25
|
+
});
|
|
26
|
+
`.trim();
|
|
27
|
+
}
|
|
28
|
+
|
|
7
29
|
return `
|
|
8
30
|
import { $module } from "alepha";
|
|
9
31
|
import { HelloController } from "./controllers/HelloController.ts";
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `components.json` is the shadcn CLI's project config — it tells
|
|
3
|
+
* `shadcn add` where to drop primitives, which tailwind tokens to use,
|
|
4
|
+
* which icon library to wire up, and which custom registries to resolve.
|
|
5
|
+
*
|
|
6
|
+
* Aliases follow shadcn's defaults (`@/components`, `@/lib/utils`) so the
|
|
7
|
+
* CLI honors them across `init` + `add` calls. Alepha app code lives at
|
|
8
|
+
* `src/web/` (Home, AppRouter, …) and the shadcn primitives live at
|
|
9
|
+
* `src/components/` — kept separate to make the registry components
|
|
10
|
+
* trivially upgradable via `shadcn add --overwrite`.
|
|
11
|
+
*
|
|
12
|
+
* The `registries` block pre-wires the public Alepha registry — consumers
|
|
13
|
+
* can immediately run e.g. `shadcn add @alepha/auth-login`.
|
|
14
|
+
*/
|
|
15
|
+
export const componentsJsonTs = () =>
|
|
16
|
+
`{
|
|
17
|
+
"$schema": "https://ui.shadcn.com/schema.json",
|
|
18
|
+
"style": "new-york",
|
|
19
|
+
"rsc": false,
|
|
20
|
+
"tsx": true,
|
|
21
|
+
"tailwind": {
|
|
22
|
+
"config": "",
|
|
23
|
+
"css": "src/main.css",
|
|
24
|
+
"baseColor": "neutral",
|
|
25
|
+
"cssVariables": true
|
|
26
|
+
},
|
|
27
|
+
"aliases": {
|
|
28
|
+
"components": "@/components",
|
|
29
|
+
"utils": "@/lib/utils",
|
|
30
|
+
"ui": "@/components/ui",
|
|
31
|
+
"lib": "@/lib",
|
|
32
|
+
"hooks": "@/hooks"
|
|
33
|
+
},
|
|
34
|
+
"iconLibrary": "lucide",
|
|
35
|
+
"registries": {
|
|
36
|
+
"@alepha": "https://alepha.dev/r/{name}.json"
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
`;
|