@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/routes/backup.ts
CHANGED
|
@@ -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: '
|
|
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:
|
|
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
|
|
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:
|
|
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:
|
|
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({
|
|
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
|
|
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:
|
|
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
|
|
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
|
|
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:
|
|
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:
|
|
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({
|
|
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:
|
|
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
|
|
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:
|
|
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:
|
|
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({
|
|
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
|
|
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
|
|
129
|
-
if (body.value === undefined) return c.json({ code: 400, message: 'value
|
|
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
|
|
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:
|
|
176
|
+
return c.json({ code: 400, message: `Unsupported KV action '${action}'.` }, 400);
|
|
166
177
|
}
|
|
167
178
|
});
|
package/src/routes/oauth.ts
CHANGED
|
@@ -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
|
|
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 ───
|