@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.
Files changed (81) hide show
  1. package/admin-build/_app/immutable/chunks/{DjOEv9M9.js → A_3UuvCe.js} +1 -1
  2. package/admin-build/_app/immutable/chunks/{Dqk2TGNU.js → B-_-hJ9o.js} +1 -1
  3. package/admin-build/_app/immutable/chunks/{BFs_qStz.js → B5Nwfelm.js} +1 -1
  4. package/admin-build/_app/immutable/chunks/{B0QyxC2M.js → BxoNtYHK.js} +3 -3
  5. package/admin-build/_app/immutable/chunks/{BsFiK_FJ.js → CZ0TVkCa.js} +1 -1
  6. package/admin-build/_app/immutable/chunks/{k0CIJkw4.js → CzSAxmuj.js} +1 -1
  7. package/admin-build/_app/immutable/chunks/{D-x55wdW.js → DCKcAiQH.js} +1 -1
  8. package/admin-build/_app/immutable/chunks/{CSGrwS7E.js → DCvwWZrm.js} +1 -1
  9. package/admin-build/_app/immutable/chunks/{BTJcQFEp.js → DRqPU3wD.js} +1 -1
  10. package/admin-build/_app/immutable/chunks/{CqUxCvs_.js → Dc1-6Po6.js} +1 -1
  11. package/admin-build/_app/immutable/chunks/{D755Tqat.js → DiyBpamp.js} +1 -1
  12. package/admin-build/_app/immutable/chunks/{BcIUK2sk.js → Dlty5069.js} +1 -1
  13. package/admin-build/_app/immutable/chunks/{BY07qVPA.js → DpVAayDG.js} +1 -1
  14. package/admin-build/_app/immutable/chunks/{BCKr7yKd.js → Du5vWVa2.js} +1 -1
  15. package/admin-build/_app/immutable/chunks/{m9QZTyVV.js → byv2rTy8.js} +1 -1
  16. package/admin-build/_app/immutable/chunks/{DnLqc9L1.js → nZvorU8i.js} +1 -1
  17. package/admin-build/_app/immutable/entry/{app.BTsq3_xq.js → app.CfrmEXPD.js} +2 -2
  18. package/admin-build/_app/immutable/entry/start.l1WvHznQ.js +1 -0
  19. package/admin-build/_app/immutable/nodes/{0.BZ00WDYH.js → 0.Cn2BZ4da.js} +1 -1
  20. package/admin-build/_app/immutable/nodes/{1.RzSJ3yyr.js → 1.Dv4LX_Co.js} +1 -1
  21. package/admin-build/_app/immutable/nodes/{10.D-rsiquF.js → 10.DPVv3kat.js} +1 -1
  22. package/admin-build/_app/immutable/nodes/{11.l7-bgtFD.js → 11.CiCb6Ayu.js} +1 -1
  23. package/admin-build/_app/immutable/nodes/{12.Dkq0H7B5.js → 12.CIPyeekF.js} +1 -1
  24. package/admin-build/_app/immutable/nodes/{13.DtK_4oRz.js → 13.Z15Lt36e.js} +1 -1
  25. package/admin-build/_app/immutable/nodes/{14.BKo7-AMx.js → 14.s0l5bAq3.js} +1 -1
  26. package/admin-build/_app/immutable/nodes/{15.CQAj_6lq.js → 15.UwSSNO76.js} +1 -1
  27. package/admin-build/_app/immutable/nodes/{16.XVIG-Ffr.js → 16.qiD8i883.js} +1 -1
  28. package/admin-build/_app/immutable/nodes/{17.g6raZLCM.js → 17.Dy3dcSvu.js} +1 -1
  29. package/admin-build/_app/immutable/nodes/{18.IQz6a3T6.js → 18.DeXyPYsO.js} +1 -1
  30. package/admin-build/_app/immutable/nodes/{19.CAAZ8i8h.js → 19.CAbuyS6w.js} +1 -1
  31. package/admin-build/_app/immutable/nodes/{20.BPcX3KPj.js → 20.Bec0T7un.js} +1 -1
  32. package/admin-build/_app/immutable/nodes/21.DuDYelMY.js +1 -0
  33. package/admin-build/_app/immutable/nodes/{22.Br5AG_5Z.js → 22.CdVprrv2.js} +1 -1
  34. package/admin-build/_app/immutable/nodes/{23.KjbrdXoE.js → 23.Y8RzVLoF.js} +1 -1
  35. package/admin-build/_app/immutable/nodes/{24.C3n2-hgw.js → 24.CWhHYFBx.js} +1 -1
  36. package/admin-build/_app/immutable/nodes/{25.SFDSBzHd.js → 25.wCBplOVt.js} +1 -1
  37. package/admin-build/_app/immutable/nodes/{26.D95vui6E.js → 26.Cod_JRFK.js} +1 -1
  38. package/admin-build/_app/immutable/nodes/{27.FgLgdjwB.js → 27.BO2HVMu9.js} +1 -1
  39. package/admin-build/_app/immutable/nodes/{28.B9sYYm1F.js → 28.DxG-FBVQ.js} +1 -1
  40. package/admin-build/_app/immutable/nodes/{29.DyqZ_wbN.js → 29.CjGqWGvE.js} +1 -1
  41. package/admin-build/_app/immutable/nodes/{3.Bzo2yVIO.js → 3.By3_OmdZ.js} +1 -1
  42. package/admin-build/_app/immutable/nodes/{30.c1CiNwiS.js → 30.M_H7Htpq.js} +1 -1
  43. package/admin-build/_app/immutable/nodes/{31.CXty66Vh.js → 31.DEU18izM.js} +1 -1
  44. package/admin-build/_app/immutable/nodes/{4.BgQaXZ27.js → 4.DeYhKtzJ.js} +1 -1
  45. package/admin-build/_app/immutable/nodes/{5.BuJrHvxH.js → 5.9WLgxhrD.js} +1 -1
  46. package/admin-build/_app/immutable/nodes/{6.CkBBC94k.js → 6.BdT2i_dd.js} +1 -1
  47. package/admin-build/_app/immutable/nodes/{7.D2YBvNFM.js → 7.CHq0s4K6.js} +1 -1
  48. package/admin-build/_app/immutable/nodes/{8.D8qQWo_z.js → 8.DuvRw-XZ.js} +1 -1
  49. package/admin-build/_app/immutable/nodes/{9.BLDLX5hV.js → 9.C2Ub82wn.js} +1 -1
  50. package/admin-build/_app/version.json +1 -1
  51. package/admin-build/index.html +7 -7
  52. package/package.json +3 -2
  53. package/src/__tests__/d1-live-broadcast-verification.test.ts +271 -0
  54. package/src/__tests__/database-live-do.test.ts +50 -0
  55. package/src/__tests__/database-live-emitter.test.ts +116 -1
  56. package/src/__tests__/error-format.test.ts +63 -0
  57. package/src/__tests__/functions-context.test.ts +592 -35
  58. package/src/__tests__/meta-export-coverage.test.ts +1 -0
  59. package/src/__tests__/postgres-field-ops-compat.test.ts +110 -0
  60. package/src/__tests__/provider-aware-sql.test.ts +157 -0
  61. package/src/__tests__/room-auth-state-loss.test.ts +124 -0
  62. package/src/__tests__/runtime-surface-accounting.test.ts +0 -4
  63. package/src/__tests__/sql-route.test.ts +187 -76
  64. package/src/durable-objects/database-live-do.ts +46 -1
  65. package/src/durable-objects/room-runtime-base.ts +26 -2
  66. package/src/durable-objects/rooms-do.ts +1 -1
  67. package/src/lib/admin-db-target.ts +30 -74
  68. package/src/lib/d1-handler.ts +45 -14
  69. package/src/lib/database-live-emitter.ts +57 -16
  70. package/src/lib/functions.ts +332 -454
  71. package/src/lib/internal-transport.ts +316 -0
  72. package/src/lib/plugin-migrations.ts +39 -39
  73. package/src/lib/postgres-handler.ts +39 -11
  74. package/src/lib/provider-aware-sql.ts +827 -0
  75. package/src/routes/admin.ts +7 -1
  76. package/src/routes/auth.ts +11 -12
  77. package/src/routes/sql.ts +51 -76
  78. package/src/routes/storage.ts +11 -12
  79. package/src/types.ts +2 -0
  80. package/admin-build/_app/immutable/entry/start.zXCirpgY.js +0 -1
  81. package/admin-build/_app/immutable/nodes/21.DoPabrY_.js +0 -1
@@ -119,10 +119,16 @@ function quoteSqlIdentifier(identifier: string): string {
119
119
  return `"${identifier}"`;
120
120
  }
121
121
 
122
+ // Browser bootstrap is opt-in and only enabled by the local dev workflow.
123
+ function isPublicAdminSetupEnabled(env: Env): boolean {
124
+ return env.EDGEBASE_ALLOW_PUBLIC_ADMIN_SETUP === '1'
125
+ || env.EDGEBASE_ALLOW_PUBLIC_ADMIN_SETUP === 'true';
126
+ }
127
+
122
128
  function isPublicAdminSetupAllowed(env: Env): boolean {
123
129
  try {
124
130
  const config = parseConfig(env);
125
- return config.release !== true;
131
+ return config.release !== true && isPublicAdminSetupEnabled(env);
126
132
  } catch {
127
133
  return false;
128
134
  }
@@ -54,6 +54,7 @@ import {
54
54
  buildFunctionPushProxy,
55
55
  buildAdminAuthContext,
56
56
  buildAdminDbProxy,
57
+ executeSqlProviderAware,
57
58
  getWorkerUrl,
58
59
  } from '../lib/functions.js';
59
60
  import * as authService from '../lib/auth-d1-service.js';
@@ -659,18 +660,16 @@ export async function executeAuthHook(
659
660
  db: adminDb,
660
661
  table: (name: string) => adminDb('shared').table(name),
661
662
  auth: authAdmin,
662
- async sql(namespace: string, id: string | undefined, query: string, params?: unknown[]) {
663
- if (options.workerUrl && serviceKey) {
664
- const res = await fetch(`${options.workerUrl}/api/sql`, {
665
- method: 'POST',
666
- headers: { 'Content-Type': 'application/json', 'X-EdgeBase-Service-Key': serviceKey },
667
- body: JSON.stringify({ namespace, id, sql: query, params: params ?? [] }),
668
- });
669
- if (!res.ok) throw new Error(`admin.sql() failed: ${res.status}`);
670
- return res.json();
671
- }
672
- throw new Error('admin.sql() requires workerUrl in auth hook context.');
673
- },
663
+ sqlProviderAware: (namespace: string, id: string | undefined, query: string, params?: unknown[]) =>
664
+ executeSqlProviderAware(
665
+ { env, config, databaseNamespace: env.DATABASE, workerUrl: options.workerUrl, serviceKey },
666
+ namespace, id, query, params,
667
+ ),
668
+ sqlWithDirectD1Access: (namespace: string, id: string | undefined, query: string, params?: unknown[]) =>
669
+ executeSqlProviderAware(
670
+ { env, config, databaseNamespace: env.DATABASE, workerUrl: options.workerUrl, serviceKey },
671
+ namespace, id, query, params,
672
+ ),
674
673
  async broadcast(channel: string, event: string, payload?: Record<string, unknown>) {
675
674
  if (options.workerUrl && serviceKey) {
676
675
  await fetch(`${options.workerUrl}/api/db/broadcast`, {
package/src/routes/sql.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * SQL endpoint — POST /api/sql
3
3
  *
4
- * Allows server SDK (with Service Key) to execute raw SQL on any DatabaseDO.
4
+ * Allows server SDK (with Service Key) to execute provider-aware raw SQL.
5
5
  * NOT available to client SDK (no sql() method on ClientEdgeBase).
6
6
  *
7
7
  * §11: URL stays /api/sql, but request body now uses
@@ -13,7 +13,7 @@
13
13
  * - id, if provided, must not contain ':' (§2)
14
14
  * - Parameterized queries enforced (sql + params separate)
15
15
  *
16
- * Flow: Server SDK → POST /api/sql → Worker → DatabaseDO sqlExec() → JSON
16
+ * Flow: Server SDK → POST /api/sql → Worker → provider-aware executor → JSON
17
17
  *
18
18
  * Request body:
19
19
  * { namespace: string, id?: string, sql: string, params?: unknown[] }
@@ -23,19 +23,15 @@
23
23
  * { namespace: 'workspace', id: 'ws-456', sql: 'SELECT * FROM documents', params: [] }
24
24
  */
25
25
  import { OpenAPIHono, createRoute, type HonoEnv } from '../lib/hono.js';
26
- import { parseConfig, getD1BindingName, shouldRouteToD1 } from '../lib/do-router.js';
27
- import { executeD1Sql } from '../lib/d1-sql.js';
26
+ import { parseConfig } from '../lib/do-router.js';
28
27
  import { validateKey, buildConstraintCtx } from '../lib/service-key.js';
29
- import { zodDefaultHook, sqlBodySchema, jsonResponseSchema, errorResponseSchema } from '../lib/schemas.js';
30
28
  import {
31
- ensureLocalDevPostgresSchema,
32
- getLocalDevPostgresExecOptions,
33
- getProviderBindingName,
34
- withPostgresConnection,
35
- } from '../lib/postgres-executor.js';
36
- import { ensurePgSchema } from '../lib/postgres-schema-init.js';
37
- import { executeDoSql } from '../lib/do-sql.js';
38
-
29
+ zodDefaultHook,
30
+ sqlBodySchema,
31
+ jsonResponseSchema,
32
+ errorResponseSchema,
33
+ } from '../lib/schemas.js';
34
+ import { executeProviderAwareSql } from '../lib/provider-aware-sql.js';
39
35
 
40
36
  export const sqlRoute = new OpenAPIHono<HonoEnv>({ defaultHook: zodDefaultHook });
41
37
 
@@ -48,15 +44,27 @@ const executeSql = createRoute({
48
44
  method: 'post',
49
45
  path: '/',
50
46
  tags: ['admin'],
51
- summary: 'Execute SQL via DatabaseDO',
47
+ summary: 'Execute provider-aware raw SQL',
52
48
  request: {
53
49
  body: { content: { 'application/json': { schema: sqlBodySchema } }, required: true },
54
50
  },
55
51
  responses: {
56
- 200: { description: 'Query results', content: { 'application/json': { schema: jsonResponseSchema } } },
57
- 400: { description: 'Bad request', content: { 'application/json': { schema: errorResponseSchema } } },
58
- 401: { description: 'Unauthorized', content: { 'application/json': { schema: errorResponseSchema } } },
59
- 403: { description: 'Forbidden', content: { 'application/json': { schema: errorResponseSchema } } },
52
+ 200: {
53
+ description: 'Query results',
54
+ content: { 'application/json': { schema: jsonResponseSchema } },
55
+ },
56
+ 400: {
57
+ description: 'Bad request',
58
+ content: { 'application/json': { schema: errorResponseSchema } },
59
+ },
60
+ 401: {
61
+ description: 'Unauthorized',
62
+ content: { 'application/json': { schema: errorResponseSchema } },
63
+ },
64
+ 403: {
65
+ description: 'Forbidden',
66
+ content: { 'application/json': { schema: errorResponseSchema } },
67
+ },
60
68
  },
61
69
  });
62
70
 
@@ -77,7 +85,7 @@ sqlRoute.openapi(executeSql, async (c) => {
77
85
  return c.json({ code: 400, message: 'id must be a string' }, 400);
78
86
  }
79
87
  if (id && id.includes(':')) {
80
- return c.json({ code: 400, message: 'id must not contain \':\' (§2)' }, 400);
88
+ return c.json({ code: 400, message: "id must not contain ':' (§2)" }, 400);
81
89
  }
82
90
  if (!sql || typeof sql !== 'string') {
83
91
  return c.json({ code: 400, message: 'sql is required' }, 400);
@@ -89,9 +97,16 @@ sqlRoute.openapi(executeSql, async (c) => {
89
97
  if (!dbBlock) {
90
98
  return c.json({ code: 404, message: `Namespace '${namespace}' not found in config` }, 404);
91
99
  }
92
- const isDynamicNamespace = !!(dbBlock.instance || dbBlock.access?.canCreate || dbBlock.access?.access);
100
+ const isDynamicNamespace = !!(
101
+ dbBlock.instance ||
102
+ dbBlock.access?.canCreate ||
103
+ dbBlock.access?.access
104
+ );
93
105
  if (isDynamicNamespace && !id) {
94
- return c.json({ code: 400, message: `id is required for dynamic namespace '${namespace}'` }, 400);
106
+ return c.json(
107
+ { code: 400, message: `id is required for dynamic namespace '${namespace}'` },
108
+ 400,
109
+ );
95
110
  }
96
111
 
97
112
  // Service Key required AND validated
@@ -110,65 +125,25 @@ sqlRoute.openapi(executeSql, async (c) => {
110
125
  return c.json({ code: 401, message: 'Unauthorized. Invalid Service Key.' }, 401);
111
126
  }
112
127
 
113
- if (!id && (dbBlock?.provider === 'neon' || dbBlock?.provider === 'postgres')) {
114
- const bindingName = getProviderBindingName(namespace);
115
- const envRecord = c.env as unknown as Record<string, unknown>;
116
- const hyperdrive = envRecord[bindingName] as { connectionString?: string } | undefined;
117
- const envKey = dbBlock.connectionString ?? `${bindingName}_URL`;
118
- const connStr = hyperdrive?.connectionString ?? (envRecord[envKey] as string | undefined);
119
- if (!connStr) {
120
- return c.json({ code: 500, message: `PostgreSQL connection '${envKey}' not found.` }, 500);
121
- }
122
-
123
- try {
124
- const localDevOptions = getLocalDevPostgresExecOptions(c.env as unknown as Record<string, unknown>, namespace);
125
- if (localDevOptions) {
126
- await ensureLocalDevPostgresSchema(localDevOptions);
127
- }
128
- const result = await withPostgresConnection(connStr, async (query) => {
129
- if (!localDevOptions) {
130
- await ensurePgSchema(connStr, namespace, dbBlock.tables ?? {}, query);
131
- }
132
- return query(sql, params ?? []);
133
- }, localDevOptions);
134
- const rows = result.rows ?? [];
135
- return c.json({ rows, items: rows, results: rows, columns: result.columns, rowCount: result.rowCount });
136
- } catch (err) {
137
- const message = err instanceof Error ? err.message : 'SQL execution failed';
138
- return c.json({ code: 500, message }, 500);
139
- }
140
- }
141
-
142
- if (!id && shouldRouteToD1(namespace, config)) {
143
- const bindingName = getD1BindingName(namespace);
144
- const d1 = (c.env as unknown as Record<string, unknown>)[bindingName] as D1Database | undefined;
145
- if (!d1) {
146
- return c.json({ code: 500, message: `D1 binding '${bindingName}' not found.` }, 500);
147
- }
148
-
149
- try {
150
- const result = await executeD1Sql(d1, sql, params ?? []);
151
- return c.json({
152
- rows: result.rows,
153
- items: result.rows,
154
- results: result.rows,
155
- rowCount: result.rowCount,
156
- });
157
- } catch (err) {
158
- const message = err instanceof Error ? err.message : 'SQL execution failed';
159
- return c.json({ code: 500, message }, 500);
160
- }
161
- }
162
-
163
128
  try {
164
- const rows = await executeDoSql({
165
- databaseNamespace: c.env.DATABASE,
129
+ const result = await executeProviderAwareSql(
130
+ {
131
+ env: c.env,
132
+ config,
133
+ databaseNamespace: c.env.DATABASE,
134
+ },
166
135
  namespace,
167
136
  id,
168
- query: sql,
169
- params: params ?? [],
137
+ sql,
138
+ params ?? [],
139
+ );
140
+ return c.json({
141
+ rows: result.rows,
142
+ items: result.rows,
143
+ results: result.rows,
144
+ columns: result.columns,
145
+ rowCount: result.rowCount,
170
146
  });
171
- return c.json({ rows, items: rows, results: rows });
172
147
  } catch (err) {
173
148
  const message = err instanceof Error ? err.message : 'SQL execution failed';
174
149
  return c.json({ code: 500, message }, 500);
@@ -44,6 +44,7 @@ import {
44
44
  buildFunctionPushProxy,
45
45
  buildAdminAuthContext,
46
46
  buildAdminDbProxy,
47
+ executeSqlProviderAware,
47
48
  getWorkerUrl,
48
49
  } from '../lib/functions.js';
49
50
 
@@ -165,18 +166,16 @@ function buildStorageHookAdminContext(
165
166
  db: adminDb,
166
167
  table: (name: string) => adminDb('shared').table(name),
167
168
  auth: buildAdminAuthContext({ d1Database: env.AUTH_DB, serviceKey, workerUrl }),
168
- async sql(namespace: string, id: string | undefined, query: string, params?: unknown[]) {
169
- if (workerUrl && serviceKey) {
170
- const res = await fetch(`${workerUrl}/api/sql`, {
171
- method: 'POST',
172
- headers: { 'Content-Type': 'application/json', 'X-EdgeBase-Service-Key': serviceKey },
173
- body: JSON.stringify({ namespace, id, sql: query, params: params ?? [] }),
174
- });
175
- if (!res.ok) throw new Error(`admin.sql() failed: ${res.status}`);
176
- return res.json();
177
- }
178
- throw new Error('admin.sql() requires workerUrl in storage hook context.');
179
- },
169
+ sqlProviderAware: (namespace: string, id: string | undefined, query: string, params?: unknown[]) =>
170
+ executeSqlProviderAware(
171
+ { env, config, databaseNamespace: env.DATABASE, workerUrl, serviceKey },
172
+ namespace, id, query, params,
173
+ ),
174
+ sqlWithDirectD1Access: (namespace: string, id: string | undefined, query: string, params?: unknown[]) =>
175
+ executeSqlProviderAware(
176
+ { env, config, databaseNamespace: env.DATABASE, workerUrl, serviceKey },
177
+ namespace, id, query, params,
178
+ ),
180
179
  async broadcast(channel: string, event: string, payload?: Record<string, unknown>) {
181
180
  if (workerUrl && serviceKey) {
182
181
  await fetch(`${workerUrl}/api/db/broadcast`, {
package/src/types.ts CHANGED
@@ -100,6 +100,8 @@ export interface Env {
100
100
  EDGEBASE_USE_TEST_CONFIG?: string;
101
101
 
102
102
  // ─── Dev Mode ───
103
+ /** Enables browser-based first-admin setup for the local dev server. */
104
+ EDGEBASE_ALLOW_PUBLIC_ADMIN_SETUP?: string;
103
105
  /** Schema Editor sidecar port — set by CLI dev command via --var */
104
106
  EDGEBASE_DEV_SIDECAR_PORT?: string;
105
107
  }
@@ -1 +0,0 @@
1
- import{a as r}from"../chunks/m9QZTyVV.js";import{w as t}from"../chunks/D755Tqat.js";export{t as load_css,r as start};
@@ -1 +0,0 @@
1
- import{_ as m}from"../chunks/B0QyxC2M.js";export{m as component};