@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
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
2
|
+
|
|
3
|
+
vi.mock('cloudflare:workers', () => ({
|
|
4
|
+
DurableObject: class DurableObject {},
|
|
5
|
+
}));
|
|
6
|
+
|
|
7
|
+
afterEach(() => {
|
|
8
|
+
vi.resetModules();
|
|
9
|
+
if (typeof globalThis === 'object' && globalThis !== null) {
|
|
10
|
+
delete (globalThis as Record<string, unknown>).__EDGEBASE_RUNTIME_CONFIG__;
|
|
11
|
+
}
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
describe('runtime startup bootstrap', () => {
|
|
15
|
+
it('initializes runtime config idempotently for lazy server and DO entrypoints', async () => {
|
|
16
|
+
const { ensureServerStartup } = await import('../lib/runtime-startup.js');
|
|
17
|
+
const { parseConfig } = await import('../lib/do-router.js');
|
|
18
|
+
|
|
19
|
+
await expect(ensureServerStartup()).resolves.toBeUndefined();
|
|
20
|
+
const firstConfig = parseConfig();
|
|
21
|
+
|
|
22
|
+
await expect(ensureServerStartup()).resolves.toBeUndefined();
|
|
23
|
+
const secondConfig = parseConfig();
|
|
24
|
+
|
|
25
|
+
expect(firstConfig).toEqual(secondConfig);
|
|
26
|
+
expect(secondConfig).toBeTypeOf('object');
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('does not clobber an explicitly injected runtime config', async () => {
|
|
30
|
+
const { ensureServerStartup } = await import('../lib/runtime-startup.js');
|
|
31
|
+
const { parseConfig, setConfig } = await import('../lib/do-router.js');
|
|
32
|
+
|
|
33
|
+
setConfig({
|
|
34
|
+
release: false,
|
|
35
|
+
auth: {
|
|
36
|
+
allowedRedirectUrls: ['http://localhost:4173'],
|
|
37
|
+
},
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
await expect(ensureServerStartup()).resolves.toBeUndefined();
|
|
41
|
+
|
|
42
|
+
expect(parseConfig()).toMatchObject({
|
|
43
|
+
release: false,
|
|
44
|
+
auth: {
|
|
45
|
+
allowedRedirectUrls: ['http://localhost:4173'],
|
|
46
|
+
},
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
});
|
|
@@ -825,10 +825,10 @@ describe('zodDefaultHook', () => {
|
|
|
825
825
|
const c = mockContext();
|
|
826
826
|
const result = zodDefaultHook({
|
|
827
827
|
success: false,
|
|
828
|
-
error: { issues: [{ message: 'field required' }, { message: 'invalid type' }] },
|
|
828
|
+
error: { issues: [{ message: 'field required', path: ['body', 'email'] }, { message: 'invalid type' }] },
|
|
829
829
|
}, c);
|
|
830
830
|
expect(result).toBeDefined();
|
|
831
|
-
expect(c.lastJson).toEqual({ code: 400, message: 'field required, invalid type' });
|
|
831
|
+
expect(c.lastJson).toEqual({ code: 400, message: 'body.email: field required, invalid type' });
|
|
832
832
|
expect(c.lastStatus).toBe(400);
|
|
833
833
|
});
|
|
834
834
|
|
|
@@ -841,13 +841,13 @@ describe('zodDefaultHook', () => {
|
|
|
841
841
|
expect(c.lastJson).toEqual({ code: 400, message: 'too short' });
|
|
842
842
|
});
|
|
843
843
|
|
|
844
|
-
it('handles empty issues →
|
|
844
|
+
it('handles empty issues → default message', () => {
|
|
845
845
|
const c = mockContext();
|
|
846
846
|
zodDefaultHook({
|
|
847
847
|
success: false,
|
|
848
848
|
error: { issues: [] },
|
|
849
849
|
}, c);
|
|
850
|
-
expect(c.lastJson).toEqual({ code: 400, message: '' });
|
|
850
|
+
expect(c.lastJson).toEqual({ code: 400, message: 'Request validation failed.' });
|
|
851
851
|
});
|
|
852
852
|
|
|
853
853
|
it('handles missing error.issues and error.errors', () => {
|
|
@@ -856,7 +856,7 @@ describe('zodDefaultHook', () => {
|
|
|
856
856
|
success: false,
|
|
857
857
|
error: {},
|
|
858
858
|
}, c);
|
|
859
|
-
expect(c.lastJson).toEqual({ code: 400, message: '' });
|
|
859
|
+
expect(c.lastJson).toEqual({ code: 400, message: 'Request validation failed.' });
|
|
860
860
|
});
|
|
861
861
|
|
|
862
862
|
it('handles undefined error', () => {
|
|
@@ -864,7 +864,16 @@ describe('zodDefaultHook', () => {
|
|
|
864
864
|
zodDefaultHook({
|
|
865
865
|
success: false,
|
|
866
866
|
}, c);
|
|
867
|
-
expect(c.lastJson).toEqual({ code: 400, message: '' });
|
|
867
|
+
expect(c.lastJson).toEqual({ code: 400, message: 'Request validation failed.' });
|
|
868
|
+
});
|
|
869
|
+
|
|
870
|
+
it('formats array indexes in issue paths', () => {
|
|
871
|
+
const c = mockContext();
|
|
872
|
+
zodDefaultHook({
|
|
873
|
+
success: false,
|
|
874
|
+
error: { issues: [{ message: 'Expected string', path: ['body', 'members', 0, 'email'] }] },
|
|
875
|
+
}, c);
|
|
876
|
+
expect(c.lastJson).toEqual({ code: 400, message: 'body.members[0].email: Expected string' });
|
|
868
877
|
});
|
|
869
878
|
});
|
|
870
879
|
|
|
@@ -60,6 +60,7 @@ import { buildDbLiveChannel, DATABASE_LIVE_HUB_DO_NAME } from '../lib/database-l
|
|
|
60
60
|
import { resolveRootServiceKey } from '../lib/service-key.js';
|
|
61
61
|
import { resolveDbLiveBatchThreshold } from '../lib/database-live-config.js';
|
|
62
62
|
import { buildTableHookRuntimeServices } from '../lib/table-hook-runtime.js';
|
|
63
|
+
import { ensureServerStartup } from '../lib/runtime-startup.js';
|
|
63
64
|
import type { Env } from '../types.js';
|
|
64
65
|
|
|
65
66
|
// ─── Types ───
|
|
@@ -80,6 +81,7 @@ export class DatabaseDO extends DurableObject<DOEnv> {
|
|
|
80
81
|
private config: EdgeBaseConfig;
|
|
81
82
|
private initialized = false;
|
|
82
83
|
private doName = '';
|
|
84
|
+
private runtimeReadyPromise: Promise<void> | null = null;
|
|
83
85
|
|
|
84
86
|
constructor(ctx: DurableObjectState, env: DOEnv) {
|
|
85
87
|
super(ctx, env);
|
|
@@ -92,6 +94,7 @@ export class DatabaseDO extends DurableObject<DOEnv> {
|
|
|
92
94
|
}
|
|
93
95
|
|
|
94
96
|
async fetch(request: Request): Promise<Response> {
|
|
97
|
+
await this.ensureRuntimeReady();
|
|
95
98
|
// Determine DO name from header or URL
|
|
96
99
|
const doNameHeader = request.headers.get('X-DO-Name');
|
|
97
100
|
|
|
@@ -1933,7 +1936,13 @@ export class DatabaseDO extends DurableObject<DOEnv> {
|
|
|
1933
1936
|
return c.json(normalizedDbError.toJSON(), normalizedDbError.code as 400);
|
|
1934
1937
|
}
|
|
1935
1938
|
console.error('DatabaseDO Error:', err);
|
|
1936
|
-
return c.json(
|
|
1939
|
+
return c.json(
|
|
1940
|
+
{
|
|
1941
|
+
code: 500,
|
|
1942
|
+
message: `Database request failed while handling '${c.req.path}'. Check the worker logs for the original exception.`,
|
|
1943
|
+
},
|
|
1944
|
+
500,
|
|
1945
|
+
);
|
|
1937
1946
|
});
|
|
1938
1947
|
|
|
1939
1948
|
return app;
|
|
@@ -1991,6 +2000,17 @@ export class DatabaseDO extends DurableObject<DOEnv> {
|
|
|
1991
2000
|
return getGlobalConfig(env);
|
|
1992
2001
|
}
|
|
1993
2002
|
|
|
2003
|
+
private async ensureRuntimeReady(): Promise<void> {
|
|
2004
|
+
if (!this.runtimeReadyPromise) {
|
|
2005
|
+
this.runtimeReadyPromise = (async () => {
|
|
2006
|
+
await ensureServerStartup();
|
|
2007
|
+
this.config = this.parseConfig(this.env);
|
|
2008
|
+
})();
|
|
2009
|
+
}
|
|
2010
|
+
|
|
2011
|
+
await this.runtimeReadyPromise;
|
|
2012
|
+
}
|
|
2013
|
+
|
|
1994
2014
|
// ─── Database Live Event Emission ───
|
|
1995
2015
|
|
|
1996
2016
|
/**
|
|
@@ -7,6 +7,7 @@ import { verifyAccessToken } from '../lib/jwt.js';
|
|
|
7
7
|
import { parseConfig as getGlobalConfig } from '../lib/do-router.js';
|
|
8
8
|
import { isDbLiveChannel } from '../lib/database-live-emitter.js';
|
|
9
9
|
import { resolveDbLiveAuthTimeoutMs } from '../lib/database-live-config.js';
|
|
10
|
+
import { ensureServerStartup } from '../lib/runtime-startup.js';
|
|
10
11
|
|
|
11
12
|
interface DOEnv {
|
|
12
13
|
JWT_USER_SECRET?: string;
|
|
@@ -142,6 +143,7 @@ export class DatabaseLiveDO extends DurableObject<DOEnv> {
|
|
|
142
143
|
private pendingAuth = new Map<string, ReturnType<typeof setTimeout>>();
|
|
143
144
|
private metaCache = new Map<WebSocket, WSMeta>();
|
|
144
145
|
private recentDeliveryIds = new Map<string, number>();
|
|
146
|
+
private runtimeReadyPromise: Promise<void> | null = null;
|
|
145
147
|
|
|
146
148
|
constructor(ctx: DurableObjectState, env: DOEnv) {
|
|
147
149
|
super(ctx, env);
|
|
@@ -149,6 +151,7 @@ export class DatabaseLiveDO extends DurableObject<DOEnv> {
|
|
|
149
151
|
}
|
|
150
152
|
|
|
151
153
|
async fetch(request: Request): Promise<Response> {
|
|
154
|
+
await this.ensureRuntimeReady();
|
|
152
155
|
const url = new URL(request.url);
|
|
153
156
|
|
|
154
157
|
if (url.pathname === '/internal/event') {
|
|
@@ -218,6 +221,7 @@ export class DatabaseLiveDO extends DurableObject<DOEnv> {
|
|
|
218
221
|
}
|
|
219
222
|
|
|
220
223
|
async webSocketMessage(ws: WebSocket, message: string | ArrayBuffer): Promise<void> {
|
|
224
|
+
await this.ensureRuntimeReady();
|
|
221
225
|
if (typeof message !== 'string') return;
|
|
222
226
|
|
|
223
227
|
let msg: Record<string, unknown>;
|
|
@@ -922,6 +926,17 @@ export class DatabaseLiveDO extends DurableObject<DOEnv> {
|
|
|
922
926
|
if (parts.length >= 5) return parts[3];
|
|
923
927
|
return null;
|
|
924
928
|
}
|
|
929
|
+
|
|
930
|
+
private async ensureRuntimeReady(): Promise<void> {
|
|
931
|
+
if (!this.runtimeReadyPromise) {
|
|
932
|
+
this.runtimeReadyPromise = (async () => {
|
|
933
|
+
await ensureServerStartup();
|
|
934
|
+
this.config = getGlobalConfig(this.env);
|
|
935
|
+
})();
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
await this.runtimeReadyPromise;
|
|
939
|
+
}
|
|
925
940
|
}
|
|
926
941
|
|
|
927
942
|
export function evaluateDatabaseLiveFilters(
|