@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.
Files changed (131) hide show
  1. package/admin-build/_app/immutable/chunks/{DILS_-VJ.js → B3CvhH3c.js} +1 -1
  2. package/admin-build/_app/immutable/chunks/BN_-k-Ck.js +1 -0
  3. package/admin-build/_app/immutable/chunks/{Dt4vL4Df.js → BYL_uBga.js} +1 -1
  4. package/admin-build/_app/immutable/chunks/{C72lTcG0.js → Bcs4KYNp.js} +1 -1
  5. package/admin-build/_app/immutable/chunks/{B8s_s9QY.js → BkZCgsc3.js} +1 -1
  6. package/admin-build/_app/immutable/chunks/{BgDzp0i0.js → BvoGcDFV.js} +1 -1
  7. package/admin-build/_app/immutable/chunks/{BME_U9TJ.js → CCUxCptE.js} +1 -1
  8. package/admin-build/_app/immutable/chunks/CLHN9MVr.js +1 -0
  9. package/admin-build/_app/immutable/chunks/{DYaCRWMA.js → CR37B8DX.js} +1 -1
  10. package/admin-build/_app/immutable/chunks/CbfX3ELZ.js +1 -0
  11. package/admin-build/_app/immutable/chunks/CjcrXziO.js +2 -0
  12. package/admin-build/_app/immutable/chunks/CrwlCAM0.js +1 -0
  13. package/admin-build/_app/immutable/chunks/{B0HRJ657.js → DOOPbWwG.js} +1 -1
  14. package/admin-build/_app/immutable/chunks/DQVP4KC-.js +1 -0
  15. package/admin-build/_app/immutable/chunks/{Dj0QUuOf.js → DdvsFblq.js} +1 -1
  16. package/admin-build/_app/immutable/chunks/DemDWbs-.js +128 -0
  17. package/admin-build/_app/immutable/chunks/{XQM1k9PM.js → DmDTovpg.js} +1 -1
  18. package/admin-build/_app/immutable/chunks/{fYEKMQ-Z.js → Ff90owjx.js} +1 -1
  19. package/admin-build/_app/immutable/chunks/{5RQRbp5q.js → LL3ulaxa.js} +1 -1
  20. package/admin-build/_app/immutable/chunks/{DBsVqhuh.js → Q3vAxeY-.js} +1 -1
  21. package/admin-build/_app/immutable/chunks/{D__dwMuW.js → SQVAC3Cv.js} +1 -1
  22. package/admin-build/_app/immutable/chunks/{Z41NK6i6.js → bguI1TeA.js} +1 -1
  23. package/admin-build/_app/immutable/chunks/{_teD5ji5.js → nlAMTi52.js} +1 -1
  24. package/admin-build/_app/immutable/chunks/{BjWZuf8W.js → qBm6xof8.js} +1 -1
  25. package/admin-build/_app/immutable/entry/{app.C8ylfBe6.js → app.CP83Ni80.js} +2 -2
  26. package/admin-build/_app/immutable/entry/start.DY6YakU0.js +1 -0
  27. package/admin-build/_app/immutable/nodes/{0.CJJ6HZbp.js → 0.DiRq7puO.js} +1 -1
  28. package/admin-build/_app/immutable/nodes/1.BFeyKLGT.js +1 -0
  29. package/admin-build/_app/immutable/nodes/10.zcee7hJx.js +1 -0
  30. package/admin-build/_app/immutable/nodes/11.BW7wLs2Y.js +1 -0
  31. package/admin-build/_app/immutable/nodes/12.CxJRlYSd.js +1 -0
  32. package/admin-build/_app/immutable/nodes/13.pp0F_5hn.js +110 -0
  33. package/admin-build/_app/immutable/nodes/14.t3AfGiGo.js +3 -0
  34. package/admin-build/_app/immutable/nodes/15.B3agc7NX.js +1 -0
  35. package/admin-build/_app/immutable/nodes/{16.D0xkPUBW.js → 16.C4uG2-i8.js} +1 -1
  36. package/admin-build/_app/immutable/nodes/{17.CebNqPeh.js → 17.CwGxi1Bn.js} +1 -1
  37. package/admin-build/_app/immutable/nodes/18.CrQyN_gU.js +1 -0
  38. package/admin-build/_app/immutable/nodes/19.NEPUOXl7.js +2 -0
  39. package/admin-build/_app/immutable/nodes/{20.DYb-q3W8.js → 20.DGHO8ipr.js} +1 -1
  40. package/admin-build/_app/immutable/nodes/21.UVKBDvp4.js +1 -0
  41. package/admin-build/_app/immutable/nodes/22.Dri5It7a.js +1 -0
  42. package/admin-build/_app/immutable/nodes/{23.BLgq21om.js → 23.BPQP_Zte.js} +2 -2
  43. package/admin-build/_app/immutable/nodes/24.D580FdSS.js +2 -0
  44. package/admin-build/_app/immutable/nodes/25.BMNPOZwF.js +2 -0
  45. package/admin-build/_app/immutable/nodes/26.XcpEcbiz.js +1 -0
  46. package/admin-build/_app/immutable/nodes/27.C1zHHcYv.js +1 -0
  47. package/admin-build/_app/immutable/nodes/28.CuKzzrY8.js +1 -0
  48. package/admin-build/_app/immutable/nodes/29.nLpBMXnM.js +1 -0
  49. package/admin-build/_app/immutable/nodes/{3.z8ut3jS-.js → 3.5G_aseoL.js} +1 -1
  50. package/admin-build/_app/immutable/nodes/30.CQC4nLoU.js +1 -0
  51. package/admin-build/_app/immutable/nodes/31.Bet8kxOK.js +1 -0
  52. package/admin-build/_app/immutable/nodes/4.nmJDYJpC.js +1 -0
  53. package/admin-build/_app/immutable/nodes/5.CnbYLG4E.js +1 -0
  54. package/admin-build/_app/immutable/nodes/6.KA01b-3y.js +1 -0
  55. package/admin-build/_app/immutable/nodes/7.CP9fkn1L.js +1 -0
  56. package/admin-build/_app/immutable/nodes/8.BTzDb---.js +1 -0
  57. package/admin-build/_app/immutable/nodes/9.DkNJg_J6.js +1 -0
  58. package/admin-build/_app/version.json +1 -1
  59. package/admin-build/index.html +7 -7
  60. package/package.json +3 -3
  61. package/src/__tests__/database-do-route-validation.test.ts +10 -7
  62. package/src/__tests__/meta-route-registration.test.ts +20 -15
  63. package/src/__tests__/push-handlers.test.ts +1 -1
  64. package/src/__tests__/room-auth-state-loss.test.ts +122 -0
  65. package/src/__tests__/room-handler-context.test.ts +4 -4
  66. package/src/__tests__/room-rate-limit-scopes.test.ts +38 -0
  67. package/src/__tests__/room-runtime-routing.test.ts +23 -0
  68. package/src/__tests__/route-parser.test.ts +6 -0
  69. package/src/__tests__/runtime-startup.test.ts +49 -0
  70. package/src/__tests__/schema.test.ts +15 -6
  71. package/src/durable-objects/database-do.ts +21 -1
  72. package/src/durable-objects/database-live-do.ts +15 -0
  73. package/src/durable-objects/room-runtime-base.ts +436 -169
  74. package/src/durable-objects/rooms-do.ts +63 -25
  75. package/src/index.ts +340 -280
  76. package/src/lib/d1-handler.ts +32 -17
  77. package/src/lib/postgres-handler.ts +24 -12
  78. package/src/lib/route-parser.ts +3 -0
  79. package/src/lib/runtime-startup.ts +53 -0
  80. package/src/lib/schemas.ts +12 -2
  81. package/src/middleware/captcha-verify.ts +16 -3
  82. package/src/middleware/error-handler.ts +1 -1
  83. package/src/middleware/rules.ts +28 -9
  84. package/src/routes/admin-auth.ts +3 -3
  85. package/src/routes/admin.ts +13 -8
  86. package/src/routes/analytics-api.ts +3 -3
  87. package/src/routes/auth.ts +1 -1
  88. package/src/routes/backup.ts +1 -1
  89. package/src/routes/d1.ts +14 -7
  90. package/src/routes/database-live.ts +13 -6
  91. package/src/routes/kv.ts +21 -10
  92. package/src/routes/oauth.ts +1 -1
  93. package/src/routes/push.ts +119 -77
  94. package/src/routes/room.ts +215 -7
  95. package/src/routes/schema-endpoint.ts +2 -2
  96. package/src/routes/sql.ts +10 -6
  97. package/src/routes/storage.ts +4 -2
  98. package/src/routes/vectorize.ts +16 -4
  99. package/admin-build/_app/immutable/chunks/BYI6CUvd.js +0 -1
  100. package/admin-build/_app/immutable/chunks/C6lpZLE2.js +0 -1
  101. package/admin-build/_app/immutable/chunks/CoI6jjbg.js +0 -2
  102. package/admin-build/_app/immutable/chunks/D5GswVnI.js +0 -128
  103. package/admin-build/_app/immutable/chunks/Dj-E9-FO.js +0 -1
  104. package/admin-build/_app/immutable/chunks/g_-Kpxu3.js +0 -1
  105. package/admin-build/_app/immutable/chunks/wCNueVYy.js +0 -1
  106. package/admin-build/_app/immutable/entry/start.CtsqDyfj.js +0 -1
  107. package/admin-build/_app/immutable/nodes/1.B4sI5cB4.js +0 -1
  108. package/admin-build/_app/immutable/nodes/10.D6hvCer6.js +0 -1
  109. package/admin-build/_app/immutable/nodes/11.Dx7b8aQ5.js +0 -1
  110. package/admin-build/_app/immutable/nodes/12.Bqmy5KIF.js +0 -1
  111. package/admin-build/_app/immutable/nodes/13.CC6KpXgS.js +0 -110
  112. package/admin-build/_app/immutable/nodes/14.yCo1Ix8E.js +0 -3
  113. package/admin-build/_app/immutable/nodes/15.co0UfPlh.js +0 -1
  114. package/admin-build/_app/immutable/nodes/18.JUoLOZxh.js +0 -1
  115. package/admin-build/_app/immutable/nodes/19.ND8kmQJe.js +0 -2
  116. package/admin-build/_app/immutable/nodes/21.cz3IN9Cc.js +0 -1
  117. package/admin-build/_app/immutable/nodes/22.UOzm8WYV.js +0 -1
  118. package/admin-build/_app/immutable/nodes/24.DN9usmUs.js +0 -2
  119. package/admin-build/_app/immutable/nodes/25.BddRfAyE.js +0 -2
  120. package/admin-build/_app/immutable/nodes/26.Dl6XHIeT.js +0 -1
  121. package/admin-build/_app/immutable/nodes/27.D0iNwALG.js +0 -1
  122. package/admin-build/_app/immutable/nodes/28.9dKQmdGi.js +0 -1
  123. package/admin-build/_app/immutable/nodes/29.wXzfJUXp.js +0 -1
  124. package/admin-build/_app/immutable/nodes/30.BtZETNsL.js +0 -1
  125. package/admin-build/_app/immutable/nodes/31.CYonj2Jh.js +0 -1
  126. package/admin-build/_app/immutable/nodes/4.COtDPQ9b.js +0 -1
  127. package/admin-build/_app/immutable/nodes/5.CTRCeIhp.js +0 -1
  128. package/admin-build/_app/immutable/nodes/6.ChHi3QkR.js +0 -1
  129. package/admin-build/_app/immutable/nodes/7.CCMtr6Ac.js +0 -1
  130. package/admin-build/_app/immutable/nodes/8.DpWJ-X_-.js +0 -1
  131. package/admin-build/_app/immutable/nodes/9.DOkvfmir.js +0 -1
@@ -86,7 +86,7 @@ backupRoute.onError((err, c) => {
86
86
  return c.json(err.toJSON(), err.code as 400);
87
87
  }
88
88
  console.error('Backup API error:', err);
89
- return c.json({ code: 500, message: 'Internal server error.' }, 500);
89
+ return c.json({ code: 500, message: 'Backup operation failed unexpectedly. Check the worker logs for the original exception.' }, 500);
90
90
  });
91
91
 
92
92
  // ─── DO Name Helpers ───
package/src/routes/d1.ts CHANGED
@@ -22,6 +22,10 @@ import { zodDefaultHook, d1BodySchema, jsonResponseSchema, errorResponseSchema }
22
22
 
23
23
  export const d1Route = new OpenAPIHono<HonoEnv>({ defaultHook: zodDefaultHook });
24
24
 
25
+ function invalidD1JsonMessage(): string {
26
+ return 'Invalid JSON body. Send application/json with { query, params? }.';
27
+ }
28
+
25
29
  /**
26
30
  * POST /api/d1/:database
27
31
  * Body: { query: string, params?: unknown[] }
@@ -51,12 +55,12 @@ d1Route.openapi(executeD1Query, async (c) => {
51
55
  try {
52
56
  body = await c.req.json();
53
57
  } catch {
54
- return c.json({ code: 400, message: 'Invalid JSON body' }, 400);
58
+ return c.json({ code: 400, message: invalidD1JsonMessage() }, 400);
55
59
  }
56
60
 
57
61
  const { query, params } = body;
58
62
  if (!query || typeof query !== 'string') {
59
- return c.json({ code: 400, message: 'query is required' }, 400);
63
+ return c.json({ code: 400, message: "Missing required field 'query'. Send the SQL string in the request body." }, 400);
60
64
  }
61
65
 
62
66
  // §2 Allowlist: validate database is declared in config
@@ -76,16 +80,19 @@ d1Route.openapi(executeD1Query, async (c) => {
76
80
  buildConstraintCtx(c.env, c.req),
77
81
  );
78
82
  if (skResult === 'missing') {
79
- return c.json({ code: 403, message: 'Service Key required to access D1' }, 403);
83
+ return c.json({ code: 403, message: `X-EdgeBase-Service-Key is required to execute raw SQL on D1 database '${nameParam}'.` }, 403);
80
84
  }
81
85
  if (skResult === 'invalid') {
82
- return c.json({ code: 401, message: 'Unauthorized. Invalid Service Key.' }, 401);
86
+ return c.json({ code: 401, message: `Invalid X-EdgeBase-Service-Key for D1 database '${nameParam}'.` }, 401);
83
87
  }
84
88
 
85
89
  // §1 Env type — dynamic binding access via type assertion
86
90
  const binding = (c.env as unknown as Record<string, unknown>)[d1Config.binding] as D1Database | undefined;
87
91
  if (!binding) {
88
- return c.json({ code: 500, message: `D1 binding '${d1Config.binding}' not available.` }, 500);
92
+ return c.json({
93
+ code: 500,
94
+ message: `D1 binding '${d1Config.binding}' is unavailable. Check the binding name in edgebase.config.ts and wrangler.toml.`,
95
+ }, 500);
89
96
  }
90
97
 
91
98
  // Execute D1 query — all SQL allowed (DDL included), ? bind variables enforced
@@ -103,7 +110,7 @@ d1Route.openapi(executeD1Query, async (c) => {
103
110
  },
104
111
  });
105
112
  } catch (err) {
106
- const message = err instanceof Error ? err.message : 'D1 query execution failed';
107
- throw new EdgeBaseError(400, message);
113
+ const message = err instanceof Error ? err.message : 'Unknown D1 query error';
114
+ throw new EdgeBaseError(400, `D1 query failed for '${nameParam}': ${message}`);
108
115
  }
109
116
  });
@@ -26,6 +26,10 @@ import {
26
26
 
27
27
  export const databaseLiveRoute = new OpenAPIHono<HonoEnv>({ defaultHook: zodDefaultHook });
28
28
 
29
+ function invalidDatabaseLiveJsonMessage(): string {
30
+ return 'Invalid JSON body for database-live broadcast. Send application/json with { channel, event, payload? }.';
31
+ }
32
+
29
33
  const MAX_PENDING_PER_IP = 5;
30
34
  const PENDING_TTL_SECONDS = 60;
31
35
  const dbLiveQuerySchema = z.object({
@@ -269,15 +273,15 @@ databaseLiveRoute.openapi(databaseLiveBroadcast, async (c) => {
269
273
  try {
270
274
  body = await c.req.json();
271
275
  } catch {
272
- return c.json({ code: 400, message: 'Invalid JSON body' }, 400);
276
+ return c.json({ code: 400, message: invalidDatabaseLiveJsonMessage() }, 400);
273
277
  }
274
278
 
275
279
  const { channel, event, payload } = body;
276
280
  if (!channel || typeof channel !== 'string') {
277
- return c.json({ code: 400, message: 'channel is required' }, 400);
281
+ return c.json({ code: 400, message: "Missing required field 'channel' for database-live broadcast." }, 400);
278
282
  }
279
283
  if (!event || typeof event !== 'string') {
280
- return c.json({ code: 400, message: 'event is required' }, 400);
284
+ return c.json({ code: 400, message: "Missing required field 'event' for database-live broadcast." }, 400);
281
285
  }
282
286
 
283
287
  // Service Key required AND validated
@@ -291,10 +295,10 @@ databaseLiveRoute.openapi(databaseLiveBroadcast, async (c) => {
291
295
  buildConstraintCtx(c.env, c.req),
292
296
  );
293
297
  if (skResult === 'missing') {
294
- return c.json({ code: 403, message: 'Service Key required for server broadcast' }, 403);
298
+ return c.json({ code: 403, message: `X-EdgeBase-Service-Key is required to broadcast to database-live channel '${channel}'.` }, 403);
295
299
  }
296
300
  if (skResult === 'invalid') {
297
- return c.json({ code: 401, message: 'Unauthorized. Invalid Service Key.' }, 401);
301
+ return c.json({ code: 401, message: `Invalid X-EdgeBase-Service-Key for database-live channel '${channel}'.` }, 401);
298
302
  }
299
303
 
300
304
  // Route broadcast through the DatabaseLiveDO hub
@@ -308,7 +312,10 @@ databaseLiveRoute.openapi(databaseLiveBroadcast, async (c) => {
308
312
  }));
309
313
 
310
314
  if (!doResponse.ok) {
311
- return c.json({ code: doResponse.status, message: 'Broadcast failed' }, doResponse.status as 400 | 500);
315
+ return c.json({
316
+ code: doResponse.status,
317
+ message: `Broadcast to database-live channel '${channel}' failed for event '${event}'.`,
318
+ }, doResponse.status as 400 | 500);
312
319
  }
313
320
 
314
321
  return c.json({ ok: true });
package/src/routes/kv.ts CHANGED
@@ -20,6 +20,14 @@ import { zodDefaultHook, kvBodySchema, jsonResponseSchema, errorResponseSchema }
20
20
 
21
21
  export const kvRoute = new OpenAPIHono<HonoEnv>({ defaultHook: zodDefaultHook });
22
22
 
23
+ function invalidKvJsonMessage(): string {
24
+ return 'Invalid JSON body. Send application/json with a KV operation payload like { action, key, value }.';
25
+ }
26
+
27
+ function missingKvFieldMessage(field: string, action: string): string {
28
+ return `Missing required field '${field}' for KV action '${action}'.`;
29
+ }
30
+
23
31
  function normalizeKvBindingError(action: string, error: unknown): EdgeBaseError {
24
32
  const message = error instanceof Error ? error.message : String(error);
25
33
  const lowered = message.toLowerCase();
@@ -75,12 +83,12 @@ kvRoute.openapi(kvOperation, async (c) => {
75
83
  try {
76
84
  body = await c.req.json();
77
85
  } catch {
78
- return c.json({ code: 400, message: 'Invalid JSON body' }, 400);
86
+ return c.json({ code: 400, message: invalidKvJsonMessage() }, 400);
79
87
  }
80
88
 
81
89
  const { action } = body;
82
90
  if (!action || !['get', 'set', 'delete', 'list'].includes(action)) {
83
- return c.json({ code: 400, message: "action must be one of: 'get', 'set', 'delete', 'list'" }, 400);
91
+ return c.json({ code: 400, message: "Invalid KV action. Expected one of: 'get', 'set', 'delete', 'list'." }, 400);
84
92
  }
85
93
 
86
94
  // §2 Allowlist: validate namespace is declared in config
@@ -105,28 +113,31 @@ kvRoute.openapi(kvOperation, async (c) => {
105
113
  buildConstraintCtx(c.env, c.req),
106
114
  );
107
115
  if (skResult === 'missing') {
108
- return c.json({ code: 403, message: 'Service Key required to access KV' }, 403);
116
+ return c.json({ code: 403, message: `X-EdgeBase-Service-Key is required to access KV namespace '${nameParam}'.` }, 403);
109
117
  }
110
118
  if (skResult === 'invalid') {
111
- return c.json({ code: 401, message: 'Unauthorized. Invalid Service Key.' }, 401);
119
+ return c.json({ code: 401, message: `Invalid X-EdgeBase-Service-Key for KV namespace '${nameParam}'.` }, 401);
112
120
  }
113
121
 
114
122
  // §1 Env type — dynamic binding access via type assertion
115
123
  const binding = (c.env as unknown as Record<string, unknown>)[kvConfig.binding] as KVNamespace | undefined;
116
124
  if (!binding) {
117
- return c.json({ code: 500, message: `KV binding '${kvConfig.binding}' not available.` }, 500);
125
+ return c.json({
126
+ code: 500,
127
+ message: `KV binding '${kvConfig.binding}' is unavailable. Check the binding name in edgebase.config.ts and wrangler.toml.`,
128
+ }, 500);
118
129
  }
119
130
 
120
131
  // Execute KV operation
121
132
  switch (action) {
122
133
  case 'get': {
123
- if (!body.key) return c.json({ code: 400, message: 'key is required for get' }, 400);
134
+ if (!body.key) return c.json({ code: 400, message: missingKvFieldMessage('key', 'get') }, 400);
124
135
  const value = await binding.get(body.key);
125
136
  return c.json({ value });
126
137
  }
127
138
  case 'set': {
128
- if (!body.key) return c.json({ code: 400, message: 'key is required for set' }, 400);
129
- if (body.value === undefined) return c.json({ code: 400, message: 'value is required for set' }, 400);
139
+ if (!body.key) return c.json({ code: 400, message: missingKvFieldMessage('key', 'set') }, 400);
140
+ if (body.value === undefined) return c.json({ code: 400, message: missingKvFieldMessage('value', 'set') }, 400);
130
141
  const putOptions: KVNamespacePutOptions = {};
131
142
  if (body.ttl) putOptions.expirationTtl = body.ttl;
132
143
  try {
@@ -137,7 +148,7 @@ kvRoute.openapi(kvOperation, async (c) => {
137
148
  return c.json({ ok: true });
138
149
  }
139
150
  case 'delete': {
140
- if (!body.key) return c.json({ code: 400, message: 'key is required for delete' }, 400);
151
+ if (!body.key) return c.json({ code: 400, message: missingKvFieldMessage('key', 'delete') }, 400);
141
152
  try {
142
153
  await binding.delete(body.key);
143
154
  } catch (error) {
@@ -162,6 +173,6 @@ kvRoute.openapi(kvOperation, async (c) => {
162
173
  });
163
174
  }
164
175
  default:
165
- return c.json({ code: 400, message: 'Unknown action' }, 400);
176
+ return c.json({ code: 400, message: `Unsupported KV action '${action}'.` }, 400);
166
177
  }
167
178
  });
@@ -86,7 +86,7 @@ oauthRoute.onError((err, c) => {
86
86
  return c.json(err.toJSON(), err.code as 400);
87
87
  }
88
88
  console.error('OAuth unhandled error:', err);
89
- return c.json({ code: 500, message: 'OAuth error.' }, 500);
89
+ return c.json({ code: 500, message: 'OAuth flow failed unexpectedly. Check the worker logs for the original exception.' }, 500);
90
90
  });
91
91
 
92
92
  // ─── Helpers ───