alepha 0.14.4 → 0.15.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/README.md +1 -4
- package/dist/api/audits/index.d.ts +619 -731
- package/dist/api/audits/index.d.ts.map +1 -1
- package/dist/api/files/index.d.ts +185 -298
- package/dist/api/files/index.d.ts.map +1 -1
- package/dist/api/files/index.js +0 -1
- package/dist/api/files/index.js.map +1 -1
- package/dist/api/jobs/index.d.ts +245 -356
- package/dist/api/jobs/index.d.ts.map +1 -1
- package/dist/api/notifications/index.d.ts +238 -350
- package/dist/api/notifications/index.d.ts.map +1 -1
- package/dist/api/parameters/index.d.ts +499 -611
- package/dist/api/parameters/index.d.ts.map +1 -1
- package/dist/api/users/index.browser.js +1 -2
- package/dist/api/users/index.browser.js.map +1 -1
- package/dist/api/users/index.d.ts +1697 -1804
- package/dist/api/users/index.d.ts.map +1 -1
- package/dist/api/users/index.js +178 -151
- 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/batch/index.js +1 -2
- package/dist/batch/index.js.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/cli/index.d.ts +302 -299
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +966 -564
- package/dist/cli/index.js.map +1 -1
- package/dist/command/index.d.ts +303 -299
- package/dist/command/index.d.ts.map +1 -1
- package/dist/command/index.js +11 -7
- package/dist/command/index.js.map +1 -1
- package/dist/core/index.browser.js +419 -99
- package/dist/core/index.browser.js.map +1 -1
- package/dist/core/index.d.ts +718 -625
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +420 -99
- package/dist/core/index.js.map +1 -1
- package/dist/core/index.native.js +419 -99
- 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/datetime/index.js +4 -4
- package/dist/datetime/index.js.map +1 -1
- package/dist/email/index.d.ts +97 -50
- package/dist/email/index.d.ts.map +1 -1
- package/dist/email/index.js +129 -33
- package/dist/email/index.js.map +1 -1
- package/dist/fake/index.d.ts +7981 -14
- package/dist/fake/index.d.ts.map +1 -1
- package/dist/file/index.d.ts +523 -390
- package/dist/file/index.d.ts.map +1 -1
- package/dist/file/index.js +253 -1
- package/dist/file/index.js.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 +25 -26
- package/dist/logger/index.d.ts.map +1 -1
- package/dist/mcp/index.d.ts +197 -197
- package/dist/mcp/index.d.ts.map +1 -1
- package/dist/orm/chunk-DtkW-qnP.js +38 -0
- package/dist/orm/index.browser.js.map +1 -1
- package/dist/orm/index.bun.js +2814 -0
- package/dist/orm/index.bun.js.map +1 -0
- package/dist/orm/index.d.ts +1205 -1057
- package/dist/orm/index.d.ts.map +1 -1
- package/dist/orm/index.js +2056 -1753
- package/dist/orm/index.js.map +1 -1
- package/dist/queue/core/index.d.ts +248 -248
- package/dist/queue/core/index.d.ts.map +1 -1
- package/dist/queue/redis/index.d.ts.map +1 -1
- package/dist/redis/index.bun.js +285 -0
- package/dist/redis/index.bun.js.map +1 -0
- package/dist/redis/index.d.ts +118 -136
- package/dist/redis/index.d.ts.map +1 -1
- package/dist/redis/index.js +18 -38
- package/dist/redis/index.js.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 +25 -25
- package/dist/scheduler/index.d.ts.map +1 -1
- package/dist/security/index.browser.js +5 -1
- package/dist/security/index.browser.js.map +1 -1
- package/dist/security/index.d.ts +417 -254
- package/dist/security/index.d.ts.map +1 -1
- package/dist/security/index.js +386 -86
- package/dist/security/index.js.map +1 -1
- package/dist/server/auth/index.d.ts +277 -277
- package/dist/server/auth/index.d.ts.map +1 -1
- package/dist/server/auth/index.js +20 -20
- package/dist/server/auth/index.js.map +1 -1
- package/dist/server/cache/index.d.ts +60 -57
- package/dist/server/cache/index.d.ts.map +1 -1
- package/dist/server/cache/index.js +1 -1
- package/dist/server/cache/index.js.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/cookies/index.js +3 -3
- package/dist/server/cookies/index.js.map +1 -1
- package/dist/server/core/index.d.ts +242 -150
- package/dist/server/core/index.d.ts.map +1 -1
- package/dist/server/core/index.js +288 -122
- package/dist/server/core/index.js.map +1 -1
- package/dist/server/cors/index.d.ts +11 -12
- package/dist/server/cors/index.d.ts.map +1 -1
- package/dist/server/health/index.d.ts +0 -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.map +1 -1
- package/dist/server/links/index.d.ts +84 -85
- package/dist/server/links/index.d.ts.map +1 -1
- package/dist/server/links/index.js +1 -2
- package/dist/server/links/index.js.map +1 -1
- package/dist/server/metrics/index.d.ts.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 -103
- 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 +48 -49
- package/dist/server/swagger/index.d.ts.map +1 -1
- package/dist/server/swagger/index.js +1 -2
- package/dist/server/swagger/index.js.map +1 -1
- package/dist/sms/index.d.ts +13 -11
- package/dist/sms/index.d.ts.map +1 -1
- package/dist/sms/index.js +7 -7
- package/dist/sms/index.js.map +1 -1
- package/dist/thread/index.d.ts +71 -72
- package/dist/thread/index.d.ts.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 +5720 -159
- package/dist/vite/index.d.ts.map +1 -1
- package/dist/vite/index.js +41 -18
- package/dist/vite/index.js.map +1 -1
- package/dist/websocket/index.browser.js +6 -6
- package/dist/websocket/index.browser.js.map +1 -1
- package/dist/websocket/index.d.ts +247 -247
- package/dist/websocket/index.d.ts.map +1 -1
- package/dist/websocket/index.js +6 -6
- package/dist/websocket/index.js.map +1 -1
- package/package.json +9 -14
- package/src/api/files/controllers/AdminFileStatsController.ts +0 -1
- package/src/api/users/atoms/realmAuthSettingsAtom.ts +5 -0
- package/src/api/users/controllers/{UserRealmController.ts → RealmController.ts} +11 -11
- package/src/api/users/entities/users.ts +1 -1
- package/src/api/users/index.ts +8 -8
- package/src/api/users/primitives/{$userRealm.ts → $realm.ts} +17 -19
- package/src/api/users/providers/{UserRealmProvider.ts → RealmProvider.ts} +26 -30
- package/src/api/users/schemas/{userRealmConfigSchema.ts → realmConfigSchema.ts} +2 -2
- package/src/api/users/services/CredentialService.ts +7 -7
- package/src/api/users/services/IdentityService.ts +4 -4
- package/src/api/users/services/RegistrationService.spec.ts +25 -27
- package/src/api/users/services/RegistrationService.ts +38 -27
- package/src/api/users/services/SessionCrudService.ts +3 -3
- package/src/api/users/services/SessionService.spec.ts +3 -3
- package/src/api/users/services/SessionService.ts +28 -9
- package/src/api/users/services/UserService.ts +7 -7
- package/src/batch/providers/BatchProvider.ts +1 -2
- package/src/cli/apps/AlephaPackageBuilderCli.ts +38 -19
- package/src/cli/assets/apiHelloControllerTs.ts +18 -0
- package/src/cli/assets/apiIndexTs.ts +16 -0
- package/src/cli/assets/claudeMd.ts +303 -0
- package/src/cli/assets/mainBrowserTs.ts +2 -2
- package/src/cli/assets/mainServerTs.ts +24 -0
- package/src/cli/assets/webAppRouterTs.ts +15 -0
- package/src/cli/assets/webHelloComponentTsx.ts +16 -0
- package/src/cli/assets/webIndexTs.ts +16 -0
- package/src/cli/commands/build.ts +41 -21
- package/src/cli/commands/db.ts +21 -18
- package/src/cli/commands/deploy.ts +17 -5
- package/src/cli/commands/dev.ts +13 -17
- package/src/cli/commands/format.ts +8 -2
- package/src/cli/commands/init.ts +74 -29
- package/src/cli/commands/lint.ts +8 -2
- package/src/cli/commands/test.ts +8 -2
- package/src/cli/commands/typecheck.ts +5 -1
- package/src/cli/commands/verify.ts +4 -2
- package/src/cli/services/AlephaCliUtils.ts +39 -600
- package/src/cli/services/PackageManagerUtils.ts +301 -0
- package/src/cli/services/ProjectScaffolder.ts +306 -0
- package/src/command/helpers/Runner.ts +15 -3
- package/src/core/__tests__/Alepha-graph.spec.ts +4 -0
- package/src/core/index.shared.ts +1 -0
- package/src/core/index.ts +2 -0
- package/src/core/primitives/$hook.ts +6 -2
- package/src/core/primitives/$module.spec.ts +4 -0
- package/src/core/providers/AlsProvider.ts +1 -1
- package/src/core/providers/CodecManager.spec.ts +12 -6
- package/src/core/providers/CodecManager.ts +26 -6
- package/src/core/providers/EventManager.ts +169 -13
- package/src/core/providers/KeylessJsonSchemaCodec.spec.ts +621 -0
- package/src/core/providers/KeylessJsonSchemaCodec.ts +407 -0
- package/src/core/providers/StateManager.spec.ts +27 -16
- package/src/email/providers/LocalEmailProvider.spec.ts +111 -87
- package/src/email/providers/LocalEmailProvider.ts +52 -15
- package/src/email/providers/NodemailerEmailProvider.ts +167 -56
- package/src/file/errors/FileError.ts +7 -0
- package/src/file/index.ts +9 -1
- package/src/file/providers/MemoryFileSystemProvider.ts +393 -0
- package/src/orm/index.browser.ts +1 -19
- package/src/orm/index.bun.ts +77 -0
- package/src/orm/index.shared-server.ts +22 -0
- package/src/orm/index.shared.ts +15 -0
- package/src/orm/index.ts +19 -39
- package/src/orm/providers/drivers/BunPostgresProvider.ts +3 -5
- package/src/orm/providers/drivers/BunSqliteProvider.ts +1 -1
- package/src/orm/providers/drivers/CloudflareD1Provider.ts +4 -0
- package/src/orm/providers/drivers/DatabaseProvider.ts +4 -0
- package/src/orm/providers/drivers/PglitePostgresProvider.ts +4 -0
- package/src/orm/services/Repository.ts +8 -0
- package/src/redis/index.bun.ts +35 -0
- package/src/redis/providers/BunRedisProvider.ts +12 -43
- package/src/redis/providers/BunRedisSubscriberProvider.ts +2 -3
- package/src/redis/providers/NodeRedisProvider.ts +16 -34
- package/src/{server/security → security}/__tests__/BasicAuth.spec.ts +11 -11
- package/src/{server/security → security}/__tests__/ServerSecurityProvider-realm.spec.ts +21 -16
- package/src/{server/security/providers → security/__tests__}/ServerSecurityProvider.spec.ts +5 -5
- package/src/security/index.browser.ts +5 -0
- package/src/security/index.ts +90 -7
- package/src/security/primitives/{$realm.spec.ts → $issuer.spec.ts} +11 -11
- package/src/security/primitives/{$realm.ts → $issuer.ts} +20 -17
- package/src/security/primitives/$role.ts +5 -5
- package/src/security/primitives/$serviceAccount.spec.ts +5 -5
- package/src/security/primitives/$serviceAccount.ts +3 -3
- package/src/{server/security → security}/providers/ServerSecurityProvider.ts +5 -7
- package/src/server/auth/primitives/$auth.ts +10 -10
- package/src/server/auth/primitives/$authCredentials.ts +3 -3
- package/src/server/auth/primitives/$authGithub.ts +3 -3
- package/src/server/auth/primitives/$authGoogle.ts +3 -3
- package/src/server/auth/providers/ServerAuthProvider.ts +13 -13
- package/src/server/cache/providers/ServerCacheProvider.ts +1 -1
- package/src/server/cookies/providers/ServerCookiesProvider.ts +3 -3
- package/src/server/core/providers/NodeHttpServerProvider.ts +25 -6
- package/src/server/core/providers/ServerBodyParserProvider.ts +19 -23
- package/src/server/core/providers/ServerLoggerProvider.ts +23 -19
- package/src/server/core/providers/ServerProvider.ts +144 -21
- package/src/server/core/providers/ServerRouterProvider.ts +259 -115
- package/src/server/core/providers/ServerTimingProvider.ts +2 -2
- package/src/server/links/index.ts +1 -1
- package/src/server/links/providers/LinkProvider.ts +1 -1
- package/src/server/swagger/index.ts +1 -1
- package/src/sms/providers/LocalSmsProvider.spec.ts +153 -111
- package/src/sms/providers/LocalSmsProvider.ts +8 -7
- package/src/vite/helpers/boot.ts +28 -17
- package/src/vite/tasks/buildServer.ts +12 -1
- package/src/vite/tasks/devServer.ts +3 -1
- package/src/vite/tasks/generateCloudflare.ts +7 -0
- package/dist/server/security/index.browser.js +0 -13
- package/dist/server/security/index.browser.js.map +0 -1
- package/dist/server/security/index.d.ts +0 -173
- package/dist/server/security/index.d.ts.map +0 -1
- package/dist/server/security/index.js +0 -311
- package/dist/server/security/index.js.map +0 -1
- package/src/cli/assets/appRouterTs.ts +0 -9
- package/src/cli/assets/mainTs.ts +0 -13
- package/src/server/security/index.browser.ts +0 -10
- package/src/server/security/index.ts +0 -94
- /package/src/{server/security → security}/primitives/$basicAuth.ts +0 -0
- /package/src/{server/security → security}/providers/ServerBasicAuthProvider.ts +0 -0
|
@@ -48,7 +48,7 @@ export class ServerCookiesProvider {
|
|
|
48
48
|
|
|
49
49
|
public readonly onRequest = $hook({
|
|
50
50
|
on: "server:onRequest",
|
|
51
|
-
handler:
|
|
51
|
+
handler: ({ request }) => {
|
|
52
52
|
request.cookies = {
|
|
53
53
|
req: this.cookieParser.parseRequestCookies(
|
|
54
54
|
request.headers.cookie ?? "",
|
|
@@ -60,7 +60,7 @@ export class ServerCookiesProvider {
|
|
|
60
60
|
|
|
61
61
|
public readonly onAction = $hook({
|
|
62
62
|
on: "action:onRequest",
|
|
63
|
-
handler:
|
|
63
|
+
handler: ({ request }) => {
|
|
64
64
|
request.cookies = {
|
|
65
65
|
req: this.cookieParser.parseRequestCookies(
|
|
66
66
|
request.headers.cookie ?? "",
|
|
@@ -72,7 +72,7 @@ export class ServerCookiesProvider {
|
|
|
72
72
|
|
|
73
73
|
public readonly onSend = $hook({
|
|
74
74
|
on: "server:onSend",
|
|
75
|
-
handler:
|
|
75
|
+
handler: ({ request }) => {
|
|
76
76
|
if (request.cookies && Object.keys(request.cookies.res).length > 0) {
|
|
77
77
|
const setCookieHeaders = this.cookieParser.serializeResponseCookies(
|
|
78
78
|
request.cookies.res,
|
|
@@ -44,13 +44,32 @@ export class NodeHttpServerProvider extends ServerProvider {
|
|
|
44
44
|
return `http://${this.env.SERVER_HOST}:${this.env.SERVER_PORT}`;
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
+
// Pre-bound error handler to avoid function allocation per request
|
|
48
|
+
protected readonly handleRequestError = (
|
|
49
|
+
res: import("node:http").ServerResponse,
|
|
50
|
+
err: Error,
|
|
51
|
+
) => {
|
|
52
|
+
this.log.error("Error handling request", err);
|
|
53
|
+
res.statusCode = 500;
|
|
54
|
+
res.end("Internal Server Error");
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
// P3: Pre-allocated event object to avoid { req, res } allocation per request
|
|
58
|
+
// Safe because handleNodeRequest completes before the next request reuses this object
|
|
59
|
+
protected readonly nodeRequestEvent = {
|
|
60
|
+
req: null as unknown as IncomingMessage,
|
|
61
|
+
res: null as unknown as ServerResponse,
|
|
62
|
+
};
|
|
63
|
+
|
|
47
64
|
public readonly server = this.createHttpServer((req, res) => {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
65
|
+
// Reuse pre-allocated event object instead of creating { req, res } per request
|
|
66
|
+
const ev = this.nodeRequestEvent;
|
|
67
|
+
ev.req = req;
|
|
68
|
+
ev.res = res;
|
|
69
|
+
// Note: handleNodeRequest returns a promise that resolves after response is sent
|
|
70
|
+
this.handleNodeRequest(ev).catch((err) =>
|
|
71
|
+
this.handleRequestError(res, err),
|
|
72
|
+
);
|
|
54
73
|
});
|
|
55
74
|
|
|
56
75
|
public readonly start = $hook({
|
|
@@ -24,7 +24,7 @@ export class ServerBodyParserProvider {
|
|
|
24
24
|
|
|
25
25
|
public readonly onRequest = $hook({
|
|
26
26
|
on: "server:onRequest",
|
|
27
|
-
handler:
|
|
27
|
+
handler: ({ route, request }) => {
|
|
28
28
|
if (request.body) {
|
|
29
29
|
return; // already parsed
|
|
30
30
|
}
|
|
@@ -46,28 +46,24 @@ export class ServerBodyParserProvider {
|
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
if (route.schema?.body) {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
)
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
},
|
|
68
|
-
error,
|
|
69
|
-
);
|
|
70
|
-
}
|
|
49
|
+
return this.parse(stream, request.headers, route.schema.body)
|
|
50
|
+
.then((body) => {
|
|
51
|
+
if (body) {
|
|
52
|
+
request.body = body;
|
|
53
|
+
}
|
|
54
|
+
})
|
|
55
|
+
.catch((error) => {
|
|
56
|
+
if (error instanceof HttpError) {
|
|
57
|
+
throw error;
|
|
58
|
+
}
|
|
59
|
+
throw new HttpError(
|
|
60
|
+
{
|
|
61
|
+
status: 400,
|
|
62
|
+
message: "Failed to parse request body",
|
|
63
|
+
},
|
|
64
|
+
error,
|
|
65
|
+
);
|
|
66
|
+
});
|
|
71
67
|
}
|
|
72
68
|
},
|
|
73
69
|
});
|
|
@@ -9,24 +9,26 @@ export class ServerLoggerProvider {
|
|
|
9
9
|
on: "server:onRequest",
|
|
10
10
|
priority: "first",
|
|
11
11
|
handler: ({ route, request }) => {
|
|
12
|
-
if (
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
const ip = request.ip;
|
|
23
|
-
if (ip) {
|
|
24
|
-
data.ip = ip;
|
|
25
|
-
}
|
|
26
|
-
}
|
|
12
|
+
if (route.silent) {
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
request.metadata.now = Date.now();
|
|
17
|
+
|
|
18
|
+
const data: Record<string, string> = {
|
|
19
|
+
method: request.method,
|
|
20
|
+
path: request.url.pathname,
|
|
21
|
+
};
|
|
27
22
|
|
|
28
|
-
|
|
23
|
+
if (this.alepha.isProduction()) {
|
|
24
|
+
data.agent = request.headers["user-agent"];
|
|
25
|
+
const ip = request.ip;
|
|
26
|
+
if (ip) {
|
|
27
|
+
data.ip = ip;
|
|
28
|
+
}
|
|
29
29
|
}
|
|
30
|
+
|
|
31
|
+
this.log.info("Incoming request", data);
|
|
30
32
|
},
|
|
31
33
|
});
|
|
32
34
|
|
|
@@ -42,10 +44,12 @@ export class ServerLoggerProvider {
|
|
|
42
44
|
on: "server:onResponse",
|
|
43
45
|
priority: "last",
|
|
44
46
|
handler: ({ route, request, response }) => {
|
|
45
|
-
if (
|
|
46
|
-
|
|
47
|
-
this.log.info("Request completed", { status: response.status, ms });
|
|
47
|
+
if (route.silent) {
|
|
48
|
+
return;
|
|
48
49
|
}
|
|
50
|
+
|
|
51
|
+
const ms = Date.now() - request.metadata.now;
|
|
52
|
+
this.log.info("Request completed", { status: response.status, ms });
|
|
49
53
|
},
|
|
50
54
|
});
|
|
51
55
|
}
|
|
@@ -11,6 +11,21 @@ import type {
|
|
|
11
11
|
} from "../interfaces/ServerRequest.ts";
|
|
12
12
|
import { ServerRouterProvider } from "./ServerRouterProvider.ts";
|
|
13
13
|
|
|
14
|
+
// ============================================================================
|
|
15
|
+
// Performance Constants
|
|
16
|
+
// ============================================================================
|
|
17
|
+
|
|
18
|
+
// Note: We cannot use frozen/shared empty objects here because downstream code
|
|
19
|
+
// may mutate params/query (e.g., validation, React page rendering)
|
|
20
|
+
|
|
21
|
+
// Header constants for fast property access
|
|
22
|
+
const HEADER_X_FORWARDED_PROTO = "x-forwarded-proto";
|
|
23
|
+
const HEADER_HOST = "host";
|
|
24
|
+
|
|
25
|
+
// Protocol prefixes
|
|
26
|
+
const PROTO_HTTPS = "https://";
|
|
27
|
+
const PROTO_HTTP = "http://";
|
|
28
|
+
|
|
14
29
|
/**
|
|
15
30
|
* Base server provider to handle incoming requests and route them.
|
|
16
31
|
*
|
|
@@ -26,6 +41,113 @@ export class ServerProvider {
|
|
|
26
41
|
|
|
27
42
|
protected readonly internalServerErrorMessage = "Internal Server Error";
|
|
28
43
|
|
|
44
|
+
// Pre-allocated error response to avoid object creation per failed request
|
|
45
|
+
protected readonly internalErrorResponse = Object.freeze({
|
|
46
|
+
status: 500,
|
|
47
|
+
headers: Object.freeze({ "content-type": "text/plain" }),
|
|
48
|
+
body: this.internalServerErrorMessage,
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
// Pre-bound error handler to avoid function allocation per request
|
|
52
|
+
protected readonly handleInternalError = () => this.internalErrorResponse;
|
|
53
|
+
|
|
54
|
+
// ============================================================================
|
|
55
|
+
// P1: URL Base Cache - cache protocol+host per unique host header
|
|
56
|
+
// Avoids string concatenation on every request
|
|
57
|
+
// ============================================================================
|
|
58
|
+
protected readonly urlBaseCache = new Map<string, string>();
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Get cached URL base (protocol + host) for a given host header.
|
|
62
|
+
* Caches the result to avoid repeated string concatenation.
|
|
63
|
+
*/
|
|
64
|
+
protected getUrlBase(headers: Record<string, string>): string {
|
|
65
|
+
const host = headers[HEADER_HOST];
|
|
66
|
+
let base = this.urlBaseCache.get(host);
|
|
67
|
+
if (!base) {
|
|
68
|
+
const proto =
|
|
69
|
+
headers[HEADER_X_FORWARDED_PROTO] === "https"
|
|
70
|
+
? PROTO_HTTPS
|
|
71
|
+
: PROTO_HTTP;
|
|
72
|
+
base = proto + host;
|
|
73
|
+
// Limit cache size to prevent memory leaks from many unique hosts
|
|
74
|
+
if (this.urlBaseCache.size < 100) {
|
|
75
|
+
this.urlBaseCache.set(host, base);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return base;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// ============================================================================
|
|
82
|
+
// P0: Manual Query String Parser - faster than URLSearchParams
|
|
83
|
+
// Parses query string without creating URL object
|
|
84
|
+
// ============================================================================
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Parse query string manually - faster than new URL() + URLSearchParams.
|
|
88
|
+
* Returns empty object if no query string.
|
|
89
|
+
*/
|
|
90
|
+
protected parseQueryString(rawUrl: string): Record<string, string> {
|
|
91
|
+
const qIndex = rawUrl.indexOf("?");
|
|
92
|
+
if (qIndex === -1) {
|
|
93
|
+
return {};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const qs = rawUrl.slice(qIndex + 1);
|
|
97
|
+
if (!qs) {
|
|
98
|
+
return {};
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const query: Record<string, string> = {};
|
|
102
|
+
let start = 0;
|
|
103
|
+
let eqIdx = -1;
|
|
104
|
+
|
|
105
|
+
for (let i = 0; i <= qs.length; i++) {
|
|
106
|
+
const char = i < qs.length ? qs.charCodeAt(i) : 38; // '&' at end
|
|
107
|
+
|
|
108
|
+
if (char === 61) {
|
|
109
|
+
// '='
|
|
110
|
+
eqIdx = i;
|
|
111
|
+
} else if (char === 38) {
|
|
112
|
+
// '&'
|
|
113
|
+
if (eqIdx !== -1 && eqIdx > start) {
|
|
114
|
+
const key = qs.slice(start, eqIdx);
|
|
115
|
+
const value = qs.slice(eqIdx + 1, i);
|
|
116
|
+
// Only decode if necessary (contains % or +)
|
|
117
|
+
query[this.fastDecode(key)] = this.fastDecode(value);
|
|
118
|
+
}
|
|
119
|
+
start = i + 1;
|
|
120
|
+
eqIdx = -1;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return query;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Fast decode - only calls decodeURIComponent if needed.
|
|
129
|
+
*/
|
|
130
|
+
protected fastDecode(str: string): string {
|
|
131
|
+
// Fast path: no encoding needed
|
|
132
|
+
if (str.indexOf("%") === -1 && str.indexOf("+") === -1) {
|
|
133
|
+
return str;
|
|
134
|
+
}
|
|
135
|
+
// Replace + with space before decoding
|
|
136
|
+
try {
|
|
137
|
+
return decodeURIComponent(str.replace(/\+/g, " "));
|
|
138
|
+
} catch {
|
|
139
|
+
return str;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Extract pathname from URL without creating URL object.
|
|
145
|
+
*/
|
|
146
|
+
protected getPathname(rawUrl: string): string {
|
|
147
|
+
const qIndex = rawUrl.indexOf("?");
|
|
148
|
+
return qIndex === -1 ? rawUrl : rawUrl.slice(0, qIndex);
|
|
149
|
+
}
|
|
150
|
+
|
|
29
151
|
public get hostname(): string {
|
|
30
152
|
if (this.alepha.isViteDev()) {
|
|
31
153
|
return `http://localhost:${this.alepha.env.SERVER_PORT}`;
|
|
@@ -54,15 +176,16 @@ export class ServerProvider {
|
|
|
54
176
|
/**
|
|
55
177
|
* Handle Node.js HTTP request event.
|
|
56
178
|
*
|
|
57
|
-
*
|
|
179
|
+
* Optimized to avoid expensive URL parsing when possible.
|
|
58
180
|
*/
|
|
59
181
|
public async handleNodeRequest(
|
|
60
182
|
nodeRequestEvent: NodeRequestEvent,
|
|
61
183
|
): Promise<void> {
|
|
62
184
|
const { req, res } = nodeRequestEvent;
|
|
63
|
-
const
|
|
185
|
+
const rawUrl = req.url!;
|
|
186
|
+
const { route, params } = this.router.match(`/${req.method}${rawUrl}`);
|
|
64
187
|
|
|
65
|
-
if (this.isViteNotFound(
|
|
188
|
+
if (this.isViteNotFound(rawUrl, route, params)) {
|
|
66
189
|
return;
|
|
67
190
|
}
|
|
68
191
|
|
|
@@ -75,11 +198,16 @@ export class ServerProvider {
|
|
|
75
198
|
}
|
|
76
199
|
|
|
77
200
|
const headers = (req.headers ?? {}) as Record<string, string>;
|
|
78
|
-
const proto = headers["x-forwarded-proto"] === "https" ? "https" : "http";
|
|
79
|
-
const url = new URL(`${proto}://${headers.host}${req.url}`);
|
|
80
|
-
const query = Object.fromEntries(url.searchParams.entries());
|
|
81
201
|
const method = (req.method?.toUpperCase() ?? "GET") as RouteMethod;
|
|
82
202
|
|
|
203
|
+
// P0: Use manual query parsing - much faster than new URL() + URLSearchParams
|
|
204
|
+
const query = this.parseQueryString(rawUrl);
|
|
205
|
+
|
|
206
|
+
// P1: Use cached URL base - avoids string concat on every request
|
|
207
|
+
// Create URL object (still needed for downstream code that uses url.pathname, etc.)
|
|
208
|
+
const urlBase = this.getUrlBase(headers);
|
|
209
|
+
const url = new URL(rawUrl, urlBase);
|
|
210
|
+
|
|
83
211
|
const request: ServerRequestData = {
|
|
84
212
|
method,
|
|
85
213
|
url,
|
|
@@ -89,13 +217,9 @@ export class ServerProvider {
|
|
|
89
217
|
raw: { node: nodeRequestEvent },
|
|
90
218
|
};
|
|
91
219
|
|
|
92
|
-
const response = await route
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
headers: { "content-type": "text/plain" },
|
|
96
|
-
body: this.internalServerErrorMessage,
|
|
97
|
-
};
|
|
98
|
-
});
|
|
220
|
+
const response = await route
|
|
221
|
+
.handler(request)
|
|
222
|
+
.catch(this.handleInternalError);
|
|
99
223
|
|
|
100
224
|
// empty body - just send status & headers
|
|
101
225
|
if (!response.body) {
|
|
@@ -175,7 +299,10 @@ export class ServerProvider {
|
|
|
175
299
|
headers[key] = value;
|
|
176
300
|
});
|
|
177
301
|
|
|
178
|
-
|
|
302
|
+
// Optimize: only parse query params if there are any
|
|
303
|
+
const query = url.search
|
|
304
|
+
? Object.fromEntries(url.searchParams.entries())
|
|
305
|
+
: {};
|
|
179
306
|
const method = (req.method.toUpperCase() ?? "GET") as RouteMethod;
|
|
180
307
|
const request: ServerRequestData = {
|
|
181
308
|
method,
|
|
@@ -186,13 +313,9 @@ export class ServerProvider {
|
|
|
186
313
|
raw: { web: ev },
|
|
187
314
|
};
|
|
188
315
|
|
|
189
|
-
const response = await route
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
headers: { "content-type": "text/plain" },
|
|
193
|
-
body: this.internalServerErrorMessage,
|
|
194
|
-
};
|
|
195
|
-
});
|
|
316
|
+
const response = await route
|
|
317
|
+
.handler(request)
|
|
318
|
+
.catch(this.handleInternalError);
|
|
196
319
|
|
|
197
320
|
// empty body - just send status & headers
|
|
198
321
|
if (!response.body) {
|