@edge-base/server 0.2.1 → 0.2.3
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/{DjOEv9M9.js → A_3UuvCe.js} +1 -1
- package/admin-build/_app/immutable/chunks/{Dqk2TGNU.js → B-_-hJ9o.js} +1 -1
- package/admin-build/_app/immutable/chunks/{BFs_qStz.js → B5Nwfelm.js} +1 -1
- package/admin-build/_app/immutable/chunks/{B0QyxC2M.js → BxoNtYHK.js} +3 -3
- package/admin-build/_app/immutable/chunks/{BsFiK_FJ.js → CZ0TVkCa.js} +1 -1
- package/admin-build/_app/immutable/chunks/{k0CIJkw4.js → CzSAxmuj.js} +1 -1
- package/admin-build/_app/immutable/chunks/{D-x55wdW.js → DCKcAiQH.js} +1 -1
- package/admin-build/_app/immutable/chunks/{CSGrwS7E.js → DCvwWZrm.js} +1 -1
- package/admin-build/_app/immutable/chunks/{BTJcQFEp.js → DRqPU3wD.js} +1 -1
- package/admin-build/_app/immutable/chunks/{CqUxCvs_.js → Dc1-6Po6.js} +1 -1
- package/admin-build/_app/immutable/chunks/{D755Tqat.js → DiyBpamp.js} +1 -1
- package/admin-build/_app/immutable/chunks/{BcIUK2sk.js → Dlty5069.js} +1 -1
- package/admin-build/_app/immutable/chunks/{BY07qVPA.js → DpVAayDG.js} +1 -1
- package/admin-build/_app/immutable/chunks/{BCKr7yKd.js → Du5vWVa2.js} +1 -1
- package/admin-build/_app/immutable/chunks/{m9QZTyVV.js → byv2rTy8.js} +1 -1
- package/admin-build/_app/immutable/chunks/{DnLqc9L1.js → nZvorU8i.js} +1 -1
- package/admin-build/_app/immutable/entry/{app.BTsq3_xq.js → app.CfrmEXPD.js} +2 -2
- package/admin-build/_app/immutable/entry/start.l1WvHznQ.js +1 -0
- package/admin-build/_app/immutable/nodes/{0.BZ00WDYH.js → 0.Cn2BZ4da.js} +1 -1
- package/admin-build/_app/immutable/nodes/{1.RzSJ3yyr.js → 1.Dv4LX_Co.js} +1 -1
- package/admin-build/_app/immutable/nodes/{10.D-rsiquF.js → 10.DPVv3kat.js} +1 -1
- package/admin-build/_app/immutable/nodes/{11.l7-bgtFD.js → 11.CiCb6Ayu.js} +1 -1
- package/admin-build/_app/immutable/nodes/{12.Dkq0H7B5.js → 12.CIPyeekF.js} +1 -1
- package/admin-build/_app/immutable/nodes/{13.DtK_4oRz.js → 13.Z15Lt36e.js} +1 -1
- package/admin-build/_app/immutable/nodes/{14.BKo7-AMx.js → 14.s0l5bAq3.js} +1 -1
- package/admin-build/_app/immutable/nodes/{15.CQAj_6lq.js → 15.UwSSNO76.js} +1 -1
- package/admin-build/_app/immutable/nodes/{16.XVIG-Ffr.js → 16.qiD8i883.js} +1 -1
- package/admin-build/_app/immutable/nodes/{17.g6raZLCM.js → 17.Dy3dcSvu.js} +1 -1
- package/admin-build/_app/immutable/nodes/{18.IQz6a3T6.js → 18.DeXyPYsO.js} +1 -1
- package/admin-build/_app/immutable/nodes/{19.CAAZ8i8h.js → 19.CAbuyS6w.js} +1 -1
- package/admin-build/_app/immutable/nodes/{20.BPcX3KPj.js → 20.Bec0T7un.js} +1 -1
- package/admin-build/_app/immutable/nodes/21.DuDYelMY.js +1 -0
- package/admin-build/_app/immutable/nodes/{22.Br5AG_5Z.js → 22.CdVprrv2.js} +1 -1
- package/admin-build/_app/immutable/nodes/{23.KjbrdXoE.js → 23.Y8RzVLoF.js} +1 -1
- package/admin-build/_app/immutable/nodes/{24.C3n2-hgw.js → 24.CWhHYFBx.js} +1 -1
- package/admin-build/_app/immutable/nodes/{25.SFDSBzHd.js → 25.wCBplOVt.js} +1 -1
- package/admin-build/_app/immutable/nodes/{26.D95vui6E.js → 26.Cod_JRFK.js} +1 -1
- package/admin-build/_app/immutable/nodes/{27.FgLgdjwB.js → 27.BO2HVMu9.js} +1 -1
- package/admin-build/_app/immutable/nodes/{28.B9sYYm1F.js → 28.DxG-FBVQ.js} +1 -1
- package/admin-build/_app/immutable/nodes/{29.DyqZ_wbN.js → 29.CjGqWGvE.js} +1 -1
- package/admin-build/_app/immutable/nodes/{3.Bzo2yVIO.js → 3.By3_OmdZ.js} +1 -1
- package/admin-build/_app/immutable/nodes/{30.c1CiNwiS.js → 30.M_H7Htpq.js} +1 -1
- package/admin-build/_app/immutable/nodes/{31.CXty66Vh.js → 31.DEU18izM.js} +1 -1
- package/admin-build/_app/immutable/nodes/{4.BgQaXZ27.js → 4.DeYhKtzJ.js} +1 -1
- package/admin-build/_app/immutable/nodes/{5.BuJrHvxH.js → 5.9WLgxhrD.js} +1 -1
- package/admin-build/_app/immutable/nodes/{6.CkBBC94k.js → 6.BdT2i_dd.js} +1 -1
- package/admin-build/_app/immutable/nodes/{7.D2YBvNFM.js → 7.CHq0s4K6.js} +1 -1
- package/admin-build/_app/immutable/nodes/{8.D8qQWo_z.js → 8.DuvRw-XZ.js} +1 -1
- package/admin-build/_app/immutable/nodes/{9.BLDLX5hV.js → 9.C2Ub82wn.js} +1 -1
- package/admin-build/_app/version.json +1 -1
- package/admin-build/index.html +7 -7
- package/package.json +3 -2
- package/src/__tests__/d1-live-broadcast-verification.test.ts +271 -0
- package/src/__tests__/database-live-do.test.ts +50 -0
- package/src/__tests__/database-live-emitter.test.ts +116 -1
- package/src/__tests__/error-format.test.ts +63 -0
- package/src/__tests__/functions-context.test.ts +592 -35
- package/src/__tests__/meta-export-coverage.test.ts +1 -0
- package/src/__tests__/postgres-field-ops-compat.test.ts +110 -0
- package/src/__tests__/provider-aware-sql.test.ts +157 -0
- package/src/__tests__/room-auth-state-loss.test.ts +124 -0
- package/src/__tests__/runtime-surface-accounting.test.ts +0 -4
- package/src/__tests__/sql-route.test.ts +187 -76
- package/src/durable-objects/database-live-do.ts +46 -1
- package/src/durable-objects/room-runtime-base.ts +26 -2
- package/src/durable-objects/rooms-do.ts +1 -1
- package/src/lib/admin-db-target.ts +30 -74
- package/src/lib/d1-handler.ts +45 -14
- package/src/lib/database-live-emitter.ts +57 -16
- package/src/lib/functions.ts +332 -454
- package/src/lib/internal-transport.ts +316 -0
- package/src/lib/plugin-migrations.ts +39 -39
- package/src/lib/postgres-handler.ts +39 -11
- package/src/lib/provider-aware-sql.ts +827 -0
- package/src/routes/admin.ts +7 -1
- package/src/routes/auth.ts +11 -12
- package/src/routes/sql.ts +51 -76
- package/src/routes/storage.ts +11 -12
- package/src/types.ts +2 -0
- package/admin-build/_app/immutable/entry/start.zXCirpgY.js +0 -1
- package/admin-build/_app/immutable/nodes/21.DoPabrY_.js +0 -1
package/src/lib/d1-handler.ts
CHANGED
|
@@ -288,6 +288,18 @@ function buildHookCtx(
|
|
|
288
288
|
};
|
|
289
289
|
}
|
|
290
290
|
|
|
291
|
+
function scheduleDbLive(
|
|
292
|
+
executionCtx: ExecutionContext,
|
|
293
|
+
promise: Promise<void>,
|
|
294
|
+
context: string,
|
|
295
|
+
): void {
|
|
296
|
+
executionCtx.waitUntil(
|
|
297
|
+
promise.catch((error) => {
|
|
298
|
+
console.warn(`[db-live] ${context} failed`, error);
|
|
299
|
+
}),
|
|
300
|
+
);
|
|
301
|
+
}
|
|
302
|
+
|
|
291
303
|
// ─── Utility ───
|
|
292
304
|
|
|
293
305
|
function esc(name: string): string {
|
|
@@ -748,10 +760,12 @@ async function handleInsert(
|
|
|
748
760
|
hookCtx.waitUntil(Promise.resolve(hook(inserted, hookCtx)).catch(() => {}));
|
|
749
761
|
}
|
|
750
762
|
|
|
751
|
-
// Emit database-live event
|
|
763
|
+
// Emit database-live event in the background so writes stay fast.
|
|
752
764
|
const eventType = isUpsert && isUpdate ? 'modified' : 'added';
|
|
753
|
-
|
|
765
|
+
scheduleDbLive(
|
|
766
|
+
c.executionCtx,
|
|
754
767
|
emitDbLiveEvent(c.env, resolved.namespace, tableName, eventType, String(inserted.id ?? ''), inserted),
|
|
768
|
+
`emit ${eventType} ${resolved.namespace}.${tableName}`,
|
|
755
769
|
);
|
|
756
770
|
c.executionCtx.waitUntil(
|
|
757
771
|
executeDbTriggers(
|
|
@@ -891,9 +905,10 @@ async function handleUpdate(
|
|
|
891
905
|
);
|
|
892
906
|
}
|
|
893
907
|
|
|
894
|
-
|
|
895
|
-
|
|
908
|
+
scheduleDbLive(
|
|
909
|
+
c.executionCtx,
|
|
896
910
|
emitDbLiveEvent(c.env, resolved.namespace, tableName, 'modified', id, updated),
|
|
911
|
+
`emit modified ${resolved.namespace}.${tableName}:${id}`,
|
|
897
912
|
);
|
|
898
913
|
c.executionCtx.waitUntil(
|
|
899
914
|
executeDbTriggers(
|
|
@@ -969,9 +984,10 @@ async function handleDelete(
|
|
|
969
984
|
);
|
|
970
985
|
}
|
|
971
986
|
|
|
972
|
-
|
|
973
|
-
|
|
987
|
+
scheduleDbLive(
|
|
988
|
+
c.executionCtx,
|
|
974
989
|
emitDbLiveEvent(c.env, resolved.namespace, tableName, 'removed', id, stripInternalFields(existingRow)),
|
|
990
|
+
`emit removed ${resolved.namespace}.${tableName}:${id}`,
|
|
975
991
|
);
|
|
976
992
|
c.executionCtx.waitUntil(
|
|
977
993
|
executeDbTriggers(
|
|
@@ -1203,15 +1219,21 @@ async function handleBatch(
|
|
|
1203
1219
|
// Emit database-live events
|
|
1204
1220
|
if (allChanges.length > 0) {
|
|
1205
1221
|
if (allChanges.length >= 10) {
|
|
1206
|
-
|
|
1222
|
+
scheduleDbLive(
|
|
1223
|
+
c.executionCtx,
|
|
1207
1224
|
emitDbLiveBatchEvent(c.env, resolved.namespace, tableName, allChanges),
|
|
1225
|
+
`emit batch ${resolved.namespace}.${tableName} (${allChanges.length} changes)`,
|
|
1208
1226
|
);
|
|
1209
1227
|
} else {
|
|
1210
|
-
|
|
1211
|
-
c.executionCtx
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1228
|
+
scheduleDbLive(
|
|
1229
|
+
c.executionCtx,
|
|
1230
|
+
Promise.all(
|
|
1231
|
+
allChanges.map((ch) =>
|
|
1232
|
+
emitDbLiveEvent(c.env, resolved.namespace, tableName, ch.type, ch.docId, ch.data),
|
|
1233
|
+
),
|
|
1234
|
+
).then(() => undefined),
|
|
1235
|
+
`emit fan-out ${resolved.namespace}.${tableName} (${allChanges.length} changes)`,
|
|
1236
|
+
);
|
|
1215
1237
|
}
|
|
1216
1238
|
}
|
|
1217
1239
|
|
|
@@ -1306,8 +1328,17 @@ async function handleBatchByFilter(
|
|
|
1306
1328
|
// Emit database-live events
|
|
1307
1329
|
if (succeeded > 0) {
|
|
1308
1330
|
const eventType = body.action === 'delete' ? 'removed' : 'modified';
|
|
1309
|
-
|
|
1310
|
-
|
|
1331
|
+
scheduleDbLive(
|
|
1332
|
+
c.executionCtx,
|
|
1333
|
+
emitDbLiveEvent(
|
|
1334
|
+
c.env,
|
|
1335
|
+
resolved.namespace,
|
|
1336
|
+
tableName,
|
|
1337
|
+
eventType as 'modified' | 'removed',
|
|
1338
|
+
'_bulk',
|
|
1339
|
+
{ action: body.action, count: succeeded },
|
|
1340
|
+
),
|
|
1341
|
+
`emit bulk ${resolved.namespace}.${tableName} (${body.action})`,
|
|
1311
1342
|
);
|
|
1312
1343
|
}
|
|
1313
1344
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Shared database live event emission helpers.
|
|
3
3
|
*
|
|
4
|
-
* Used by d1-handler.ts and postgres-handler.ts for
|
|
4
|
+
* Used by d1-handler.ts and postgres-handler.ts for background
|
|
5
5
|
* event delivery to DatabaseLiveDO after successful CUD operations.
|
|
6
6
|
*
|
|
7
7
|
* database-do.ts keeps its own internal version (uses DO env).
|
|
@@ -10,6 +10,16 @@ import type { Env } from '../types.js';
|
|
|
10
10
|
|
|
11
11
|
export const DATABASE_LIVE_HUB_DO_NAME = 'database-live:hub';
|
|
12
12
|
|
|
13
|
+
function withDeliveryId(event: Record<string, unknown>): Record<string, unknown> {
|
|
14
|
+
if (typeof event.deliveryId === 'string' && event.deliveryId.length > 0) {
|
|
15
|
+
return event;
|
|
16
|
+
}
|
|
17
|
+
return {
|
|
18
|
+
...event,
|
|
19
|
+
deliveryId: crypto.randomUUID(),
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
13
23
|
export function buildDbLiveChannel(
|
|
14
24
|
namespace: string,
|
|
15
25
|
table: string,
|
|
@@ -34,7 +44,7 @@ export function isDbLiveChannel(channel: string): boolean {
|
|
|
34
44
|
|
|
35
45
|
/**
|
|
36
46
|
* Emit a single CUD event to DatabaseLiveDO.
|
|
37
|
-
* Mirrors database-do.ts emitDbLiveEvent()
|
|
47
|
+
* Mirrors database-do.ts emitDbLiveEvent().
|
|
38
48
|
*/
|
|
39
49
|
export function emitDbLiveEvent(
|
|
40
50
|
env: Env,
|
|
@@ -87,25 +97,56 @@ export function emitDbLiveBatchEvent(
|
|
|
87
97
|
return sendToDatabaseLiveDO(env, event, '/internal/batch-event');
|
|
88
98
|
}
|
|
89
99
|
|
|
100
|
+
async function postToDatabaseLiveDO(
|
|
101
|
+
env: Env,
|
|
102
|
+
event: Record<string, unknown>,
|
|
103
|
+
path = '/internal/event',
|
|
104
|
+
): Promise<void> {
|
|
105
|
+
const liveNamespace = env.DATABASE_LIVE;
|
|
106
|
+
if (!liveNamespace) {
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const doId = liveNamespace.idFromName(DATABASE_LIVE_HUB_DO_NAME);
|
|
111
|
+
const stub = liveNamespace.get(doId);
|
|
112
|
+
const response = await stub.fetch(`http://internal${path}`, {
|
|
113
|
+
method: 'POST',
|
|
114
|
+
headers: { 'Content-Type': 'application/json' },
|
|
115
|
+
body: JSON.stringify(event),
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
if (!response.ok) {
|
|
119
|
+
const detail = await response.text().catch(() => '');
|
|
120
|
+
const suffix = detail ? `: ${detail.slice(0, 200)}` : '';
|
|
121
|
+
throw new Error(`DatabaseLiveDO ${path} failed with ${response.status}${suffix}`);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
90
125
|
/**
|
|
91
|
-
*
|
|
92
|
-
*
|
|
126
|
+
* Send an event to DatabaseLiveDO via stub.fetch().
|
|
127
|
+
* Callers should schedule this with waitUntil() when they want
|
|
128
|
+
* fire-and-forget request semantics without hiding delivery failures.
|
|
93
129
|
*/
|
|
94
|
-
export function sendToDatabaseLiveDO(
|
|
130
|
+
export async function sendToDatabaseLiveDO(
|
|
95
131
|
env: Env,
|
|
96
132
|
event: Record<string, unknown>,
|
|
97
133
|
path = '/internal/event',
|
|
98
134
|
): Promise<void> {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
135
|
+
const eventWithDeliveryId = withDeliveryId(event);
|
|
136
|
+
let lastError: unknown;
|
|
137
|
+
|
|
138
|
+
for (let attempt = 0; attempt < 2; attempt++) {
|
|
139
|
+
try {
|
|
140
|
+
await postToDatabaseLiveDO(env, eventWithDeliveryId, path);
|
|
141
|
+
return;
|
|
142
|
+
} catch (error) {
|
|
143
|
+
lastError = error;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (lastError instanceof Error) {
|
|
148
|
+
throw lastError;
|
|
110
149
|
}
|
|
150
|
+
|
|
151
|
+
throw new Error('DatabaseLiveDO delivery failed.');
|
|
111
152
|
}
|