alepha 0.13.2 → 0.13.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/dist/api-files/index.browser.js +80 -0
- package/dist/api-files/index.browser.js.map +1 -0
- package/dist/api-jobs/index.browser.js +56 -0
- package/dist/api-jobs/index.browser.js.map +1 -0
- package/dist/api-notifications/index.browser.js +382 -0
- package/dist/api-notifications/index.browser.js.map +1 -0
- package/dist/api-notifications/index.d.ts +124 -69
- package/dist/api-notifications/index.js +107 -55
- package/dist/api-notifications/index.js.map +1 -1
- package/dist/api-parameters/index.browser.js +29 -0
- package/dist/api-parameters/index.browser.js.map +1 -0
- package/dist/api-users/index.d.ts +16 -3
- package/dist/api-users/index.js +75 -28
- package/dist/api-users/index.js.map +1 -1
- package/dist/api-verifications/index.browser.js +52 -0
- package/dist/api-verifications/index.browser.js.map +1 -0
- package/dist/api-verifications/index.d.ts +117 -95
- package/dist/api-verifications/index.js +1 -1
- package/dist/api-verifications/index.js.map +1 -1
- package/dist/batch/index.js +0 -5
- package/dist/batch/index.js.map +1 -1
- package/dist/bucket/index.js +7 -5
- package/dist/bucket/index.js.map +1 -1
- package/dist/cli/{dist-Dl9Vl7Ur.js → dist-lGnqsKpu.js} +11 -15
- package/dist/cli/dist-lGnqsKpu.js.map +1 -0
- package/dist/cli/index.d.ts +26 -45
- package/dist/cli/index.js +40 -58
- package/dist/cli/index.js.map +1 -1
- package/dist/command/index.d.ts +1 -0
- package/dist/command/index.js +9 -0
- package/dist/command/index.js.map +1 -1
- package/dist/email/index.js +5 -0
- package/dist/email/index.js.map +1 -1
- package/dist/orm/index.js +3 -3
- package/dist/orm/index.js.map +1 -1
- package/dist/redis/index.d.ts +10 -10
- package/dist/security/index.d.ts +28 -28
- package/dist/security/index.js +3 -3
- package/dist/security/index.js.map +1 -1
- package/dist/server/index.d.ts +9 -9
- package/dist/server-auth/index.d.ts +152 -152
- package/dist/server-cookies/index.js +2 -2
- package/dist/server-cookies/index.js.map +1 -1
- package/dist/server-links/index.d.ts +33 -33
- package/dist/server-static/index.js +18 -2
- package/dist/server-static/index.js.map +1 -1
- package/package.json +16 -6
- package/src/api-files/index.browser.ts +17 -0
- package/src/api-jobs/index.browser.ts +15 -0
- package/src/api-notifications/controllers/NotificationController.ts +26 -1
- package/src/api-notifications/index.browser.ts +17 -0
- package/src/api-notifications/index.ts +1 -0
- package/src/api-notifications/schemas/notificationQuerySchema.ts +13 -0
- package/src/api-notifications/services/NotificationService.ts +45 -2
- package/src/api-parameters/index.browser.ts +12 -0
- package/src/api-users/atoms/realmAuthSettingsAtom.ts +3 -1
- package/src/api-users/controllers/UserController.ts +21 -1
- package/src/api-users/primitives/$userRealm.ts +33 -10
- package/src/api-users/providers/UserRealmProvider.ts +1 -0
- package/src/api-users/services/SessionService.ts +2 -0
- package/src/api-users/services/UserService.ts +56 -16
- package/src/api-verifications/index.browser.ts +15 -0
- package/src/api-verifications/index.ts +1 -0
- package/src/batch/providers/BatchProvider.ts +0 -7
- package/src/bucket/index.ts +7 -5
- package/src/cli/apps/AlephaCli.ts +27 -1
- package/src/cli/apps/AlephaPackageBuilderCli.ts +3 -0
- package/src/cli/commands/CoreCommands.ts +6 -2
- package/src/cli/commands/ViteCommands.ts +2 -1
- package/src/cli/services/ProjectUtils.ts +40 -75
- package/src/command/helpers/Asker.ts +10 -0
- package/src/email/index.ts +13 -5
- package/src/orm/providers/drivers/NodeSqliteProvider.ts +3 -3
- package/src/server-cookies/providers/ServerCookiesProvider.ts +2 -1
- package/src/server-static/providers/ServerStaticProvider.ts +18 -3
- package/dist/cli/dist-Dl9Vl7Ur.js.map +0 -1
|
@@ -23,12 +23,22 @@ export class UserService {
|
|
|
23
23
|
|
|
24
24
|
/**
|
|
25
25
|
* Request email verification for a user.
|
|
26
|
+
* @param email - The email address to verify.
|
|
27
|
+
* @param userRealmName - Optional realm name.
|
|
28
|
+
* @param method - The verification method: "code" (default) or "link".
|
|
29
|
+
* @param verifyUrl - Base URL for verification link (required when method is "link").
|
|
26
30
|
*/
|
|
27
31
|
public async requestEmailVerification(
|
|
28
32
|
email: string,
|
|
29
33
|
userRealmName?: string,
|
|
34
|
+
method: "code" | "link" = "code",
|
|
35
|
+
verifyUrl?: string,
|
|
30
36
|
): Promise<boolean> {
|
|
31
|
-
this.log.trace("Requesting email verification", {
|
|
37
|
+
this.log.trace("Requesting email verification", {
|
|
38
|
+
email,
|
|
39
|
+
userRealmName,
|
|
40
|
+
method,
|
|
41
|
+
});
|
|
32
42
|
|
|
33
43
|
const user = await this.users(userRealmName)
|
|
34
44
|
.findOne({
|
|
@@ -54,23 +64,47 @@ export class UserService {
|
|
|
54
64
|
try {
|
|
55
65
|
const verification =
|
|
56
66
|
await this.verificationController.requestVerificationCode({
|
|
57
|
-
params: { type:
|
|
67
|
+
params: { type: method },
|
|
58
68
|
body: { target: email },
|
|
59
69
|
});
|
|
60
70
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
71
|
+
if (method === "link") {
|
|
72
|
+
// Build verification URL with token
|
|
73
|
+
const url = new URL(verifyUrl || "/verify-email", "http://localhost");
|
|
74
|
+
url.searchParams.set("email", email);
|
|
75
|
+
url.searchParams.set("token", verification.token);
|
|
76
|
+
const fullVerifyUrl = verifyUrl
|
|
77
|
+
? `${verifyUrl}${url.search}`
|
|
78
|
+
: url.pathname + url.search;
|
|
79
|
+
|
|
80
|
+
await this.userNotifications.emailVerificationLink.push({
|
|
81
|
+
contact: email,
|
|
82
|
+
variables: {
|
|
83
|
+
email,
|
|
84
|
+
verifyUrl: fullVerifyUrl,
|
|
85
|
+
expiresInMinutes: Math.floor(verification.codeExpiration / 60),
|
|
86
|
+
},
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
this.log.debug("Email verification link sent", {
|
|
64
90
|
email,
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
91
|
+
userId: user.id,
|
|
92
|
+
});
|
|
93
|
+
} else {
|
|
94
|
+
await this.userNotifications.emailVerification.push({
|
|
95
|
+
contact: email,
|
|
96
|
+
variables: {
|
|
97
|
+
email,
|
|
98
|
+
code: verification.token,
|
|
99
|
+
expiresInMinutes: Math.floor(verification.codeExpiration / 60),
|
|
100
|
+
},
|
|
101
|
+
});
|
|
69
102
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
103
|
+
this.log.debug("Email verification code sent", {
|
|
104
|
+
email,
|
|
105
|
+
userId: user.id,
|
|
106
|
+
});
|
|
107
|
+
}
|
|
74
108
|
} catch (error) {
|
|
75
109
|
// Silent fail for security
|
|
76
110
|
this.log.warn("Failed to send email verification", { email, error });
|
|
@@ -81,6 +115,7 @@ export class UserService {
|
|
|
81
115
|
|
|
82
116
|
/**
|
|
83
117
|
* Verify a user's email using a valid verification token.
|
|
118
|
+
* Supports both code (6-digit) and link (UUID) verification tokens.
|
|
84
119
|
*/
|
|
85
120
|
public async verifyEmail(
|
|
86
121
|
email: string,
|
|
@@ -89,13 +124,18 @@ export class UserService {
|
|
|
89
124
|
): Promise<void> {
|
|
90
125
|
this.log.trace("Verifying email", { email, userRealmName });
|
|
91
126
|
|
|
127
|
+
// Detect verification type based on token format
|
|
128
|
+
// Codes are 6-digit numbers, links are UUIDs
|
|
129
|
+
const isCode = /^\d{6}$/.test(token);
|
|
130
|
+
const type = isCode ? "code" : "link";
|
|
131
|
+
|
|
92
132
|
const result = await this.verificationController
|
|
93
133
|
.validateVerificationCode({
|
|
94
|
-
params: { type
|
|
134
|
+
params: { type },
|
|
95
135
|
body: { target: email, token },
|
|
96
136
|
})
|
|
97
137
|
.catch(() => {
|
|
98
|
-
this.log.warn("Invalid email verification token", { email });
|
|
138
|
+
this.log.warn("Invalid email verification token", { email, type });
|
|
99
139
|
throw new BadRequestError("Invalid or expired verification token");
|
|
100
140
|
});
|
|
101
141
|
|
|
@@ -112,7 +152,7 @@ export class UserService {
|
|
|
112
152
|
emailVerified: true,
|
|
113
153
|
});
|
|
114
154
|
|
|
115
|
-
this.log.info("Email verified", { email, userId: user.id });
|
|
155
|
+
this.log.info("Email verified", { email, userId: user.id, type });
|
|
116
156
|
}
|
|
117
157
|
|
|
118
158
|
/**
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { $module } from "alepha";
|
|
2
|
+
|
|
3
|
+
// ---------------------------------------------------------------------------------------------------------------------
|
|
4
|
+
|
|
5
|
+
export * from "./entities/verifications.ts";
|
|
6
|
+
export * from "./schemas/requestVerificationCodeResponseSchema.ts";
|
|
7
|
+
export * from "./schemas/validateVerificationCodeResponseSchema.ts";
|
|
8
|
+
export * from "./schemas/verificationTypeEnumSchema.ts";
|
|
9
|
+
|
|
10
|
+
// ---------------------------------------------------------------------------------------------------------------------
|
|
11
|
+
|
|
12
|
+
export const AlephaApiVerification = $module({
|
|
13
|
+
name: "alepha.api.verifications",
|
|
14
|
+
services: [],
|
|
15
|
+
});
|
|
@@ -6,6 +6,7 @@ import { VerificationService } from "./services/VerificationService.ts";
|
|
|
6
6
|
// ---------------------------------------------------------------------------------------------------------------------
|
|
7
7
|
|
|
8
8
|
export * from "./controllers/VerificationController.ts";
|
|
9
|
+
export * from "./entities/verifications.ts";
|
|
9
10
|
export * from "./schemas/requestVerificationCodeResponseSchema.ts";
|
|
10
11
|
export * from "./schemas/validateVerificationCodeResponseSchema.ts";
|
|
11
12
|
export * from "./schemas/verificationTypeEnumSchema.ts";
|
|
@@ -213,13 +213,6 @@ export class BatchProvider {
|
|
|
213
213
|
};
|
|
214
214
|
|
|
215
215
|
// CAUTION: Do not log.debug/info here as it may cause infinite loops if logging is batched
|
|
216
|
-
// log.trace is safe
|
|
217
|
-
|
|
218
|
-
this.log.trace("Pushing item to batch", {
|
|
219
|
-
id,
|
|
220
|
-
partitionKey,
|
|
221
|
-
item,
|
|
222
|
-
});
|
|
223
216
|
|
|
224
217
|
context.itemStates.set(id, itemState);
|
|
225
218
|
|
package/src/bucket/index.ts
CHANGED
|
@@ -61,12 +61,14 @@ export const AlephaBucket = $module({
|
|
|
61
61
|
MemoryFileStorageProvider,
|
|
62
62
|
LocalFileStorageProvider,
|
|
63
63
|
],
|
|
64
|
-
register: (alepha) =>
|
|
64
|
+
register: (alepha) => {
|
|
65
65
|
alepha.with({
|
|
66
66
|
optional: true,
|
|
67
67
|
provide: FileStorageProvider,
|
|
68
|
-
use:
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
68
|
+
use:
|
|
69
|
+
alepha.isTest() || alepha.isServerless()
|
|
70
|
+
? MemoryFileStorageProvider
|
|
71
|
+
: LocalFileStorageProvider,
|
|
72
|
+
});
|
|
73
|
+
},
|
|
72
74
|
});
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { join } from "node:path";
|
|
2
|
+
import { $hook, $inject, $module, Alepha } from "alepha";
|
|
3
|
+
import { FileSystemProvider } from "alepha/file";
|
|
2
4
|
import { BiomeCommands } from "../commands/BiomeCommands.ts";
|
|
3
5
|
import { CoreCommands } from "../commands/CoreCommands.ts";
|
|
4
6
|
import { DrizzleCommands } from "../commands/DrizzleCommands.ts";
|
|
@@ -6,9 +8,33 @@ import { VerifyCommands } from "../commands/VerifyCommands.ts";
|
|
|
6
8
|
import { ViteCommands } from "../commands/ViteCommands.ts";
|
|
7
9
|
import { ProcessRunner } from "../services/ProcessRunner.ts";
|
|
8
10
|
|
|
11
|
+
class AlephaCliExtension {
|
|
12
|
+
protected readonly alepha = $inject(Alepha);
|
|
13
|
+
protected readonly fs = $inject(FileSystemProvider);
|
|
14
|
+
protected readonly onConfigure = $hook({
|
|
15
|
+
on: "configure",
|
|
16
|
+
handler: async () => {
|
|
17
|
+
const extensionPath = join(process.cwd(), "alepha.config.ts");
|
|
18
|
+
const hasExtension = await this.fs.exists(extensionPath);
|
|
19
|
+
if (!hasExtension) {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// import
|
|
24
|
+
const { default: Extension } = await import(extensionPath);
|
|
25
|
+
if (typeof Extension !== "function") {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
this.alepha.with(Extension);
|
|
30
|
+
},
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
|
|
9
34
|
export const AlephaCli = $module({
|
|
10
35
|
name: "alepha.cli",
|
|
11
36
|
services: [
|
|
37
|
+
AlephaCliExtension,
|
|
12
38
|
ProcessRunner,
|
|
13
39
|
CoreCommands,
|
|
14
40
|
DrizzleCommands,
|
|
@@ -49,10 +49,13 @@ export class AlephaPackageBuilderCli {
|
|
|
49
49
|
pkgData.exports[path]["react-native"] =
|
|
50
50
|
`./src/${item.name}/index.browser.ts`;
|
|
51
51
|
}
|
|
52
|
+
|
|
52
53
|
if (item.browser) {
|
|
53
54
|
pkgData.exports[path].browser = `./src/${item.name}/index.browser.ts`;
|
|
54
55
|
}
|
|
56
|
+
|
|
55
57
|
pkgData.exports[path].import = `./src/${item.name}/index.ts`;
|
|
58
|
+
pkgData.exports[path].default = `./src/${item.name}/index.ts`;
|
|
56
59
|
}
|
|
57
60
|
|
|
58
61
|
if (packageName === "alepha") {
|
|
@@ -62,11 +62,15 @@ export class CoreCommands {
|
|
|
62
62
|
react: t.optional(
|
|
63
63
|
t.boolean({ description: "Include Alepha React dependencies" }),
|
|
64
64
|
),
|
|
65
|
-
|
|
66
|
-
t.boolean({ description: "Include Alepha
|
|
65
|
+
ui: t.optional(
|
|
66
|
+
t.boolean({ description: "Include Alepha UI dependencies" }),
|
|
67
67
|
),
|
|
68
68
|
}),
|
|
69
69
|
handler: async ({ run, flags, root }) => {
|
|
70
|
+
if (flags.ui) {
|
|
71
|
+
flags.react = true;
|
|
72
|
+
}
|
|
73
|
+
|
|
70
74
|
await run({
|
|
71
75
|
name: "Ensuring configuration files",
|
|
72
76
|
handler: async () => {
|
|
@@ -145,6 +145,7 @@ export class ViteCommands {
|
|
|
145
145
|
] ?? {};
|
|
146
146
|
|
|
147
147
|
const stats = flags.stats ?? viteAlephaBuildOptions.stats ?? false;
|
|
148
|
+
const hasServer = viteAlephaBuildOptions.serverEntry !== false;
|
|
148
149
|
|
|
149
150
|
let hasClient = false;
|
|
150
151
|
try {
|
|
@@ -189,7 +190,7 @@ export class ViteCommands {
|
|
|
189
190
|
});
|
|
190
191
|
|
|
191
192
|
// Server will handle index.html if both client & server are built
|
|
192
|
-
if (clientBuilt) {
|
|
193
|
+
if (clientBuilt && hasServer) {
|
|
193
194
|
await unlink(`${distDir}/${clientDir}/index.html`);
|
|
194
195
|
}
|
|
195
196
|
},
|
|
@@ -72,6 +72,11 @@ export class ProjectUtils {
|
|
|
72
72
|
|
|
73
73
|
const devDependencies: Record<string, string> = {};
|
|
74
74
|
|
|
75
|
+
if (modes.ui) {
|
|
76
|
+
dependencies["@alepha/ui"] = `^${version}`;
|
|
77
|
+
modes.react = true;
|
|
78
|
+
}
|
|
79
|
+
|
|
75
80
|
if (modes.react) {
|
|
76
81
|
dependencies["@alepha/react"] = `^${version}`;
|
|
77
82
|
dependencies.react = "^19.2.0";
|
|
@@ -79,10 +84,6 @@ export class ProjectUtils {
|
|
|
79
84
|
devDependencies["@types/react"] = "^19.2.0";
|
|
80
85
|
}
|
|
81
86
|
|
|
82
|
-
if (modes.admin) {
|
|
83
|
-
dependencies["@alepha/ui"] = `^${version}`;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
87
|
return {
|
|
87
88
|
type: "module",
|
|
88
89
|
dependencies,
|
|
@@ -174,33 +175,6 @@ export class ProjectUtils {
|
|
|
174
175
|
await Promise.all(tasks);
|
|
175
176
|
}
|
|
176
177
|
|
|
177
|
-
/**
|
|
178
|
-
* Ensure package.json exists and is configured as ES module.
|
|
179
|
-
*
|
|
180
|
-
* Similar to ensurePackageJson but only validates/sets the "type": "module" field.
|
|
181
|
-
* Throws an error if no package.json exists.
|
|
182
|
-
*
|
|
183
|
-
* @param root - The root directory of the project
|
|
184
|
-
* @throws {AlephaError} If no package.json is found
|
|
185
|
-
*/
|
|
186
|
-
public async ensurePackageJsonModule(root: string): Promise<void> {
|
|
187
|
-
const packageJsonPath = join(root, "package.json");
|
|
188
|
-
try {
|
|
189
|
-
await access(packageJsonPath);
|
|
190
|
-
} catch (error) {
|
|
191
|
-
throw new AlephaError(
|
|
192
|
-
"No package.json found in project root. Run 'npx alepha init' to create one.",
|
|
193
|
-
);
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
const content = await readFile(packageJsonPath, "utf8");
|
|
197
|
-
const packageJson = JSON.parse(content);
|
|
198
|
-
if (!packageJson.type || packageJson.type !== "module") {
|
|
199
|
-
packageJson.type = "module";
|
|
200
|
-
await writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2));
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
|
|
204
178
|
/**
|
|
205
179
|
* Ensure tsconfig.json exists in the project.
|
|
206
180
|
*
|
|
@@ -217,25 +191,30 @@ export class ProjectUtils {
|
|
|
217
191
|
*
|
|
218
192
|
* Creates a standard Alepha vite.config.ts if none exists.
|
|
219
193
|
*/
|
|
220
|
-
public async ensureViteConfig(
|
|
221
|
-
|
|
194
|
+
public async ensureViteConfig(
|
|
195
|
+
root: string,
|
|
196
|
+
serverEntry?: string,
|
|
197
|
+
): Promise<void> {
|
|
198
|
+
await this.ensureFileExists(
|
|
199
|
+
root,
|
|
200
|
+
"vite.config.ts",
|
|
201
|
+
viteConfigTs(serverEntry),
|
|
202
|
+
false,
|
|
203
|
+
);
|
|
222
204
|
}
|
|
223
205
|
|
|
224
|
-
protected async
|
|
206
|
+
protected async checkFileExists(
|
|
225
207
|
root: string,
|
|
226
208
|
name: string,
|
|
227
|
-
content: string,
|
|
228
209
|
checkParentDirectories: boolean = false,
|
|
229
|
-
): Promise<
|
|
210
|
+
): Promise<boolean> {
|
|
230
211
|
const configPath = join(root, name);
|
|
231
|
-
|
|
232
212
|
if (!checkParentDirectories) {
|
|
233
213
|
try {
|
|
234
214
|
await access(configPath);
|
|
235
|
-
return;
|
|
215
|
+
return true;
|
|
236
216
|
} catch {
|
|
237
|
-
|
|
238
|
-
return;
|
|
217
|
+
return false;
|
|
239
218
|
}
|
|
240
219
|
}
|
|
241
220
|
|
|
@@ -259,8 +238,23 @@ export class ProjectUtils {
|
|
|
259
238
|
level += 1;
|
|
260
239
|
}
|
|
261
240
|
|
|
241
|
+
return found;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
protected async ensureFileExists(
|
|
245
|
+
root: string,
|
|
246
|
+
name: string,
|
|
247
|
+
content: string,
|
|
248
|
+
checkParentDirectories: boolean = false,
|
|
249
|
+
): Promise<void> {
|
|
250
|
+
const found = await this.checkFileExists(
|
|
251
|
+
root,
|
|
252
|
+
name,
|
|
253
|
+
checkParentDirectories,
|
|
254
|
+
);
|
|
255
|
+
|
|
262
256
|
if (!found) {
|
|
263
|
-
await writeFile(
|
|
257
|
+
await writeFile(join(root, name), content);
|
|
264
258
|
}
|
|
265
259
|
}
|
|
266
260
|
|
|
@@ -277,35 +271,6 @@ export class ProjectUtils {
|
|
|
277
271
|
await this.ensureFileExists(root, "biome.json", biomeJson, true);
|
|
278
272
|
}
|
|
279
273
|
|
|
280
|
-
// ===================================================================================================================
|
|
281
|
-
// Vite Configuration
|
|
282
|
-
// ===================================================================================================================
|
|
283
|
-
|
|
284
|
-
/**
|
|
285
|
-
* Get the path to Vite configuration file.
|
|
286
|
-
*
|
|
287
|
-
* Looks for an existing vite.config.ts in the project root, or creates one if it doesn't exist.
|
|
288
|
-
*
|
|
289
|
-
* @param root - The root directory of the project (defaults to process.cwd())
|
|
290
|
-
* @param serverEntry - Optional path to the server entry file to include in the config
|
|
291
|
-
* @returns Absolute path to the vite.config.ts file
|
|
292
|
-
*/
|
|
293
|
-
public async getViteConfigPath(
|
|
294
|
-
root: string,
|
|
295
|
-
serverEntry?: string,
|
|
296
|
-
): Promise<string> {
|
|
297
|
-
try {
|
|
298
|
-
const viteConfigPath = join(root, "vite.config.ts");
|
|
299
|
-
await access(viteConfigPath);
|
|
300
|
-
return viteConfigPath;
|
|
301
|
-
} catch {
|
|
302
|
-
return this.runner.writeConfigFile(
|
|
303
|
-
"vite.config.ts",
|
|
304
|
-
viteConfigTs(serverEntry),
|
|
305
|
-
);
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
|
|
309
274
|
// ===================================================================================================================
|
|
310
275
|
// Drizzle ORM & Kit Utilities
|
|
311
276
|
// ===================================================================================================================
|
|
@@ -544,13 +509,13 @@ ${models.map((it: string) => `export const ${it} = models["${it}"];`).join("\n")
|
|
|
544
509
|
public async getPackageManager(
|
|
545
510
|
root: string,
|
|
546
511
|
): Promise<"yarn" | "pnpm" | "npm"> {
|
|
547
|
-
if (await this.
|
|
512
|
+
if (await this.checkFileExists(root, "yarn.lock", true)) {
|
|
548
513
|
return "yarn";
|
|
549
|
-
}
|
|
514
|
+
}
|
|
515
|
+
if (await this.checkFileExists(root, "pnpm-lock.yaml", true)) {
|
|
550
516
|
return "pnpm";
|
|
551
|
-
} else {
|
|
552
|
-
return "npm";
|
|
553
517
|
}
|
|
518
|
+
return "npm";
|
|
554
519
|
}
|
|
555
520
|
|
|
556
521
|
public async ensureIndexHtml(root: string) {
|
|
@@ -597,5 +562,5 @@ ${models.map((it: string) => `export const ${it} = models["${it}"];`).join("\n")
|
|
|
597
562
|
|
|
598
563
|
export interface DependencyModes {
|
|
599
564
|
react?: boolean;
|
|
600
|
-
|
|
565
|
+
ui?: boolean;
|
|
601
566
|
}
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
type Static,
|
|
8
8
|
type TSchema,
|
|
9
9
|
type TString,
|
|
10
|
+
t,
|
|
10
11
|
} from "alepha";
|
|
11
12
|
import { $logger } from "alepha/logger";
|
|
12
13
|
|
|
@@ -44,6 +45,8 @@ export interface AskMethod {
|
|
|
44
45
|
question: string,
|
|
45
46
|
options?: AskOptions<T>,
|
|
46
47
|
): Promise<Static<T>>;
|
|
48
|
+
|
|
49
|
+
permission: (question: string) => Promise<boolean>;
|
|
47
50
|
}
|
|
48
51
|
|
|
49
52
|
export class Asker {
|
|
@@ -63,6 +66,13 @@ export class Asker {
|
|
|
63
66
|
return await this.prompt<T>(question, options);
|
|
64
67
|
};
|
|
65
68
|
|
|
69
|
+
askFn.permission = async (question: string) => {
|
|
70
|
+
const response = await this.prompt(`${question} [Y/n]`, {
|
|
71
|
+
schema: t.enum(["Y", "y", "n", "no", "yes"], { default: "Y" }),
|
|
72
|
+
});
|
|
73
|
+
return response.charAt(0).toLowerCase() === "y";
|
|
74
|
+
};
|
|
75
|
+
|
|
66
76
|
return askFn;
|
|
67
77
|
}
|
|
68
78
|
|
package/src/email/index.ts
CHANGED
|
@@ -68,11 +68,19 @@ export const AlephaEmail = $module({
|
|
|
68
68
|
use: NodemailerEmailProvider,
|
|
69
69
|
});
|
|
70
70
|
} else {
|
|
71
|
-
alepha.
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
71
|
+
if (alepha.isServerless()) {
|
|
72
|
+
alepha.with({
|
|
73
|
+
optional: true,
|
|
74
|
+
provide: EmailProvider,
|
|
75
|
+
use: MemoryEmailProvider,
|
|
76
|
+
});
|
|
77
|
+
} else {
|
|
78
|
+
alepha.with({
|
|
79
|
+
optional: true,
|
|
80
|
+
provide: EmailProvider,
|
|
81
|
+
use: LocalEmailProvider,
|
|
82
|
+
});
|
|
83
|
+
}
|
|
76
84
|
}
|
|
77
85
|
},
|
|
78
86
|
});
|
|
@@ -82,10 +82,10 @@ export class NodeSqliteProvider extends DatabaseProvider {
|
|
|
82
82
|
return path;
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
-
if (this.alepha.isTest()) {
|
|
85
|
+
if (this.alepha.isTest() || this.alepha.isServerless()) {
|
|
86
86
|
return ":memory:";
|
|
87
87
|
} else {
|
|
88
|
-
return "node_modules/sqlite.db";
|
|
88
|
+
return "node_modules/.alepha/sqlite.db";
|
|
89
89
|
}
|
|
90
90
|
}
|
|
91
91
|
|
|
@@ -149,7 +149,7 @@ export class NodeSqliteProvider extends DatabaseProvider {
|
|
|
149
149
|
if (filepath !== ":memory:" && filepath !== "") {
|
|
150
150
|
const dirname = filepath.split("/").slice(0, -1).join("/");
|
|
151
151
|
if (dirname) {
|
|
152
|
-
await mkdir(dirname, { recursive: true });
|
|
152
|
+
await mkdir(dirname, { recursive: true }).catch(() => null);
|
|
153
153
|
}
|
|
154
154
|
}
|
|
155
155
|
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
$hook,
|
|
12
12
|
$inject,
|
|
13
13
|
Alepha,
|
|
14
|
+
AlephaError,
|
|
14
15
|
type Static,
|
|
15
16
|
type TSchema,
|
|
16
17
|
t,
|
|
@@ -89,7 +90,7 @@ export class ServerCookiesProvider {
|
|
|
89
90
|
this.alepha.context.get<ServerRequest>("request")?.cookies;
|
|
90
91
|
if (cookies) return cookies;
|
|
91
92
|
if (contextCookies) return contextCookies;
|
|
92
|
-
throw new
|
|
93
|
+
throw new AlephaError(
|
|
93
94
|
"Cookie context is not available. This method must be called within a server request cycle.",
|
|
94
95
|
);
|
|
95
96
|
}
|
|
@@ -98,8 +98,15 @@ export class ServerStaticProvider {
|
|
|
98
98
|
reply.headers["content-type"] = "text/html";
|
|
99
99
|
reply.status = 200;
|
|
100
100
|
|
|
101
|
-
|
|
102
|
-
|
|
101
|
+
return new Promise<any>((resolve, reject) => {
|
|
102
|
+
const stream = createReadStream(join(root, "index.html"));
|
|
103
|
+
stream.on("open", () => {
|
|
104
|
+
resolve(stream);
|
|
105
|
+
});
|
|
106
|
+
stream.on("error", (err) => {
|
|
107
|
+
reject(err);
|
|
108
|
+
});
|
|
109
|
+
});
|
|
103
110
|
},
|
|
104
111
|
});
|
|
105
112
|
}
|
|
@@ -161,7 +168,15 @@ export class ServerStaticProvider {
|
|
|
161
168
|
return;
|
|
162
169
|
}
|
|
163
170
|
|
|
164
|
-
return
|
|
171
|
+
return new Promise<any>((resolve, reject) => {
|
|
172
|
+
const stream = createReadStream(path);
|
|
173
|
+
stream.on("open", () => {
|
|
174
|
+
resolve(stream);
|
|
175
|
+
});
|
|
176
|
+
stream.on("error", (err) => {
|
|
177
|
+
reject(err);
|
|
178
|
+
});
|
|
179
|
+
});
|
|
165
180
|
};
|
|
166
181
|
}
|
|
167
182
|
|