@edge-base/server 0.1.1

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 (309) hide show
  1. package/admin-build/.gitkeep +0 -0
  2. package/admin-build/_app/env.js +1 -0
  3. package/admin-build/_app/immutable/assets/0.Bm6cF078.css +1 -0
  4. package/admin-build/_app/immutable/assets/1.BfW3pUNa.css +1 -0
  5. package/admin-build/_app/immutable/assets/11.CVmQOewb.css +1 -0
  6. package/admin-build/_app/immutable/assets/12.B1EhbRZT.css +1 -0
  7. package/admin-build/_app/immutable/assets/13.BvwYeuwE.css +1 -0
  8. package/admin-build/_app/immutable/assets/14.CdVfcO0R.css +1 -0
  9. package/admin-build/_app/immutable/assets/15.2yeZ66b-.css +1 -0
  10. package/admin-build/_app/immutable/assets/17.BVg0JEVu.css +1 -0
  11. package/admin-build/_app/immutable/assets/18.Rwnl3x_i.css +1 -0
  12. package/admin-build/_app/immutable/assets/20.DsPWA9AV.css +1 -0
  13. package/admin-build/_app/immutable/assets/21.Dz2RJ56c.css +1 -0
  14. package/admin-build/_app/immutable/assets/22.DwNLk5Ai.css +1 -0
  15. package/admin-build/_app/immutable/assets/23.CFpu0gOO.css +1 -0
  16. package/admin-build/_app/immutable/assets/24.Cy5LBeoJ.css +1 -0
  17. package/admin-build/_app/immutable/assets/25.pUyLVf-h.css +1 -0
  18. package/admin-build/_app/immutable/assets/26.DBcGrlXa.css +1 -0
  19. package/admin-build/_app/immutable/assets/27.BswYyAJD.css +1 -0
  20. package/admin-build/_app/immutable/assets/28.B4ueB1Kf.css +1 -0
  21. package/admin-build/_app/immutable/assets/29.B-qU6PdF.css +1 -0
  22. package/admin-build/_app/immutable/assets/3.Dg81Pgmd.css +1 -0
  23. package/admin-build/_app/immutable/assets/30.CsdWum94.css +1 -0
  24. package/admin-build/_app/immutable/assets/31.U6OwIp50.css +1 -0
  25. package/admin-build/_app/immutable/assets/4.CyawCCux.css +1 -0
  26. package/admin-build/_app/immutable/assets/5.C0YO2HTk.css +1 -0
  27. package/admin-build/_app/immutable/assets/8.Br5jd6kD.css +1 -0
  28. package/admin-build/_app/immutable/assets/Badge.EMYLHBxE.css +1 -0
  29. package/admin-build/_app/immutable/assets/Button.DpzMRTjK.css +1 -0
  30. package/admin-build/_app/immutable/assets/ConfirmDialog.DAnaWRRk.css +1 -0
  31. package/admin-build/_app/immutable/assets/EmptyState.CwKsu57Y.css +1 -0
  32. package/admin-build/_app/immutable/assets/Input.BDUSenmU.css +1 -0
  33. package/admin-build/_app/immutable/assets/Modal.Dm5B0Xie.css +1 -0
  34. package/admin-build/_app/immutable/assets/PageShell.CmU-Xh-b.css +1 -0
  35. package/admin-build/_app/immutable/assets/SchemaFieldEditor.g4NsCdno.css +1 -0
  36. package/admin-build/_app/immutable/assets/Select.BW4Keufm.css +1 -0
  37. package/admin-build/_app/immutable/assets/Skeleton.KWUulTKJ.css +1 -0
  38. package/admin-build/_app/immutable/assets/Tabs.CniGYb67.css +1 -0
  39. package/admin-build/_app/immutable/assets/TimeChart.BTCDAvmT.css +1 -0
  40. package/admin-build/_app/immutable/assets/Toggle.Cy_K12OM.css +1 -0
  41. package/admin-build/_app/immutable/assets/TopList.ClFzmPlA.css +1 -0
  42. package/admin-build/_app/immutable/chunks/7B47DvSx.js +1 -0
  43. package/admin-build/_app/immutable/chunks/7f08Id8e.js +1 -0
  44. package/admin-build/_app/immutable/chunks/8wJeQ7LN.js +1 -0
  45. package/admin-build/_app/immutable/chunks/B-h2afW5.js +1 -0
  46. package/admin-build/_app/immutable/chunks/B8vJP3wz.js +1 -0
  47. package/admin-build/_app/immutable/chunks/BR_fL5Yv.js +1 -0
  48. package/admin-build/_app/immutable/chunks/BY92tFS2.js +1 -0
  49. package/admin-build/_app/immutable/chunks/BcR-Rdj9.js +1 -0
  50. package/admin-build/_app/immutable/chunks/BdrwyZv8.js +1 -0
  51. package/admin-build/_app/immutable/chunks/Bh56EfQ_.js +1 -0
  52. package/admin-build/_app/immutable/chunks/BkrCkgYp.js +1 -0
  53. package/admin-build/_app/immutable/chunks/BmRjiP5k.js +1 -0
  54. package/admin-build/_app/immutable/chunks/BsokvhWC.js +1 -0
  55. package/admin-build/_app/immutable/chunks/C4D51vTW.js +1 -0
  56. package/admin-build/_app/immutable/chunks/C6puvcoR.js +2 -0
  57. package/admin-build/_app/immutable/chunks/CCKNu7m7.js +1 -0
  58. package/admin-build/_app/immutable/chunks/CWj6FrbW.js +1 -0
  59. package/admin-build/_app/immutable/chunks/Ce-ngf4p.js +5 -0
  60. package/admin-build/_app/immutable/chunks/Cs0GwzJA.js +1 -0
  61. package/admin-build/_app/immutable/chunks/CwROoZK0.js +1 -0
  62. package/admin-build/_app/immutable/chunks/CxCPv_Ut.js +1 -0
  63. package/admin-build/_app/immutable/chunks/CxbRue-5.js +1 -0
  64. package/admin-build/_app/immutable/chunks/CyqB6g-D.js +1 -0
  65. package/admin-build/_app/immutable/chunks/D5h5A1cc.js +2 -0
  66. package/admin-build/_app/immutable/chunks/DnyL7Zq-.js +1 -0
  67. package/admin-build/_app/immutable/chunks/DoPXzH7F.js +1 -0
  68. package/admin-build/_app/immutable/chunks/DrQSgw-f.js +1 -0
  69. package/admin-build/_app/immutable/chunks/DttM2zNO.js +1 -0
  70. package/admin-build/_app/immutable/chunks/DuXuUBWN.js +1 -0
  71. package/admin-build/_app/immutable/chunks/MdeqaOQx.js +10 -0
  72. package/admin-build/_app/immutable/chunks/NuUjtcO2.js +1 -0
  73. package/admin-build/_app/immutable/chunks/Q2nPFxS6.js +1 -0
  74. package/admin-build/_app/immutable/chunks/R6arueIl.js +1 -0
  75. package/admin-build/_app/immutable/chunks/UUazaC_N.js +1 -0
  76. package/admin-build/_app/immutable/chunks/cOYbrQxx.js +1 -0
  77. package/admin-build/_app/immutable/chunks/eFQHTGwA.js +1 -0
  78. package/admin-build/_app/immutable/chunks/ehbppgYb.js +1 -0
  79. package/admin-build/_app/immutable/chunks/glwixJlP.js +1 -0
  80. package/admin-build/_app/immutable/chunks/vApWTCBs.js +1 -0
  81. package/admin-build/_app/immutable/chunks/w89G9Xpi.js +1 -0
  82. package/admin-build/_app/immutable/chunks/wJsUhbfZ.js +1 -0
  83. package/admin-build/_app/immutable/chunks/zfauFM8P.js +1 -0
  84. package/admin-build/_app/immutable/entry/app.CcO-Uos3.js +2 -0
  85. package/admin-build/_app/immutable/entry/start.COebYq3I.js +1 -0
  86. package/admin-build/_app/immutable/nodes/0.CjtHKU-6.js +1 -0
  87. package/admin-build/_app/immutable/nodes/1.DEisjlM0.js +1 -0
  88. package/admin-build/_app/immutable/nodes/10.CvhdyWVB.js +1 -0
  89. package/admin-build/_app/immutable/nodes/11.DjHqcOvy.js +1 -0
  90. package/admin-build/_app/immutable/nodes/12.mQLz4Mj_.js +1 -0
  91. package/admin-build/_app/immutable/nodes/13.CBonZZyP.js +110 -0
  92. package/admin-build/_app/immutable/nodes/14.d-oiZL0j.js +3 -0
  93. package/admin-build/_app/immutable/nodes/15.CKPQsUYF.js +1 -0
  94. package/admin-build/_app/immutable/nodes/16.wPzAPQGx.js +1 -0
  95. package/admin-build/_app/immutable/nodes/17.DayhKyEZ.js +1 -0
  96. package/admin-build/_app/immutable/nodes/18.DKwS0Ir0.js +1 -0
  97. package/admin-build/_app/immutable/nodes/19.wPzAPQGx.js +1 -0
  98. package/admin-build/_app/immutable/nodes/2.BKoKrw1i.js +1 -0
  99. package/admin-build/_app/immutable/nodes/20.BvIkkkrW.js +1 -0
  100. package/admin-build/_app/immutable/nodes/21.DMaFhdHk.js +128 -0
  101. package/admin-build/_app/immutable/nodes/22.3xdgwuK1.js +1 -0
  102. package/admin-build/_app/immutable/nodes/23.8Bvgjbsl.js +112 -0
  103. package/admin-build/_app/immutable/nodes/24.DzSSzRhG.js +2 -0
  104. package/admin-build/_app/immutable/nodes/25.9KKYBnAE.js +2 -0
  105. package/admin-build/_app/immutable/nodes/26.Bhn9dfhY.js +1 -0
  106. package/admin-build/_app/immutable/nodes/27.kRLiC24G.js +1 -0
  107. package/admin-build/_app/immutable/nodes/28.BVIN1-7N.js +1 -0
  108. package/admin-build/_app/immutable/nodes/29.3yabZWj4.js +1 -0
  109. package/admin-build/_app/immutable/nodes/3.BFtSOkX7.js +2 -0
  110. package/admin-build/_app/immutable/nodes/30.CyCQlwaP.js +1 -0
  111. package/admin-build/_app/immutable/nodes/31.C4LDXjES.js +1 -0
  112. package/admin-build/_app/immutable/nodes/4.CvbiMlCa.js +1 -0
  113. package/admin-build/_app/immutable/nodes/5.C6BLv2eM.js +1 -0
  114. package/admin-build/_app/immutable/nodes/6.BcXvfl2P.js +1 -0
  115. package/admin-build/_app/immutable/nodes/7.CIuqhPiK.js +1 -0
  116. package/admin-build/_app/immutable/nodes/8.BQOR_JfO.js +1 -0
  117. package/admin-build/_app/immutable/nodes/9.NZqXQxPy.js +1 -0
  118. package/admin-build/_app/version.json +1 -0
  119. package/admin-build/favicon.svg +26 -0
  120. package/admin-build/index.html +45 -0
  121. package/openapi.json +19543 -0
  122. package/package.json +66 -0
  123. package/src/__tests__/admin-assets.test.ts +55 -0
  124. package/src/__tests__/admin-data-routes.test.ts +488 -0
  125. package/src/__tests__/admin-db-target.test.ts +103 -0
  126. package/src/__tests__/admin-routing.test.ts +31 -0
  127. package/src/__tests__/admin-user-management.test.ts +311 -0
  128. package/src/__tests__/analytics-query.test.ts +75 -0
  129. package/src/__tests__/auth-d1.test.ts +749 -0
  130. package/src/__tests__/auth-db-adapter.test.ts +73 -0
  131. package/src/__tests__/auth-jwt.test.ts +440 -0
  132. package/src/__tests__/auth-oauth.test.ts +389 -0
  133. package/src/__tests__/auth-password.test.ts +367 -0
  134. package/src/__tests__/auth-redirect.test.ts +87 -0
  135. package/src/__tests__/backup-restore.test.ts +711 -0
  136. package/src/__tests__/broadcast.test.ts +128 -0
  137. package/src/__tests__/cli.test.ts +178 -0
  138. package/src/__tests__/cloudflare-realtime.test.ts +113 -0
  139. package/src/__tests__/config.test.ts +469 -0
  140. package/src/__tests__/cors.test.ts +154 -0
  141. package/src/__tests__/cron.test.ts +302 -0
  142. package/src/__tests__/d1-handler.test.ts +402 -0
  143. package/src/__tests__/d1-sql.test.ts +120 -0
  144. package/src/__tests__/database-live-config.test.ts +42 -0
  145. package/src/__tests__/database-live-emitter.test.ts +56 -0
  146. package/src/__tests__/database-live-filters.test.ts +63 -0
  147. package/src/__tests__/database-live-route.test.ts +113 -0
  148. package/src/__tests__/db-sql.test.ts +163 -0
  149. package/src/__tests__/do-lifecycle.test.ts +263 -0
  150. package/src/__tests__/do-router.test.ts +729 -0
  151. package/src/__tests__/email-provider.test.ts +128 -0
  152. package/src/__tests__/email-templates.test.ts +528 -0
  153. package/src/__tests__/error-format.test.ts +250 -0
  154. package/src/__tests__/field-ops.test.ts +242 -0
  155. package/src/__tests__/functions-context.test.ts +334 -0
  156. package/src/__tests__/functions-d1-proxy.test.ts +229 -0
  157. package/src/__tests__/functions-registry-runtime-config.test.ts +17 -0
  158. package/src/__tests__/functions-route.test.ts +139 -0
  159. package/src/__tests__/internal-request.test.ts +77 -0
  160. package/src/__tests__/log-writer.test.ts +44 -0
  161. package/src/__tests__/logger.test.ts +58 -0
  162. package/src/__tests__/meta-admin-proxy.test.ts +48 -0
  163. package/src/__tests__/meta-export-coverage.test.ts +191 -0
  164. package/src/__tests__/meta-route-registration.test.ts +47 -0
  165. package/src/__tests__/namespace-dump.test.ts +28 -0
  166. package/src/__tests__/oauth-providers.test.ts +337 -0
  167. package/src/__tests__/openapi-coverage.test.ts +144 -0
  168. package/src/__tests__/pagination.test.ts +59 -0
  169. package/src/__tests__/password-policy.test.ts +191 -0
  170. package/src/__tests__/plugin-migrations.test.ts +379 -0
  171. package/src/__tests__/postgres-batch-compat.test.ts +133 -0
  172. package/src/__tests__/postgres-dialect.test.ts +328 -0
  173. package/src/__tests__/postgres-executor.test.ts +79 -0
  174. package/src/__tests__/postgres-field-ops-compat.test.ts +222 -0
  175. package/src/__tests__/postgres-schema-init.test.ts +105 -0
  176. package/src/__tests__/postgres-table-utils.test.ts +107 -0
  177. package/src/__tests__/presence.test.ts +199 -0
  178. package/src/__tests__/provider.test.ts +550 -0
  179. package/src/__tests__/public-user-profile.test.ts +339 -0
  180. package/src/__tests__/push-handlers.test.ts +179 -0
  181. package/src/__tests__/push-provider.test.ts +80 -0
  182. package/src/__tests__/push-token.test.ts +418 -0
  183. package/src/__tests__/query.test.ts +771 -0
  184. package/src/__tests__/rate-limit.test.ts +260 -0
  185. package/src/__tests__/room-access-policy.test.ts +101 -0
  186. package/src/__tests__/room-handler-context.test.ts +130 -0
  187. package/src/__tests__/room-monitoring.test.ts +138 -0
  188. package/src/__tests__/room-runtime-routing.test.ts +222 -0
  189. package/src/__tests__/room.test.ts +254 -0
  190. package/src/__tests__/route-parser.test.ts +490 -0
  191. package/src/__tests__/rules.test.ts +234 -0
  192. package/src/__tests__/runtime-surface-accounting.test.ts +120 -0
  193. package/src/__tests__/scheduled.test.ts +80 -0
  194. package/src/__tests__/schema.test.ts +1273 -0
  195. package/src/__tests__/security-hardening.test.ts +312 -0
  196. package/src/__tests__/server.unit.test.ts +333 -0
  197. package/src/__tests__/service-key-db-proxy.test.ts +650 -0
  198. package/src/__tests__/service-key-provider-bypass.test.ts +138 -0
  199. package/src/__tests__/service-key.test.ts +757 -0
  200. package/src/__tests__/smoke-skip-report.test.ts +72 -0
  201. package/src/__tests__/sms-provider.test.ts +39 -0
  202. package/src/__tests__/sql-route.test.ts +218 -0
  203. package/src/__tests__/storage-hook-context.test.ts +115 -0
  204. package/src/__tests__/totp.test.ts +200 -0
  205. package/src/__tests__/uuid.test.ts +144 -0
  206. package/src/__tests__/validation.test.ts +773 -0
  207. package/src/__tests__/websocket-pending.test.ts +163 -0
  208. package/src/_functions-registry.ts +51 -0
  209. package/src/bench-entry.ts +9 -0
  210. package/src/cloudflare-test.d.ts +1 -0
  211. package/src/durable-objects/auth-do.ts +49 -0
  212. package/src/durable-objects/database-do.ts +2240 -0
  213. package/src/durable-objects/database-live-do.ts +949 -0
  214. package/src/durable-objects/logs-do.ts +1200 -0
  215. package/src/durable-objects/room-runtime-base.ts +1604 -0
  216. package/src/durable-objects/rooms-do.ts +2191 -0
  217. package/src/generated-config.ts +6 -0
  218. package/src/index.ts +382 -0
  219. package/src/lib/admin-assets.ts +54 -0
  220. package/src/lib/admin-db-target.ts +301 -0
  221. package/src/lib/admin-routing.ts +35 -0
  222. package/src/lib/admin-user-management.ts +464 -0
  223. package/src/lib/analytics-adapter.ts +103 -0
  224. package/src/lib/analytics-query.ts +579 -0
  225. package/src/lib/auth-d1-service.ts +1193 -0
  226. package/src/lib/auth-d1.ts +1056 -0
  227. package/src/lib/auth-db-adapter.ts +289 -0
  228. package/src/lib/auth-redirect.ts +116 -0
  229. package/src/lib/cidr.ts +115 -0
  230. package/src/lib/client-ip.ts +51 -0
  231. package/src/lib/cloudflare-realtime.ts +251 -0
  232. package/src/lib/control-db.ts +36 -0
  233. package/src/lib/cron.ts +163 -0
  234. package/src/lib/d1-handler.ts +1425 -0
  235. package/src/lib/d1-schema-init.ts +255 -0
  236. package/src/lib/d1-sql.ts +33 -0
  237. package/src/lib/database-live-config.ts +24 -0
  238. package/src/lib/database-live-emitter.ts +111 -0
  239. package/src/lib/db-sql.ts +66 -0
  240. package/src/lib/do-retry.ts +36 -0
  241. package/src/lib/do-router.ts +270 -0
  242. package/src/lib/do-sql.ts +73 -0
  243. package/src/lib/email-provider.ts +379 -0
  244. package/src/lib/email-templates.ts +285 -0
  245. package/src/lib/email-translations.ts +422 -0
  246. package/src/lib/errors.ts +151 -0
  247. package/src/lib/functions.ts +2091 -0
  248. package/src/lib/hono.ts +56 -0
  249. package/src/lib/internal-request.ts +56 -0
  250. package/src/lib/jwt.ts +354 -0
  251. package/src/lib/log-writer.ts +272 -0
  252. package/src/lib/namespace-dump.ts +125 -0
  253. package/src/lib/oauth-providers.ts +1225 -0
  254. package/src/lib/op-parser.ts +99 -0
  255. package/src/lib/openapi.ts +146 -0
  256. package/src/lib/pagination.ts +19 -0
  257. package/src/lib/password-policy.ts +102 -0
  258. package/src/lib/password.ts +145 -0
  259. package/src/lib/plugin-migrations.ts +612 -0
  260. package/src/lib/postgres-executor.ts +203 -0
  261. package/src/lib/postgres-handler.ts +1102 -0
  262. package/src/lib/postgres-schema-init.ts +341 -0
  263. package/src/lib/postgres-table-utils.ts +87 -0
  264. package/src/lib/public-user-profile.ts +187 -0
  265. package/src/lib/push-provider.ts +409 -0
  266. package/src/lib/push-token.ts +294 -0
  267. package/src/lib/query-engine.ts +768 -0
  268. package/src/lib/room-monitoring.ts +97 -0
  269. package/src/lib/room-runtime.ts +14 -0
  270. package/src/lib/route-parser.ts +434 -0
  271. package/src/lib/schema.ts +538 -0
  272. package/src/lib/schemas.ts +152 -0
  273. package/src/lib/service-key.ts +419 -0
  274. package/src/lib/sms-provider.ts +230 -0
  275. package/src/lib/startup-config.ts +99 -0
  276. package/src/lib/totp.ts +242 -0
  277. package/src/lib/uuid.ts +87 -0
  278. package/src/lib/validation.ts +205 -0
  279. package/src/lib/version.ts +2 -0
  280. package/src/lib/websocket-pending.ts +40 -0
  281. package/src/middleware/auth.ts +169 -0
  282. package/src/middleware/captcha-verify.ts +217 -0
  283. package/src/middleware/cors.ts +159 -0
  284. package/src/middleware/error-handler.ts +54 -0
  285. package/src/middleware/internal-guard.ts +26 -0
  286. package/src/middleware/logger.ts +126 -0
  287. package/src/middleware/rate-limit.ts +283 -0
  288. package/src/middleware/rules.ts +475 -0
  289. package/src/routes/admin-auth.ts +447 -0
  290. package/src/routes/admin.ts +3501 -0
  291. package/src/routes/analytics-api.ts +290 -0
  292. package/src/routes/auth.ts +4222 -0
  293. package/src/routes/backup.ts +1466 -0
  294. package/src/routes/config.ts +53 -0
  295. package/src/routes/d1.ts +109 -0
  296. package/src/routes/database-live.ts +281 -0
  297. package/src/routes/functions.ts +155 -0
  298. package/src/routes/health.ts +32 -0
  299. package/src/routes/kv.ts +167 -0
  300. package/src/routes/oauth.ts +1055 -0
  301. package/src/routes/push.ts +1465 -0
  302. package/src/routes/room.ts +639 -0
  303. package/src/routes/schema-endpoint.ts +76 -0
  304. package/src/routes/sql.ts +176 -0
  305. package/src/routes/storage.ts +1674 -0
  306. package/src/routes/tables.ts +699 -0
  307. package/src/routes/users.ts +21 -0
  308. package/src/routes/vectorize.ts +372 -0
  309. package/src/types.ts +99 -0
@@ -0,0 +1,301 @@
1
+ import type {
2
+ AdminInstanceDiscovery,
3
+ AdminInstanceDiscoveryContext,
4
+ AdminInstanceDiscoveryOption,
5
+ EdgeBaseConfig,
6
+ } from '@edge-base/shared';
7
+ import { executeD1Sql } from './d1-sql.js';
8
+ import { executeDoSql } from './do-sql.js';
9
+ import { getD1BindingName, shouldRouteToD1 } from './do-router.js';
10
+ import {
11
+ ensureLocalDevPostgresSchema,
12
+ getLocalDevPostgresExecOptions,
13
+ getProviderBindingName,
14
+ withPostgresConnection,
15
+ } from './postgres-executor.js';
16
+ import { ensurePgSchema } from './postgres-schema-init.js';
17
+ import type { Env } from '../types.js';
18
+
19
+ export interface AdminDbQueryResult {
20
+ columns: string[];
21
+ rows: Record<string, unknown>[];
22
+ rowCount: number;
23
+ }
24
+
25
+ export interface AdminInstanceDiscoveryMetadata {
26
+ source: 'manual' | 'table' | 'function';
27
+ targetLabel?: string;
28
+ placeholder?: string;
29
+ helperText?: string;
30
+ }
31
+
32
+ interface ExecuteAdminDbQueryOptions {
33
+ env: Env;
34
+ config: EdgeBaseConfig;
35
+ namespace: string;
36
+ id?: string;
37
+ sql: string;
38
+ params?: unknown[];
39
+ }
40
+
41
+ interface ResolveAdminInstanceOptions {
42
+ env: Env;
43
+ config: EdgeBaseConfig;
44
+ namespace: string;
45
+ query?: string;
46
+ limit?: number;
47
+ }
48
+
49
+ function isDynamicDbBlock(
50
+ dbBlock: {
51
+ instance?: boolean;
52
+ access?: {
53
+ canCreate?: unknown;
54
+ access?: unknown;
55
+ };
56
+ } | undefined,
57
+ ): boolean {
58
+ if (!dbBlock) return false;
59
+ return !!(dbBlock.instance || dbBlock.access?.canCreate || dbBlock.access?.access);
60
+ }
61
+
62
+ function defaultManualDiscovery(): AdminInstanceDiscoveryMetadata {
63
+ return {
64
+ source: 'manual',
65
+ targetLabel: 'Target',
66
+ placeholder: 'Target ID',
67
+ helperText: 'Enter a target ID to browse records and run queries for this table.',
68
+ };
69
+ }
70
+
71
+ export function serializeAdminInstanceDiscovery(
72
+ discovery?: AdminInstanceDiscovery,
73
+ options: { fallbackManual?: boolean } = {},
74
+ ): AdminInstanceDiscoveryMetadata | undefined {
75
+ if (!discovery) {
76
+ return options.fallbackManual ? defaultManualDiscovery() : undefined;
77
+ }
78
+ return {
79
+ source: discovery.source,
80
+ targetLabel: discovery.targetLabel,
81
+ placeholder: discovery.placeholder,
82
+ helperText: discovery.helperText,
83
+ };
84
+ }
85
+
86
+ function clampLimit(value: number | undefined, fallback: number): number {
87
+ if (!Number.isFinite(value)) return fallback;
88
+ return Math.max(1, Math.min(100, Math.trunc(value ?? fallback)));
89
+ }
90
+
91
+ function quoteIdentifier(identifier: string): string {
92
+ return `"${identifier.replace(/"/g, '""')}"`;
93
+ }
94
+
95
+ function placeholder(index: number, usesPostgres: boolean): string {
96
+ return usesPostgres ? `$${index}` : '?';
97
+ }
98
+
99
+ function uniqueStrings(values: Array<string | undefined>): string[] {
100
+ const seen = new Set<string>();
101
+ const result: string[] = [];
102
+ for (const value of values) {
103
+ if (!value) continue;
104
+ if (seen.has(value)) continue;
105
+ seen.add(value);
106
+ result.push(value);
107
+ }
108
+ return result;
109
+ }
110
+
111
+ function normalizeDiscoveryItems(items: AdminInstanceDiscoveryOption[]): AdminInstanceDiscoveryOption[] {
112
+ const seen = new Set<string>();
113
+ const normalized: AdminInstanceDiscoveryOption[] = [];
114
+ for (const item of items) {
115
+ const id = `${item.id ?? ''}`.trim();
116
+ if (!id || id.includes(':') || seen.has(id)) continue;
117
+ seen.add(id);
118
+ normalized.push({
119
+ id,
120
+ label: item.label?.trim() || undefined,
121
+ description: item.description?.trim() || undefined,
122
+ });
123
+ }
124
+ return normalized;
125
+ }
126
+
127
+ export async function executeAdminDbQuery({
128
+ env,
129
+ config,
130
+ namespace,
131
+ id,
132
+ sql,
133
+ params = [],
134
+ }: ExecuteAdminDbQueryOptions): Promise<AdminDbQueryResult> {
135
+ const dbBlock = config.databases?.[namespace];
136
+ if (!dbBlock) {
137
+ throw new Error(`Namespace not found: ${namespace}`);
138
+ }
139
+
140
+ if (!id && (dbBlock.provider === 'neon' || dbBlock.provider === 'postgres')) {
141
+ const bindingName = getProviderBindingName(namespace);
142
+ const envRecord = env as unknown as Record<string, unknown>;
143
+ const hyperdrive = envRecord[bindingName] as { connectionString?: string } | undefined;
144
+ const envKey = dbBlock.connectionString ?? `${bindingName}_URL`;
145
+ const connectionString = hyperdrive?.connectionString ?? (envRecord[envKey] as string | undefined);
146
+ if (!connectionString) {
147
+ throw new Error(`PostgreSQL connection '${envKey}' not found.`);
148
+ }
149
+
150
+ const localDevOptions = getLocalDevPostgresExecOptions(env as unknown as Record<string, unknown>, namespace);
151
+ if (localDevOptions) {
152
+ await ensureLocalDevPostgresSchema(localDevOptions);
153
+ }
154
+ return withPostgresConnection(connectionString, async (query) => {
155
+ if (!localDevOptions) {
156
+ await ensurePgSchema(connectionString, namespace, dbBlock.tables ?? {}, query);
157
+ }
158
+ return query(sql, params);
159
+ }, localDevOptions);
160
+ }
161
+
162
+ if (!id && shouldRouteToD1(namespace, config)) {
163
+ const bindingName = getD1BindingName(namespace);
164
+ const d1 = (env as unknown as Record<string, unknown>)[bindingName] as D1Database | undefined;
165
+ if (!d1) {
166
+ throw new Error(`D1 binding '${bindingName}' not found.`);
167
+ }
168
+ const result = await executeD1Sql(d1, sql, params);
169
+ const rows = result.rows;
170
+ return {
171
+ columns: rows.length > 0 ? Object.keys(rows[0]) : [],
172
+ rows,
173
+ rowCount: result.rowCount,
174
+ };
175
+ }
176
+
177
+ const rows = await executeDoSql({
178
+ databaseNamespace: env.DATABASE,
179
+ namespace,
180
+ id,
181
+ query: sql,
182
+ params,
183
+ });
184
+ return {
185
+ columns: rows.length > 0 ? Object.keys(rows[0]) : [],
186
+ rows,
187
+ rowCount: rows.length,
188
+ };
189
+ }
190
+
191
+ export async function resolveAdminInstanceOptions({
192
+ env,
193
+ config,
194
+ namespace,
195
+ query = '',
196
+ limit,
197
+ }: ResolveAdminInstanceOptions): Promise<{
198
+ discovery: AdminInstanceDiscoveryMetadata;
199
+ items: AdminInstanceDiscoveryOption[];
200
+ }> {
201
+ const dbBlock = config.databases?.[namespace];
202
+ if (!dbBlock) {
203
+ throw new Error(`Namespace not found: ${namespace}`);
204
+ }
205
+ if (!isDynamicDbBlock(dbBlock)) {
206
+ throw new Error(`Namespace '${namespace}' is not dynamic.`);
207
+ }
208
+
209
+ const discovery = dbBlock.admin?.instances;
210
+ const metadata = serializeAdminInstanceDiscovery(discovery, { fallbackManual: true })!;
211
+ const normalizedQuery = query.trim();
212
+ const requestedLimit = clampLimit(limit, 12);
213
+
214
+ if (!discovery || discovery.source === 'manual') {
215
+ return { discovery: metadata, items: [] };
216
+ }
217
+
218
+ if (discovery.source === 'function') {
219
+ const ctx: AdminInstanceDiscoveryContext = {
220
+ namespace,
221
+ query: normalizedQuery,
222
+ limit: requestedLimit,
223
+ admin: {
224
+ sql: async (targetNamespace, sql, options = {}) => {
225
+ const result = await executeAdminDbQuery({
226
+ env,
227
+ config,
228
+ namespace: targetNamespace,
229
+ id: options.id,
230
+ sql,
231
+ params: options.params ?? [],
232
+ });
233
+ return result.rows;
234
+ },
235
+ },
236
+ };
237
+ const items = await Promise.resolve(discovery.resolve(ctx));
238
+ return {
239
+ discovery: metadata,
240
+ items: normalizeDiscoveryItems(Array.isArray(items) ? items : []),
241
+ };
242
+ }
243
+
244
+ const sourceNamespace = discovery.namespace;
245
+ const sourceLimit = clampLimit(discovery.limit, 12);
246
+ const effectiveLimit = Math.min(requestedLimit, sourceLimit);
247
+ const sourceDbBlock = config.databases?.[sourceNamespace];
248
+ const usesPostgres = Boolean(sourceDbBlock && !isDynamicDbBlock(sourceDbBlock) && (sourceDbBlock.provider === 'neon' || sourceDbBlock.provider === 'postgres'));
249
+ const idField = discovery.idField ?? 'id';
250
+ const labelField = discovery.labelField;
251
+ const descriptionField = discovery.descriptionField;
252
+ const orderBy = discovery.orderBy ?? labelField ?? idField;
253
+ const searchFields = uniqueStrings(discovery.searchFields ?? [idField, labelField]);
254
+ const aliasId = '__edgebase_id';
255
+ const aliasLabel = '__edgebase_label';
256
+ const aliasDescription = '__edgebase_description';
257
+ const selectParts = [
258
+ `${quoteIdentifier(idField)} AS ${quoteIdentifier(aliasId)}`,
259
+ ];
260
+ if (labelField) {
261
+ selectParts.push(`${quoteIdentifier(labelField)} AS ${quoteIdentifier(aliasLabel)}`);
262
+ }
263
+ if (descriptionField) {
264
+ selectParts.push(`${quoteIdentifier(descriptionField)} AS ${quoteIdentifier(aliasDescription)}`);
265
+ }
266
+
267
+ const params: unknown[] = [];
268
+ let sql = `SELECT ${selectParts.join(', ')} FROM ${quoteIdentifier(discovery.table)}`;
269
+ if (normalizedQuery && searchFields.length > 0) {
270
+ const likeValue = `%${normalizedQuery.toLowerCase()}%`;
271
+ const predicates = searchFields.map((field) => {
272
+ params.push(likeValue);
273
+ return `LOWER(CAST(${quoteIdentifier(field)} AS TEXT)) LIKE ${placeholder(params.length, usesPostgres)}`;
274
+ });
275
+ sql += ` WHERE ${predicates.join(' OR ')}`;
276
+ }
277
+ sql += ` ORDER BY ${quoteIdentifier(orderBy)} ASC`;
278
+ params.push(effectiveLimit);
279
+ sql += ` LIMIT ${placeholder(params.length, usesPostgres)}`;
280
+
281
+ const result = await executeAdminDbQuery({
282
+ env,
283
+ config,
284
+ namespace: sourceNamespace,
285
+ sql,
286
+ params,
287
+ });
288
+
289
+ const items = normalizeDiscoveryItems(
290
+ result.rows.map((row) => ({
291
+ id: `${row[aliasId] ?? ''}`,
292
+ label: row[aliasLabel] == null ? undefined : `${row[aliasLabel]}`,
293
+ description: row[aliasDescription] == null ? undefined : `${row[aliasDescription]}`,
294
+ })),
295
+ );
296
+
297
+ return {
298
+ discovery: metadata,
299
+ items,
300
+ };
301
+ }
@@ -0,0 +1,35 @@
1
+ function normalizeOrigin(value: string | undefined): string | null {
2
+ if (!value) return null;
3
+ const trimmed = value.trim().replace(/\/+$/, '');
4
+ if (!trimmed) return null;
5
+ return trimmed;
6
+ }
7
+
8
+ export function resolveAdminRedirectTarget(
9
+ requestUrl: string,
10
+ adminOrigin: string | undefined,
11
+ ): string | null {
12
+ const origin = normalizeOrigin(adminOrigin);
13
+ if (!origin) return null;
14
+
15
+ const request = new URL(requestUrl);
16
+ let pathname = request.pathname;
17
+ if (pathname === '/' || pathname === '') {
18
+ pathname = '/';
19
+ } else if (pathname === '/admin' || pathname === '/admin/') {
20
+ pathname = '/';
21
+ } else if (pathname.startsWith('/admin/')) {
22
+ pathname = pathname.slice('/admin'.length) || '/';
23
+ }
24
+
25
+ const target = new URL(pathname, `${origin}/`);
26
+ target.search = request.search;
27
+ target.hash = request.hash;
28
+ return target.toString();
29
+ }
30
+
31
+ export function resolveAdminFaviconTarget(adminOrigin: string | undefined): string | null {
32
+ const origin = normalizeOrigin(adminOrigin);
33
+ if (!origin) return null;
34
+ return `${origin}/favicon.svg`;
35
+ }