alepha 0.13.8 → 0.14.0
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/audits/index.d.ts +2 -1
- package/dist/api/audits/index.d.ts.map +1 -0
- package/dist/api/files/index.d.ts +2 -1
- package/dist/api/files/index.d.ts.map +1 -0
- package/dist/api/jobs/index.d.ts +158 -157
- package/dist/api/jobs/index.d.ts.map +1 -0
- package/dist/api/notifications/index.d.ts.map +1 -0
- package/dist/api/parameters/index.d.ts +4 -4
- package/dist/api/parameters/index.d.ts.map +1 -0
- package/dist/api/users/index.d.ts +132 -131
- package/dist/api/users/index.d.ts.map +1 -0
- package/dist/api/verifications/index.d.ts.map +1 -0
- package/dist/batch/index.d.ts.map +1 -0
- package/dist/bucket/index.d.ts.map +1 -0
- package/dist/cache/core/index.d.ts.map +1 -0
- package/dist/cache/redis/index.d.ts.map +1 -0
- package/dist/cli/index.d.ts +44 -32
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +380 -109
- package/dist/cli/index.js.map +1 -1
- package/dist/command/index.d.ts +11 -1
- package/dist/command/index.d.ts.map +1 -0
- package/dist/command/index.js +45 -6
- package/dist/command/index.js.map +1 -1
- package/dist/core/index.browser.js +1334 -1318
- package/dist/core/index.browser.js.map +1 -1
- package/dist/core/index.d.ts +75 -71
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +1337 -1321
- package/dist/core/index.js.map +1 -1
- package/dist/core/index.native.js +1337 -1321
- package/dist/core/index.native.js.map +1 -1
- package/dist/datetime/index.d.ts.map +1 -0
- package/dist/email/index.d.ts.map +1 -0
- package/dist/fake/index.d.ts.map +1 -0
- package/dist/file/index.d.ts.map +1 -0
- package/dist/lock/core/index.d.ts.map +1 -0
- package/dist/lock/redis/index.d.ts.map +1 -0
- package/dist/logger/index.d.ts +1 -0
- package/dist/logger/index.d.ts.map +1 -0
- package/dist/mcp/index.d.ts +820 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +978 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/orm/index.d.ts +180 -107
- package/dist/orm/index.d.ts.map +1 -0
- package/dist/orm/index.js +260 -174
- package/dist/orm/index.js.map +1 -1
- package/dist/queue/core/index.d.ts +4 -4
- package/dist/queue/core/index.d.ts.map +1 -0
- package/dist/queue/redis/index.d.ts.map +1 -0
- package/dist/redis/index.d.ts.map +1 -0
- package/dist/retry/index.d.ts.map +1 -0
- package/dist/router/index.d.ts.map +1 -0
- package/dist/scheduler/index.d.ts.map +1 -0
- package/dist/security/index.d.ts.map +1 -0
- package/dist/server/auth/index.d.ts +155 -155
- package/dist/server/auth/index.d.ts.map +1 -0
- package/dist/server/cache/index.d.ts.map +1 -0
- package/dist/server/compress/index.d.ts.map +1 -0
- package/dist/server/cookies/index.d.ts.map +1 -0
- package/dist/server/core/index.d.ts.map +1 -0
- package/dist/server/cors/index.d.ts.map +1 -0
- package/dist/server/health/index.d.ts.map +1 -0
- package/dist/server/helmet/index.d.ts.map +1 -0
- package/dist/server/links/index.d.ts +33 -33
- package/dist/server/links/index.d.ts.map +1 -0
- package/dist/server/metrics/index.d.ts.map +1 -0
- package/dist/server/multipart/index.d.ts.map +1 -0
- package/dist/server/proxy/index.d.ts.map +1 -0
- package/dist/server/rate-limit/index.d.ts.map +1 -0
- package/dist/server/security/index.d.ts +9 -9
- package/dist/server/security/index.d.ts.map +1 -0
- package/dist/server/static/index.d.ts.map +1 -0
- package/dist/server/swagger/index.d.ts.map +1 -0
- package/dist/sms/index.d.ts.map +1 -0
- package/dist/thread/index.d.ts.map +1 -0
- package/dist/topic/core/index.d.ts.map +1 -0
- package/dist/topic/redis/index.d.ts.map +1 -0
- package/dist/vite/index.d.ts +10 -2
- package/dist/vite/index.d.ts.map +1 -0
- package/dist/vite/index.js +36 -14
- package/dist/vite/index.js.map +1 -1
- package/dist/websocket/index.d.ts.map +1 -0
- package/package.json +9 -4
- package/src/cli/apps/AlephaCli.ts +2 -0
- package/src/cli/apps/AlephaPackageBuilderCli.ts +12 -8
- package/src/cli/assets/mainTs.ts +9 -10
- package/src/cli/commands/ChangelogCommands.ts +389 -0
- package/src/cli/commands/DrizzleCommands.ts +204 -4
- package/src/cli/commands/ViteCommands.ts +26 -16
- package/src/cli/services/AlephaCliUtils.ts +23 -150
- package/src/command/providers/CliProvider.ts +76 -5
- package/src/core/providers/SchemaValidator.ts +23 -1
- package/src/mcp/errors/McpError.ts +72 -0
- package/src/mcp/helpers/jsonrpc.ts +163 -0
- package/src/mcp/index.ts +132 -0
- package/src/mcp/interfaces/McpTypes.ts +248 -0
- package/src/mcp/primitives/$prompt.ts +188 -0
- package/src/mcp/primitives/$resource.ts +171 -0
- package/src/mcp/primitives/$tool.ts +285 -0
- package/src/mcp/providers/McpServerProvider.ts +382 -0
- package/src/mcp/transports/SseMcpTransport.ts +172 -0
- package/src/mcp/transports/StdioMcpTransport.ts +126 -0
- package/src/orm/index.ts +12 -0
- package/src/orm/providers/drivers/CloudflareD1Provider.ts +164 -0
- package/src/orm/providers/drivers/NodeSqliteProvider.ts +3 -1
- package/src/vite/plugins/viteAlephaBuild.ts +8 -2
- package/src/vite/plugins/viteAlephaDev.ts +6 -2
- package/src/vite/tasks/buildServer.ts +1 -1
- package/src/vite/tasks/generateCloudflare.ts +43 -15
- package/src/vite/tasks/runAlepha.ts +1 -0
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { $env, $hook, $inject, AlephaError, t } from "alepha";
|
|
2
|
+
import { $logger } from "alepha/logger";
|
|
3
|
+
import type { DrizzleD1Database } from "drizzle-orm/d1";
|
|
4
|
+
import type { PgDatabase } from "drizzle-orm/pg-core";
|
|
5
|
+
import { SqliteModelBuilder } from "../../services/SqliteModelBuilder.ts";
|
|
6
|
+
import { DrizzleKitProvider } from "../DrizzleKitProvider.ts";
|
|
7
|
+
import { DatabaseProvider, type SQLLike } from "./DatabaseProvider.ts";
|
|
8
|
+
|
|
9
|
+
// ---------------------------------------------------------------------------------------------------------------------
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* D1Database interface matching Cloudflare's D1 API.
|
|
13
|
+
*/
|
|
14
|
+
export interface D1Database {
|
|
15
|
+
prepare(query: string): D1PreparedStatement;
|
|
16
|
+
batch<T = unknown>(statements: D1PreparedStatement[]): Promise<T[]>;
|
|
17
|
+
exec(query: string): Promise<D1ExecResult>;
|
|
18
|
+
dump(): Promise<ArrayBuffer>;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface D1PreparedStatement {
|
|
22
|
+
bind(...values: unknown[]): D1PreparedStatement;
|
|
23
|
+
first<T = unknown>(colName?: string): Promise<T | null>;
|
|
24
|
+
run(): Promise<D1Result>;
|
|
25
|
+
all<T = unknown>(): Promise<D1Result<T>>;
|
|
26
|
+
raw<T = unknown>(): Promise<T[]>;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface D1Result<T = unknown> {
|
|
30
|
+
results: T[];
|
|
31
|
+
success: boolean;
|
|
32
|
+
meta: {
|
|
33
|
+
duration: number;
|
|
34
|
+
changes: number;
|
|
35
|
+
last_row_id: number;
|
|
36
|
+
served_by: string;
|
|
37
|
+
internal_stats: unknown;
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface D1ExecResult {
|
|
42
|
+
count: number;
|
|
43
|
+
duration: number;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// ---------------------------------------------------------------------------------------------------------------------
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Cloudflare D1 SQLite provider using Drizzle ORM.
|
|
50
|
+
*
|
|
51
|
+
* This provider requires a D1 binding to be set via `cloudflareD1Options` before starting.
|
|
52
|
+
* The binding is typically obtained from the Cloudflare Workers environment.
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* ```ts
|
|
56
|
+
* // In your Cloudflare Worker
|
|
57
|
+
* alepha.set(cloudflareD1Options, { binding: env.DB });
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
60
|
+
export class CloudflareD1Provider extends DatabaseProvider {
|
|
61
|
+
protected readonly kit = $inject(DrizzleKitProvider);
|
|
62
|
+
protected readonly log = $logger();
|
|
63
|
+
protected readonly builder = $inject(SqliteModelBuilder);
|
|
64
|
+
protected readonly env = $env(
|
|
65
|
+
t.object({
|
|
66
|
+
DATABASE_URL: t.string({
|
|
67
|
+
description: "Expect to be 'cloudflare-d1://name:id'",
|
|
68
|
+
}),
|
|
69
|
+
}),
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
protected d1?: D1Database;
|
|
73
|
+
protected drizzleDb?: DrizzleD1Database;
|
|
74
|
+
|
|
75
|
+
public get name() {
|
|
76
|
+
return "d1";
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
public override readonly dialect = "sqlite";
|
|
80
|
+
|
|
81
|
+
public override get url(): string {
|
|
82
|
+
return this.env.DATABASE_URL;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
public override get db(): PgDatabase<any> {
|
|
86
|
+
if (!this.drizzleDb) {
|
|
87
|
+
throw new AlephaError("D1 database not initialized");
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return this.drizzleDb as unknown as PgDatabase<any>;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
public override async execute(
|
|
94
|
+
query: SQLLike,
|
|
95
|
+
): Promise<Array<Record<string, unknown>>> {
|
|
96
|
+
const { rows } = await (this.db as any).run(query);
|
|
97
|
+
return rows;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
protected readonly onStart = $hook({
|
|
101
|
+
on: "start",
|
|
102
|
+
handler: async () => {
|
|
103
|
+
const [bindingName] = this.env.DATABASE_URL.replace(
|
|
104
|
+
"cloudflare-d1://",
|
|
105
|
+
"",
|
|
106
|
+
).split(":");
|
|
107
|
+
const cloudflareEnv = this.alepha.store.get("cloudflare.env" as any);
|
|
108
|
+
if (!cloudflareEnv) {
|
|
109
|
+
throw new AlephaError(
|
|
110
|
+
"Cloudflare Workers environment not found in Alepha store under 'cloudflare.env'.",
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const binding = cloudflareEnv[bindingName] as D1Database;
|
|
115
|
+
if (!binding) {
|
|
116
|
+
throw new AlephaError(
|
|
117
|
+
`D1 binding '${bindingName}' not found in Cloudflare Workers environment.`,
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
this.d1 = binding;
|
|
122
|
+
|
|
123
|
+
// Dynamic import to avoid crashes when not on Cloudflare
|
|
124
|
+
const { drizzle } = await import("drizzle-orm/d1");
|
|
125
|
+
|
|
126
|
+
this.drizzleDb = drizzle(this.d1) as DrizzleD1Database;
|
|
127
|
+
|
|
128
|
+
await this.migrateDatabase();
|
|
129
|
+
|
|
130
|
+
this.log.info("Using Cloudflare D1 database");
|
|
131
|
+
},
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
protected async executeMigrations(migrationsFolder: string): Promise<void> {
|
|
135
|
+
// Dynamic import for D1 migrator
|
|
136
|
+
const { migrate } = await import("drizzle-orm/d1/migrator");
|
|
137
|
+
await migrate(this.db as any, { migrationsFolder });
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Override development migration to skip sync (not supported on D1).
|
|
142
|
+
* D1 requires proper migrations to be applied.
|
|
143
|
+
*/
|
|
144
|
+
protected override async runDevelopmentMigration(
|
|
145
|
+
migrationsFolder: string,
|
|
146
|
+
): Promise<void> {
|
|
147
|
+
await this.executeMigrations(migrationsFolder);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Override test migration to run migrations instead of sync.
|
|
152
|
+
* D1 doesn't support schema synchronization.
|
|
153
|
+
*/
|
|
154
|
+
protected override async runTestMigration(): Promise<void> {
|
|
155
|
+
const migrationsFolder = this.getMigrationsFolder();
|
|
156
|
+
try {
|
|
157
|
+
await this.executeMigrations(migrationsFolder);
|
|
158
|
+
} catch {
|
|
159
|
+
this.log.warn(
|
|
160
|
+
"D1 migrations failed in test environment - ensure migrations exist",
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
@@ -145,7 +145,9 @@ export class NodeSqliteProvider extends DatabaseProvider {
|
|
|
145
145
|
on: "start",
|
|
146
146
|
handler: async () => {
|
|
147
147
|
const { DatabaseSync } = await import("node:sqlite");
|
|
148
|
-
|
|
148
|
+
|
|
149
|
+
const filepath = this.url.replace("sqlite://", "").replace("sqlite:", "");
|
|
150
|
+
|
|
149
151
|
if (filepath !== ":memory:" && filepath !== "") {
|
|
150
152
|
const dirname = filepath.split("/").slice(0, -1).join("/");
|
|
151
153
|
if (dirname) {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { readFile, unlink, writeFile } from "node:fs/promises";
|
|
2
|
+
import { OPTIONS } from "alepha";
|
|
2
3
|
import type { Plugin, UserConfig } from "vite";
|
|
3
4
|
import { boot } from "../helpers/boot.ts";
|
|
4
5
|
import { fileExists } from "../helpers/fileExists.ts";
|
|
@@ -14,6 +15,7 @@ import {
|
|
|
14
15
|
generateVercel,
|
|
15
16
|
prerenderPages,
|
|
16
17
|
type VercelConfig,
|
|
18
|
+
type WranglerConfig,
|
|
17
19
|
} from "../tasks/index.ts";
|
|
18
20
|
|
|
19
21
|
export interface ViteAlephaBuildOptions {
|
|
@@ -43,7 +45,7 @@ export interface ViteAlephaBuildOptions {
|
|
|
43
45
|
*
|
|
44
46
|
* @default false
|
|
45
47
|
*/
|
|
46
|
-
cloudflare?: boolean;
|
|
48
|
+
cloudflare?: boolean | WranglerConfig;
|
|
47
49
|
|
|
48
50
|
/**
|
|
49
51
|
* If true, the build will be optimized for Docker deployment.
|
|
@@ -89,8 +91,9 @@ export async function viteAlephaBuild(
|
|
|
89
91
|
let rootConfig: UserConfig = {};
|
|
90
92
|
|
|
91
93
|
return {
|
|
92
|
-
name: "alepha
|
|
94
|
+
name: "alepha:build",
|
|
93
95
|
apply: "build",
|
|
96
|
+
[OPTIONS as any]: options,
|
|
94
97
|
config(config, ctx) {
|
|
95
98
|
const buildMode = process.env.ALEPHA_BUILD_MODE as
|
|
96
99
|
| AlephaBuildMode
|
|
@@ -254,8 +257,11 @@ export async function viteAlephaBuild(
|
|
|
254
257
|
}
|
|
255
258
|
|
|
256
259
|
if (options.cloudflare) {
|
|
260
|
+
const config =
|
|
261
|
+
typeof options.cloudflare === "boolean" ? {} : options.cloudflare;
|
|
257
262
|
await generateCloudflare({
|
|
258
263
|
distDir,
|
|
264
|
+
config,
|
|
259
265
|
});
|
|
260
266
|
}
|
|
261
267
|
|
|
@@ -132,12 +132,16 @@ export async function viteAlephaDev(
|
|
|
132
132
|
});
|
|
133
133
|
|
|
134
134
|
server.config.logger.info = (msg: string) => {
|
|
135
|
-
|
|
135
|
+
console.log(msg);
|
|
136
136
|
};
|
|
137
137
|
|
|
138
138
|
server.config.logger.clearScreen = () => {};
|
|
139
139
|
|
|
140
|
-
|
|
140
|
+
// Return a function - it runs AFTER internal middlewares are set up
|
|
141
|
+
// and after buildStart has been called
|
|
142
|
+
return async () => {
|
|
143
|
+
await runner.start(server);
|
|
144
|
+
};
|
|
141
145
|
},
|
|
142
146
|
async closeBundle() {
|
|
143
147
|
// Cleanup handled by runner
|
|
@@ -144,7 +144,7 @@ export async function buildServer(
|
|
|
144
144
|
|
|
145
145
|
await writeFile(
|
|
146
146
|
`${opts.distDir}/index.js`,
|
|
147
|
-
`${warning}\nimport './server/${entryFile}'
|
|
147
|
+
`${warning}\nimport './server/${entryFile}';\n\n${template}`.trim(),
|
|
148
148
|
);
|
|
149
149
|
|
|
150
150
|
return { entryFile };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { writeFile } from "node:fs/promises";
|
|
1
|
+
import { access, writeFile } from "node:fs/promises";
|
|
2
2
|
import { basename, join } from "node:path";
|
|
3
3
|
|
|
4
4
|
export interface GenerateCloudflareOptions {
|
|
@@ -8,6 +8,15 @@ export interface GenerateCloudflareOptions {
|
|
|
8
8
|
* @default "dist"
|
|
9
9
|
*/
|
|
10
10
|
distDir?: string;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Additional Wrangler configuration options to merge into wrangler.jsonc.
|
|
14
|
+
*/
|
|
15
|
+
config?: WranglerConfig;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface WranglerConfig {
|
|
19
|
+
[key: string]: any;
|
|
11
20
|
}
|
|
12
21
|
|
|
13
22
|
const WARNING_COMMENT =
|
|
@@ -27,30 +36,47 @@ export async function generateCloudflare(
|
|
|
27
36
|
const distDir = opts.distDir ?? "dist";
|
|
28
37
|
const root = process.cwd();
|
|
29
38
|
const name = basename(root);
|
|
39
|
+
const hasAssets = await access(join(root, distDir, "public"))
|
|
40
|
+
.then(() => true)
|
|
41
|
+
.catch(() => false);
|
|
30
42
|
|
|
31
|
-
|
|
32
|
-
await writeWorkerEntryPoint(root, distDir);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Write the wrangler.jsonc configuration file for Cloudflare Workers
|
|
37
|
-
*/
|
|
38
|
-
async function writeWranglerConfig(
|
|
39
|
-
root: string,
|
|
40
|
-
distDir: string,
|
|
41
|
-
name: string,
|
|
42
|
-
): Promise<void> {
|
|
43
|
-
const wrangler = {
|
|
43
|
+
const wrangler: WranglerConfig = {
|
|
44
44
|
name,
|
|
45
45
|
main: "./main.cloudflare.js",
|
|
46
46
|
compatibility_flags: ["nodejs_compat"],
|
|
47
47
|
compatibility_date: "2025-11-17",
|
|
48
|
+
...opts.config,
|
|
48
49
|
};
|
|
49
50
|
|
|
51
|
+
if (hasAssets) {
|
|
52
|
+
wrangler.assets ??= {
|
|
53
|
+
directory: "./public",
|
|
54
|
+
binding: "ASSETS",
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const url = process.env.DATABASE_URL;
|
|
59
|
+
if (url?.startsWith("cloudflare-d1:")) {
|
|
60
|
+
const [name, id] = url
|
|
61
|
+
.replace("cloudflare-d1://", "")
|
|
62
|
+
.replace("cloudflare-d1:", "")
|
|
63
|
+
.split(":");
|
|
64
|
+
wrangler.d1_databases = wrangler.d1_databases || [];
|
|
65
|
+
wrangler.d1_databases.push({
|
|
66
|
+
binding: name,
|
|
67
|
+
database_name: name,
|
|
68
|
+
database_id: id,
|
|
69
|
+
});
|
|
70
|
+
wrangler.vars ??= {};
|
|
71
|
+
wrangler.vars.DATABASE_URL = `cloudflare-d1://${name}:${id}`;
|
|
72
|
+
}
|
|
73
|
+
|
|
50
74
|
await writeFile(
|
|
51
75
|
join(root, distDir, "wrangler.jsonc"),
|
|
52
76
|
JSON.stringify(wrangler, null, 2),
|
|
53
77
|
);
|
|
78
|
+
|
|
79
|
+
await writeWorkerEntryPoint(root, distDir);
|
|
54
80
|
}
|
|
55
81
|
|
|
56
82
|
/**
|
|
@@ -64,9 +90,11 @@ async function writeWorkerEntryPoint(
|
|
|
64
90
|
import "./index.js";
|
|
65
91
|
|
|
66
92
|
export default {
|
|
67
|
-
fetch: async (request) => {
|
|
93
|
+
fetch: async (request, env) => {
|
|
68
94
|
const ctx = { req: request, res: undefined };
|
|
69
95
|
|
|
96
|
+
__alepha.set("cloudflare.env", env);
|
|
97
|
+
|
|
70
98
|
await __alepha.start();
|
|
71
99
|
await __alepha.events.emit("web:request", ctx);
|
|
72
100
|
|