@edge-base/server 0.2.3 → 0.2.4

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 (82) hide show
  1. package/admin-build/_app/immutable/chunks/{CzSAxmuj.js → 5RQRbp5q.js} +1 -1
  2. package/admin-build/_app/immutable/chunks/{B5Nwfelm.js → BME_U9TJ.js} +1 -1
  3. package/admin-build/_app/immutable/chunks/{Dlty5069.js → BYI6CUvd.js} +1 -1
  4. package/admin-build/_app/immutable/chunks/{A_3UuvCe.js → BgDzp0i0.js} +1 -1
  5. package/admin-build/_app/immutable/chunks/{DRqPU3wD.js → BjWZuf8W.js} +1 -1
  6. package/admin-build/_app/immutable/chunks/{Dc1-6Po6.js → C6lpZLE2.js} +1 -1
  7. package/admin-build/_app/immutable/chunks/{BxoNtYHK.js → D5GswVnI.js} +3 -3
  8. package/admin-build/_app/immutable/chunks/DBsVqhuh.js +1 -0
  9. package/admin-build/_app/immutable/chunks/{nZvorU8i.js → DYaCRWMA.js} +1 -1
  10. package/admin-build/_app/immutable/chunks/D__dwMuW.js +1 -0
  11. package/admin-build/_app/immutable/chunks/{DpVAayDG.js → Dj-E9-FO.js} +1 -1
  12. package/admin-build/_app/immutable/chunks/{DCvwWZrm.js → Dj0QUuOf.js} +1 -1
  13. package/admin-build/_app/immutable/chunks/{B-_-hJ9o.js → XQM1k9PM.js} +1 -1
  14. package/admin-build/_app/immutable/chunks/{Du5vWVa2.js → fYEKMQ-Z.js} +1 -1
  15. package/admin-build/_app/immutable/chunks/{CZ0TVkCa.js → g_-Kpxu3.js} +1 -1
  16. package/admin-build/_app/immutable/chunks/{DCKcAiQH.js → wCNueVYy.js} +1 -1
  17. package/admin-build/_app/immutable/entry/{app.CfrmEXPD.js → app.C8ylfBe6.js} +2 -2
  18. package/admin-build/_app/immutable/entry/start.CtsqDyfj.js +1 -0
  19. package/admin-build/_app/immutable/nodes/{0.Cn2BZ4da.js → 0.CJJ6HZbp.js} +1 -1
  20. package/admin-build/_app/immutable/nodes/{1.Dv4LX_Co.js → 1.B4sI5cB4.js} +1 -1
  21. package/admin-build/_app/immutable/nodes/{10.DPVv3kat.js → 10.D6hvCer6.js} +1 -1
  22. package/admin-build/_app/immutable/nodes/{11.CiCb6Ayu.js → 11.Dx7b8aQ5.js} +1 -1
  23. package/admin-build/_app/immutable/nodes/{12.CIPyeekF.js → 12.Bqmy5KIF.js} +1 -1
  24. package/admin-build/_app/immutable/nodes/{13.Z15Lt36e.js → 13.CC6KpXgS.js} +1 -1
  25. package/admin-build/_app/immutable/nodes/{14.s0l5bAq3.js → 14.yCo1Ix8E.js} +1 -1
  26. package/admin-build/_app/immutable/nodes/{15.UwSSNO76.js → 15.co0UfPlh.js} +1 -1
  27. package/admin-build/_app/immutable/nodes/{16.qiD8i883.js → 16.D0xkPUBW.js} +1 -1
  28. package/admin-build/_app/immutable/nodes/{17.Dy3dcSvu.js → 17.CebNqPeh.js} +1 -1
  29. package/admin-build/_app/immutable/nodes/{18.DeXyPYsO.js → 18.JUoLOZxh.js} +1 -1
  30. package/admin-build/_app/immutable/nodes/{19.CAbuyS6w.js → 19.ND8kmQJe.js} +1 -1
  31. package/admin-build/_app/immutable/nodes/{20.Bec0T7un.js → 20.DYb-q3W8.js} +1 -1
  32. package/admin-build/_app/immutable/nodes/21.cz3IN9Cc.js +1 -0
  33. package/admin-build/_app/immutable/nodes/{22.CdVprrv2.js → 22.UOzm8WYV.js} +1 -1
  34. package/admin-build/_app/immutable/nodes/{23.Y8RzVLoF.js → 23.BLgq21om.js} +1 -1
  35. package/admin-build/_app/immutable/nodes/{24.CWhHYFBx.js → 24.DN9usmUs.js} +1 -1
  36. package/admin-build/_app/immutable/nodes/{25.wCBplOVt.js → 25.BddRfAyE.js} +1 -1
  37. package/admin-build/_app/immutable/nodes/{26.Cod_JRFK.js → 26.Dl6XHIeT.js} +1 -1
  38. package/admin-build/_app/immutable/nodes/{27.BO2HVMu9.js → 27.D0iNwALG.js} +1 -1
  39. package/admin-build/_app/immutable/nodes/{28.DxG-FBVQ.js → 28.9dKQmdGi.js} +1 -1
  40. package/admin-build/_app/immutable/nodes/{29.CjGqWGvE.js → 29.wXzfJUXp.js} +1 -1
  41. package/admin-build/_app/immutable/nodes/{3.By3_OmdZ.js → 3.z8ut3jS-.js} +1 -1
  42. package/admin-build/_app/immutable/nodes/{30.M_H7Htpq.js → 30.BtZETNsL.js} +1 -1
  43. package/admin-build/_app/immutable/nodes/{31.DEU18izM.js → 31.CYonj2Jh.js} +1 -1
  44. package/admin-build/_app/immutable/nodes/{4.DeYhKtzJ.js → 4.COtDPQ9b.js} +1 -1
  45. package/admin-build/_app/immutable/nodes/{5.9WLgxhrD.js → 5.CTRCeIhp.js} +1 -1
  46. package/admin-build/_app/immutable/nodes/{6.BdT2i_dd.js → 6.ChHi3QkR.js} +1 -1
  47. package/admin-build/_app/immutable/nodes/{7.CHq0s4K6.js → 7.CCMtr6Ac.js} +1 -1
  48. package/admin-build/_app/immutable/nodes/{8.DuvRw-XZ.js → 8.DpWJ-X_-.js} +1 -1
  49. package/admin-build/_app/immutable/nodes/{9.C2Ub82wn.js → 9.DOkvfmir.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 -3
  53. package/src/__tests__/admin-data-routes.test.ts +29 -0
  54. package/src/__tests__/database-do-route-validation.test.ts +105 -0
  55. package/src/__tests__/database-live-route.test.ts +82 -0
  56. package/src/__tests__/do-router.test.ts +116 -0
  57. package/src/__tests__/functions-context.test.ts +84 -0
  58. package/src/__tests__/functions-d1-proxy.test.ts +54 -0
  59. package/src/__tests__/plugin-migration-routing.test.ts +32 -0
  60. package/src/__tests__/provider-aware-sql.test.ts +9 -3
  61. package/src/__tests__/scheduled.test.ts +55 -0
  62. package/src/__tests__/service-key-db-proxy.test.ts +122 -1
  63. package/src/__tests__/sql-route.test.ts +66 -0
  64. package/src/__tests__/table-hook-runtime.test.ts +137 -0
  65. package/src/durable-objects/database-do.ts +36 -45
  66. package/src/index.ts +12 -6
  67. package/src/lib/d1-handler.ts +10 -21
  68. package/src/lib/do-router.ts +135 -3
  69. package/src/lib/functions.ts +4 -3
  70. package/src/lib/internal-transport.ts +28 -12
  71. package/src/lib/plugin-migration-routing.ts +28 -0
  72. package/src/lib/postgres-handler.ts +12 -20
  73. package/src/lib/provider-aware-sql.ts +19 -15
  74. package/src/lib/table-hook-runtime.ts +62 -0
  75. package/src/routes/admin.ts +41 -41
  76. package/src/routes/database-live.ts +110 -12
  77. package/src/routes/sql.ts +22 -17
  78. package/src/routes/tables.ts +42 -29
  79. package/admin-build/_app/immutable/chunks/DiyBpamp.js +0 -1
  80. package/admin-build/_app/immutable/chunks/byv2rTy8.js +0 -1
  81. package/admin-build/_app/immutable/entry/start.l1WvHznQ.js +0 -1
  82. package/admin-build/_app/immutable/nodes/21.DuDYelMY.js +0 -1
@@ -23,7 +23,16 @@ import {
23
23
  import { hashPassword, verifyPassword } from '../lib/password.js';
24
24
  import { generateId } from '../lib/uuid.js';
25
25
  import { validateKey, buildConstraintCtx, extractBearerToken, resolveServiceKeyCandidate } from '../lib/service-key.js';
26
- import { parseConfig, getDbDoName, getD1BindingName, shouldRouteToD1 } from '../lib/do-router.js';
26
+ import {
27
+ formatDbTargetValidationIssue,
28
+ getD1BindingName,
29
+ getDbDoName,
30
+ isDynamicDbBlock,
31
+ normalizeDbInstanceId,
32
+ parseConfig,
33
+ resolveDbTarget,
34
+ shouldRouteToD1,
35
+ } from '../lib/do-router.js';
27
36
  import { handleD1Request, d1BatchImport } from '../lib/d1-handler.js';
28
37
  import { fetchDOWithRetry } from '../lib/do-retry.js';
29
38
  import { dumpNamespaceTables } from '../lib/namespace-dump.js';
@@ -734,19 +743,6 @@ function getTableDO(env: Env, tableName: string, config: ReturnType<typeof parse
734
743
  return { stub: env.DATABASE.get(env.DATABASE.idFromName(doName)), doName };
735
744
  }
736
745
 
737
- function isDynamicDbBlock(
738
- dbBlock: {
739
- instance?: boolean;
740
- access?: {
741
- canCreate?: unknown;
742
- access?: unknown;
743
- };
744
- } | undefined,
745
- ): boolean {
746
- if (!dbBlock) return false;
747
- return !!(dbBlock.instance || dbBlock.access?.canCreate || dbBlock.access?.access);
748
- }
749
-
750
746
  function getEffectiveDbProvider(namespace: string, config: ReturnType<typeof parseConfig>): 'do' | 'd1' | 'postgres' | 'neon' {
751
747
  const dbBlock = config.databases?.[namespace];
752
748
  if (!dbBlock) return 'do';
@@ -763,10 +759,7 @@ function getEffectiveDbProvider(namespace: string, config: ReturnType<typeof par
763
759
  }
764
760
 
765
761
  function getRequestedInstanceId(c: { req: { query: (name: string) => string | undefined } }): string | undefined {
766
- const raw = c.req.query('instanceId');
767
- if (!raw) return undefined;
768
- const trimmed = raw.trim();
769
- return trimmed.length > 0 ? trimmed : undefined;
762
+ return normalizeDbInstanceId(c.req.query('instanceId'));
770
763
  }
771
764
 
772
765
  function validateAdminTableInstanceId(
@@ -774,28 +767,27 @@ function validateAdminTableInstanceId(
774
767
  config: ReturnType<typeof parseConfig>,
775
768
  instanceId: string | undefined,
776
769
  ): Response | null {
777
- const dynamic = isDynamicDbBlock(config.databases?.[namespace]);
778
- if (!instanceId) {
779
- if (dynamic) {
780
- return new Response(
781
- JSON.stringify({
782
- code: 400,
783
- message: `instanceId is required for dynamic namespace '${namespace}'`,
784
- }),
785
- {
786
- status: 400,
787
- headers: { 'Content-Type': 'application/json' },
788
- },
789
- );
790
- }
770
+ const target = resolveDbTarget(config, namespace, instanceId);
771
+ if (target.ok) {
791
772
  return null;
792
773
  }
793
-
794
- if (instanceId.includes(':')) {
774
+ if (target.status !== 400) {
775
+ return new Response(
776
+ JSON.stringify({
777
+ code: target.status,
778
+ message: formatDbTargetValidationIssue(target.issue, namespace),
779
+ }),
780
+ {
781
+ status: target.status,
782
+ headers: { 'Content-Type': 'application/json' },
783
+ },
784
+ );
785
+ }
786
+ if (target.issue === 'instance_id_invalid') {
795
787
  return new Response(
796
788
  JSON.stringify({
797
789
  code: 400,
798
- message: 'instanceId must not contain \':\'',
790
+ message: formatDbTargetValidationIssue(target.issue, namespace),
799
791
  }),
800
792
  {
801
793
  status: 400,
@@ -803,8 +795,16 @@ function validateAdminTableInstanceId(
803
795
  },
804
796
  );
805
797
  }
806
-
807
- return null;
798
+ return new Response(
799
+ JSON.stringify({
800
+ code: 400,
801
+ message: formatDbTargetValidationIssue(target.issue, namespace),
802
+ }),
803
+ {
804
+ status: 400,
805
+ headers: { 'Content-Type': 'application/json' },
806
+ },
807
+ );
808
808
  }
809
809
 
810
810
  async function restoreAdminNamespaceTables(
@@ -974,7 +974,7 @@ api.openapi(adminGetTableRecords, async (c) => {
974
974
  const name = c.req.param('name')!;
975
975
  const config = parseConfig(c.env);
976
976
  const namespace = findNamespaceForTable(name, config);
977
- const instanceId = isDynamicDbBlock(config.databases?.[namespace]) ? getRequestedInstanceId(c) : undefined;
977
+ const instanceId = getRequestedInstanceId(c);
978
978
  const instanceError = validateAdminTableInstanceId(namespace, config, instanceId);
979
979
  if (instanceError) return instanceError;
980
980
 
@@ -1027,7 +1027,7 @@ api.openapi(adminCreateTableRecord, async (c) => {
1027
1027
  const name = c.req.param('name')!;
1028
1028
  const config = parseConfig(c.env);
1029
1029
  const namespace = findNamespaceForTable(name, config);
1030
- const instanceId = isDynamicDbBlock(config.databases?.[namespace]) ? getRequestedInstanceId(c) : undefined;
1030
+ const instanceId = getRequestedInstanceId(c);
1031
1031
  const instanceError = validateAdminTableInstanceId(namespace, config, instanceId);
1032
1032
  if (instanceError) return instanceError;
1033
1033
 
@@ -1081,7 +1081,7 @@ api.openapi(adminUpdateTableRecord, async (c) => {
1081
1081
  const id = c.req.param('id')!;
1082
1082
  const config = parseConfig(c.env);
1083
1083
  const namespace = findNamespaceForTable(name, config);
1084
- const instanceId = isDynamicDbBlock(config.databases?.[namespace]) ? getRequestedInstanceId(c) : undefined;
1084
+ const instanceId = getRequestedInstanceId(c);
1085
1085
  const instanceError = validateAdminTableInstanceId(namespace, config, instanceId);
1086
1086
  if (instanceError) return instanceError;
1087
1087
 
@@ -1129,7 +1129,7 @@ api.openapi(adminDeleteTableRecord, async (c) => {
1129
1129
  const id = c.req.param('id')!;
1130
1130
  const config = parseConfig(c.env);
1131
1131
  const namespace = findNamespaceForTable(name, config);
1132
- const instanceId = isDynamicDbBlock(config.databases?.[namespace]) ? getRequestedInstanceId(c) : undefined;
1132
+ const instanceId = getRequestedInstanceId(c);
1133
1133
  const instanceError = validateAdminTableInstanceId(namespace, config, instanceId);
1134
1134
  if (instanceError) return instanceError;
1135
1135
 
@@ -9,7 +9,12 @@ import {
9
9
  DATABASE_LIVE_HUB_DO_NAME,
10
10
  isDbLiveChannel,
11
11
  } from '../lib/database-live-emitter.js';
12
- import { parseConfig } from '../lib/do-router.js';
12
+ import {
13
+ formatDbTargetValidationIssue,
14
+ isDynamicDbBlock,
15
+ parseConfig,
16
+ resolveDbTarget,
17
+ } from '../lib/do-router.js';
13
18
  import { validateKey, buildConstraintCtx } from '../lib/service-key.js';
14
19
  import { getTrustedClientIp } from '../lib/client-ip.js';
15
20
  import {
@@ -50,18 +55,107 @@ const dbConnectDiagnosticSchema = z.object({
50
55
  maxPending: z.number().optional(),
51
56
  });
52
57
 
53
- function resolveDatabaseLiveChannel(query: {
58
+ function resolveStructuredDatabaseLiveChannel(
59
+ config: ReturnType<typeof parseConfig>,
60
+ query: {
61
+ namespace?: string;
62
+ instanceId?: string;
63
+ table?: string;
64
+ docId?: string;
65
+ },
66
+ ): { ok: true; channel: string } | { ok: false; message: string } {
67
+ if (!query.namespace || !query.table) {
68
+ return { ok: false, message: 'Database subscription target required' };
69
+ }
70
+
71
+ const target = resolveDbTarget(config, query.namespace, query.instanceId);
72
+ if (!target.ok) {
73
+ return {
74
+ ok: false,
75
+ message: formatDbTargetValidationIssue(target.issue, query.namespace),
76
+ };
77
+ }
78
+ if (!target.value.dbBlock.tables?.[query.table]) {
79
+ return {
80
+ ok: false,
81
+ message: `Table '${query.table}' not found in database '${query.namespace}'`,
82
+ };
83
+ }
84
+
85
+ const channel = buildDbLiveChannel(
86
+ query.namespace,
87
+ query.table,
88
+ target.value.instanceId,
89
+ query.docId,
90
+ );
91
+ if (!isDbLiveChannel(channel)) {
92
+ return { ok: false, message: 'Invalid database subscription target' };
93
+ }
94
+
95
+ return { ok: true, channel };
96
+ }
97
+
98
+ function resolveDatabaseLiveChannel(
99
+ config: ReturnType<typeof parseConfig>,
100
+ query: {
54
101
  channel?: string;
55
102
  namespace?: string;
56
103
  instanceId?: string;
57
104
  table?: string;
58
105
  docId?: string;
59
- }): string | null {
106
+ }): { ok: true; channel: string } | { ok: false; message: string } {
60
107
  if (query.channel) {
61
- return isDbLiveChannel(query.channel) ? query.channel : null;
108
+ if (!isDbLiveChannel(query.channel)) {
109
+ return {
110
+ ok: false,
111
+ message: `Database live only supports DB channels: ${query.channel}`,
112
+ };
113
+ }
114
+
115
+ const parts = query.channel.split(':');
116
+ const namespace = parts[1];
117
+ if (!namespace) {
118
+ return { ok: false, message: 'Database subscription target required' };
119
+ }
120
+
121
+ const dbBlock = config.databases?.[namespace];
122
+ if (!dbBlock) {
123
+ return {
124
+ ok: false,
125
+ message: formatDbTargetValidationIssue('namespace_not_found', namespace),
126
+ };
127
+ }
128
+
129
+ const dynamic = isDynamicDbBlock(dbBlock);
130
+ if (dynamic && parts.length < 4) {
131
+ return {
132
+ ok: false,
133
+ message: formatDbTargetValidationIssue('instance_id_required', namespace),
134
+ };
135
+ }
136
+ if (!dynamic && parts.length > 4) {
137
+ return {
138
+ ok: false,
139
+ message: formatDbTargetValidationIssue('instance_id_not_allowed', namespace),
140
+ };
141
+ }
142
+
143
+ const structured = dynamic
144
+ ? {
145
+ namespace,
146
+ instanceId: parts[2],
147
+ table: parts[3],
148
+ docId: parts[4],
149
+ }
150
+ : {
151
+ namespace,
152
+ table: parts[2],
153
+ docId: parts[3],
154
+ };
155
+ return resolveStructuredDatabaseLiveChannel(config, structured);
62
156
  }
63
- if (!query.namespace || !query.table) return null;
64
- return buildDbLiveChannel(query.namespace, query.table, query.instanceId, query.docId);
157
+
158
+ return resolveStructuredDatabaseLiveChannel(config, query);
65
159
  }
66
160
 
67
161
  function getPendingKey(ip: string): string {
@@ -85,7 +179,8 @@ const checkDatabaseConnection = createRoute({
85
179
  });
86
180
 
87
181
  databaseLiveRoute.openapi(checkDatabaseConnection, async (c) => {
88
- const channel = resolveDatabaseLiveChannel({
182
+ const config = parseConfig(c.env);
183
+ const channelResult = resolveDatabaseLiveChannel(config, {
89
184
  channel: c.req.query('channel') ?? undefined,
90
185
  namespace: c.req.query('namespace') ?? undefined,
91
186
  instanceId: c.req.query('instanceId') ?? undefined,
@@ -93,14 +188,15 @@ databaseLiveRoute.openapi(checkDatabaseConnection, async (c) => {
93
188
  docId: c.req.query('docId') ?? undefined,
94
189
  });
95
190
 
96
- if (!channel) {
191
+ if (!channelResult.ok) {
97
192
  return c.json({
98
193
  ok: false,
99
194
  type: 'db_connect_invalid_request',
100
195
  category: 'request',
101
- message: 'Database subscription target required',
196
+ message: channelResult.message,
102
197
  }, 400);
103
198
  }
199
+ const channel = channelResult.channel;
104
200
 
105
201
  const ip = getTrustedClientIp(c.env, c.req) ?? 'unknown';
106
202
  const kvKey = getPendingKey(ip);
@@ -224,16 +320,18 @@ databaseLiveRoute.openapi(connectDatabaseSubscription, async (c) => {
224
320
  return c.json({ code: 400, message: 'Expected WebSocket upgrade' }, 400);
225
321
  }
226
322
 
227
- const channel = resolveDatabaseLiveChannel({
323
+ const config = parseConfig(c.env);
324
+ const channelResult = resolveDatabaseLiveChannel(config, {
228
325
  channel: c.req.query('channel') ?? undefined,
229
326
  namespace: c.req.query('namespace') ?? undefined,
230
327
  instanceId: c.req.query('instanceId') ?? undefined,
231
328
  table: c.req.query('table') ?? undefined,
232
329
  docId: c.req.query('docId') ?? undefined,
233
330
  });
234
- if (!channel) {
235
- return c.json({ code: 400, message: 'Database subscription target required' }, 400);
331
+ if (!channelResult.ok) {
332
+ return c.json({ code: 400, message: channelResult.message }, 400);
236
333
  }
334
+ const channel = channelResult.channel;
237
335
 
238
336
  const ip = getTrustedClientIp(c.env, c.req) ?? 'unknown';
239
337
  const kvKey = getPendingKey(ip);
package/src/routes/sql.ts CHANGED
@@ -23,7 +23,11 @@
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 } from '../lib/do-router.js';
26
+ import {
27
+ formatDbTargetValidationIssue,
28
+ parseConfig,
29
+ resolveDbTarget,
30
+ } from '../lib/do-router.js';
27
31
  import { validateKey, buildConstraintCtx } from '../lib/service-key.js';
28
32
  import {
29
33
  zodDefaultHook,
@@ -65,6 +69,10 @@ const executeSql = createRoute({
65
69
  description: 'Forbidden',
66
70
  content: { 'application/json': { schema: errorResponseSchema } },
67
71
  },
72
+ 404: {
73
+ description: 'Namespace not found',
74
+ content: { 'application/json': { schema: errorResponseSchema } },
75
+ },
68
76
  },
69
77
  });
70
78
 
@@ -84,30 +92,27 @@ sqlRoute.openapi(executeSql, async (c) => {
84
92
  if (id !== undefined && id !== null && typeof id !== 'string') {
85
93
  return c.json({ code: 400, message: 'id must be a string' }, 400);
86
94
  }
87
- if (id && id.includes(':')) {
88
- return c.json({ code: 400, message: "id must not contain ':' (§2)" }, 400);
89
- }
90
95
  if (!sql || typeof sql !== 'string') {
91
96
  return c.json({ code: 400, message: 'sql is required' }, 400);
92
97
  }
93
98
 
94
99
  // Validate namespace is declared in databases config (§1)
95
100
  const config = parseConfig(c.env);
96
- const dbBlock = config.databases?.[namespace];
97
- if (!dbBlock) {
98
- return c.json({ code: 404, message: `Namespace '${namespace}' not found in config` }, 404);
99
- }
100
- const isDynamicNamespace = !!(
101
- dbBlock.instance ||
102
- dbBlock.access?.canCreate ||
103
- dbBlock.access?.access
104
- );
105
- if (isDynamicNamespace && !id) {
101
+ const target = resolveDbTarget(config, namespace, id);
102
+ if (!target.ok) {
106
103
  return c.json(
107
- { code: 400, message: `id is required for dynamic namespace '${namespace}'` },
108
- 400,
104
+ {
105
+ code: target.status,
106
+ message: formatDbTargetValidationIssue(target.issue, namespace, {
107
+ namespaceLabel: 'Namespace',
108
+ instanceIdLabel: 'id',
109
+ includeSectionRef: target.issue === 'instance_id_invalid',
110
+ }),
111
+ },
112
+ target.status,
109
113
  );
110
114
  }
115
+ const { instanceId } = target.value;
111
116
 
112
117
  // Service Key required AND validated
113
118
  const { result: skResult } = validateKey(
@@ -133,7 +138,7 @@ sqlRoute.openapi(executeSql, async (c) => {
133
138
  databaseNamespace: c.env.DATABASE,
134
139
  },
135
140
  namespace,
136
- id,
141
+ instanceId,
137
142
  sql,
138
143
  params ?? [],
139
144
  );
@@ -22,7 +22,13 @@
22
22
  */
23
23
  import { OpenAPIHono, createRoute, z, type HonoEnv } from '../lib/hono.js';
24
24
  import type { Context } from 'hono';
25
- import { getDbDoName, parseConfig, shouldRouteToD1 } from '../lib/do-router.js';
25
+ import {
26
+ formatDbTargetValidationIssue,
27
+ getDbDoName,
28
+ parseConfig,
29
+ resolveDbTarget,
30
+ shouldRouteToD1,
31
+ } from '../lib/do-router.js';
26
32
  import { fetchDOWithRetry } from '../lib/do-retry.js';
27
33
  import {
28
34
  queryParamsSchema, listResponseSchema, recordResponseSchema,
@@ -562,7 +568,8 @@ tablesRoute.openapi(dbDeleteRecord, async (c) => {
562
568
  * - provider='do' (default): forwards to DatabaseDO instance
563
569
  * - provider='neon'|'postgres': handles in Worker via postgres-handler
564
570
  *
565
- * Handles §36 canCreate 2-RTT flow for dynamic DOs.
571
+ * Handles §36 canCreate 2-RTT flow for dynamic DOs and auto-retries bootstrap
572
+ * for single-instance provider='do' namespaces.
566
573
  */
567
574
  async function routeToDO(
568
575
  c: Context<HonoEnv>,
@@ -574,14 +581,17 @@ async function routeToDO(
574
581
  const tableName = decodeURIComponent(_tableName);
575
582
  // Check provider — route to D1 or PostgreSQL handler if not DO
576
583
  const config = parseConfig(c.env);
577
- const dbBlock = config.databases?.[namespace];
578
-
579
- if (!dbBlock) {
580
- return c.json({ code: 404, message: `Database '${namespace}' not found in config.` }, 404);
584
+ const target = resolveDbTarget(config, namespace, instanceId);
585
+ if (!target.ok) {
586
+ return c.json({
587
+ code: target.status,
588
+ message: formatDbTargetValidationIssue(target.issue, namespace),
589
+ }, target.status);
581
590
  }
591
+ const { dbBlock, dynamic: dynamicDbBlock, instanceId: normalizedInstanceId } = target.value;
582
592
 
583
593
  // D1 route: single-instance namespaces without dynamic instanceId
584
- if (!instanceId && shouldRouteToD1(namespace, config)) {
594
+ if (!normalizedInstanceId && shouldRouteToD1(namespace, config)) {
585
595
  return handleD1Request(c as unknown as Context<HonoEnv>, namespace, tableName, doPath);
586
596
  }
587
597
 
@@ -590,9 +600,10 @@ async function routeToDO(
590
600
  if (provider === 'neon' || provider === 'postgres') {
591
601
  return handlePgRequest(c as unknown as Context<HonoEnv>, namespace, tableName, doPath);
592
602
  }
603
+ const requiresCreateAuthorization = dynamicDbBlock;
593
604
 
594
605
  // Build DO name: 'shared' | 'workspace:ws-456' (§2)
595
- const doName = getDbDoName(namespace, instanceId);
606
+ const doName = getDbDoName(namespace, normalizedInstanceId);
596
607
 
597
608
  const doId = c.env.DATABASE.idFromName(doName);
598
609
  const stub = c.env.DATABASE.get(doId);
@@ -648,26 +659,33 @@ async function routeToDO(
648
659
  body: bodyText,
649
660
  }, { safeToRetry });
650
661
 
651
- // §36: Handle needsCreate 2-RTT flow for dynamic DOs (not 'shared' or static)
652
- if (res.status === 201 && instanceId) {
662
+ // §36: Handle needsCreate 2-RTT flow for dynamic DOs and bootstrap retry for
663
+ // single-instance provider='do' namespaces.
664
+ if (res.status === 201) {
653
665
  const body = await res.clone().json().catch(() => null) as
654
666
  | { needsCreate?: boolean; namespace?: string; id?: string }
655
667
  | null;
656
668
  if (body?.needsCreate) {
657
- // Evaluate DbLevelRules.canCreate(auth, id) in Worker (#133 §36)
658
- const config = parseConfig(c.env);
659
- const dbBlock = config.databases?.[namespace];
660
- const canCreateFn = dbBlock?.access?.canCreate;
661
-
662
- // Internal/admin DB proxy calls already bypass row-level rules.
663
- // Dynamic DB bootstrap must honor that bypass too, otherwise
664
- // context.admin.db(namespace, id).table(...).insert() fails on first write.
665
- let allowed = isServiceKey;
666
- if (!allowed && canCreateFn) {
667
- try {
668
- allowed = await Promise.resolve(canCreateFn(auth ?? null, body.id ?? instanceId));
669
- } catch {
670
- allowed = false; // fail-closed
669
+ let allowed = !requiresCreateAuthorization;
670
+
671
+ if (!allowed) {
672
+ // Evaluate DbLevelRules.canCreate(auth, id) in Worker (#133 §36)
673
+ const config = parseConfig(c.env);
674
+ const currentDbBlock = config.databases?.[namespace];
675
+ const canCreateFn = currentDbBlock?.access?.canCreate;
676
+
677
+ // Internal/admin DB proxy calls already bypass row-level rules.
678
+ // Dynamic DB bootstrap must honor that bypass too, otherwise
679
+ // context.admin.db(namespace, id).table(...).insert() fails on first write.
680
+ allowed = isServiceKey;
681
+ if (!allowed && canCreateFn) {
682
+ try {
683
+ allowed = await Promise.resolve(
684
+ canCreateFn(auth ?? null, body.id ?? normalizedInstanceId ?? namespace),
685
+ );
686
+ } catch {
687
+ allowed = false; // fail-closed
688
+ }
671
689
  }
672
690
  }
673
691
 
@@ -681,11 +699,6 @@ async function routeToDO(
681
699
  // Authorized — retry with X-DO-Create-Authorized header
682
700
  const retryHeaders = new Headers(headers);
683
701
  retryHeaders.set('X-DO-Create-Authorized', '1');
684
- const retryInit: RequestInit = { method: c.req.raw.method, headers: retryHeaders };
685
- // BUG-008 fix: use pre-read body text (stream already consumed above)
686
- if (c.req.raw.method !== 'GET' && c.req.raw.method !== 'HEAD') {
687
- retryInit.body = bodyText ?? null;
688
- }
689
702
  // needsCreate 2-RTT: DO is empty at this point, safe to retry
690
703
  return fetchDOWithRetry(stub, doUrl, {
691
704
  method: c.req.raw.method,
@@ -1 +0,0 @@
1
- var x=t=>{throw TypeError(t)};var B=(t,e,n)=>e.has(t)||x("Cannot "+n);var a=(t,e,n)=>(B(t,e,"read from private field"),n?n.call(t):e.get(t)),c=(t,e,n)=>e.has(t)?x("Cannot add the same private member more than once"):e instanceof WeakSet?e.add(t):e.set(t,n);import{w as G,o as I}from"./Bn2NtlTj.js";import{d as u,g as f,b as d}from"./BdTBlfLy.js";new URL("sveltekit-internal://");function se(t,e){return t==="/"||e==="ignore"?t:e==="never"?t.endsWith("/")?t.slice(0,-1):t:e==="always"&&!t.endsWith("/")?t+"/":t}function ae(t){return t.split("%25").map(decodeURI).join("%25")}function oe(t){for(const e in t)t[e]=decodeURIComponent(t[e]);return t}function ie({href:t}){return t.split("#")[0]}function W(...t){let e=5381;for(const n of t)if(typeof n=="string"){let r=n.length;for(;r;)e=e*33^n.charCodeAt(--r)}else if(ArrayBuffer.isView(n)){const r=new Uint8Array(n.buffer,n.byteOffset,n.byteLength);let s=r.length;for(;s;)e=e*33^r[--s]}else throw new TypeError("value must be a string or TypedArray");return(e>>>0).toString(36)}new TextEncoder;new TextDecoder;function X(t){const e=atob(t),n=new Uint8Array(e.length);for(let r=0;r<e.length;r++)n[r]=e.charCodeAt(r);return n}const z=window.fetch;window.fetch=(t,e)=>((t instanceof Request?t.method:(e==null?void 0:e.method)||"GET")!=="GET"&&b.delete(U(t)),z(t,e));const b=new Map;function le(t,e){const n=U(t,e),r=document.querySelector(n);if(r!=null&&r.textContent){r.remove();let{body:s,...l}=JSON.parse(r.textContent);const o=r.getAttribute("data-ttl");return o&&b.set(n,{body:s,init:l,ttl:1e3*Number(o)}),r.getAttribute("data-b64")!==null&&(s=X(s)),Promise.resolve(new Response(s,l))}return window.fetch(t,e)}function ce(t,e,n){if(b.size>0){const r=U(t,n),s=b.get(r);if(s){if(performance.now()<s.ttl&&["default","force-cache","only-if-cached",void 0].includes(n==null?void 0:n.cache))return new Response(s.body,s.init);b.delete(r)}}return window.fetch(e,n)}function U(t,e){let r=`script[data-sveltekit-fetched][data-url=${JSON.stringify(t instanceof Request?t.url:t)}]`;if(e!=null&&e.headers||e!=null&&e.body){const s=[];e.headers&&s.push([...new Headers(e.headers)].join(",")),e.body&&(typeof e.body=="string"||ArrayBuffer.isView(e.body))&&s.push(e.body),r+=`[data-hash="${W(...s)}"]`}return r}var $;const J=(($=globalThis.__sveltekit_1thdx8y)==null?void 0:$.base)??"/admin";var C;const M=((C=globalThis.__sveltekit_1thdx8y)==null?void 0:C.assets)??J??"",F="1774317332252",ue="sveltekit:snapshot",fe="sveltekit:scroll",de="sveltekit:states",he="sveltekit:pageurl",ge="sveltekit:history",be="sveltekit:navigation",N={tap:1,hover:2,viewport:3,eager:4,off:-1,false:-1},Y=location.origin;function _e(t){if(t instanceof URL)return t;let e=document.baseURI;if(!e){const n=document.getElementsByTagName("base");e=n.length?n[0].href:document.URL}return new URL(t,e)}function we(){return{x:pageXOffset,y:pageYOffset}}function g(t,e){return t.getAttribute(`data-sveltekit-${e}`)}const L={...N,"":N.hover};function q(t){let e=t.assignedSlot??t.parentNode;return(e==null?void 0:e.nodeType)===11&&(e=e.host),e}function me(t,e){for(;t&&t!==e;){if(t.nodeName.toUpperCase()==="A"&&t.hasAttribute("href"))return t;t=q(t)}}function pe(t,e,n){let r;try{if(r=new URL(t instanceof SVGAElement?t.href.baseVal:t.href,document.baseURI),n&&r.hash.match(/^#[^/]/)){const i=location.hash.split("#")[1]||"/";r.hash=`#${i}${r.hash}`}}catch{}const s=t instanceof SVGAElement?t.target.baseVal:t.target,l=!r||!!s||Q(r,e,n)||(t.getAttribute("rel")||"").split(/\s+/).includes("external"),o=(r==null?void 0:r.origin)===Y&&t.hasAttribute("download");return{url:r,external:l,target:s,download:o}}function ve(t){let e=null,n=null,r=null,s=null,l=null,o=null,i=t;for(;i&&i!==document.documentElement;)r===null&&(r=g(i,"preload-code")),s===null&&(s=g(i,"preload-data")),e===null&&(e=g(i,"keepfocus")),n===null&&(n=g(i,"noscroll")),l===null&&(l=g(i,"reload")),o===null&&(o=g(i,"replacestate")),i=q(i);function h(K){switch(K){case"":case"true":return!0;case"off":case"false":return!1;default:return}}return{preload_code:L[r??"off"],preload_data:L[s??"off"],keepfocus:h(e),noscroll:h(n),reload:h(l),replace_state:h(o)}}function ye(t){const e=G(t);let n=!0;function r(){n=!0,e.update(o=>o)}function s(o){n=!1,e.set(o)}function l(o){let i;return e.subscribe(h=>{(i===void 0||n&&h!==i)&&o(i=h)})}return{notify:r,set:s,subscribe:l}}const D={v:()=>{}};function Ae(){const{set:t,subscribe:e}=G(!1);let n;async function r(){clearTimeout(n);try{const s=await fetch(`${M}/_app/version.json`,{headers:{pragma:"no-cache","cache-control":"no-cache"}});if(!s.ok)return!1;const o=(await s.json()).version!==F;return o&&(t(!0),D.v(),clearTimeout(n)),o}catch{return!1}}return{subscribe:e,check:r}}function Q(t,e,n){return t.origin!==Y||!t.pathname.startsWith(e)?!0:n?t.pathname!==location.pathname:!1}function Re(t){}const H=new Set(["load","prerender","csr","ssr","trailingSlash","config"]);[...H];const Z=new Set([...H]);[...Z];let E,O,T;const ee=I.toString().includes("$$")||/function \w+\(\) \{\}/.test(I.toString());var _,w,m,p,v,y,A,R,P,S,V,k,j;ee?(E={data:{},form:null,error:null,params:{},route:{id:null},state:{},status:-1,url:new URL("https://example.com")},O={current:null},T={current:!1}):(E=new(P=class{constructor(){c(this,_,u({}));c(this,w,u(null));c(this,m,u(null));c(this,p,u({}));c(this,v,u({id:null}));c(this,y,u({}));c(this,A,u(-1));c(this,R,u(new URL("https://example.com")))}get data(){return f(a(this,_))}set data(e){d(a(this,_),e)}get form(){return f(a(this,w))}set form(e){d(a(this,w),e)}get error(){return f(a(this,m))}set error(e){d(a(this,m),e)}get params(){return f(a(this,p))}set params(e){d(a(this,p),e)}get route(){return f(a(this,v))}set route(e){d(a(this,v),e)}get state(){return f(a(this,y))}set state(e){d(a(this,y),e)}get status(){return f(a(this,A))}set status(e){d(a(this,A),e)}get url(){return f(a(this,R))}set url(e){d(a(this,R),e)}},_=new WeakMap,w=new WeakMap,m=new WeakMap,p=new WeakMap,v=new WeakMap,y=new WeakMap,A=new WeakMap,R=new WeakMap,P),O=new(V=class{constructor(){c(this,S,u(null))}get current(){return f(a(this,S))}set current(e){d(a(this,S),e)}},S=new WeakMap,V),T=new(j=class{constructor(){c(this,k,u(!1))}get current(){return f(a(this,k))}set current(e){d(a(this,k),e)}},k=new WeakMap,j),D.v=()=>T.current=!0);function Ee(t){Object.assign(E,t)}export{ge as H,be as N,he as P,de as S,ve as a,J as b,ie as c,oe as d,se as e,me as f,pe as g,Ae as h,Q as i,ye as j,N as k,ae as l,ue as m,O as n,Y as o,E as p,ce as q,_e as r,we as s,le as t,fe as u,Ee as v,Re as w};
@@ -1 +0,0 @@
1
- import{ab as J,bm as ee}from"./BdTBlfLy.js";import{w as ae}from"./Bn2NtlTj.js";import{H as N,N as M,r as gt,o as $t,i as _t,b as L,s as C,p as x,n as ft,f as Nt,g as ut,a as X,c as it,S as Dt,P as ne,d as re,e as oe,h as se,j as Pt,k as q,l as ie,m as qt,q as ce,t as le,u as Kt,v as fe}from"./DiyBpamp.js";class wt{constructor(a,e){this.status=a,typeof e=="string"?this.body={message:e}:e?this.body=e:this.body={message:`Error: ${a}`}}toString(){return JSON.stringify(this.body)}}class vt{constructor(a,e){this.status=a,this.location=e}}class yt extends Error{constructor(a,e,r){super(r),this.status=a,this.text=e}}const ue=/^(\[)?(\.\.\.)?(\w+)(?:=(\w+))?(\])?$/;function he(t){const a=[];return{pattern:t==="/"?/^\/$/:new RegExp(`^${pe(t).map(r=>{const n=/^\[\.\.\.(\w+)(?:=(\w+))?\]$/.exec(r);if(n)return a.push({name:n[1],matcher:n[2],optional:!1,rest:!0,chained:!0}),"(?:/([^]*))?";const o=/^\[\[(\w+)(?:=(\w+))?\]\]$/.exec(r);if(o)return a.push({name:o[1],matcher:o[2],optional:!0,rest:!1,chained:!0}),"(?:/([^/]+))?";if(!r)return;const s=r.split(/\[(.+?)\](?!\])/);return"/"+s.map((c,l)=>{if(l%2){if(c.startsWith("x+"))return ct(String.fromCharCode(parseInt(c.slice(2),16)));if(c.startsWith("u+"))return ct(String.fromCharCode(...c.slice(2).split("-").map(_=>parseInt(_,16))));const h=ue.exec(c),[,u,w,f,d]=h;return a.push({name:f,matcher:d,optional:!!u,rest:!!w,chained:w?l===1&&s[0]==="":!1}),w?"([^]*?)":u?"([^/]*)?":"([^/]+?)"}return ct(c)}).join("")}).join("")}/?$`),params:a}}function de(t){return t!==""&&!/^\([^)]+\)$/.test(t)}function pe(t){return t.slice(1).split("/").filter(de)}function me(t,a,e){const r={},n=t.slice(1),o=n.filter(i=>i!==void 0);let s=0;for(let i=0;i<a.length;i+=1){const c=a[i];let l=n[i-s];if(c.chained&&c.rest&&s&&(l=n.slice(i-s,i+1).filter(h=>h).join("/"),s=0),l===void 0)if(c.rest)l="";else continue;if(!c.matcher||e[c.matcher](l)){r[c.name]=l;const h=a[i+1],u=n[i+1];h&&!h.rest&&h.optional&&u&&c.chained&&(s=0),!h&&!u&&Object.keys(r).length===o.length&&(s=0);continue}if(c.optional&&c.chained){s++;continue}return}if(!s)return r}function ct(t){return t.normalize().replace(/[[\]]/g,"\\$&").replace(/%/g,"%25").replace(/\//g,"%2[Ff]").replace(/\?/g,"%3[Ff]").replace(/#/g,"%23").replace(/[.*+?^${}()|\\]/g,"\\$&")}function ge({nodes:t,server_loads:a,dictionary:e,matchers:r}){const n=new Set(a);return Object.entries(e).map(([i,[c,l,h]])=>{const{pattern:u,params:w}=he(i),f={id:i,exec:d=>{const _=u.exec(d);if(_)return me(_,w,r)},errors:[1,...h||[]].map(d=>t[d]),layouts:[0,...l||[]].map(s),leaf:o(c)};return f.errors.length=f.layouts.length=Math.max(f.errors.length,f.layouts.length),f});function o(i){const c=i<0;return c&&(i=~i),[c,t[i]]}function s(i){return i===void 0?i:[n.has(i),t[i]]}}function Ft(t,a=JSON.parse){try{return a(sessionStorage[t])}catch{}}function It(t,a,e=JSON.stringify){const r=e(a);try{sessionStorage[t]=r}catch{}}function _e(t){return t.filter(a=>a!=null)}function bt(t){return t instanceof wt||t instanceof yt?t.status:500}function we(t){return t instanceof yt?t.text:"Internal Error"}const ve=new Set(["icon","shortcut icon","apple-touch-icon"]),I=Ft(Kt)??{},V=Ft(qt)??{},P={url:Pt({}),page:Pt({}),navigating:ae(null),updated:se()};function Et(t){I[t]=C()}function ye(t,a){let e=t+1;for(;I[e];)delete I[e],e+=1;for(e=a+1;V[e];)delete V[e],e+=1}function B(t,a=!1){return a?location.replace(t.href):location.href=t.href,new Promise(()=>{})}async function Mt(){if("serviceWorker"in navigator){const t=await navigator.serviceWorker.getRegistration(L||"/");t&&await t.update()}}function Tt(){}let kt,ht,Q,U,dt,E;const Z=[],tt=[];let v=null;function pt(){var t;(t=v==null?void 0:v.fork)==null||t.then(a=>a==null?void 0:a.discard()),v=null}const G=new Map,Vt=new Set,be=new Set,F=new Set;let g={branch:[],error:null,url:null},Bt=!1,et=!1,Ot=!0,H=!1,K=!1,Ht=!1,St=!1,Yt,b,R,O;const at=new Set,Ct=new Map;async function Fe(t,a,e){var o,s,i,c,l;(o=globalThis.__sveltekit_1thdx8y)!=null&&o.data&&globalThis.__sveltekit_1thdx8y.data,document.URL!==location.href&&(location.href=location.href),E=t,await((i=(s=t.hooks).init)==null?void 0:i.call(s)),kt=ge(t),U=document.documentElement,dt=a,ht=t.nodes[0],Q=t.nodes[1],ht(),Q(),b=(c=history.state)==null?void 0:c[N],R=(l=history.state)==null?void 0:l[M],b||(b=R=Date.now(),history.replaceState({...history.state,[N]:b,[M]:R},""));const r=I[b];function n(){r&&(history.scrollRestoration="manual",scrollTo(r.x,r.y))}e?(n(),await Ce(dt,e)):(await D({type:"enter",url:gt(E.hash?Ne(new URL(location.href)):location.href),replace_state:!0}),n()),Oe()}function Ee(){Z.length=0,St=!1}function zt(t){tt.some(a=>a==null?void 0:a.snapshot)&&(V[t]=tt.map(a=>{var e;return(e=a==null?void 0:a.snapshot)==null?void 0:e.capture()}))}function Wt(t){var a;(a=V[t])==null||a.forEach((e,r)=>{var n,o;(o=(n=tt[r])==null?void 0:n.snapshot)==null||o.restore(e)})}function jt(){Et(b),It(Kt,I),zt(R),It(qt,V)}async function Gt(t,a,e,r){let n;a.invalidateAll&&pt(),await D({type:"goto",url:gt(t),keepfocus:a.keepFocus,noscroll:a.noScroll,replace_state:a.replaceState,state:a.state,redirect_count:e,nav_token:r,accept:()=>{a.invalidateAll&&(St=!0,n=[...Ct.keys()]),a.invalidate&&a.invalidate.forEach(Te)}}),a.invalidateAll&&J().then(J).then(()=>{Ct.forEach(({resource:o},s)=>{var i;n!=null&&n.includes(s)&&((i=o.refresh)==null||i.call(o))})})}async function ke(t){if(t.id!==(v==null?void 0:v.id)){pt();const a={};at.add(a),v={id:t.id,token:a,promise:Xt({...t,preload:a}).then(e=>(at.delete(a),e.type==="loaded"&&e.state.error&&pt(),e)),fork:null}}return v.promise}async function lt(t){var e;const a=(e=await ot(t,!1))==null?void 0:e.route;a&&await Promise.all([...a.layouts,a.leaf].map(r=>r==null?void 0:r[1]()))}async function Jt(t,a,e){var n;g=t.state;const r=document.querySelector("style[data-sveltekit]");if(r&&r.remove(),Object.assign(x,t.props.page),Yt=new E.root({target:a,props:{...t.props,stores:P,components:tt},hydrate:e,sync:!1}),await Promise.resolve(),Wt(R),e){const o={from:null,to:{params:g.params,route:{id:((n=g.route)==null?void 0:n.id)??null},url:new URL(location.href),scroll:I[b]??C()},willUnload:!1,type:"enter",complete:Promise.resolve()};F.forEach(s=>s(o))}et=!0}function nt({url:t,params:a,branch:e,status:r,error:n,route:o,form:s}){let i="never";if(L&&(t.pathname===L||t.pathname===L+"/"))i="always";else for(const f of e)(f==null?void 0:f.slash)!==void 0&&(i=f.slash);t.pathname=oe(t.pathname,i),t.search=t.search;const c={type:"loaded",state:{url:t,params:a,branch:e,error:n,route:o},props:{constructors:_e(e).map(f=>f.node.component),page:At(x)}};s!==void 0&&(c.props.form=s);let l={},h=!x,u=0;for(let f=0;f<Math.max(e.length,g.branch.length);f+=1){const d=e[f],_=g.branch[f];(d==null?void 0:d.data)!==(_==null?void 0:_.data)&&(h=!0),d&&(l={...l,...d.data},h&&(c.props[`data_${u}`]=l),u+=1)}return(!g.url||t.href!==g.url.href||g.error!==n||s!==void 0&&s!==x.form||h)&&(c.props.page={error:n,params:a,route:{id:(o==null?void 0:o.id)??null},state:{},status:r,url:new URL(t),form:s??null,data:h?l:x.data}),c}async function Rt({loader:t,parent:a,url:e,params:r,route:n,server_data_node:o}){var l,h;let s=null;const i={dependencies:new Set,params:new Set,parent:!1,route:!1,url:!1,search_params:new Set},c=await t();return{node:c,loader:t,server:o,universal:(l=c.universal)!=null&&l.load?{type:"data",data:s,uses:i}:null,data:s??(o==null?void 0:o.data)??null,slash:((h=c.universal)==null?void 0:h.trailingSlash)??(o==null?void 0:o.slash)}}function Se(t,a,e){let r=t instanceof Request?t.url:t;const n=new URL(r,e);n.origin===e.origin&&(r=n.href.slice(e.origin.length));const o=et?ce(r,n.href,a):le(r,a);return{resolved:n,promise:o}}function Re(t,a,e,r,n,o){if(St)return!0;if(!n)return!1;if(n.parent&&t||n.route&&a||n.url&&e)return!0;for(const s of n.search_params)if(r.has(s))return!0;for(const s of n.params)if(o[s]!==g.params[s])return!0;for(const s of n.dependencies)if(Z.some(i=>i(new URL(s))))return!0;return!1}function xt(t,a){return(t==null?void 0:t.type)==="data"?t:(t==null?void 0:t.type)==="skip"?a??null:null}function xe(t,a){if(!t)return new Set(a.searchParams.keys());const e=new Set([...t.searchParams.keys(),...a.searchParams.keys()]);for(const r of e){const n=t.searchParams.getAll(r),o=a.searchParams.getAll(r);n.every(s=>o.includes(s))&&o.every(s=>n.includes(s))&&e.delete(r)}return e}function Le({error:t,url:a,route:e,params:r}){return{type:"loaded",state:{error:t,url:a,route:e,params:r,branch:[]},props:{page:At(x),constructors:[]}}}async function Xt({id:t,invalidating:a,url:e,params:r,route:n,preload:o}){if((v==null?void 0:v.id)===t)return at.delete(v.token),v.promise;const{errors:s,layouts:i,leaf:c}=n,l=[...i,c];s.forEach(m=>m==null?void 0:m().catch(()=>{})),l.forEach(m=>m==null?void 0:m[1]().catch(()=>{}));const h=g.url?t!==rt(g.url):!1,u=g.route?n.id!==g.route.id:!1,w=xe(g.url,e);let f=!1;const d=l.map(async(m,p)=>{var A;if(!m)return;const y=g.branch[p];return m[1]===(y==null?void 0:y.loader)&&!Re(f,u,h,w,(A=y.universal)==null?void 0:A.uses,r)?y:(f=!0,Rt({loader:m[1],url:e,params:r,route:n,parent:async()=>{var z;const T={};for(let j=0;j<p;j+=1)Object.assign(T,(z=await d[j])==null?void 0:z.data);return T},server_data_node:xt(m[0]?{type:"skip"}:null,m[0]?y==null?void 0:y.server:void 0)}))});for(const m of d)m.catch(()=>{});const _=[];for(let m=0;m<l.length;m+=1)if(l[m])try{_.push(await d[m])}catch(p){if(p instanceof vt)return{type:"redirect",location:p.location};if(at.has(o))return Le({error:await Y(p,{params:r,url:e,route:{id:n.id}}),url:e,params:r,route:n});let y=bt(p),S;if(p instanceof wt)S=p.body;else{if(await P.updated.check())return await Mt(),await B(e);S=await Y(p,{params:r,url:e,route:{id:n.id}})}const A=await Ue(m,_,s);return A?nt({url:e,params:r,branch:_.slice(0,A.idx).concat(A.node),status:y,error:S,route:n}):await Zt(e,{id:n.id},S,y)}else _.push(void 0);return nt({url:e,params:r,branch:_,status:200,error:null,route:n,form:a?void 0:null})}async function Ue(t,a,e){for(;t--;)if(e[t]){let r=t;for(;!a[r];)r-=1;try{return{idx:r+1,node:{node:await e[t](),loader:e[t],data:{},server:null,universal:null}}}catch{continue}}}async function Lt({status:t,error:a,url:e,route:r}){const n={};let o=null;try{const s=await Rt({loader:ht,url:e,params:n,route:r,parent:()=>Promise.resolve({}),server_data_node:xt(o)}),i={node:await Q(),loader:Q,universal:null,server:null,data:null};return nt({url:e,params:n,branch:[s,i],status:t,error:a,route:null})}catch(s){if(s instanceof vt)return Gt(new URL(s.location,location.href),{},0);throw s}}async function Ae(t){const a=t.href;if(G.has(a))return G.get(a);let e;try{const r=(async()=>{let n=await E.hooks.reroute({url:new URL(t),fetch:async(o,s)=>Se(o,s,t).promise})??t;if(typeof n=="string"){const o=new URL(t);E.hash?o.hash=n:o.pathname=n,n=o}return n})();G.set(a,r),e=await r}catch{G.delete(a);return}return e}async function ot(t,a){if(t&&!_t(t,L,E.hash)){const e=await Ae(t);if(!e)return;const r=Pe(e);for(const n of kt){const o=n.exec(r);if(o)return{id:rt(t),invalidating:a,route:n,params:re(o),url:t}}}}function Pe(t){return ie(E.hash?t.hash.replace(/^#/,"").replace(/[?#].+/,""):t.pathname.slice(L.length))||"/"}function rt(t){return(E.hash?t.hash.replace(/^#/,""):t.pathname)+t.search}function Qt({url:t,type:a,intent:e,delta:r,event:n,scroll:o}){let s=!1;const i=Ut(g,e,t,a,o??null);r!==void 0&&(i.navigation.delta=r),n!==void 0&&(i.navigation.event=n);const c={...i.navigation,cancel:()=>{s=!0,i.reject(new Error("navigation cancelled"))}};return H||Vt.forEach(l=>l(c)),s?null:i}async function D({type:t,url:a,popped:e,keepfocus:r,noscroll:n,replace_state:o,state:s={},redirect_count:i=0,nav_token:c={},accept:l=Tt,block:h=Tt,event:u}){var j;const w=O;O=c;const f=await ot(a,!1),d=t==="enter"?Ut(g,f,a,t):Qt({url:a,type:t,delta:e==null?void 0:e.delta,intent:f,scroll:e==null?void 0:e.scroll,event:u});if(!d){h(),O===c&&(O=w);return}const _=b,m=R;l(),H=!0,et&&d.navigation.type!=="enter"&&P.navigating.set(ft.current=d.navigation);let p=f&&await Xt(f);if(!p){if(_t(a,L,E.hash))return await B(a,o);p=await Zt(a,{id:null},await Y(new yt(404,"Not Found",`Not found: ${a.pathname}`),{url:a,params:{},route:{id:null}}),404,o)}if(a=(f==null?void 0:f.url)||a,O!==c)return d.reject(new Error("navigation aborted")),!1;if(p.type==="redirect"){if(i<20){await D({type:t,url:new URL(p.location,a),popped:e,keepfocus:r,noscroll:n,replace_state:o,state:s,redirect_count:i+1,nav_token:c}),d.fulfil(void 0);return}p=await Lt({status:500,error:await Y(new Error("Redirect loop"),{url:a,params:{},route:{id:null}}),url:a,route:{id:null}})}else p.props.page.status>=400&&await P.updated.check()&&(await Mt(),await B(a,o));if(Ee(),Et(_),zt(m),p.props.page.url.pathname!==a.pathname&&(a.pathname=p.props.page.url.pathname),s=e?e.state:s,!e){const k=o?0:1,W={[N]:b+=k,[M]:R+=k,[Dt]:s};(o?history.replaceState:history.pushState).call(history,W,"",a),o||ye(b,R)}const y=f&&(v==null?void 0:v.id)===f.id?v.fork:null;v=null,p.props.page.state=s;let S;if(et){const k=(await Promise.all(Array.from(be,$=>$(d.navigation)))).filter($=>typeof $=="function");if(k.length>0){let $=function(){k.forEach(st=>{F.delete(st)})};k.push($),k.forEach(st=>{F.add(st)})}g=p.state,p.props.page&&(p.props.page.url=a);const W=y&&await y;W?S=W.commit():(Yt.$set(p.props),fe(p.props.page),S=(j=ee)==null?void 0:j()),Ht=!0}else await Jt(p,dt,!1);const{activeElement:A}=document;await S,await J(),await J();let T=null;if(Ot){const k=e?e.scroll:n?C():null;k?scrollTo(k.x,k.y):(T=a.hash&&document.getElementById(te(a)))?T.scrollIntoView():scrollTo(0,0)}const z=document.activeElement!==A&&document.activeElement!==document.body;!r&&!z&&$e(a,!T),Ot=!0,p.props.page&&Object.assign(x,p.props.page),H=!1,t==="popstate"&&Wt(R),d.fulfil(void 0),d.navigation.to&&(d.navigation.to.scroll=C()),F.forEach(k=>k(d.navigation)),P.navigating.set(ft.current=null)}async function Zt(t,a,e,r,n){return t.origin===$t&&t.pathname===location.pathname&&!Bt?await Lt({status:r,error:e,url:t,route:a}):await B(t,n)}function Ie(){let t,a={element:void 0,href:void 0},e;U.addEventListener("mousemove",i=>{const c=i.target;clearTimeout(t),t=setTimeout(()=>{o(c,q.hover)},20)});function r(i){i.defaultPrevented||o(i.composedPath()[0],q.tap)}U.addEventListener("mousedown",r),U.addEventListener("touchstart",r,{passive:!0});const n=new IntersectionObserver(i=>{for(const c of i)c.isIntersecting&&(lt(new URL(c.target.href)),n.unobserve(c.target))},{threshold:0});async function o(i,c){const l=Nt(i,U),h=l===a.element&&(l==null?void 0:l.href)===a.href&&c>=e;if(!l||h)return;const{url:u,external:w,download:f}=ut(l,L,E.hash);if(w||f)return;const d=X(l),_=u&&rt(g.url)===rt(u);if(!(d.reload||_))if(c<=d.preload_data){a={element:l,href:l.href},e=q.tap;const m=await ot(u,!1);if(!m)return;ke(m)}else c<=d.preload_code&&(a={element:l,href:l.href},e=c,lt(u))}function s(){n.disconnect();for(const i of U.querySelectorAll("a")){const{url:c,external:l,download:h}=ut(i,L,E.hash);if(l||h)continue;const u=X(i);u.reload||(u.preload_code===q.viewport&&n.observe(i),u.preload_code===q.eager&&lt(c))}}F.add(s),s()}function Y(t,a){if(t instanceof wt)return t.body;const e=bt(t),r=we(t);return E.hooks.handleError({error:t,event:a,status:e,message:r})??{message:r}}function Me(t,a={}){return t=new URL(gt(t)),t.origin!==$t?Promise.reject(new Error("goto: invalid URL")):Gt(t,a,0)}function Te(t){if(typeof t=="function")Z.push(t);else{const{href:a}=new URL(t,location.href);Z.push(e=>e.href===a)}}function Oe(){var a;history.scrollRestoration="manual",addEventListener("beforeunload",e=>{let r=!1;if(jt(),!H){const n=Ut(g,void 0,null,"leave"),o={...n.navigation,cancel:()=>{r=!0,n.reject(new Error("navigation cancelled"))}};Vt.forEach(s=>s(o))}r?(e.preventDefault(),e.returnValue=""):history.scrollRestoration="auto"}),addEventListener("visibilitychange",()=>{document.visibilityState==="hidden"&&jt()}),(a=navigator.connection)!=null&&a.saveData||Ie(),U.addEventListener("click",async e=>{if(e.button||e.which!==1||e.metaKey||e.ctrlKey||e.shiftKey||e.altKey||e.defaultPrevented)return;const r=Nt(e.composedPath()[0],U);if(!r)return;const{url:n,external:o,target:s,download:i}=ut(r,L,E.hash);if(!n)return;if(s==="_parent"||s==="_top"){if(window.parent!==window)return}else if(s&&s!=="_self")return;const c=X(r);if(!(r instanceof SVGAElement)&&n.protocol!==location.protocol&&!(n.protocol==="https:"||n.protocol==="http:")||i)return;const[h,u]=(E.hash?n.hash.replace(/^#/,""):n.href).split("#"),w=h===it(location);if(o||c.reload&&(!w||!u)){Qt({url:n,type:"link",event:e})?H=!0:e.preventDefault();return}if(u!==void 0&&w){const[,f]=g.url.href.split("#");if(f===u){if(e.preventDefault(),u===""||u==="top"&&r.ownerDocument.getElementById("top")===null)scrollTo({top:0});else{const d=r.ownerDocument.getElementById(decodeURIComponent(u));d&&(d.scrollIntoView(),d.focus())}return}if(K=!0,Et(b),t(n),!c.replace_state)return;K=!1}e.preventDefault(),await new Promise(f=>{requestAnimationFrame(()=>{setTimeout(f,0)}),setTimeout(f,100)}),await D({type:"link",url:n,keepfocus:c.keepfocus,noscroll:c.noscroll,replace_state:c.replace_state??n.href===location.href,event:e})}),U.addEventListener("submit",e=>{if(e.defaultPrevented)return;const r=HTMLFormElement.prototype.cloneNode.call(e.target),n=e.submitter;if(((n==null?void 0:n.formTarget)||r.target)==="_blank"||((n==null?void 0:n.formMethod)||r.method)!=="get")return;const i=new URL((n==null?void 0:n.hasAttribute("formaction"))&&(n==null?void 0:n.formAction)||r.action);if(_t(i,L,!1))return;const c=e.target,l=X(c);if(l.reload)return;e.preventDefault(),e.stopPropagation();const h=new FormData(c,n);i.search=new URLSearchParams(h).toString(),D({type:"form",url:i,keepfocus:l.keepfocus,noscroll:l.noscroll,replace_state:l.replace_state??i.href===location.href,event:e})}),addEventListener("popstate",async e=>{var r;if(!mt){if((r=e.state)!=null&&r[N]){const n=e.state[N];if(O={},n===b)return;const o=I[n],s=e.state[Dt]??{},i=new URL(e.state[ne]??location.href),c=e.state[M],l=g.url?it(location)===it(g.url):!1;if(c===R&&(Ht||l)){s!==x.state&&(x.state=s),t(i),I[b]=C(),o&&scrollTo(o.x,o.y),b=n;return}const u=n-b;await D({type:"popstate",url:i,popped:{state:s,scroll:o,delta:u},accept:()=>{b=n,R=c},block:()=>{history.go(-u)},nav_token:O,event:e})}else if(!K){const n=new URL(location.href);t(n),E.hash&&location.reload()}}}),addEventListener("hashchange",()=>{K&&(K=!1,history.replaceState({...history.state,[N]:++b,[M]:R},"",location.href))});for(const e of document.querySelectorAll("link"))ve.has(e.rel)&&(e.href=e.href);addEventListener("pageshow",e=>{e.persisted&&P.navigating.set(ft.current=null)});function t(e){g.url=x.url=e,P.page.set(At(x)),P.page.notify()}}async function Ce(t,{status:a=200,error:e,node_ids:r,params:n,route:o,server_route:s,data:i,form:c}){Bt=!0;const l=new URL(location.href);let h;({params:n={},route:o={id:null}}=await ot(l,!1)||{}),h=kt.find(({id:f})=>f===o.id);let u,w=!0;try{const f=r.map(async(_,m)=>{const p=i[m];return p!=null&&p.uses&&(p.uses=je(p.uses)),Rt({loader:E.nodes[_],url:l,params:n,route:o,parent:async()=>{const y={};for(let S=0;S<m;S+=1)Object.assign(y,(await f[S]).data);return y},server_data_node:xt(p)})}),d=await Promise.all(f);if(h){const _=h.layouts;for(let m=0;m<_.length;m++)_[m]||d.splice(m,0,void 0)}u=nt({url:l,params:n,branch:d,status:a,error:e,form:c,route:h??null})}catch(f){if(f instanceof vt){await B(new URL(f.location,location.href));return}u=await Lt({status:bt(f),error:await Y(f,{url:l,params:n,route:o}),url:l,route:o}),t.textContent="",w=!1}u.props.page&&(u.props.page.state={}),await Jt(u,t,w)}function je(t){return{dependencies:new Set((t==null?void 0:t.dependencies)??[]),params:new Set((t==null?void 0:t.params)??[]),parent:!!(t!=null&&t.parent),route:!!(t!=null&&t.route),url:!!(t!=null&&t.url),search_params:new Set((t==null?void 0:t.search_params)??[])}}let mt=!1;function $e(t,a=!0){const e=document.querySelector("[autofocus]");if(e)e.focus();else{const r=te(t);if(r&&document.getElementById(r)){const{x:o,y:s}=C();setTimeout(()=>{const i=history.state;mt=!0,location.replace(new URL(`#${r}`,location.href)),history.replaceState(i,"",t),a&&scrollTo(o,s),mt=!1})}else{const o=document.body,s=o.getAttribute("tabindex");o.tabIndex=-1,o.focus({preventScroll:!0,focusVisible:!1}),s!==null?o.setAttribute("tabindex",s):o.removeAttribute("tabindex")}const n=getSelection();if(n&&n.type!=="None"){const o=[];for(let s=0;s<n.rangeCount;s+=1)o.push(n.getRangeAt(s));setTimeout(()=>{if(n.rangeCount===o.length){for(let s=0;s<n.rangeCount;s+=1){const i=o[s],c=n.getRangeAt(s);if(i.commonAncestorContainer!==c.commonAncestorContainer||i.startContainer!==c.startContainer||i.endContainer!==c.endContainer||i.startOffset!==c.startOffset||i.endOffset!==c.endOffset)return}n.removeAllRanges()}})}}}function Ut(t,a,e,r,n=null){var l,h;let o,s;const i=new Promise((u,w)=>{o=u,s=w});return i.catch(()=>{}),{navigation:{from:{params:t.params,route:{id:((l=t.route)==null?void 0:l.id)??null},url:t.url,scroll:C()},to:e&&{params:(a==null?void 0:a.params)??null,route:{id:((h=a==null?void 0:a.route)==null?void 0:h.id)??null},url:e,scroll:n},willUnload:!a,type:r,complete:i},fulfil:o,reject:s}}function At(t){return{data:t.data,error:t.error,form:t.form,params:t.params,route:t.route,state:t.state,status:t.status,url:t.url}}function Ne(t){const a=new URL(t);return a.hash=decodeURIComponent(t.hash),a}function te(t){let a;if(E.hash){const[,,e]=t.hash.split("#",3);a=e??""}else a=t.hash.slice(1);return decodeURIComponent(a)}export{Fe as a,Me as g,P as s};
@@ -1 +0,0 @@
1
- import{a as r}from"../chunks/byv2rTy8.js";import{w as t}from"../chunks/DiyBpamp.js";export{t as load_css,r as start};
@@ -1 +0,0 @@
1
- import{_ as m}from"../chunks/BxoNtYHK.js";export{m as component};