alepha 0.15.0 → 0.15.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +43 -98
- package/dist/api/audits/index.d.ts +240 -240
- package/dist/api/audits/index.d.ts.map +1 -1
- package/dist/api/audits/index.js +2 -2
- package/dist/api/audits/index.js.map +1 -1
- package/dist/api/files/index.d.ts +185 -185
- package/dist/api/files/index.d.ts.map +1 -1
- package/dist/api/files/index.js +2 -2
- package/dist/api/files/index.js.map +1 -1
- package/dist/api/jobs/index.d.ts +245 -245
- package/dist/api/jobs/index.d.ts.map +1 -1
- package/dist/api/notifications/index.browser.js +4 -4
- package/dist/api/notifications/index.browser.js.map +1 -1
- package/dist/api/notifications/index.d.ts +74 -74
- package/dist/api/notifications/index.d.ts.map +1 -1
- package/dist/api/notifications/index.js +4 -4
- package/dist/api/notifications/index.js.map +1 -1
- package/dist/api/parameters/index.d.ts +221 -221
- package/dist/api/parameters/index.d.ts.map +1 -1
- package/dist/api/users/index.d.ts +1632 -1631
- package/dist/api/users/index.d.ts.map +1 -1
- package/dist/api/users/index.js +26 -34
- package/dist/api/users/index.js.map +1 -1
- package/dist/api/verifications/index.d.ts +132 -132
- package/dist/api/verifications/index.d.ts.map +1 -1
- package/dist/batch/index.d.ts +122 -122
- package/dist/batch/index.d.ts.map +1 -1
- package/dist/bucket/index.d.ts +163 -163
- package/dist/bucket/index.d.ts.map +1 -1
- package/dist/cache/core/index.d.ts +46 -46
- package/dist/cache/core/index.d.ts.map +1 -1
- package/dist/cache/redis/index.d.ts.map +1 -1
- package/dist/cache/redis/index.js +2 -2
- package/dist/cache/redis/index.js.map +1 -1
- package/dist/cli/index.d.ts +5933 -201
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +609 -169
- package/dist/cli/index.js.map +1 -1
- package/dist/command/index.d.ts +296 -296
- package/dist/command/index.d.ts.map +1 -1
- package/dist/command/index.js +19 -19
- package/dist/command/index.js.map +1 -1
- package/dist/core/index.browser.js +268 -79
- package/dist/core/index.browser.js.map +1 -1
- package/dist/core/index.d.ts +768 -694
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +268 -79
- package/dist/core/index.js.map +1 -1
- package/dist/core/index.native.js +268 -79
- package/dist/core/index.native.js.map +1 -1
- package/dist/datetime/index.d.ts +44 -44
- package/dist/datetime/index.d.ts.map +1 -1
- package/dist/email/index.d.ts +25 -25
- package/dist/email/index.d.ts.map +1 -1
- package/dist/fake/index.d.ts +5409 -5409
- package/dist/fake/index.d.ts.map +1 -1
- package/dist/fake/index.js +22 -22
- package/dist/fake/index.js.map +1 -1
- package/dist/file/index.d.ts +435 -435
- package/dist/file/index.d.ts.map +1 -1
- package/dist/lock/core/index.d.ts +208 -208
- package/dist/lock/core/index.d.ts.map +1 -1
- package/dist/lock/redis/index.d.ts.map +1 -1
- package/dist/logger/index.d.ts +24 -24
- package/dist/logger/index.d.ts.map +1 -1
- package/dist/logger/index.js +1 -5
- package/dist/logger/index.js.map +1 -1
- package/dist/mcp/index.d.ts +216 -198
- package/dist/mcp/index.d.ts.map +1 -1
- package/dist/mcp/index.js +28 -4
- package/dist/mcp/index.js.map +1 -1
- package/dist/orm/index.browser.js +9 -9
- package/dist/orm/index.browser.js.map +1 -1
- package/dist/orm/index.bun.js +83 -76
- package/dist/orm/index.bun.js.map +1 -1
- package/dist/orm/index.d.ts +961 -960
- package/dist/orm/index.d.ts.map +1 -1
- package/dist/orm/index.js +88 -81
- package/dist/orm/index.js.map +1 -1
- package/dist/queue/core/index.d.ts +244 -244
- package/dist/queue/core/index.d.ts.map +1 -1
- package/dist/queue/redis/index.d.ts.map +1 -1
- package/dist/redis/index.d.ts +105 -105
- package/dist/redis/index.d.ts.map +1 -1
- package/dist/retry/index.d.ts +69 -69
- package/dist/retry/index.d.ts.map +1 -1
- package/dist/router/index.d.ts +6 -6
- package/dist/router/index.d.ts.map +1 -1
- package/dist/scheduler/index.d.ts +108 -26
- package/dist/scheduler/index.d.ts.map +1 -1
- package/dist/scheduler/index.js +393 -1
- package/dist/scheduler/index.js.map +1 -1
- package/dist/security/index.d.ts +532 -209
- package/dist/security/index.d.ts.map +1 -1
- package/dist/security/index.js +1422 -11
- package/dist/security/index.js.map +1 -1
- package/dist/server/auth/index.d.ts +1296 -271
- package/dist/server/auth/index.d.ts.map +1 -1
- package/dist/server/auth/index.js +1249 -18
- package/dist/server/auth/index.js.map +1 -1
- package/dist/server/cache/index.d.ts +56 -56
- package/dist/server/cache/index.d.ts.map +1 -1
- package/dist/server/compress/index.d.ts +3 -3
- package/dist/server/compress/index.d.ts.map +1 -1
- package/dist/server/cookies/index.d.ts +6 -6
- package/dist/server/cookies/index.d.ts.map +1 -1
- package/dist/server/core/index.d.ts +196 -186
- package/dist/server/core/index.d.ts.map +1 -1
- package/dist/server/core/index.js +43 -27
- package/dist/server/core/index.js.map +1 -1
- package/dist/server/cors/index.d.ts +11 -11
- package/dist/server/cors/index.d.ts.map +1 -1
- package/dist/server/health/index.d.ts.map +1 -1
- package/dist/server/helmet/index.d.ts +2 -2
- package/dist/server/helmet/index.d.ts.map +1 -1
- package/dist/server/links/index.browser.js +9 -1
- package/dist/server/links/index.browser.js.map +1 -1
- package/dist/server/links/index.d.ts +83 -83
- package/dist/server/links/index.d.ts.map +1 -1
- package/dist/server/links/index.js +13 -5
- package/dist/server/links/index.js.map +1 -1
- package/dist/server/metrics/index.d.ts +514 -1
- package/dist/server/metrics/index.d.ts.map +1 -1
- package/dist/server/metrics/index.js +4462 -4
- package/dist/server/metrics/index.js.map +1 -1
- package/dist/server/multipart/index.d.ts +6 -6
- package/dist/server/multipart/index.d.ts.map +1 -1
- package/dist/server/proxy/index.d.ts +102 -102
- package/dist/server/proxy/index.d.ts.map +1 -1
- package/dist/server/rate-limit/index.d.ts +16 -16
- package/dist/server/rate-limit/index.d.ts.map +1 -1
- package/dist/server/static/index.d.ts +44 -44
- package/dist/server/static/index.d.ts.map +1 -1
- package/dist/server/swagger/index.d.ts +47 -47
- package/dist/server/swagger/index.d.ts.map +1 -1
- package/dist/sms/index.d.ts +11 -11
- package/dist/sms/index.d.ts.map +1 -1
- package/dist/sms/index.js +3 -3
- package/dist/sms/index.js.map +1 -1
- package/dist/thread/index.d.ts +71 -71
- package/dist/thread/index.d.ts.map +1 -1
- package/dist/thread/index.js +2 -2
- package/dist/thread/index.js.map +1 -1
- package/dist/topic/core/index.d.ts +318 -318
- package/dist/topic/core/index.d.ts.map +1 -1
- package/dist/topic/redis/index.d.ts +6 -6
- package/dist/topic/redis/index.d.ts.map +1 -1
- package/dist/vite/index.d.ts +2324 -1719
- package/dist/vite/index.d.ts.map +1 -1
- package/dist/vite/index.js +123 -475
- package/dist/vite/index.js.map +1 -1
- package/dist/websocket/index.browser.js +3 -3
- package/dist/websocket/index.browser.js.map +1 -1
- package/dist/websocket/index.d.ts +275 -275
- package/dist/websocket/index.d.ts.map +1 -1
- package/dist/websocket/index.js +3 -3
- package/dist/websocket/index.js.map +1 -1
- package/package.json +9 -9
- package/src/api/users/services/SessionService.ts +0 -10
- package/src/cli/apps/AlephaCli.ts +2 -2
- package/src/cli/apps/AlephaPackageBuilderCli.ts +9 -1
- package/src/cli/assets/apiHelloControllerTs.ts +2 -1
- package/src/cli/assets/biomeJson.ts +2 -1
- package/src/cli/assets/claudeMd.ts +9 -4
- package/src/cli/assets/dummySpecTs.ts +2 -1
- package/src/cli/assets/editorconfig.ts +2 -1
- package/src/cli/assets/mainBrowserTs.ts +2 -1
- package/src/cli/assets/mainCss.ts +24 -0
- package/src/cli/assets/tsconfigJson.ts +2 -1
- package/src/cli/assets/webAppRouterTs.ts +2 -1
- package/src/cli/assets/webHelloComponentTsx.ts +6 -2
- package/src/cli/atoms/appEntryOptions.ts +13 -0
- package/src/cli/atoms/buildOptions.ts +1 -1
- package/src/cli/atoms/changelogOptions.ts +1 -1
- package/src/cli/commands/build.ts +63 -47
- package/src/cli/commands/dev.ts +16 -33
- package/src/cli/commands/gen/env.ts +1 -1
- package/src/cli/commands/init.ts +17 -8
- package/src/cli/commands/lint.ts +1 -1
- package/src/cli/defineConfig.ts +9 -0
- package/src/cli/index.ts +2 -1
- package/src/cli/providers/AppEntryProvider.ts +131 -0
- package/src/cli/providers/ViteBuildProvider.ts +82 -0
- package/src/cli/providers/ViteDevServerProvider.ts +350 -0
- package/src/cli/providers/ViteTemplateProvider.ts +27 -0
- package/src/cli/services/AlephaCliUtils.ts +33 -2
- package/src/cli/services/PackageManagerUtils.ts +13 -6
- package/src/cli/services/ProjectScaffolder.ts +72 -49
- package/src/core/Alepha.ts +2 -8
- package/src/core/primitives/$module.ts +12 -0
- package/src/core/providers/KeylessJsonSchemaCodec.spec.ts +257 -0
- package/src/core/providers/KeylessJsonSchemaCodec.ts +396 -14
- package/src/core/providers/SchemaValidator.spec.ts +236 -0
- package/src/logger/providers/PrettyFormatterProvider.ts +0 -9
- package/src/mcp/errors/McpError.ts +30 -0
- package/src/mcp/index.ts +3 -0
- package/src/mcp/transports/SseMcpTransport.ts +16 -6
- package/src/orm/providers/DrizzleKitProvider.ts +3 -5
- package/src/orm/services/Repository.ts +11 -0
- package/src/server/core/index.ts +1 -1
- package/src/server/core/providers/BunHttpServerProvider.ts +1 -1
- package/src/server/core/providers/NodeHttpServerProvider.spec.ts +125 -0
- package/src/server/core/providers/NodeHttpServerProvider.ts +71 -22
- package/src/server/core/providers/ServerLoggerProvider.ts +2 -2
- package/src/server/core/providers/ServerProvider.ts +9 -12
- package/src/server/links/atoms/apiLinksAtom.ts +7 -0
- package/src/server/links/index.browser.ts +2 -0
- package/src/server/links/index.ts +2 -0
- package/src/vite/index.ts +3 -2
- package/src/vite/tasks/buildClient.ts +0 -1
- package/src/vite/tasks/buildServer.ts +68 -21
- package/src/vite/tasks/copyAssets.ts +5 -4
- package/src/vite/tasks/generateSitemap.ts +64 -23
- package/src/vite/tasks/index.ts +0 -2
- package/src/vite/tasks/prerenderPages.ts +49 -24
- package/src/cli/assets/indexHtml.ts +0 -15
- package/src/cli/commands/format.ts +0 -23
- package/src/vite/helpers/boot.ts +0 -117
- package/src/vite/plugins/viteAlephaDev.ts +0 -177
- package/src/vite/tasks/devServer.ts +0 -71
- package/src/vite/tasks/runAlepha.ts +0 -270
- /package/dist/orm/{chunk-DtkW-qnP.js → chunk-DH6iiROE.js} +0 -0
|
@@ -8,8 +8,8 @@ import { biomeJson } from "../assets/biomeJson.ts";
|
|
|
8
8
|
import { type ClaudeMdOptions, claudeMd } from "../assets/claudeMd.ts";
|
|
9
9
|
import { dummySpecTs } from "../assets/dummySpecTs.ts";
|
|
10
10
|
import { editorconfig } from "../assets/editorconfig.ts";
|
|
11
|
-
import { indexHtml } from "../assets/indexHtml.ts";
|
|
12
11
|
import { mainBrowserTs } from "../assets/mainBrowserTs.ts";
|
|
12
|
+
import { mainCss } from "../assets/mainCss.ts";
|
|
13
13
|
import { mainServerTs } from "../assets/mainServerTs.ts";
|
|
14
14
|
import { tsconfigJson } from "../assets/tsconfigJson.ts";
|
|
15
15
|
import { webAppRouterTs } from "../assets/webAppRouterTs.ts";
|
|
@@ -54,6 +54,7 @@ export class ProjectScaffolder {
|
|
|
54
54
|
public async ensureConfig(
|
|
55
55
|
root: string,
|
|
56
56
|
opts: {
|
|
57
|
+
force?: boolean;
|
|
57
58
|
packageJson?: boolean | DependencyModes;
|
|
58
59
|
tsconfigJson?: boolean;
|
|
59
60
|
indexHtml?: boolean;
|
|
@@ -63,6 +64,7 @@ export class ProjectScaffolder {
|
|
|
63
64
|
},
|
|
64
65
|
): Promise<void> {
|
|
65
66
|
const tasks: Promise<void>[] = [];
|
|
67
|
+
const force = opts.force ?? false;
|
|
66
68
|
|
|
67
69
|
if (opts.packageJson) {
|
|
68
70
|
tasks.push(
|
|
@@ -75,22 +77,24 @@ export class ProjectScaffolder {
|
|
|
75
77
|
);
|
|
76
78
|
}
|
|
77
79
|
if (opts.tsconfigJson) {
|
|
78
|
-
tasks.push(this.ensureTsConfig(root));
|
|
80
|
+
tasks.push(this.ensureTsConfig(root, { force }));
|
|
79
81
|
}
|
|
80
82
|
if (opts.indexHtml) {
|
|
81
|
-
tasks.push(this.ensureReactProject(root));
|
|
83
|
+
tasks.push(this.ensureReactProject(root, { force }));
|
|
82
84
|
}
|
|
83
85
|
if (opts.biomeJson) {
|
|
84
|
-
tasks.push(this.ensureBiomeConfig(root));
|
|
86
|
+
tasks.push(this.ensureBiomeConfig(root, { force }));
|
|
85
87
|
}
|
|
86
88
|
if (opts.editorconfig) {
|
|
87
|
-
tasks.push(this.ensureEditorConfig(root));
|
|
89
|
+
tasks.push(this.ensureEditorConfig(root, { force }));
|
|
88
90
|
}
|
|
89
91
|
if (opts.claudeMd) {
|
|
90
92
|
tasks.push(
|
|
91
93
|
this.ensureClaudeMd(
|
|
92
94
|
root,
|
|
93
|
-
typeof opts.claudeMd === "boolean"
|
|
95
|
+
typeof opts.claudeMd === "boolean"
|
|
96
|
+
? { force }
|
|
97
|
+
: { ...opts.claudeMd, force },
|
|
94
98
|
),
|
|
95
99
|
);
|
|
96
100
|
}
|
|
@@ -102,30 +106,39 @@ export class ProjectScaffolder {
|
|
|
102
106
|
// Config Files
|
|
103
107
|
// ===========================================
|
|
104
108
|
|
|
105
|
-
public async ensureTsConfig(
|
|
109
|
+
public async ensureTsConfig(
|
|
110
|
+
root: string,
|
|
111
|
+
opts: { force?: boolean } = {},
|
|
112
|
+
): Promise<void> {
|
|
106
113
|
// Check if tsconfig.json exists in current or parent directories
|
|
107
|
-
if (await this.existsInParents(root, "tsconfig.json")) {
|
|
114
|
+
if (!opts.force && (await this.existsInParents(root, "tsconfig.json"))) {
|
|
108
115
|
return;
|
|
109
116
|
}
|
|
110
|
-
await this.fs.writeFile(
|
|
117
|
+
await this.fs.writeFile(
|
|
118
|
+
this.fs.join(root, "tsconfig.json"),
|
|
119
|
+
tsconfigJson(),
|
|
120
|
+
);
|
|
111
121
|
}
|
|
112
122
|
|
|
113
|
-
public async ensureBiomeConfig(
|
|
114
|
-
|
|
123
|
+
public async ensureBiomeConfig(
|
|
124
|
+
root: string,
|
|
125
|
+
opts: { force?: boolean } = {},
|
|
126
|
+
): Promise<void> {
|
|
127
|
+
await this.ensureFile(root, "biome.json", biomeJson(), opts.force);
|
|
115
128
|
}
|
|
116
129
|
|
|
117
|
-
public async ensureEditorConfig(
|
|
118
|
-
|
|
130
|
+
public async ensureEditorConfig(
|
|
131
|
+
root: string,
|
|
132
|
+
opts: { force?: boolean } = {},
|
|
133
|
+
): Promise<void> {
|
|
134
|
+
await this.ensureFile(root, ".editorconfig", editorconfig(), opts.force);
|
|
119
135
|
}
|
|
120
136
|
|
|
121
137
|
public async ensureClaudeMd(
|
|
122
138
|
root: string,
|
|
123
|
-
options: ClaudeMdOptions = {},
|
|
139
|
+
options: ClaudeMdOptions & { force?: boolean } = {},
|
|
124
140
|
): Promise<void> {
|
|
125
|
-
|
|
126
|
-
if (!(await this.fs.exists(path))) {
|
|
127
|
-
await this.fs.writeFile(path, claudeMd(options));
|
|
128
|
-
}
|
|
141
|
+
await this.ensureFile(root, "CLAUDE.md", claudeMd(options), options.force);
|
|
129
142
|
}
|
|
130
143
|
|
|
131
144
|
// ===========================================
|
|
@@ -140,11 +153,14 @@ export class ProjectScaffolder {
|
|
|
140
153
|
* - src/api/index.ts (API module)
|
|
141
154
|
* - src/api/controllers/HelloController.ts (example controller)
|
|
142
155
|
*/
|
|
143
|
-
public async ensureApiProject(
|
|
156
|
+
public async ensureApiProject(
|
|
157
|
+
root: string,
|
|
158
|
+
opts: { force?: boolean } = {},
|
|
159
|
+
): Promise<void> {
|
|
144
160
|
const srcDir = this.fs.join(root, "src");
|
|
145
161
|
|
|
146
|
-
// Don't overwrite existing content
|
|
147
|
-
if (await this.fs.exists(srcDir)) {
|
|
162
|
+
// Don't overwrite existing content unless force is set
|
|
163
|
+
if (!opts.force && (await this.fs.exists(srcDir))) {
|
|
148
164
|
const files = await this.fs.ls(srcDir);
|
|
149
165
|
if (files.length > 0) return;
|
|
150
166
|
}
|
|
@@ -157,17 +173,18 @@ export class ProjectScaffolder {
|
|
|
157
173
|
});
|
|
158
174
|
|
|
159
175
|
// Create files
|
|
160
|
-
await this.
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
await this.fs.writeFile(
|
|
165
|
-
this.fs.join(srcDir, "api/index.ts"),
|
|
176
|
+
await this.ensureFile(srcDir, "main.server.ts", mainServerTs(), opts.force);
|
|
177
|
+
await this.ensureFile(
|
|
178
|
+
srcDir,
|
|
179
|
+
"api/index.ts",
|
|
166
180
|
apiIndexTs({ appName }),
|
|
181
|
+
opts.force,
|
|
167
182
|
);
|
|
168
|
-
await this.
|
|
169
|
-
|
|
183
|
+
await this.ensureFile(
|
|
184
|
+
srcDir,
|
|
185
|
+
"api/controllers/HelloController.ts",
|
|
170
186
|
apiHelloControllerTs(),
|
|
187
|
+
opts.force,
|
|
171
188
|
);
|
|
172
189
|
}
|
|
173
190
|
|
|
@@ -179,16 +196,14 @@ export class ProjectScaffolder {
|
|
|
179
196
|
* Ensure full React project structure exists.
|
|
180
197
|
*
|
|
181
198
|
* Creates:
|
|
182
|
-
* - index.html
|
|
183
199
|
* - src/main.server.ts, src/main.browser.ts
|
|
184
200
|
* - src/api/index.ts, src/api/controllers/HelloController.ts
|
|
185
201
|
* - src/web/index.ts, src/web/AppRouter.ts, src/web/components/Hello.tsx
|
|
186
202
|
*/
|
|
187
|
-
public async ensureReactProject(
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
203
|
+
public async ensureReactProject(
|
|
204
|
+
root: string,
|
|
205
|
+
opts: { force?: boolean } = {},
|
|
206
|
+
): Promise<void> {
|
|
192
207
|
const appName = this.getAppName(root);
|
|
193
208
|
|
|
194
209
|
// Create directories
|
|
@@ -199,49 +214,53 @@ export class ProjectScaffolder {
|
|
|
199
214
|
recursive: true,
|
|
200
215
|
});
|
|
201
216
|
|
|
202
|
-
//
|
|
203
|
-
await this.
|
|
204
|
-
this.fs.join(root, "index.html"),
|
|
205
|
-
indexHtml("src/main.browser.ts"),
|
|
206
|
-
);
|
|
217
|
+
// src/main.css
|
|
218
|
+
await this.ensureFile(root, "src/main.css", mainCss(), opts.force);
|
|
207
219
|
|
|
208
220
|
// API structure
|
|
209
|
-
await this.
|
|
221
|
+
await this.ensureFile(
|
|
210
222
|
root,
|
|
211
223
|
"src/api/index.ts",
|
|
212
224
|
apiIndexTs({ appName }),
|
|
225
|
+
opts.force,
|
|
213
226
|
);
|
|
214
|
-
await this.
|
|
227
|
+
await this.ensureFile(
|
|
215
228
|
root,
|
|
216
229
|
"src/api/controllers/HelloController.ts",
|
|
217
230
|
apiHelloControllerTs(),
|
|
231
|
+
opts.force,
|
|
218
232
|
);
|
|
219
|
-
await this.
|
|
233
|
+
await this.ensureFile(
|
|
220
234
|
root,
|
|
221
235
|
"src/main.server.ts",
|
|
222
236
|
mainServerTs({ react: true }),
|
|
237
|
+
opts.force,
|
|
223
238
|
);
|
|
224
239
|
|
|
225
240
|
// Web structure
|
|
226
|
-
await this.
|
|
241
|
+
await this.ensureFile(
|
|
227
242
|
root,
|
|
228
243
|
"src/web/index.ts",
|
|
229
244
|
webIndexTs({ appName }),
|
|
245
|
+
opts.force,
|
|
230
246
|
);
|
|
231
|
-
await this.
|
|
247
|
+
await this.ensureFile(
|
|
232
248
|
root,
|
|
233
249
|
"src/web/AppRouter.ts",
|
|
234
250
|
webAppRouterTs(),
|
|
251
|
+
opts.force,
|
|
235
252
|
);
|
|
236
|
-
await this.
|
|
253
|
+
await this.ensureFile(
|
|
237
254
|
root,
|
|
238
255
|
"src/web/components/Hello.tsx",
|
|
239
256
|
webHelloComponentTsx(),
|
|
257
|
+
opts.force,
|
|
240
258
|
);
|
|
241
|
-
await this.
|
|
259
|
+
await this.ensureFile(
|
|
242
260
|
root,
|
|
243
261
|
"src/main.browser.ts",
|
|
244
262
|
mainBrowserTs(),
|
|
263
|
+
opts.force,
|
|
245
264
|
);
|
|
246
265
|
}
|
|
247
266
|
|
|
@@ -272,13 +291,17 @@ export class ProjectScaffolder {
|
|
|
272
291
|
// Helpers
|
|
273
292
|
// ===========================================
|
|
274
293
|
|
|
275
|
-
|
|
294
|
+
/**
|
|
295
|
+
* Write a file, optionally overriding if it exists.
|
|
296
|
+
*/
|
|
297
|
+
protected async ensureFile(
|
|
276
298
|
root: string,
|
|
277
299
|
relativePath: string,
|
|
278
300
|
content: string,
|
|
301
|
+
force?: boolean,
|
|
279
302
|
): Promise<void> {
|
|
280
303
|
const fullPath = this.fs.join(root, relativePath);
|
|
281
|
-
if (!(await this.fs.exists(fullPath))) {
|
|
304
|
+
if (force || !(await this.fs.exists(fullPath))) {
|
|
282
305
|
await this.fs.writeFile(fullPath, content);
|
|
283
306
|
}
|
|
284
307
|
}
|
package/src/core/Alepha.ts
CHANGED
|
@@ -165,13 +165,6 @@ export class Alepha {
|
|
|
165
165
|
...state.env,
|
|
166
166
|
...process.env,
|
|
167
167
|
};
|
|
168
|
-
|
|
169
|
-
// remove empty env variables
|
|
170
|
-
for (const key in state.env) {
|
|
171
|
-
if (state.env[key] === "") {
|
|
172
|
-
delete (state.env as any)[key];
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
168
|
}
|
|
176
169
|
|
|
177
170
|
// force production mode when building with vite
|
|
@@ -765,8 +758,9 @@ export class Alepha {
|
|
|
765
758
|
}
|
|
766
759
|
|
|
767
760
|
if (this.started) {
|
|
761
|
+
const mod = (service as WithModule)[MODULE]?.name;
|
|
768
762
|
throw new ContainerLockedError(
|
|
769
|
-
`Container is locked. No more services can be added. ${parent?.name}
|
|
763
|
+
`Container is locked. No more services can be added. Attempted to inject '${service.name}' from '${parent?.name}'. ${mod ? `Maybe register module '${mod}' in Alepha.` : ""}`,
|
|
770
764
|
);
|
|
771
765
|
}
|
|
772
766
|
}
|
|
@@ -4,6 +4,7 @@ import { MODULE } from "../constants/MODULE.ts";
|
|
|
4
4
|
import { AlephaError } from "../errors/AlephaError.ts";
|
|
5
5
|
import type { PrimitiveFactoryLike } from "../helpers/primitive.ts";
|
|
6
6
|
import type { Service } from "../interfaces/Service.ts";
|
|
7
|
+
import type { Atom } from "./$atom.ts";
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* Wrap Services and Primitives into a Module.
|
|
@@ -69,6 +70,12 @@ export const $module = <T extends object = {}>(
|
|
|
69
70
|
options = options;
|
|
70
71
|
|
|
71
72
|
register(alepha: Alepha): void {
|
|
73
|
+
if (options.atoms) {
|
|
74
|
+
for (const atom of options.atoms) {
|
|
75
|
+
alepha.store.register(atom);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
72
79
|
if (typeof options.register === "function") {
|
|
73
80
|
options.register(alepha);
|
|
74
81
|
return;
|
|
@@ -134,6 +141,11 @@ export interface ModulePrimitiveOptions {
|
|
|
134
141
|
* Again, if you declare 'register', you must handle the registration of ALL services manually.
|
|
135
142
|
*/
|
|
136
143
|
register?: (alepha: Alepha) => void;
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* List of atoms to register in the module.
|
|
147
|
+
*/
|
|
148
|
+
atoms?: Array<Atom<any>>;
|
|
137
149
|
}
|
|
138
150
|
|
|
139
151
|
/**
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Alepha, t } from "alepha";
|
|
2
2
|
import { describe, test } from "vitest";
|
|
3
|
+
import { KeylessJsonSchemaCodec } from "./KeylessJsonSchemaCodec.ts";
|
|
3
4
|
|
|
4
5
|
describe("KeylessJsonSchemaCodec", () => {
|
|
5
6
|
describe("Basic types", () => {
|
|
@@ -618,4 +619,260 @@ describe("KeylessJsonSchemaCodec", () => {
|
|
|
618
619
|
expect(keylessSize).toBeLessThan(jsonSize);
|
|
619
620
|
});
|
|
620
621
|
});
|
|
622
|
+
|
|
623
|
+
describe("Safe Mode (Interpreted)", () => {
|
|
624
|
+
test("should work correctly in safe mode", async ({ expect }) => {
|
|
625
|
+
const alepha = Alepha.create();
|
|
626
|
+
const codec = alepha.inject(KeylessJsonSchemaCodec);
|
|
627
|
+
|
|
628
|
+
// Force safe mode (no Function compilation)
|
|
629
|
+
codec.configure({ useFunctionCompilation: false });
|
|
630
|
+
|
|
631
|
+
const schema = t.object({
|
|
632
|
+
name: t.text(),
|
|
633
|
+
age: t.integer(),
|
|
634
|
+
active: t.boolean(),
|
|
635
|
+
});
|
|
636
|
+
|
|
637
|
+
const data = {
|
|
638
|
+
name: "Alice",
|
|
639
|
+
age: 30,
|
|
640
|
+
active: true,
|
|
641
|
+
};
|
|
642
|
+
|
|
643
|
+
const encoded = codec.encodeToString(schema, data);
|
|
644
|
+
expect(encoded).toBe('["Alice",30,true]');
|
|
645
|
+
|
|
646
|
+
const decoded = codec.decode(schema, encoded);
|
|
647
|
+
expect(decoded).toEqual(data);
|
|
648
|
+
});
|
|
649
|
+
|
|
650
|
+
test("should handle nested objects in safe mode", async ({ expect }) => {
|
|
651
|
+
const alepha = Alepha.create();
|
|
652
|
+
const codec = alepha.inject(KeylessJsonSchemaCodec);
|
|
653
|
+
|
|
654
|
+
codec.configure({ useFunctionCompilation: false });
|
|
655
|
+
|
|
656
|
+
const schema = t.object({
|
|
657
|
+
user: t.object({
|
|
658
|
+
name: t.text(),
|
|
659
|
+
profile: t.object({
|
|
660
|
+
bio: t.text(),
|
|
661
|
+
age: t.integer(),
|
|
662
|
+
}),
|
|
663
|
+
}),
|
|
664
|
+
});
|
|
665
|
+
|
|
666
|
+
const data = {
|
|
667
|
+
user: {
|
|
668
|
+
name: "Alice",
|
|
669
|
+
profile: {
|
|
670
|
+
bio: "Developer",
|
|
671
|
+
age: 30,
|
|
672
|
+
},
|
|
673
|
+
},
|
|
674
|
+
};
|
|
675
|
+
|
|
676
|
+
const encoded = codec.encodeToString(schema, data);
|
|
677
|
+
expect(encoded).toBe('[["Alice",["Developer",30]]]');
|
|
678
|
+
|
|
679
|
+
const decoded = codec.decode(schema, encoded);
|
|
680
|
+
expect(decoded).toEqual(data);
|
|
681
|
+
});
|
|
682
|
+
|
|
683
|
+
test("should handle arrays of objects in safe mode", async ({ expect }) => {
|
|
684
|
+
const alepha = Alepha.create();
|
|
685
|
+
const codec = alepha.inject(KeylessJsonSchemaCodec);
|
|
686
|
+
|
|
687
|
+
codec.configure({ useFunctionCompilation: false });
|
|
688
|
+
|
|
689
|
+
const schema = t.object({
|
|
690
|
+
users: t.array(
|
|
691
|
+
t.object({
|
|
692
|
+
name: t.text(),
|
|
693
|
+
age: t.integer(),
|
|
694
|
+
}),
|
|
695
|
+
),
|
|
696
|
+
});
|
|
697
|
+
|
|
698
|
+
const data = {
|
|
699
|
+
users: [
|
|
700
|
+
{ name: "Alice", age: 30 },
|
|
701
|
+
{ name: "Bob", age: 25 },
|
|
702
|
+
],
|
|
703
|
+
};
|
|
704
|
+
|
|
705
|
+
const encoded = codec.encodeToString(schema, data);
|
|
706
|
+
const decoded = codec.decode(schema, encoded);
|
|
707
|
+
expect(decoded).toEqual(data);
|
|
708
|
+
});
|
|
709
|
+
|
|
710
|
+
test("should handle optional fields in safe mode", async ({ expect }) => {
|
|
711
|
+
const alepha = Alepha.create();
|
|
712
|
+
const codec = alepha.inject(KeylessJsonSchemaCodec);
|
|
713
|
+
|
|
714
|
+
codec.configure({ useFunctionCompilation: false });
|
|
715
|
+
|
|
716
|
+
const schema = t.object({
|
|
717
|
+
name: t.text(),
|
|
718
|
+
bio: t.optional(t.text()),
|
|
719
|
+
});
|
|
720
|
+
|
|
721
|
+
// With optional field
|
|
722
|
+
const dataWithBio = { name: "Alice", bio: "Developer" };
|
|
723
|
+
const encodedWith = codec.encodeToString(schema, dataWithBio);
|
|
724
|
+
const decodedWith = codec.decode(schema, encodedWith);
|
|
725
|
+
expect(decodedWith).toEqual(dataWithBio);
|
|
726
|
+
|
|
727
|
+
// Without optional field
|
|
728
|
+
const dataWithoutBio = { name: "Bob" };
|
|
729
|
+
const encodedWithout = codec.encodeToString(schema, dataWithoutBio);
|
|
730
|
+
const decodedWithout = codec.decode<{ name: string; bio?: string }>(
|
|
731
|
+
schema,
|
|
732
|
+
encodedWithout,
|
|
733
|
+
);
|
|
734
|
+
expect(decodedWithout.name).toBe("Bob");
|
|
735
|
+
expect(decodedWithout.bio).toBeUndefined();
|
|
736
|
+
});
|
|
737
|
+
|
|
738
|
+
test("should handle nullable fields in safe mode", async ({ expect }) => {
|
|
739
|
+
const alepha = Alepha.create();
|
|
740
|
+
const codec = alepha.inject(KeylessJsonSchemaCodec);
|
|
741
|
+
|
|
742
|
+
codec.configure({ useFunctionCompilation: false });
|
|
743
|
+
|
|
744
|
+
const schema = t.object({
|
|
745
|
+
name: t.text(),
|
|
746
|
+
deletedAt: t.nullable(t.datetime()),
|
|
747
|
+
});
|
|
748
|
+
|
|
749
|
+
// With null value
|
|
750
|
+
const dataNull = { name: "Alice", deletedAt: null };
|
|
751
|
+
const encodedNull = codec.encodeToString(schema, dataNull);
|
|
752
|
+
const decodedNull = codec.decode<{
|
|
753
|
+
name: string;
|
|
754
|
+
deletedAt: string | null;
|
|
755
|
+
}>(schema, encodedNull);
|
|
756
|
+
expect(decodedNull.deletedAt).toBeNull();
|
|
757
|
+
|
|
758
|
+
// With non-null value
|
|
759
|
+
const dataValue = { name: "Bob", deletedAt: "2024-01-15T10:00:00Z" };
|
|
760
|
+
const encodedValue = codec.encodeToString(schema, dataValue);
|
|
761
|
+
const decodedValue = codec.decode(schema, encodedValue);
|
|
762
|
+
expect(decodedValue).toEqual(dataValue);
|
|
763
|
+
});
|
|
764
|
+
});
|
|
765
|
+
|
|
766
|
+
describe("Compiled Mode (Function)", () => {
|
|
767
|
+
test("should work correctly in compiled mode", async ({ expect }) => {
|
|
768
|
+
const alepha = Alepha.create();
|
|
769
|
+
const codec = alepha.inject(KeylessJsonSchemaCodec);
|
|
770
|
+
|
|
771
|
+
// Force compiled mode
|
|
772
|
+
codec.configure({ useFunctionCompilation: true });
|
|
773
|
+
|
|
774
|
+
const schema = t.object({
|
|
775
|
+
name: t.text(),
|
|
776
|
+
age: t.integer(),
|
|
777
|
+
active: t.boolean(),
|
|
778
|
+
});
|
|
779
|
+
|
|
780
|
+
const data = {
|
|
781
|
+
name: "Alice",
|
|
782
|
+
age: 30,
|
|
783
|
+
active: true,
|
|
784
|
+
};
|
|
785
|
+
|
|
786
|
+
const encoded = codec.encodeToString(schema, data);
|
|
787
|
+
expect(encoded).toBe('["Alice",30,true]');
|
|
788
|
+
|
|
789
|
+
const decoded = codec.decode(schema, encoded);
|
|
790
|
+
expect(decoded).toEqual(data);
|
|
791
|
+
});
|
|
792
|
+
|
|
793
|
+
test("should produce same results as safe mode", async ({ expect }) => {
|
|
794
|
+
const alepha = Alepha.create();
|
|
795
|
+
|
|
796
|
+
const codecSafe = alepha.inject(KeylessJsonSchemaCodec);
|
|
797
|
+
codecSafe.configure({ useFunctionCompilation: false });
|
|
798
|
+
|
|
799
|
+
// Create a second Alepha instance for the compiled codec
|
|
800
|
+
const alepha2 = Alepha.create();
|
|
801
|
+
const codecCompiled = alepha2.inject(KeylessJsonSchemaCodec);
|
|
802
|
+
codecCompiled.configure({ useFunctionCompilation: true });
|
|
803
|
+
|
|
804
|
+
const schema = t.object({
|
|
805
|
+
user: t.object({
|
|
806
|
+
name: t.text(),
|
|
807
|
+
age: t.integer(),
|
|
808
|
+
}),
|
|
809
|
+
tags: t.array(t.text()),
|
|
810
|
+
active: t.boolean(),
|
|
811
|
+
});
|
|
812
|
+
|
|
813
|
+
const data = {
|
|
814
|
+
user: { name: "Alice", age: 30 },
|
|
815
|
+
tags: ["dev", "typescript"],
|
|
816
|
+
active: true,
|
|
817
|
+
};
|
|
818
|
+
|
|
819
|
+
const encodedSafe = codecSafe.encodeToString(schema, data);
|
|
820
|
+
const encodedCompiled = codecCompiled.encodeToString(schema, data);
|
|
821
|
+
|
|
822
|
+
// Both modes should produce the same output
|
|
823
|
+
expect(encodedSafe).toBe(encodedCompiled);
|
|
824
|
+
|
|
825
|
+
const decodedSafe = codecSafe.decode(schema, encodedSafe);
|
|
826
|
+
const decodedCompiled = codecCompiled.decode(schema, encodedCompiled);
|
|
827
|
+
|
|
828
|
+
// Both modes should decode to the same result
|
|
829
|
+
expect(decodedSafe).toEqual(data);
|
|
830
|
+
expect(decodedCompiled).toEqual(data);
|
|
831
|
+
});
|
|
832
|
+
});
|
|
833
|
+
|
|
834
|
+
describe("Configuration", () => {
|
|
835
|
+
test("should allow configuring options", async ({ expect }) => {
|
|
836
|
+
const alepha = Alepha.create();
|
|
837
|
+
const codec = alepha.inject(KeylessJsonSchemaCodec);
|
|
838
|
+
|
|
839
|
+
// Configure all options
|
|
840
|
+
codec.configure({
|
|
841
|
+
useFunctionCompilation: false,
|
|
842
|
+
maxArrayLength: 100,
|
|
843
|
+
maxStringLength: 1000,
|
|
844
|
+
maxDepth: 10,
|
|
845
|
+
});
|
|
846
|
+
|
|
847
|
+
// Test that configuration works by encoding/decoding
|
|
848
|
+
const schema = t.object({ name: t.text() });
|
|
849
|
+
const data = { name: "test" };
|
|
850
|
+
|
|
851
|
+
const encoded = codec.encodeToString(schema, data);
|
|
852
|
+
const decoded = codec.decode(schema, encoded);
|
|
853
|
+
|
|
854
|
+
expect(decoded).toEqual(data);
|
|
855
|
+
});
|
|
856
|
+
|
|
857
|
+
test("should clear cache when compilation mode changes", async ({
|
|
858
|
+
expect,
|
|
859
|
+
}) => {
|
|
860
|
+
const alepha = Alepha.create();
|
|
861
|
+
const codec = alepha.inject(KeylessJsonSchemaCodec);
|
|
862
|
+
|
|
863
|
+
const schema = t.object({ name: t.text() });
|
|
864
|
+
const data = { name: "test" };
|
|
865
|
+
|
|
866
|
+
// Use compiled mode first
|
|
867
|
+
codec.configure({ useFunctionCompilation: true });
|
|
868
|
+
const encoded1 = codec.encodeToString(schema, data);
|
|
869
|
+
|
|
870
|
+
// Switch to safe mode (cache should be cleared)
|
|
871
|
+
codec.configure({ useFunctionCompilation: false });
|
|
872
|
+
const encoded2 = codec.encodeToString(schema, data);
|
|
873
|
+
|
|
874
|
+
// Both should produce the same result
|
|
875
|
+
expect(encoded1).toBe(encoded2);
|
|
876
|
+
});
|
|
877
|
+
});
|
|
621
878
|
});
|