@edge-base/server 0.2.4 → 0.2.6
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/admin-build/_app/immutable/chunks/{DILS_-VJ.js → B3CvhH3c.js} +1 -1
- package/admin-build/_app/immutable/chunks/BN_-k-Ck.js +1 -0
- package/admin-build/_app/immutable/chunks/{Dt4vL4Df.js → BYL_uBga.js} +1 -1
- package/admin-build/_app/immutable/chunks/{C72lTcG0.js → Bcs4KYNp.js} +1 -1
- package/admin-build/_app/immutable/chunks/{B8s_s9QY.js → BkZCgsc3.js} +1 -1
- package/admin-build/_app/immutable/chunks/{BgDzp0i0.js → BvoGcDFV.js} +1 -1
- package/admin-build/_app/immutable/chunks/{BME_U9TJ.js → CCUxCptE.js} +1 -1
- package/admin-build/_app/immutable/chunks/CLHN9MVr.js +1 -0
- package/admin-build/_app/immutable/chunks/{DYaCRWMA.js → CR37B8DX.js} +1 -1
- package/admin-build/_app/immutable/chunks/CbfX3ELZ.js +1 -0
- package/admin-build/_app/immutable/chunks/CjcrXziO.js +2 -0
- package/admin-build/_app/immutable/chunks/CrwlCAM0.js +1 -0
- package/admin-build/_app/immutable/chunks/{B0HRJ657.js → DOOPbWwG.js} +1 -1
- package/admin-build/_app/immutable/chunks/DQVP4KC-.js +1 -0
- package/admin-build/_app/immutable/chunks/{Dj0QUuOf.js → DdvsFblq.js} +1 -1
- package/admin-build/_app/immutable/chunks/DemDWbs-.js +128 -0
- package/admin-build/_app/immutable/chunks/{XQM1k9PM.js → DmDTovpg.js} +1 -1
- package/admin-build/_app/immutable/chunks/{fYEKMQ-Z.js → Ff90owjx.js} +1 -1
- package/admin-build/_app/immutable/chunks/{5RQRbp5q.js → LL3ulaxa.js} +1 -1
- package/admin-build/_app/immutable/chunks/{DBsVqhuh.js → Q3vAxeY-.js} +1 -1
- package/admin-build/_app/immutable/chunks/{D__dwMuW.js → SQVAC3Cv.js} +1 -1
- package/admin-build/_app/immutable/chunks/{Z41NK6i6.js → bguI1TeA.js} +1 -1
- package/admin-build/_app/immutable/chunks/{_teD5ji5.js → nlAMTi52.js} +1 -1
- package/admin-build/_app/immutable/chunks/{BjWZuf8W.js → qBm6xof8.js} +1 -1
- package/admin-build/_app/immutable/entry/{app.C8ylfBe6.js → app.CP83Ni80.js} +2 -2
- package/admin-build/_app/immutable/entry/start.DY6YakU0.js +1 -0
- package/admin-build/_app/immutable/nodes/{0.CJJ6HZbp.js → 0.DiRq7puO.js} +1 -1
- package/admin-build/_app/immutable/nodes/1.BFeyKLGT.js +1 -0
- package/admin-build/_app/immutable/nodes/10.zcee7hJx.js +1 -0
- package/admin-build/_app/immutable/nodes/11.BW7wLs2Y.js +1 -0
- package/admin-build/_app/immutable/nodes/12.CxJRlYSd.js +1 -0
- package/admin-build/_app/immutable/nodes/13.pp0F_5hn.js +110 -0
- package/admin-build/_app/immutable/nodes/14.t3AfGiGo.js +3 -0
- package/admin-build/_app/immutable/nodes/15.B3agc7NX.js +1 -0
- package/admin-build/_app/immutable/nodes/{16.D0xkPUBW.js → 16.C4uG2-i8.js} +1 -1
- package/admin-build/_app/immutable/nodes/{17.CebNqPeh.js → 17.CwGxi1Bn.js} +1 -1
- package/admin-build/_app/immutable/nodes/18.CrQyN_gU.js +1 -0
- package/admin-build/_app/immutable/nodes/19.NEPUOXl7.js +2 -0
- package/admin-build/_app/immutable/nodes/{20.DYb-q3W8.js → 20.DGHO8ipr.js} +1 -1
- package/admin-build/_app/immutable/nodes/21.UVKBDvp4.js +1 -0
- package/admin-build/_app/immutable/nodes/22.Dri5It7a.js +1 -0
- package/admin-build/_app/immutable/nodes/{23.BLgq21om.js → 23.BPQP_Zte.js} +2 -2
- package/admin-build/_app/immutable/nodes/24.D580FdSS.js +2 -0
- package/admin-build/_app/immutable/nodes/25.BMNPOZwF.js +2 -0
- package/admin-build/_app/immutable/nodes/26.XcpEcbiz.js +1 -0
- package/admin-build/_app/immutable/nodes/27.C1zHHcYv.js +1 -0
- package/admin-build/_app/immutable/nodes/28.CuKzzrY8.js +1 -0
- package/admin-build/_app/immutable/nodes/29.nLpBMXnM.js +1 -0
- package/admin-build/_app/immutable/nodes/{3.z8ut3jS-.js → 3.5G_aseoL.js} +1 -1
- package/admin-build/_app/immutable/nodes/30.CQC4nLoU.js +1 -0
- package/admin-build/_app/immutable/nodes/31.Bet8kxOK.js +1 -0
- package/admin-build/_app/immutable/nodes/4.nmJDYJpC.js +1 -0
- package/admin-build/_app/immutable/nodes/5.CnbYLG4E.js +1 -0
- package/admin-build/_app/immutable/nodes/6.KA01b-3y.js +1 -0
- package/admin-build/_app/immutable/nodes/7.CP9fkn1L.js +1 -0
- package/admin-build/_app/immutable/nodes/8.BTzDb---.js +1 -0
- package/admin-build/_app/immutable/nodes/9.DkNJg_J6.js +1 -0
- package/admin-build/_app/version.json +1 -1
- package/admin-build/index.html +7 -7
- package/package.json +3 -3
- package/src/__tests__/database-do-route-validation.test.ts +10 -7
- package/src/__tests__/meta-route-registration.test.ts +20 -15
- package/src/__tests__/push-handlers.test.ts +1 -1
- package/src/__tests__/room-auth-state-loss.test.ts +122 -0
- package/src/__tests__/room-handler-context.test.ts +4 -4
- package/src/__tests__/room-rate-limit-scopes.test.ts +38 -0
- package/src/__tests__/room-runtime-routing.test.ts +23 -0
- package/src/__tests__/route-parser.test.ts +6 -0
- package/src/__tests__/runtime-startup.test.ts +49 -0
- package/src/__tests__/schema.test.ts +15 -6
- package/src/durable-objects/database-do.ts +21 -1
- package/src/durable-objects/database-live-do.ts +15 -0
- package/src/durable-objects/room-runtime-base.ts +436 -169
- package/src/durable-objects/rooms-do.ts +63 -25
- package/src/index.ts +340 -280
- package/src/lib/d1-handler.ts +32 -17
- package/src/lib/postgres-handler.ts +24 -12
- package/src/lib/route-parser.ts +3 -0
- package/src/lib/runtime-startup.ts +53 -0
- package/src/lib/schemas.ts +12 -2
- package/src/middleware/captcha-verify.ts +16 -3
- package/src/middleware/error-handler.ts +1 -1
- package/src/middleware/rules.ts +28 -9
- package/src/routes/admin-auth.ts +3 -3
- package/src/routes/admin.ts +13 -8
- package/src/routes/analytics-api.ts +3 -3
- package/src/routes/auth.ts +1 -1
- package/src/routes/backup.ts +1 -1
- package/src/routes/d1.ts +14 -7
- package/src/routes/database-live.ts +13 -6
- package/src/routes/kv.ts +21 -10
- package/src/routes/oauth.ts +1 -1
- package/src/routes/push.ts +119 -77
- package/src/routes/room.ts +215 -7
- package/src/routes/schema-endpoint.ts +2 -2
- package/src/routes/sql.ts +10 -6
- package/src/routes/storage.ts +4 -2
- package/src/routes/vectorize.ts +16 -4
- package/admin-build/_app/immutable/chunks/BYI6CUvd.js +0 -1
- package/admin-build/_app/immutable/chunks/C6lpZLE2.js +0 -1
- package/admin-build/_app/immutable/chunks/CoI6jjbg.js +0 -2
- package/admin-build/_app/immutable/chunks/D5GswVnI.js +0 -128
- package/admin-build/_app/immutable/chunks/Dj-E9-FO.js +0 -1
- package/admin-build/_app/immutable/chunks/g_-Kpxu3.js +0 -1
- package/admin-build/_app/immutable/chunks/wCNueVYy.js +0 -1
- package/admin-build/_app/immutable/entry/start.CtsqDyfj.js +0 -1
- package/admin-build/_app/immutable/nodes/1.B4sI5cB4.js +0 -1
- package/admin-build/_app/immutable/nodes/10.D6hvCer6.js +0 -1
- package/admin-build/_app/immutable/nodes/11.Dx7b8aQ5.js +0 -1
- package/admin-build/_app/immutable/nodes/12.Bqmy5KIF.js +0 -1
- package/admin-build/_app/immutable/nodes/13.CC6KpXgS.js +0 -110
- package/admin-build/_app/immutable/nodes/14.yCo1Ix8E.js +0 -3
- package/admin-build/_app/immutable/nodes/15.co0UfPlh.js +0 -1
- package/admin-build/_app/immutable/nodes/18.JUoLOZxh.js +0 -1
- package/admin-build/_app/immutable/nodes/19.ND8kmQJe.js +0 -2
- package/admin-build/_app/immutable/nodes/21.cz3IN9Cc.js +0 -1
- package/admin-build/_app/immutable/nodes/22.UOzm8WYV.js +0 -1
- package/admin-build/_app/immutable/nodes/24.DN9usmUs.js +0 -2
- package/admin-build/_app/immutable/nodes/25.BddRfAyE.js +0 -2
- package/admin-build/_app/immutable/nodes/26.Dl6XHIeT.js +0 -1
- package/admin-build/_app/immutable/nodes/27.D0iNwALG.js +0 -1
- package/admin-build/_app/immutable/nodes/28.9dKQmdGi.js +0 -1
- package/admin-build/_app/immutable/nodes/29.wXzfJUXp.js +0 -1
- package/admin-build/_app/immutable/nodes/30.BtZETNsL.js +0 -1
- package/admin-build/_app/immutable/nodes/31.CYonj2Jh.js +0 -1
- package/admin-build/_app/immutable/nodes/4.COtDPQ9b.js +0 -1
- package/admin-build/_app/immutable/nodes/5.CTRCeIhp.js +0 -1
- package/admin-build/_app/immutable/nodes/6.ChHi3QkR.js +0 -1
- package/admin-build/_app/immutable/nodes/7.CCMtr6Ac.js +0 -1
- package/admin-build/_app/immutable/nodes/8.DpWJ-X_-.js +0 -1
- package/admin-build/_app/immutable/nodes/9.DOkvfmir.js +0 -1
package/src/index.ts
CHANGED
|
@@ -1,55 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { initFunctionRegistry } from './_functions-registry.js';
|
|
4
|
-
import { corsMiddleware } from './middleware/cors.js';
|
|
5
|
-
import { rateLimitMiddleware } from './middleware/rate-limit.js';
|
|
6
|
-
import { errorHandlerMiddleware } from './middleware/error-handler.js';
|
|
7
|
-
import { internalGuardMiddleware } from './middleware/internal-guard.js';
|
|
8
|
-
import { authMiddleware } from './middleware/auth.js';
|
|
9
|
-
import { rulesMiddleware } from './middleware/rules.js';
|
|
10
|
-
|
|
11
|
-
import { loggerMiddleware } from './middleware/logger.js';
|
|
12
|
-
import { EdgeBaseError } from '@edge-base/shared';
|
|
13
|
-
import { SERVER_VERSION } from './lib/version.js';
|
|
14
|
-
import { healthRoute } from './routes/health.js';
|
|
15
|
-
import { tablesRoute } from './routes/tables.js';
|
|
16
|
-
import { schemaRoute } from './routes/schema-endpoint.js';
|
|
17
|
-
import { authRoute } from './routes/auth.js';
|
|
18
|
-
import { adminAuthRoute } from './routes/admin-auth.js';
|
|
19
|
-
import { oauthRoute } from './routes/oauth.js';
|
|
20
|
-
import { databaseLiveRoute } from './routes/database-live.js';
|
|
21
|
-
import { storageRoute } from './routes/storage.js';
|
|
22
|
-
import { functionsRoute } from './routes/functions.js';
|
|
23
|
-
import { adminRoute } from './routes/admin.js';
|
|
24
|
-
import { backupRoute } from './routes/backup.js';
|
|
25
|
-
import { sqlRoute } from './routes/sql.js';
|
|
26
|
-
import { kvRoute } from './routes/kv.js';
|
|
27
|
-
import { d1Route } from './routes/d1.js';
|
|
28
|
-
import { vectorizeRoute } from './routes/vectorize.js';
|
|
29
|
-
import { configRoute } from './routes/config.js';
|
|
30
|
-
import { pushRoute } from './routes/push.js';
|
|
31
|
-
import { roomRoute } from './routes/room.js';
|
|
32
|
-
import { analyticsApi } from './routes/analytics-api.js';
|
|
33
|
-
import { parseConfig, setConfig } from './lib/do-router.js';
|
|
34
|
-
import { createAdminAssetRequest } from './lib/admin-assets.js';
|
|
35
|
-
import { resolveAdminFaviconTarget, resolveAdminRedirectTarget } from './lib/admin-routing.js';
|
|
36
|
-
import { zodDefaultHook } from './lib/schemas.js';
|
|
37
|
-
import { executePluginMigrations } from './lib/plugin-migrations.js';
|
|
38
|
-
import { shouldRunPluginMigrationsForRequestPath } from './lib/plugin-migration-routing.js';
|
|
39
|
-
import { getFunctionsByTrigger, buildFunctionContext, getWorkerUrl } from './lib/functions.js';
|
|
40
|
-
import { parseCron, matchesCron } from './lib/cron.js';
|
|
41
|
-
import { parseDuration } from './lib/jwt.js';
|
|
42
|
-
import { resolveStartupConfig } from './lib/startup-config.js';
|
|
43
|
-
import * as authService from './lib/auth-d1-service.js';
|
|
44
|
-
import { ensureAuthSchema, deleteAnon } from './lib/auth-d1.js';
|
|
45
|
-
import { resolveAuthDb } from './lib/auth-db-adapter.js';
|
|
46
|
-
import { resolveRootServiceKey } from './lib/service-key.js';
|
|
47
|
-
import { normalizeOpenApiDocument, type OpenApiSpec } from './lib/openapi.js';
|
|
48
|
-
import generatedConfig from './generated-config.js';
|
|
1
|
+
import type { HonoEnv } from './lib/hono.js';
|
|
2
|
+
import type { OpenApiSpec } from './lib/openapi.js';
|
|
49
3
|
import type { Env } from './types.js';
|
|
50
|
-
|
|
51
|
-
// Compile-time constant — injected by wrangler [define] in wrangler.test.toml
|
|
52
|
-
declare const EDGEBASE_TEST_BUILD: boolean | undefined;
|
|
4
|
+
import { ensureServerStartup } from './lib/runtime-startup.js';
|
|
53
5
|
|
|
54
6
|
// ─── DO Re-exports (wrangler needs exports from main entry) ───
|
|
55
7
|
export { DatabaseDO } from './durable-objects/database-do.js';
|
|
@@ -58,252 +10,365 @@ export { AuthDO } from './durable-objects/auth-do.js';
|
|
|
58
10
|
export { RoomsDO } from './durable-objects/rooms-do.js';
|
|
59
11
|
export { LogsDO } from './durable-objects/logs-do.js';
|
|
60
12
|
|
|
61
|
-
|
|
62
|
-
const processEnv = typeof process !== 'undefined' ? process.env : undefined;
|
|
63
|
-
// EDGEBASE_TEST_BUILD is a compile-time constant injected by wrangler [define]
|
|
64
|
-
// in wrangler.test.toml. typeof is safe for undefined identifiers.
|
|
65
|
-
const isTestBuild = typeof EDGEBASE_TEST_BUILD !== 'undefined';
|
|
66
|
-
const preferTestConfig = await detectWorkersTestRuntime() || isTestBuild;
|
|
67
|
-
const resolvedConfig = await resolveStartupConfig(
|
|
68
|
-
generatedConfig,
|
|
69
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
70
|
-
async () => import('../edgebase.test.config.ts' as any),
|
|
71
|
-
processEnv,
|
|
72
|
-
{ preferTestConfig },
|
|
73
|
-
);
|
|
74
|
-
|
|
75
|
-
if (resolvedConfig) {
|
|
76
|
-
setConfig(resolvedConfig);
|
|
77
|
-
}
|
|
78
|
-
} catch (err) {
|
|
79
|
-
console.error('[EdgeBase] Failed to initialize config at startup:', err);
|
|
80
|
-
throw err;
|
|
81
|
-
}
|
|
13
|
+
let appPromise: Promise<Awaited<ReturnType<typeof buildApp>>> | null = null;
|
|
82
14
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
}
|
|
15
|
+
function assetUnavailableMessage(
|
|
16
|
+
assetName: 'admin dashboard' | 'harness assets',
|
|
17
|
+
): string {
|
|
18
|
+
const label = `${assetName[0].toUpperCase()}${assetName.slice(1)}`;
|
|
19
|
+
const verb = assetName === 'admin dashboard' ? 'is' : 'are';
|
|
20
|
+
return `${label} ${verb} not deployed for this worker. Deploy the assets bundle or configure ADMIN_ORIGIN if they are hosted elsewhere.`;
|
|
90
21
|
}
|
|
91
22
|
|
|
92
|
-
|
|
23
|
+
async function buildApp() {
|
|
24
|
+
await ensureServerStartup();
|
|
25
|
+
|
|
26
|
+
const [
|
|
27
|
+
honoModule,
|
|
28
|
+
httpExceptionModule,
|
|
29
|
+
corsModule,
|
|
30
|
+
rateLimitModule,
|
|
31
|
+
errorHandlerModule,
|
|
32
|
+
internalGuardModule,
|
|
33
|
+
authMiddlewareModule,
|
|
34
|
+
rulesMiddlewareModule,
|
|
35
|
+
loggerModule,
|
|
36
|
+
sharedModule,
|
|
37
|
+
versionModule,
|
|
38
|
+
healthRouteModule,
|
|
39
|
+
tablesRouteModule,
|
|
40
|
+
schemaRouteModule,
|
|
41
|
+
authRouteModule,
|
|
42
|
+
adminAuthRouteModule,
|
|
43
|
+
oauthRouteModule,
|
|
44
|
+
databaseLiveRouteModule,
|
|
45
|
+
storageRouteModule,
|
|
46
|
+
functionsRouteModule,
|
|
47
|
+
adminRouteModule,
|
|
48
|
+
backupRouteModule,
|
|
49
|
+
sqlRouteModule,
|
|
50
|
+
kvRouteModule,
|
|
51
|
+
d1RouteModule,
|
|
52
|
+
vectorizeRouteModule,
|
|
53
|
+
configRouteModule,
|
|
54
|
+
pushRouteModule,
|
|
55
|
+
roomRouteModule,
|
|
56
|
+
analyticsRouteModule,
|
|
57
|
+
adminAssetsModule,
|
|
58
|
+
adminRoutingModule,
|
|
59
|
+
schemasModule,
|
|
60
|
+
pluginMigrationsModule,
|
|
61
|
+
pluginMigrationRoutingModule,
|
|
62
|
+
functionsModule,
|
|
63
|
+
openApiModule,
|
|
64
|
+
doRouterModule,
|
|
65
|
+
] = await Promise.all([
|
|
66
|
+
import('./lib/hono.js'),
|
|
67
|
+
import('hono/http-exception'),
|
|
68
|
+
import('./middleware/cors.js'),
|
|
69
|
+
import('./middleware/rate-limit.js'),
|
|
70
|
+
import('./middleware/error-handler.js'),
|
|
71
|
+
import('./middleware/internal-guard.js'),
|
|
72
|
+
import('./middleware/auth.js'),
|
|
73
|
+
import('./middleware/rules.js'),
|
|
74
|
+
import('./middleware/logger.js'),
|
|
75
|
+
import('@edge-base/shared'),
|
|
76
|
+
import('./lib/version.js'),
|
|
77
|
+
import('./routes/health.js'),
|
|
78
|
+
import('./routes/tables.js'),
|
|
79
|
+
import('./routes/schema-endpoint.js'),
|
|
80
|
+
import('./routes/auth.js'),
|
|
81
|
+
import('./routes/admin-auth.js'),
|
|
82
|
+
import('./routes/oauth.js'),
|
|
83
|
+
import('./routes/database-live.js'),
|
|
84
|
+
import('./routes/storage.js'),
|
|
85
|
+
import('./routes/functions.js'),
|
|
86
|
+
import('./routes/admin.js'),
|
|
87
|
+
import('./routes/backup.js'),
|
|
88
|
+
import('./routes/sql.js'),
|
|
89
|
+
import('./routes/kv.js'),
|
|
90
|
+
import('./routes/d1.js'),
|
|
91
|
+
import('./routes/vectorize.js'),
|
|
92
|
+
import('./routes/config.js'),
|
|
93
|
+
import('./routes/push.js'),
|
|
94
|
+
import('./routes/room.js'),
|
|
95
|
+
import('./routes/analytics-api.js'),
|
|
96
|
+
import('./lib/admin-assets.js'),
|
|
97
|
+
import('./lib/admin-routing.js'),
|
|
98
|
+
import('./lib/schemas.js'),
|
|
99
|
+
import('./lib/plugin-migrations.js'),
|
|
100
|
+
import('./lib/plugin-migration-routing.js'),
|
|
101
|
+
import('./lib/functions.js'),
|
|
102
|
+
import('./lib/openapi.js'),
|
|
103
|
+
import('./lib/do-router.js'),
|
|
104
|
+
]);
|
|
105
|
+
|
|
106
|
+
const { OpenAPIHono } = honoModule;
|
|
107
|
+
const { HTTPException } = httpExceptionModule;
|
|
108
|
+
const { corsMiddleware } = corsModule;
|
|
109
|
+
const { rateLimitMiddleware } = rateLimitModule;
|
|
110
|
+
const { errorHandlerMiddleware } = errorHandlerModule;
|
|
111
|
+
const { internalGuardMiddleware } = internalGuardModule;
|
|
112
|
+
const { authMiddleware } = authMiddlewareModule;
|
|
113
|
+
const { rulesMiddleware } = rulesMiddlewareModule;
|
|
114
|
+
const { loggerMiddleware } = loggerModule;
|
|
115
|
+
const { EdgeBaseError } = sharedModule;
|
|
116
|
+
const { SERVER_VERSION } = versionModule;
|
|
117
|
+
const { createAdminAssetRequest } = adminAssetsModule;
|
|
118
|
+
const { resolveAdminFaviconTarget, resolveAdminRedirectTarget } = adminRoutingModule;
|
|
119
|
+
const { zodDefaultHook } = schemasModule;
|
|
120
|
+
const { executePluginMigrations } = pluginMigrationsModule;
|
|
121
|
+
const { shouldRunPluginMigrationsForRequestPath } = pluginMigrationRoutingModule;
|
|
122
|
+
const { getWorkerUrl } = functionsModule;
|
|
123
|
+
const { normalizeOpenApiDocument } = openApiModule;
|
|
124
|
+
|
|
125
|
+
const app = new OpenAPIHono<HonoEnv>({ defaultHook: zodDefaultHook });
|
|
126
|
+
|
|
127
|
+
app.use('*', errorHandlerMiddleware);
|
|
128
|
+
app.use('*', loggerMiddleware);
|
|
129
|
+
app.use('*', corsMiddleware);
|
|
130
|
+
|
|
131
|
+
app.use('*', async (c, next) => {
|
|
132
|
+
const env = c.env as Env;
|
|
133
|
+
const config = doRouterModule.parseConfig(env);
|
|
134
|
+
const requestPath = new URL(c.req.url).pathname;
|
|
135
|
+
if (config?.plugins?.length && shouldRunPluginMigrationsForRequestPath(requestPath)) {
|
|
136
|
+
await executePluginMigrations(config.plugins, env, config, getWorkerUrl(c.req.url, env));
|
|
137
|
+
}
|
|
138
|
+
return next();
|
|
139
|
+
});
|
|
93
140
|
|
|
94
|
-
|
|
141
|
+
app.use('*', rateLimitMiddleware);
|
|
142
|
+
app.use('/api/*', authMiddleware);
|
|
143
|
+
app.use('/api/db/*', rulesMiddleware);
|
|
144
|
+
app.use('/internal/*', internalGuardMiddleware);
|
|
145
|
+
|
|
146
|
+
app.route('/api', healthRouteModule.healthRoute);
|
|
147
|
+
app.route('/api/auth', authRouteModule.authRoute);
|
|
148
|
+
app.route('/api/auth/admin', adminAuthRouteModule.adminAuthRoute);
|
|
149
|
+
app.route('/api/auth/oauth', oauthRouteModule.oauthRoute);
|
|
150
|
+
app.route('/api/db', tablesRouteModule.tablesRoute);
|
|
151
|
+
app.route('/api/db', databaseLiveRouteModule.databaseLiveRoute);
|
|
152
|
+
app.route('/api/schema', schemaRouteModule.schemaRoute);
|
|
153
|
+
app.route('/api/storage', storageRouteModule.storageRoute);
|
|
154
|
+
app.route('/api/functions', functionsRouteModule.functionsRoute);
|
|
155
|
+
app.route('/api/sql', sqlRouteModule.sqlRoute);
|
|
156
|
+
app.route('/api/kv', kvRouteModule.kvRoute);
|
|
157
|
+
app.route('/api/d1', d1RouteModule.d1Route);
|
|
158
|
+
app.route('/api/vectorize', vectorizeRouteModule.vectorizeRoute);
|
|
159
|
+
app.route('/api/config', configRouteModule.configRoute);
|
|
160
|
+
app.route('/api/push', pushRouteModule.pushRoute);
|
|
161
|
+
app.route('/api/room', roomRouteModule.roomRoute);
|
|
162
|
+
app.route('/api/analytics', analyticsRouteModule.analyticsApi);
|
|
163
|
+
app.route('/admin/api', adminRouteModule.adminRoute);
|
|
164
|
+
app.route('/admin/api/backup', backupRouteModule.backupRoute);
|
|
165
|
+
|
|
166
|
+
app.get('/', (c) => {
|
|
167
|
+
const env = c.env as Env;
|
|
168
|
+
const externalAdminUrl = resolveAdminRedirectTarget(c.req.url, env.ADMIN_ORIGIN);
|
|
169
|
+
if (externalAdminUrl) {
|
|
170
|
+
return c.redirect(externalAdminUrl, 302);
|
|
171
|
+
}
|
|
172
|
+
if (env.ASSETS) {
|
|
173
|
+
return c.redirect('/admin', 302);
|
|
174
|
+
}
|
|
175
|
+
return c.json({
|
|
176
|
+
name: 'EdgeBase API',
|
|
177
|
+
docs: '/openapi.json',
|
|
178
|
+
admin: null,
|
|
179
|
+
});
|
|
180
|
+
});
|
|
95
181
|
|
|
96
|
-
|
|
97
|
-
|
|
182
|
+
app.get('/favicon.ico', async (c) => {
|
|
183
|
+
const env = c.env as Env;
|
|
184
|
+
const externalFaviconUrl = resolveAdminFaviconTarget(env.ADMIN_ORIGIN);
|
|
185
|
+
if (externalFaviconUrl) {
|
|
186
|
+
return c.redirect(externalFaviconUrl, 302);
|
|
187
|
+
}
|
|
98
188
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
189
|
+
if (!env.ASSETS) {
|
|
190
|
+
return c.json({ code: 404, message: assetUnavailableMessage('admin dashboard') }, 404);
|
|
191
|
+
}
|
|
102
192
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
193
|
+
const url = new URL(c.req.url);
|
|
194
|
+
url.pathname = '/admin/favicon.svg';
|
|
195
|
+
return env.ASSETS.fetch(createAdminAssetRequest(new Request(url.toString(), c.req.raw)));
|
|
196
|
+
});
|
|
107
197
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
// Auth middleware — JWT verification + auth context injection (M3)
|
|
122
|
-
app.use('/api/*', authMiddleware);
|
|
123
|
-
|
|
124
|
-
// Context middleware removed — DB-level access rules (§4,) handle multi-tenancy.
|
|
125
|
-
|
|
126
|
-
// Rules middleware — access rules evaluation (M4,)
|
|
127
|
-
app.use('/api/db/*', rulesMiddleware);
|
|
128
|
-
|
|
129
|
-
// ─── Internal Guard ───
|
|
130
|
-
app.use('/internal/*', internalGuardMiddleware);
|
|
131
|
-
|
|
132
|
-
// ─── Routes ───
|
|
133
|
-
app.route('/api', healthRoute);
|
|
134
|
-
app.route('/api/auth', authRoute);
|
|
135
|
-
app.route('/api/auth/admin', adminAuthRoute);
|
|
136
|
-
app.route('/api/auth/oauth', oauthRoute);
|
|
137
|
-
app.route('/api/db', tablesRoute);
|
|
138
|
-
app.route('/api/db', databaseLiveRoute);
|
|
139
|
-
app.route('/api/schema', schemaRoute);
|
|
140
|
-
app.route('/api/storage', storageRoute);
|
|
141
|
-
app.route('/api/functions', functionsRoute);
|
|
142
|
-
app.route('/api/sql', sqlRoute);
|
|
143
|
-
app.route('/api/kv', kvRoute);
|
|
144
|
-
app.route('/api/d1', d1Route);
|
|
145
|
-
app.route('/api/vectorize', vectorizeRoute);
|
|
146
|
-
app.route('/api/config', configRoute);
|
|
147
|
-
app.route('/api/push', pushRoute);
|
|
148
|
-
app.route('/api/room', roomRoute);
|
|
149
|
-
app.route('/api/analytics', analyticsApi);
|
|
150
|
-
// ─── Admin Dashboard (M12,) ───
|
|
151
|
-
app.route('/admin/api', adminRoute);
|
|
152
|
-
app.route('/admin/api/backup', backupRoute);
|
|
153
|
-
|
|
154
|
-
app.get('/', (c) => {
|
|
155
|
-
const externalAdminUrl = resolveAdminRedirectTarget(c.req.url, c.env.ADMIN_ORIGIN);
|
|
156
|
-
if (externalAdminUrl) {
|
|
157
|
-
return c.redirect(externalAdminUrl, 302);
|
|
158
|
-
}
|
|
159
|
-
if (c.env.ASSETS) {
|
|
160
|
-
return c.redirect('/admin', 302);
|
|
161
|
-
}
|
|
162
|
-
return c.json({
|
|
163
|
-
name: 'EdgeBase API',
|
|
164
|
-
docs: '/openapi.json',
|
|
165
|
-
admin: null,
|
|
198
|
+
app.get('/favicon.svg', async (c) => {
|
|
199
|
+
const env = c.env as Env;
|
|
200
|
+
const externalFaviconUrl = resolveAdminFaviconTarget(env.ADMIN_ORIGIN);
|
|
201
|
+
if (externalFaviconUrl) {
|
|
202
|
+
return c.redirect(externalFaviconUrl, 302);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
if (env.ASSETS) {
|
|
206
|
+
return env.ASSETS.fetch(c.req.raw);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
return c.json({ code: 404, message: assetUnavailableMessage('admin dashboard') }, 404);
|
|
166
210
|
});
|
|
167
|
-
});
|
|
168
211
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
}
|
|
212
|
+
app.get('/_app/*', async (c) => {
|
|
213
|
+
const env = c.env as Env;
|
|
214
|
+
if (env.ASSETS) {
|
|
215
|
+
return env.ASSETS.fetch(c.req.raw);
|
|
216
|
+
}
|
|
175
217
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
}
|
|
218
|
+
return c.json({ code: 404, message: assetUnavailableMessage('admin dashboard') }, 404);
|
|
219
|
+
});
|
|
179
220
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
221
|
+
app.get('/admin/*', async (c) => {
|
|
222
|
+
const env = c.env as Env;
|
|
223
|
+
const externalAdminUrl = resolveAdminRedirectTarget(c.req.url, env.ADMIN_ORIGIN);
|
|
224
|
+
if (externalAdminUrl) {
|
|
225
|
+
return c.redirect(externalAdminUrl, 302);
|
|
226
|
+
}
|
|
227
|
+
if (env.ASSETS) {
|
|
228
|
+
return env.ASSETS.fetch(createAdminAssetRequest(c.req.raw));
|
|
229
|
+
}
|
|
230
|
+
return c.json({ code: 404, message: assetUnavailableMessage('admin dashboard') }, 404);
|
|
231
|
+
});
|
|
184
232
|
|
|
185
|
-
app.get('/
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
233
|
+
app.get('/admin', async (c) => {
|
|
234
|
+
const env = c.env as Env;
|
|
235
|
+
const externalAdminUrl = resolveAdminRedirectTarget(c.req.url, env.ADMIN_ORIGIN);
|
|
236
|
+
if (externalAdminUrl) {
|
|
237
|
+
return c.redirect(externalAdminUrl, 302);
|
|
238
|
+
}
|
|
239
|
+
if (env.ASSETS) {
|
|
240
|
+
return env.ASSETS.fetch(createAdminAssetRequest(c.req.raw));
|
|
241
|
+
}
|
|
242
|
+
return c.json({ code: 404, message: assetUnavailableMessage('admin dashboard') }, 404);
|
|
243
|
+
});
|
|
190
244
|
|
|
191
|
-
|
|
192
|
-
return c.
|
|
193
|
-
}
|
|
245
|
+
app.get('/harness', (c) => {
|
|
246
|
+
return c.redirect('/harness/', 302);
|
|
247
|
+
});
|
|
194
248
|
|
|
195
|
-
|
|
196
|
-
|
|
249
|
+
app.get('/harness/', async (c) => {
|
|
250
|
+
const env = c.env as Env;
|
|
251
|
+
if (env.ASSETS) {
|
|
252
|
+
return env.ASSETS.fetch(c.req.raw);
|
|
253
|
+
}
|
|
254
|
+
return c.json({ code: 404, message: assetUnavailableMessage('harness assets') }, 404);
|
|
255
|
+
});
|
|
197
256
|
|
|
198
|
-
app.get('/
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
257
|
+
app.get('/harness/assets/*', async (c) => {
|
|
258
|
+
const env = c.env as Env;
|
|
259
|
+
if (env.ASSETS) {
|
|
260
|
+
return env.ASSETS.fetch(c.req.raw);
|
|
261
|
+
}
|
|
262
|
+
return c.json({ code: 404, message: assetUnavailableMessage('harness assets') }, 404);
|
|
263
|
+
});
|
|
202
264
|
|
|
203
|
-
|
|
204
|
-
|
|
265
|
+
app.get('/harness/*', (c) => {
|
|
266
|
+
return c.redirect('/harness/', 302);
|
|
267
|
+
});
|
|
205
268
|
|
|
206
|
-
app.get('/
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
return c.
|
|
213
|
-
}
|
|
214
|
-
return c.json({ code: 404, message: 'Admin dashboard not deployed.' }, 404);
|
|
215
|
-
});
|
|
216
|
-
app.get('/admin', async (c) => {
|
|
217
|
-
const externalAdminUrl = resolveAdminRedirectTarget(c.req.url, c.env.ADMIN_ORIGIN);
|
|
218
|
-
if (externalAdminUrl) {
|
|
219
|
-
return c.redirect(externalAdminUrl, 302);
|
|
220
|
-
}
|
|
221
|
-
if (c.env.ASSETS) {
|
|
222
|
-
return c.env.ASSETS.fetch(createAdminAssetRequest(c.req.raw));
|
|
223
|
-
}
|
|
224
|
-
return c.json({ code: 404, message: 'Admin dashboard not deployed.' }, 404);
|
|
225
|
-
});
|
|
226
|
-
|
|
227
|
-
app.get('/harness', (c) => {
|
|
228
|
-
return c.redirect('/harness/', 302);
|
|
229
|
-
});
|
|
230
|
-
app.get('/harness/', async (c) => {
|
|
231
|
-
if (c.env.ASSETS) {
|
|
232
|
-
return c.env.ASSETS.fetch(c.req.raw);
|
|
233
|
-
}
|
|
234
|
-
return c.json({ code: 404, message: 'Harness assets not deployed.' }, 404);
|
|
235
|
-
});
|
|
236
|
-
app.get('/harness/assets/*', async (c) => {
|
|
237
|
-
if (c.env.ASSETS) {
|
|
238
|
-
return c.env.ASSETS.fetch(c.req.raw);
|
|
239
|
-
}
|
|
240
|
-
return c.json({ code: 404, message: 'Harness assets not deployed.' }, 404);
|
|
241
|
-
});
|
|
242
|
-
app.get('/harness/*', (c) => {
|
|
243
|
-
return c.redirect('/harness/', 302);
|
|
244
|
-
});
|
|
245
|
-
|
|
246
|
-
// ─── OpenAPI Spec ───
|
|
247
|
-
app.get('/openapi.json', (c) => {
|
|
248
|
-
const spec = app.getOpenAPI31Document({
|
|
249
|
-
openapi: '3.1.0',
|
|
250
|
-
info: { title: 'EdgeBase API', version: SERVER_VERSION },
|
|
269
|
+
app.get('/openapi.json', (c) => {
|
|
270
|
+
const spec = app.getOpenAPI31Document({
|
|
271
|
+
openapi: '3.1.0',
|
|
272
|
+
info: { title: 'EdgeBase API', version: SERVER_VERSION },
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
return c.json(normalizeOpenApiDocument(spec as OpenApiSpec, new URL(c.req.url).origin));
|
|
251
276
|
});
|
|
252
277
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
)
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
278
|
+
app.notFound((c) => {
|
|
279
|
+
return c.json({
|
|
280
|
+
code: 404,
|
|
281
|
+
message: `Path '${new URL(c.req.url).pathname}' was not found on this EdgeBase server.`,
|
|
282
|
+
}, 404);
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
app.onError((err, c) => {
|
|
286
|
+
if (err instanceof SyntaxError) {
|
|
287
|
+
return c.json(
|
|
288
|
+
{
|
|
289
|
+
code: 400,
|
|
290
|
+
message: 'Invalid JSON payload. Please ensure your request body is valid JSON.',
|
|
291
|
+
},
|
|
292
|
+
400,
|
|
293
|
+
);
|
|
294
|
+
}
|
|
295
|
+
if (err instanceof EdgeBaseError) {
|
|
296
|
+
return c.json(err.toJSON(), err.code as 400);
|
|
297
|
+
}
|
|
298
|
+
if (err instanceof HTTPException) {
|
|
299
|
+
return c.json({ code: err.status, message: err.message }, err.status as 400);
|
|
300
|
+
}
|
|
301
|
+
const e = err as unknown as Record<string, unknown>;
|
|
302
|
+
if (
|
|
303
|
+
typeof e.code === 'number' &&
|
|
304
|
+
e.code >= 400 &&
|
|
305
|
+
e.code < 600 &&
|
|
306
|
+
typeof e.message === 'string'
|
|
307
|
+
) {
|
|
308
|
+
const body: { code: number; message: string; data?: unknown } = {
|
|
309
|
+
code: e.code as number,
|
|
310
|
+
message: e.message as string,
|
|
311
|
+
};
|
|
312
|
+
if (e.data) body.data = e.data;
|
|
313
|
+
return c.json(body, e.code as number as 400);
|
|
314
|
+
}
|
|
315
|
+
console.error('Unhandled error:', err);
|
|
316
|
+
return c.json({
|
|
317
|
+
code: 500,
|
|
318
|
+
message: `Internal server error while handling '${new URL(c.req.url).pathname}'. Check the worker logs for the original exception.`,
|
|
319
|
+
}, 500);
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
return app;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
async function getApp() {
|
|
326
|
+
if (!appPromise) {
|
|
327
|
+
appPromise = buildApp();
|
|
293
328
|
}
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
});
|
|
329
|
+
return appPromise;
|
|
330
|
+
}
|
|
297
331
|
|
|
298
332
|
export default {
|
|
299
|
-
fetch:
|
|
333
|
+
async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
|
|
334
|
+
const app = await getApp();
|
|
335
|
+
return app.fetch(request, env, ctx);
|
|
336
|
+
},
|
|
300
337
|
|
|
301
|
-
/**
|
|
302
|
-
* Cloudflare Cron Triggers — replaces db:_system alarm-based scheduling.
|
|
303
|
-
* CLI generates [triggers] section in wrangler.toml from config schedule functions.
|
|
304
|
-
*/
|
|
305
338
|
async scheduled(event: ScheduledEvent, env: Env, ctx: ExecutionContext): Promise<void> {
|
|
306
|
-
|
|
339
|
+
await ensureServerStartup();
|
|
340
|
+
|
|
341
|
+
const [
|
|
342
|
+
pluginMigrationsModule,
|
|
343
|
+
functionsModule,
|
|
344
|
+
cronModule,
|
|
345
|
+
jwtModule,
|
|
346
|
+
authServiceModule,
|
|
347
|
+
authD1Module,
|
|
348
|
+
authDbAdapterModule,
|
|
349
|
+
serviceKeyModule,
|
|
350
|
+
doRouterModule,
|
|
351
|
+
] = await Promise.all([
|
|
352
|
+
import('./lib/plugin-migrations.js'),
|
|
353
|
+
import('./lib/functions.js'),
|
|
354
|
+
import('./lib/cron.js'),
|
|
355
|
+
import('./lib/jwt.js'),
|
|
356
|
+
import('./lib/auth-d1-service.js'),
|
|
357
|
+
import('./lib/auth-d1.js'),
|
|
358
|
+
import('./lib/auth-db-adapter.js'),
|
|
359
|
+
import('./lib/service-key.js'),
|
|
360
|
+
import('./lib/do-router.js'),
|
|
361
|
+
]);
|
|
362
|
+
|
|
363
|
+
const { executePluginMigrations } = pluginMigrationsModule;
|
|
364
|
+
const { getFunctionsByTrigger, buildFunctionContext, getWorkerUrl } = functionsModule;
|
|
365
|
+
const { parseCron, matchesCron } = cronModule;
|
|
366
|
+
const { parseDuration } = jwtModule;
|
|
367
|
+
const { ensureAuthSchema, deleteAnon } = authD1Module;
|
|
368
|
+
const { resolveAuthDb } = authDbAdapterModule;
|
|
369
|
+
const { resolveRootServiceKey } = serviceKeyModule;
|
|
370
|
+
|
|
371
|
+
const config = doRouterModule.parseConfig(env);
|
|
307
372
|
if (config.plugins?.length) {
|
|
308
373
|
await executePluginMigrations(
|
|
309
374
|
config.plugins,
|
|
@@ -315,23 +380,18 @@ export default {
|
|
|
315
380
|
const scheduleFns = getFunctionsByTrigger('schedule');
|
|
316
381
|
|
|
317
382
|
const now = new Date(event.scheduledTime);
|
|
318
|
-
|
|
319
|
-
// Schedule function timeout (default: 10s)
|
|
320
383
|
const timeoutStr = config.functions?.scheduleFunctionTimeout ?? '10s';
|
|
321
384
|
const timeoutMs = parseDuration(timeoutStr) * 1000;
|
|
322
385
|
|
|
323
|
-
// ── System cron: session cleanup + anonymous account cleanup ──
|
|
324
386
|
ctx.waitUntil(
|
|
325
387
|
(async () => {
|
|
326
388
|
try {
|
|
327
389
|
const authDb = resolveAuthDb(env as unknown as Record<string, unknown>);
|
|
328
390
|
await ensureAuthSchema(authDb);
|
|
329
|
-
|
|
330
|
-
await authService.cleanExpiredSessions(authDb);
|
|
331
|
-
// Clean stale anonymous accounts
|
|
391
|
+
await authServiceModule.cleanExpiredSessions(authDb);
|
|
332
392
|
if (config?.auth?.anonymousAuth) {
|
|
333
393
|
const retentionDays = config.auth.anonymousRetentionDays ?? 30;
|
|
334
|
-
const deletedIds = await
|
|
394
|
+
const deletedIds = await authServiceModule.cleanStaleAnonymousAccounts(authDb, retentionDays);
|
|
335
395
|
for (const id of deletedIds) {
|
|
336
396
|
await deleteAnon(authDb, id).catch(() => {});
|
|
337
397
|
}
|
|
@@ -351,7 +411,7 @@ export default {
|
|
|
351
411
|
if (!matchesCron(now, schedule)) continue;
|
|
352
412
|
|
|
353
413
|
const fnCtx = buildFunctionContext({
|
|
354
|
-
request: new Request(
|
|
414
|
+
request: new Request(`http://internal/schedule/${name}`),
|
|
355
415
|
auth: null,
|
|
356
416
|
databaseNamespace: env.DATABASE,
|
|
357
417
|
authNamespace: env.AUTH,
|