@edge-base/server 0.2.0 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/admin-build/_app/immutable/assets/19.4Si2ZFC_.css +1 -0
- package/admin-build/_app/immutable/assets/{3.Dg81Pgmd.css → 3.BtHYobTg.css} +1 -1
- package/admin-build/_app/immutable/assets/SqlEditor.Bbp1RIk0.css +1 -0
- package/admin-build/_app/immutable/assets/TableSqlTab.yeNZfhgG.css +1 -0
- package/admin-build/_app/immutable/chunks/4vlsb8ej.js +1 -0
- package/admin-build/_app/immutable/chunks/{CfPHB4r5.js → 5PDcRlfX.js} +1 -1
- package/admin-build/_app/immutable/chunks/{BSfSfeDG.js → B8DT4fss.js} +1 -1
- package/admin-build/_app/immutable/chunks/{DP9kmlCd.js → BEYYl662.js} +1 -1
- package/admin-build/_app/immutable/chunks/{B-WlnirM.js → BKXmgPq4.js} +1 -1
- package/admin-build/_app/immutable/chunks/{cqSkc6KP.js → BWyDPAjM.js} +1 -1
- package/admin-build/_app/immutable/chunks/{mD4EETH_.js → BaCHY17I.js} +1 -1
- package/admin-build/_app/immutable/chunks/C-DsDCNG.js +128 -0
- package/admin-build/_app/immutable/chunks/{2nyN5wuZ.js → C85dMlzL.js} +1 -1
- package/admin-build/_app/immutable/chunks/{DgxOZ3uv.js → CPdXvRUb.js} +1 -1
- package/admin-build/_app/immutable/chunks/{DpuSetmN.js → CTngeX8H.js} +1 -1
- package/admin-build/_app/immutable/chunks/{BKLsgaNT.js → DzXaj-Ja.js} +1 -1
- package/admin-build/_app/immutable/chunks/{D43CH5ty.js → c5iKSdWY.js} +1 -1
- package/admin-build/_app/immutable/chunks/{B14gOIqE.js → g3ZZdY-r.js} +1 -1
- package/admin-build/_app/immutable/chunks/{CN6aakgF.js → kiJ6KthZ.js} +1 -1
- package/admin-build/_app/immutable/chunks/lSpxLU5p.js +2 -0
- package/admin-build/_app/immutable/chunks/{uboHVq-x.js → qiZXAKh-.js} +1 -1
- package/admin-build/_app/immutable/entry/{app.Dc071f6C.js → app.BZxfavhF.js} +2 -2
- package/admin-build/_app/immutable/entry/start.Mr9mmopc.js +1 -0
- package/admin-build/_app/immutable/nodes/0.DlsaydXO.js +1 -0
- package/admin-build/_app/immutable/nodes/{1.rMaczUKT.js → 1.D2NWN5eG.js} +1 -1
- package/admin-build/_app/immutable/nodes/{10.DIOlO4hv.js → 10.EMDaN3nw.js} +1 -1
- package/admin-build/_app/immutable/nodes/{11.WxD9E0Eq.js → 11.BasqQ_o9.js} +1 -1
- package/admin-build/_app/immutable/nodes/{12.CNcefK3l.js → 12.DO31Ljs7.js} +1 -1
- package/admin-build/_app/immutable/nodes/{13.aAWsqDdR.js → 13.DhyAy-GZ.js} +1 -1
- package/admin-build/_app/immutable/nodes/{14.C9hdr3EN.js → 14.CLecGWc4.js} +1 -1
- package/admin-build/_app/immutable/nodes/{15.43r5uVx5.js → 15.B9kp3W4e.js} +1 -1
- package/admin-build/_app/immutable/nodes/{16.D519948J.js → 16.Pu_8T3RI.js} +1 -1
- package/admin-build/_app/immutable/nodes/{17.ks4I4yoH.js → 17.DX4z43t6.js} +1 -1
- package/admin-build/_app/immutable/nodes/{18.ZuNm22dY.js → 18.BKsSaxrr.js} +1 -1
- package/admin-build/_app/immutable/nodes/19.DXNF1htN.js +2 -0
- package/admin-build/_app/immutable/nodes/{20.C9ASlwCn.js → 20.VRVb0wee.js} +1 -1
- package/admin-build/_app/immutable/nodes/21.Ck3_0D2f.js +1 -0
- package/admin-build/_app/immutable/nodes/{22.6k8cg0Pr.js → 22.DqZf4CtH.js} +1 -1
- package/admin-build/_app/immutable/nodes/{23.B9hcFTU-.js → 23.DtyxMiQG.js} +1 -1
- package/admin-build/_app/immutable/nodes/{24.OsQM9QtS.js → 24.CloWNmTd.js} +1 -1
- package/admin-build/_app/immutable/nodes/{25.ClwkdaPp.js → 25.CnZWMq7_.js} +1 -1
- package/admin-build/_app/immutable/nodes/26.DrV7XOmf.js +1 -0
- package/admin-build/_app/immutable/nodes/{27.J1QASB3b.js → 27.DV8L32OF.js} +1 -1
- package/admin-build/_app/immutable/nodes/{28.BKP1tVcZ.js → 28.Stil2D4u.js} +1 -1
- package/admin-build/_app/immutable/nodes/{29.mqIe62On.js → 29.Zsm1e5Dc.js} +1 -1
- package/admin-build/_app/immutable/nodes/3.CKoj2vNz.js +2 -0
- package/admin-build/_app/immutable/nodes/{30.BRk-4B3j.js → 30.Ni0k5bER.js} +1 -1
- package/admin-build/_app/immutable/nodes/{31.BBqGNVXN.js → 31.mnqj9EbV.js} +1 -1
- package/admin-build/_app/immutable/nodes/{4.Bi91lv2V.js → 4.B_-z9AzT.js} +1 -1
- package/admin-build/_app/immutable/nodes/{5.BumjsbNK.js → 5.yiZ72j4k.js} +1 -1
- package/admin-build/_app/immutable/nodes/{6.CMTP_7xN.js → 6.BqykybBG.js} +1 -1
- package/admin-build/_app/immutable/nodes/{7.4T4wo7Kg.js → 7.BDAHlhsF.js} +1 -1
- package/admin-build/_app/immutable/nodes/{8.MUZQPNsN.js → 8.D8Xvy0lH.js} +1 -1
- package/admin-build/_app/immutable/nodes/{9.3SV00WXe.js → 9.Dddmd7_F.js} +1 -1
- package/admin-build/_app/version.json +1 -1
- package/admin-build/index.html +7 -7
- package/package.json +3 -2
- package/src/__tests__/functions-context.test.ts +5 -5
- package/src/__tests__/meta-export-coverage.test.ts +1 -0
- package/src/__tests__/pagination.test.ts +12 -8
- package/src/__tests__/postgres-dialect.test.ts +2 -2
- package/src/__tests__/query.test.ts +7 -7
- package/src/durable-objects/database-do.ts +3 -3
- package/src/durable-objects/logs-do.ts +2 -2
- package/src/lib/auth-d1-service.ts +1 -1
- package/src/lib/auth-d1.ts +10 -0
- package/src/lib/d1-handler.ts +23 -4
- package/src/lib/functions.ts +204 -397
- package/src/lib/internal-transport.ts +316 -0
- package/src/lib/pagination.ts +3 -3
- package/src/lib/plugin-migrations.ts +2 -2
- package/src/lib/postgres-handler.ts +2 -2
- package/src/lib/query-engine.ts +2 -2
- package/src/middleware/rate-limit.ts +11 -11
- package/src/routes/admin.ts +9 -3
- package/src/routes/auth.ts +13 -12
- package/src/routes/storage.ts +6 -12
- package/src/types.ts +2 -0
- package/admin-build/_app/immutable/assets/TableSqlTab.BHquaMBM.css +0 -1
- package/admin-build/_app/immutable/chunks/CkdaVlhQ.js +0 -2
- package/admin-build/_app/immutable/chunks/D8Nrx_IG.js +0 -128
- package/admin-build/_app/immutable/entry/start.Bhlxoqtt.js +0 -1
- package/admin-build/_app/immutable/nodes/0.CCfcYVV2.js +0 -1
- package/admin-build/_app/immutable/nodes/19.D519948J.js +0 -1
- package/admin-build/_app/immutable/nodes/21.BhSD2EfX.js +0 -1
- package/admin-build/_app/immutable/nodes/26._-65WG0q.js +0 -1
- package/admin-build/_app/immutable/nodes/3.WkDZWDQC.js +0 -2
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Internal HttpTransport implementation for server-side function context.
|
|
3
|
+
*
|
|
4
|
+
* Replaces the old TableProxy by implementing the same HttpTransport interface
|
|
5
|
+
* that @edge-base/core's DefaultDbApi expects. This lets us use the real
|
|
6
|
+
* TableRef/DbRef classes from the core SDK while routing requests directly
|
|
7
|
+
* to D1, PostgreSQL, or DurableObject handlers — no HTTP round-trip.
|
|
8
|
+
*/
|
|
9
|
+
import type { HttpTransport } from '@edge-base/core';
|
|
10
|
+
import type { EdgeBaseConfig } from '@edge-base/shared';
|
|
11
|
+
import { getDbDoName, callDO, shouldRouteToD1 } from './do-router.js';
|
|
12
|
+
import { handleD1Request } from './d1-handler.js';
|
|
13
|
+
import { handlePgRequest } from './postgres-handler.js';
|
|
14
|
+
import { buildInternalHandlerContext } from './internal-request.js';
|
|
15
|
+
import type { Env } from '../types.js';
|
|
16
|
+
|
|
17
|
+
export interface InternalTransportOptions {
|
|
18
|
+
databaseNamespace: DurableObjectNamespace;
|
|
19
|
+
config: EdgeBaseConfig;
|
|
20
|
+
workerUrl?: string;
|
|
21
|
+
serviceKey?: string;
|
|
22
|
+
env?: Env;
|
|
23
|
+
executionCtx?: ExecutionContext;
|
|
24
|
+
preferDirectDo?: boolean;
|
|
25
|
+
/**
|
|
26
|
+
* When set, the transport knows this DbRef targets a specific
|
|
27
|
+
* namespace + optional instanceId. This avoids ambiguous path parsing
|
|
28
|
+
* when instanceId happens to be "tables".
|
|
29
|
+
*/
|
|
30
|
+
dbContext?: { namespace: string; instanceId?: string };
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Parse a DefaultDbApi path into routing components.
|
|
35
|
+
*
|
|
36
|
+
* Paths follow two patterns:
|
|
37
|
+
* /api/db/{namespace}/tables/{table}[/rest] → static DB
|
|
38
|
+
* /api/db/{namespace}/{instanceId}/tables/{table}[/rest] → dynamic DB
|
|
39
|
+
*
|
|
40
|
+
* Returns namespace, optional instanceId, tableName, and directPath
|
|
41
|
+
* (everything from /tables/... onward, which D1/PG handlers expect).
|
|
42
|
+
*/
|
|
43
|
+
/**
|
|
44
|
+
* Parse a DefaultDbApi path, optionally guided by known dbContext.
|
|
45
|
+
*
|
|
46
|
+
* When dbContext is provided (recommended), we know whether this is a
|
|
47
|
+
* static or dynamic DB, so we can unambiguously find the 'tables' keyword
|
|
48
|
+
* even when instanceId === 'tables'.
|
|
49
|
+
*
|
|
50
|
+
* Without dbContext, falls back to heuristic: first 'tables' at index 1
|
|
51
|
+
* means static, at index 2 means dynamic.
|
|
52
|
+
*/
|
|
53
|
+
function parsePath(
|
|
54
|
+
path: string,
|
|
55
|
+
dbContext?: { namespace: string; instanceId?: string },
|
|
56
|
+
): {
|
|
57
|
+
namespace: string;
|
|
58
|
+
instanceId?: string;
|
|
59
|
+
tableName: string;
|
|
60
|
+
directPath: string;
|
|
61
|
+
} {
|
|
62
|
+
// Strip leading /api/db/
|
|
63
|
+
const stripped = path.replace(/^\/api\/db\//, '');
|
|
64
|
+
const segments = stripped.split('/');
|
|
65
|
+
|
|
66
|
+
let tablesIdx: number;
|
|
67
|
+
if (dbContext) {
|
|
68
|
+
// We know the shape: static has 'tables' at index 1, dynamic at index 2
|
|
69
|
+
tablesIdx = dbContext.instanceId ? 2 : 1;
|
|
70
|
+
} else {
|
|
71
|
+
// Heuristic fallback: find first 'tables' keyword
|
|
72
|
+
tablesIdx = segments.indexOf('tables', 1);
|
|
73
|
+
}
|
|
74
|
+
if (tablesIdx < 0 || segments[tablesIdx] !== 'tables') {
|
|
75
|
+
throw new Error(`Invalid DB path: missing 'tables' segment in ${path}`);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const namespace = segments[0];
|
|
79
|
+
const instanceId = tablesIdx === 2 ? segments[1] : undefined;
|
|
80
|
+
const rawTableName = segments[tablesIdx + 1];
|
|
81
|
+
// Decode URL-encoded table names (e.g. 'plugin-a%2Fevents' → 'plugin-a/events')
|
|
82
|
+
// Use decoded name consistently in both tableName and directPath so that
|
|
83
|
+
// handler suffix parsing (doPath.replace(`/tables/${tableName}`, '')) matches.
|
|
84
|
+
const tableName = decodeURIComponent(rawTableName);
|
|
85
|
+
const rest = segments.slice(tablesIdx + 2);
|
|
86
|
+
const directPath = `/tables/${tableName}${rest.length ? '/' + rest.join('/') : ''}`;
|
|
87
|
+
|
|
88
|
+
return { namespace, instanceId, tableName, directPath };
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export class InternalHttpTransport implements HttpTransport {
|
|
92
|
+
private readonly databaseNamespace: DurableObjectNamespace;
|
|
93
|
+
private readonly config: EdgeBaseConfig;
|
|
94
|
+
private readonly workerUrl?: string;
|
|
95
|
+
private readonly serviceKey?: string;
|
|
96
|
+
private readonly env?: Env;
|
|
97
|
+
private readonly executionCtx?: ExecutionContext;
|
|
98
|
+
private readonly preferDirectDo: boolean;
|
|
99
|
+
private readonly dbContext?: { namespace: string; instanceId?: string };
|
|
100
|
+
|
|
101
|
+
constructor(options: InternalTransportOptions) {
|
|
102
|
+
this.databaseNamespace = options.databaseNamespace;
|
|
103
|
+
this.config = options.config;
|
|
104
|
+
this.workerUrl = options.workerUrl;
|
|
105
|
+
this.serviceKey = options.serviceKey;
|
|
106
|
+
this.env = options.env;
|
|
107
|
+
this.executionCtx = options.executionCtx;
|
|
108
|
+
this.preferDirectDo = options.preferDirectDo ?? false;
|
|
109
|
+
this.dbContext = options.dbContext;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
async request<T>(
|
|
113
|
+
method: string,
|
|
114
|
+
path: string,
|
|
115
|
+
options?: { query?: Record<string, string>; body?: unknown },
|
|
116
|
+
): Promise<T> {
|
|
117
|
+
const { namespace, instanceId, tableName, directPath } = parsePath(path, this.dbContext);
|
|
118
|
+
const doName = getDbDoName(namespace, instanceId);
|
|
119
|
+
|
|
120
|
+
// Build internal headers
|
|
121
|
+
const headers: Record<string, string> = {
|
|
122
|
+
'Content-Type': 'application/json',
|
|
123
|
+
'X-DO-Name': doName,
|
|
124
|
+
'X-EdgeBase-Internal': 'true',
|
|
125
|
+
};
|
|
126
|
+
if (this.serviceKey) {
|
|
127
|
+
headers['X-EdgeBase-Service-Key'] = this.serviceKey;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Convert query Record to URLSearchParams
|
|
131
|
+
const query = new URLSearchParams();
|
|
132
|
+
if (options?.query) {
|
|
133
|
+
for (const [k, v] of Object.entries(options.query)) {
|
|
134
|
+
if (v !== undefined && v !== '') query.set(k, v);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const body = options?.body as Record<string, unknown> | undefined;
|
|
139
|
+
|
|
140
|
+
// Route to the appropriate handler
|
|
141
|
+
const res = await this.routeRequest(
|
|
142
|
+
method as 'GET' | 'POST' | 'PATCH' | 'DELETE' | 'PUT',
|
|
143
|
+
namespace,
|
|
144
|
+
instanceId,
|
|
145
|
+
tableName,
|
|
146
|
+
directPath,
|
|
147
|
+
doName,
|
|
148
|
+
headers,
|
|
149
|
+
query,
|
|
150
|
+
body,
|
|
151
|
+
);
|
|
152
|
+
|
|
153
|
+
if (!res.ok) {
|
|
154
|
+
const err = (await res.json().catch(() => ({}))) as Record<string, unknown>;
|
|
155
|
+
throw new Error(String(err.message || `Internal request failed: ${res.status}`));
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return (await res.json()) as T;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
async head(_path: string): Promise<boolean> {
|
|
162
|
+
// HEAD is only used by StorageClient.checkFileExists — not relevant for DB ops
|
|
163
|
+
return false;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
private async routeRequest(
|
|
167
|
+
method: 'GET' | 'POST' | 'PATCH' | 'DELETE' | 'PUT',
|
|
168
|
+
namespace: string,
|
|
169
|
+
instanceId: string | undefined,
|
|
170
|
+
tableName: string,
|
|
171
|
+
directPath: string,
|
|
172
|
+
doName: string,
|
|
173
|
+
headers: Record<string, string>,
|
|
174
|
+
query: URLSearchParams,
|
|
175
|
+
body?: Record<string, unknown>,
|
|
176
|
+
): Promise<Response> {
|
|
177
|
+
const queryString = Array.from(query.keys()).length > 0 ? `?${query.toString()}` : '';
|
|
178
|
+
const directPathWithQuery = `${directPath}${queryString}`;
|
|
179
|
+
const provider = this.config.databases?.[namespace]?.provider;
|
|
180
|
+
const httpMethod = method === 'PUT' ? 'PATCH' : method; // normalize PUT → PATCH
|
|
181
|
+
|
|
182
|
+
// 1. D1 route
|
|
183
|
+
if (!this.preferDirectDo && shouldRouteToD1(namespace, this.config) && this.env) {
|
|
184
|
+
return this.requestViaD1Handler(httpMethod, namespace, instanceId, tableName, directPath, headers, query, body);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// 2. PostgreSQL route
|
|
188
|
+
if ((provider === 'neon' || provider === 'postgres') && this.env) {
|
|
189
|
+
return this.requestViaPgHandler(httpMethod, namespace, instanceId, tableName, directPath, headers, query, body);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// 3. Direct DO route
|
|
193
|
+
if (this.env) {
|
|
194
|
+
return this.requestViaDirectDo(httpMethod, doName, directPathWithQuery, headers, body, !!instanceId);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// 4. Worker HTTP fallback
|
|
198
|
+
if (this.workerUrl) {
|
|
199
|
+
const apiPath = instanceId
|
|
200
|
+
? `/api/db/${namespace}/${instanceId}${directPathWithQuery}`
|
|
201
|
+
: `/api/db/${namespace}${directPathWithQuery}`;
|
|
202
|
+
return this.requestViaWorker(httpMethod, apiPath, headers, body);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// 5. Fallback: direct DO
|
|
206
|
+
return this.requestViaDirectDo(httpMethod, doName, directPathWithQuery, headers, body, !!instanceId);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
private async requestViaWorker(
|
|
210
|
+
method: string,
|
|
211
|
+
path: string,
|
|
212
|
+
headers: Record<string, string>,
|
|
213
|
+
body?: Record<string, unknown>,
|
|
214
|
+
): Promise<Response> {
|
|
215
|
+
return fetch(`${this.workerUrl}${path}`, {
|
|
216
|
+
method,
|
|
217
|
+
headers,
|
|
218
|
+
body: body === undefined || method === 'GET' || method === 'DELETE'
|
|
219
|
+
? undefined
|
|
220
|
+
: JSON.stringify(body),
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
private async requestViaD1Handler(
|
|
225
|
+
method: string,
|
|
226
|
+
namespace: string,
|
|
227
|
+
instanceId: string | undefined,
|
|
228
|
+
tableName: string,
|
|
229
|
+
directPath: string,
|
|
230
|
+
headers: Record<string, string>,
|
|
231
|
+
query: URLSearchParams,
|
|
232
|
+
body?: Record<string, unknown>,
|
|
233
|
+
): Promise<Response> {
|
|
234
|
+
if (!this.env) throw new Error('D1 table proxy requires env.');
|
|
235
|
+
|
|
236
|
+
const queryString = Array.from(query.keys()).length > 0 ? `?${query.toString()}` : '';
|
|
237
|
+
const url = `http://internal/api/db/${namespace}${instanceId ? `/${instanceId}` : ''}${directPath}${queryString}`;
|
|
238
|
+
|
|
239
|
+
const request = new Request(url, {
|
|
240
|
+
method,
|
|
241
|
+
headers,
|
|
242
|
+
body: body === undefined || method === 'GET' || method === 'DELETE'
|
|
243
|
+
? undefined
|
|
244
|
+
: JSON.stringify(body),
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
return handleD1Request(
|
|
248
|
+
buildInternalHandlerContext({ env: this.env, request, body, executionCtx: this.executionCtx }),
|
|
249
|
+
namespace,
|
|
250
|
+
tableName,
|
|
251
|
+
directPath,
|
|
252
|
+
);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
private async requestViaPgHandler(
|
|
256
|
+
method: string,
|
|
257
|
+
namespace: string,
|
|
258
|
+
instanceId: string | undefined,
|
|
259
|
+
tableName: string,
|
|
260
|
+
directPath: string,
|
|
261
|
+
headers: Record<string, string>,
|
|
262
|
+
query: URLSearchParams,
|
|
263
|
+
body?: Record<string, unknown>,
|
|
264
|
+
): Promise<Response> {
|
|
265
|
+
if (!this.env) throw new Error('PostgreSQL table proxy requires env.');
|
|
266
|
+
|
|
267
|
+
const queryString = Array.from(query.keys()).length > 0 ? `?${query.toString()}` : '';
|
|
268
|
+
const url = `http://internal/api/db/${namespace}${instanceId ? `/${instanceId}` : ''}${directPath}${queryString}`;
|
|
269
|
+
|
|
270
|
+
const request = new Request(url, {
|
|
271
|
+
method,
|
|
272
|
+
headers,
|
|
273
|
+
body: body === undefined || method === 'GET' || method === 'DELETE'
|
|
274
|
+
? undefined
|
|
275
|
+
: JSON.stringify(body),
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
return handlePgRequest(
|
|
279
|
+
buildInternalHandlerContext({ env: this.env, request, body, executionCtx: this.executionCtx }),
|
|
280
|
+
namespace,
|
|
281
|
+
tableName,
|
|
282
|
+
directPath,
|
|
283
|
+
);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
private async requestViaDirectDo(
|
|
287
|
+
method: string,
|
|
288
|
+
doName: string,
|
|
289
|
+
directPathWithQuery: string,
|
|
290
|
+
headers: Record<string, string>,
|
|
291
|
+
body?: Record<string, unknown>,
|
|
292
|
+
isDynamic?: boolean,
|
|
293
|
+
): Promise<Response> {
|
|
294
|
+
const res = await callDO(this.databaseNamespace, doName, directPathWithQuery, {
|
|
295
|
+
method,
|
|
296
|
+
body,
|
|
297
|
+
headers,
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
// Handle dynamic DO creation
|
|
301
|
+
if (isDynamic && res.status === 201) {
|
|
302
|
+
const createPayload = await res.clone().json().catch(() => null) as
|
|
303
|
+
| { needsCreate?: boolean }
|
|
304
|
+
| null;
|
|
305
|
+
if (createPayload?.needsCreate) {
|
|
306
|
+
return callDO(this.databaseNamespace, doName, directPathWithQuery, {
|
|
307
|
+
method,
|
|
308
|
+
body,
|
|
309
|
+
headers: { ...headers, 'X-DO-Create-Authorized': '1' },
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
return res;
|
|
315
|
+
}
|
|
316
|
+
}
|
package/src/lib/pagination.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Pagination parameter validation.
|
|
3
3
|
*
|
|
4
|
-
* Clamps limit to 1..
|
|
4
|
+
* Clamps limit to 1..1000 (default 100) and offset to ≥0 (default 0).
|
|
5
5
|
* Handles NaN, negative, and absurdly large values safely.
|
|
6
6
|
*/
|
|
7
7
|
|
|
@@ -9,8 +9,8 @@ export function parsePagination(
|
|
|
9
9
|
limitParam: string | undefined,
|
|
10
10
|
offsetParam: string | undefined,
|
|
11
11
|
): { limit: number; offset: number } {
|
|
12
|
-
const rawLimit = parseInt(limitParam || '
|
|
13
|
-
const limit = Number.isFinite(rawLimit) && rawLimit > 0 ? Math.min(rawLimit,
|
|
12
|
+
const rawLimit = parseInt(limitParam || '100', 10);
|
|
13
|
+
const limit = Number.isFinite(rawLimit) && rawLimit > 0 ? Math.min(rawLimit, 1000) : 100;
|
|
14
14
|
|
|
15
15
|
const rawOffset = parseInt(offsetParam || '0', 10);
|
|
16
16
|
const offset = Number.isFinite(rawOffset) && rawOffset >= 0 ? rawOffset : 0;
|
|
@@ -350,7 +350,7 @@ function buildMigrationAdminContext(
|
|
|
350
350
|
return doAdminDb(namespace, id);
|
|
351
351
|
},
|
|
352
352
|
|
|
353
|
-
async
|
|
353
|
+
async sqlWithDirectD1Access(
|
|
354
354
|
namespace: string,
|
|
355
355
|
id: string | undefined,
|
|
356
356
|
query: string,
|
|
@@ -359,7 +359,7 @@ function buildMigrationAdminContext(
|
|
|
359
359
|
const dbBlock = config.databases?.[namespace];
|
|
360
360
|
const isDynamicNamespace = !!(dbBlock?.instance || dbBlock?.access?.canCreate || dbBlock?.access?.access);
|
|
361
361
|
if (isDynamicNamespace && !id) {
|
|
362
|
-
throw new Error(`admin.
|
|
362
|
+
throw new Error(`admin.sqlWithDirectD1Access() requires an id for dynamic namespace '${namespace}'.`);
|
|
363
363
|
}
|
|
364
364
|
|
|
365
365
|
const pgConnStr = resolvePgConnString(namespace);
|
|
@@ -365,7 +365,7 @@ async function handleList(
|
|
|
365
365
|
total = Number(countResult.rows[0]?.total ?? 0);
|
|
366
366
|
}
|
|
367
367
|
|
|
368
|
-
const perPage = queryOpts.pagination?.limit ?? queryOpts.pagination?.perPage ??
|
|
368
|
+
const perPage = queryOpts.pagination?.limit ?? queryOpts.pagination?.perPage ?? 100;
|
|
369
369
|
const page = queryOpts.pagination?.page ?? 1;
|
|
370
370
|
const hasMore = queryOpts.pagination?.after || queryOpts.pagination?.before
|
|
371
371
|
? items.length >= perPage
|
|
@@ -428,7 +428,7 @@ async function handleSearch(
|
|
|
428
428
|
const ftsFields = tableConfig.fts?.length
|
|
429
429
|
? tableConfig.fts
|
|
430
430
|
: getTextFields(tableConfig);
|
|
431
|
-
const limit = queryOpts.pagination?.limit ?? queryOpts.pagination?.perPage ??
|
|
431
|
+
const limit = queryOpts.pagination?.limit ?? queryOpts.pagination?.perPage ?? 100;
|
|
432
432
|
const offset = queryOpts.pagination?.offset ?? ((queryOpts.pagination?.page ?? 1) - 1) * limit;
|
|
433
433
|
const searchQuery = buildSearchQuery(tableName, searchTerm, {
|
|
434
434
|
pagination: queryOpts.pagination,
|
package/src/lib/query-engine.ts
CHANGED
|
@@ -657,10 +657,10 @@ function buildLimitClause(
|
|
|
657
657
|
const _bt = bt ?? new BindTracker('sqlite');
|
|
658
658
|
|
|
659
659
|
if (!pagination) {
|
|
660
|
-
return { limitClause: `LIMIT ${_bt.next()}`, limitParams: [
|
|
660
|
+
return { limitClause: `LIMIT ${_bt.next()}`, limitParams: [100] }; // Default limit
|
|
661
661
|
}
|
|
662
662
|
|
|
663
|
-
const limit = pagination.limit ?? pagination.perPage ??
|
|
663
|
+
const limit = Math.min(pagination.limit ?? pagination.perPage ?? 100, 1000);
|
|
664
664
|
|
|
665
665
|
// Cursor-based: no offset
|
|
666
666
|
if (pagination.after || pagination.before) {
|
|
@@ -50,17 +50,17 @@ export const RATE_LIMIT_DEFAULTS: Record<string, { requests: number; windowSec:
|
|
|
50
50
|
events: { requests: 100, windowSec: 60 },
|
|
51
51
|
};
|
|
52
52
|
|
|
53
|
-
// Dev mode defaults:
|
|
54
|
-
// hot-reload page refreshes,
|
|
53
|
+
// Dev mode defaults: significantly higher to accommodate React strict mode double-rendering,
|
|
54
|
+
// hot-reload page refreshes, onSnapshot polling, and multi-client testing during development.
|
|
55
55
|
export const RATE_LIMIT_DEV_DEFAULTS: Record<string, { requests: number; windowSec: number }> = {
|
|
56
56
|
global: { requests: 10_000_000, windowSec: 60 },
|
|
57
|
-
db: { requests:
|
|
58
|
-
storage: { requests:
|
|
59
|
-
functions: { requests:
|
|
60
|
-
auth: { requests:
|
|
57
|
+
db: { requests: 5000, windowSec: 60 },
|
|
58
|
+
storage: { requests: 1000, windowSec: 60 },
|
|
59
|
+
functions: { requests: 1000, windowSec: 60 },
|
|
60
|
+
auth: { requests: 500, windowSec: 60 },
|
|
61
61
|
authSignin: { requests: 100, windowSec: 60 },
|
|
62
62
|
authSignup: { requests: 100, windowSec: 60 },
|
|
63
|
-
events: { requests:
|
|
63
|
+
events: { requests: 5000, windowSec: 60 },
|
|
64
64
|
};
|
|
65
65
|
|
|
66
66
|
// ─── Window parser ───
|
|
@@ -256,7 +256,7 @@ export const rateLimitMiddleware: MiddlewareHandler<HonoEnv> = async (c, next) =
|
|
|
256
256
|
if (!counter.check(counterKey, requests, windowSec)) {
|
|
257
257
|
c.header('Retry-After', String(counter.getRetryAfter(counterKey)));
|
|
258
258
|
return c.json(
|
|
259
|
-
{ code: 429, message: 'Too many requests. Please try again later.' },
|
|
259
|
+
{ code: 429, message: 'Too many requests. Please try again later.', group },
|
|
260
260
|
429,
|
|
261
261
|
);
|
|
262
262
|
}
|
|
@@ -268,7 +268,7 @@ export const rateLimitMiddleware: MiddlewareHandler<HonoEnv> = async (c, next) =
|
|
|
268
268
|
if (!success) {
|
|
269
269
|
c.header('Retry-After', '60');
|
|
270
270
|
return c.json(
|
|
271
|
-
{ code: 429, message: 'Too many requests. Please try again later.' },
|
|
271
|
+
{ code: 429, message: 'Too many requests. Please try again later.', group },
|
|
272
272
|
429,
|
|
273
273
|
);
|
|
274
274
|
}
|
|
@@ -282,7 +282,7 @@ export const rateLimitMiddleware: MiddlewareHandler<HonoEnv> = async (c, next) =
|
|
|
282
282
|
if (!counter.check(globalKey, globalLimit.requests, globalLimit.windowSec)) {
|
|
283
283
|
c.header('Retry-After', String(counter.getRetryAfter(globalKey)));
|
|
284
284
|
return c.json(
|
|
285
|
-
{ code: 429, message: 'Too many requests. Please try again later.' },
|
|
285
|
+
{ code: 429, message: 'Too many requests. Please try again later.', group: 'global' },
|
|
286
286
|
429,
|
|
287
287
|
);
|
|
288
288
|
}
|
|
@@ -294,7 +294,7 @@ export const rateLimitMiddleware: MiddlewareHandler<HonoEnv> = async (c, next) =
|
|
|
294
294
|
if (!success) {
|
|
295
295
|
c.header('Retry-After', '60');
|
|
296
296
|
return c.json(
|
|
297
|
-
{ code: 429, message: 'Too many requests. Please try again later.' },
|
|
297
|
+
{ code: 429, message: 'Too many requests. Please try again later.', group: 'global' },
|
|
298
298
|
429,
|
|
299
299
|
);
|
|
300
300
|
}
|
package/src/routes/admin.ts
CHANGED
|
@@ -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
|
}
|
|
@@ -240,8 +246,8 @@ function getLogStatusCode(log: Record<string, unknown>): number {
|
|
|
240
246
|
function matchesLogLevel(status: number, level: string): boolean {
|
|
241
247
|
const normalized = level.toLowerCase();
|
|
242
248
|
if (normalized === 'error') return status >= 500;
|
|
243
|
-
if (normalized === 'warn') return status >= 300 && status < 500;
|
|
244
|
-
if (normalized === 'info') return status >= 200 && status < 300;
|
|
249
|
+
if (normalized === 'warn') return (status >= 300 && status < 500 && status !== 304);
|
|
250
|
+
if (normalized === 'info') return (status >= 200 && status < 300) || status === 304;
|
|
245
251
|
return true;
|
|
246
252
|
}
|
|
247
253
|
|
package/src/routes/auth.ts
CHANGED
|
@@ -54,6 +54,7 @@ import {
|
|
|
54
54
|
buildFunctionPushProxy,
|
|
55
55
|
buildAdminAuthContext,
|
|
56
56
|
buildAdminDbProxy,
|
|
57
|
+
executeSqlWithDirectD1Access,
|
|
57
58
|
getWorkerUrl,
|
|
58
59
|
} from '../lib/functions.js';
|
|
59
60
|
import * as authService from '../lib/auth-d1-service.js';
|
|
@@ -509,6 +510,13 @@ async function createSessionAndTokens(
|
|
|
509
510
|
metadata,
|
|
510
511
|
});
|
|
511
512
|
|
|
513
|
+
// Update lastSignedInAt on the user record
|
|
514
|
+
try {
|
|
515
|
+
await db.run('UPDATE _users SET lastSignedInAt = ? WHERE id = ?', [now, userId]);
|
|
516
|
+
} catch {
|
|
517
|
+
// Non-critical: don't block sign-in if this column doesn't exist yet
|
|
518
|
+
}
|
|
519
|
+
|
|
512
520
|
return { accessToken, refreshToken, sessionId };
|
|
513
521
|
}
|
|
514
522
|
|
|
@@ -652,18 +660,11 @@ export async function executeAuthHook(
|
|
|
652
660
|
db: adminDb,
|
|
653
661
|
table: (name: string) => adminDb('shared').table(name),
|
|
654
662
|
auth: authAdmin,
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
body: JSON.stringify({ namespace, id, sql: query, params: params ?? [] }),
|
|
661
|
-
});
|
|
662
|
-
if (!res.ok) throw new Error(`admin.sql() failed: ${res.status}`);
|
|
663
|
-
return res.json();
|
|
664
|
-
}
|
|
665
|
-
throw new Error('admin.sql() requires workerUrl in auth hook context.');
|
|
666
|
-
},
|
|
663
|
+
sqlWithDirectD1Access: (namespace: string, id: string | undefined, query: string, params?: unknown[]) =>
|
|
664
|
+
executeSqlWithDirectD1Access(
|
|
665
|
+
{ env, config, databaseNamespace: env.DATABASE, workerUrl: options.workerUrl, serviceKey },
|
|
666
|
+
namespace, id, query, params,
|
|
667
|
+
),
|
|
667
668
|
async broadcast(channel: string, event: string, payload?: Record<string, unknown>) {
|
|
668
669
|
if (options.workerUrl && serviceKey) {
|
|
669
670
|
await fetch(`${options.workerUrl}/api/db/broadcast`, {
|
package/src/routes/storage.ts
CHANGED
|
@@ -44,6 +44,7 @@ import {
|
|
|
44
44
|
buildFunctionPushProxy,
|
|
45
45
|
buildAdminAuthContext,
|
|
46
46
|
buildAdminDbProxy,
|
|
47
|
+
executeSqlWithDirectD1Access,
|
|
47
48
|
getWorkerUrl,
|
|
48
49
|
} from '../lib/functions.js';
|
|
49
50
|
|
|
@@ -165,18 +166,11 @@ 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
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
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
|
+
sqlWithDirectD1Access: (namespace: string, id: string | undefined, query: string, params?: unknown[]) =>
|
|
170
|
+
executeSqlWithDirectD1Access(
|
|
171
|
+
{ env, config, databaseNamespace: env.DATABASE, workerUrl, serviceKey },
|
|
172
|
+
namespace, id, query, params,
|
|
173
|
+
),
|
|
180
174
|
async broadcast(channel: string, event: string, payload?: Record<string, unknown>) {
|
|
181
175
|
if (workerUrl && serviceKey) {
|
|
182
176
|
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
|
-
.sql-editor-wrap.svelte-392xt8{border:1px solid var(--color-border);border-radius:var(--radius-md);overflow:hidden}.sql-editor-wrap.svelte-392xt8 .cm-editor{min-height:120px}.sql-editor-wrap.svelte-392xt8 .cm-editor.cm-focused{border-color:var(--color-primary);box-shadow:0 0 0 2px color-mix(in srgb,var(--color-primary) 20%,transparent)}.table-sql.svelte-1syrthj{display:flex;flex-direction:column;gap:var(--space-4)}.table-sql__toolbar.svelte-1syrthj{display:flex;align-items:center;gap:var(--space-3);flex-wrap:wrap}.table-sql__target.svelte-1syrthj{display:inline-flex;align-items:center;gap:var(--space-2);padding:var(--space-2) var(--space-3);border:1px solid var(--color-border);border-radius:var(--radius-md);background:var(--color-bg-secondary);font-size:12px}.table-sql__target-label.svelte-1syrthj{color:var(--color-text-tertiary);text-transform:uppercase;letter-spacing:.04em}.table-sql__target.svelte-1syrthj code:where(.svelte-1syrthj){font-family:var(--font-mono);color:var(--color-text)}.table-sql__shortcut.svelte-1syrthj{font-size:12px;color:var(--color-text-tertiary);margin-left:auto}.table-sql__result-tabs.svelte-1syrthj{display:flex;flex-wrap:wrap;gap:var(--space-2)}.table-sql__result-tab.svelte-1syrthj{display:inline-flex;align-items:center;gap:var(--space-2);padding:var(--space-2) var(--space-3);border:1px solid var(--color-border);border-radius:var(--radius-md);background:var(--color-bg-secondary);color:var(--color-text-secondary);cursor:pointer}.table-sql__result-tab--active.svelte-1syrthj{border-color:var(--color-primary);color:var(--color-primary)}.table-sql__result-open.svelte-1syrthj{border:none;background:transparent;color:inherit;cursor:pointer;padding:0;font:inherit}.table-sql__result-close.svelte-1syrthj{border:none;background:transparent;color:inherit;cursor:pointer;padding:0;line-height:1}.table-sql__result-panel.svelte-1syrthj{border:1px solid var(--color-border);border-radius:var(--radius-md);padding:var(--space-4);background:var(--color-bg)}.table-sql__result-meta.svelte-1syrthj{margin-bottom:var(--space-3);font-size:12px;color:var(--color-text-secondary)}.table-sql__result-error.svelte-1syrthj{color:var(--color-danger, #ef4444)}.table-sql__error-block.svelte-1syrthj,.table-sql__empty.svelte-1syrthj{margin:0;padding:var(--space-4);border-radius:var(--radius-md);background:var(--color-bg-secondary);color:var(--color-text-secondary);font-size:13px}
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import"./CWj6FrbW.js";import{p as je,w as le,a as Be,b as k,g as o,d as M,M as Ke,t as E,u as D,s as w,c as g,r as h,ae as ke,f as Ge}from"./BdTBlfLy.js";import{s as B,d as Ye,a as pe}from"./DtZk82gG.js";import{a as C,f as P,t as He}from"./DEELgv7K.js";import{i as W}from"./Y22E1hJM.js";import{a as Je,t as $e,e as et}from"./B14gOIqE.js";import{s as tt,a as at}from"./CoI6jjbg.js";import{a as rt,s as st}from"./Cp8V0Xy2.js";import{B as ot}from"./C72lTcG0.js";import{D as nt}from"./D8Nrx_IG.js";import{o as lt,a as it}from"./Bn2NtlTj.js";import{b as ct}from"./CGgVJi7f.js";import{p as xe}from"./F9_4wRrd.js";import{L as dt,a as ft,i as mt,c as ut,b as ht,d as vt,f as Ot,s as gt,t as m,E as bt,e as kt,g as pt,h as se,j as xt,k as yt,l as Qt,m as _t,n as Ct,p as St,o as wt,q as Pt,r as Tt}from"./gtu8uwJD.js";import{s as ye}from"./BKLsgaNT.js";const qt=36,Qe=1,Ut=2,V=3,oe=4,jt=5,Bt=6,Et=7,It=8,Dt=9,Lt=10,Rt=11,Xt=12,Nt=13,Zt=14,zt=15,Vt=16,Mt=17,_e=18,At=19,Ee=20,Ie=21,Ce=22,Ft=23,Wt=24;function ie(t){return t>=65&&t<=90||t>=97&&t<=122||t>=48&&t<=57}function Kt(t){return t>=48&&t<=57||t>=97&&t<=102||t>=65&&t<=70}function R(t,e,r){for(let a=!1;;){if(t.next<0)return;if(t.next==e&&!a){t.advance();return}a=r&&!a&&t.next==92,t.advance()}}function Gt(t,e){e:for(;;){if(t.next<0)return;if(t.next==36){t.advance();for(let r=0;r<e.length;r++){if(t.next!=e.charCodeAt(r))continue e;t.advance()}if(t.next==36){t.advance();return}}else t.advance()}}function Yt(t,e){let r="[{<(".indexOf(String.fromCharCode(e)),a=r<0?e:"]}>)".charCodeAt(r);for(;;){if(t.next<0)return;if(t.next==a&&t.peek(1)==39){t.advance(2);return}t.advance()}}function ce(t,e){for(;!(t.next!=95&&!ie(t.next));)e!=null&&(e+=String.fromCharCode(t.next)),t.advance();return e}function Ht(t){if(t.next==39||t.next==34||t.next==96){let e=t.next;t.advance(),R(t,e,!1)}else ce(t)}function Se(t,e){for(;t.next==48||t.next==49;)t.advance();e&&t.next==e&&t.advance()}function we(t,e){for(;;){if(t.next==46){if(e)break;e=!0}else if(t.next<48||t.next>57)break;t.advance()}if(t.next==69||t.next==101)for(t.advance(),(t.next==43||t.next==45)&&t.advance();t.next>=48&&t.next<=57;)t.advance()}function Pe(t){for(;!(t.next<0||t.next==10);)t.advance()}function L(t,e){for(let r=0;r<e.length;r++)if(e.charCodeAt(r)==t)return!0;return!1}const ne=` \r
|
|
2
|
-
`;function De(t,e,r){let a=Object.create(null);a.true=a.false=jt,a.null=a.unknown=Bt;for(let s of t.split(" "))s&&(a[s]=Ee);for(let s of e.split(" "))s&&(a[s]=Ie);for(let s of(r||"").split(" "))s&&(a[s]=Wt);return a}const Le="array binary bit boolean char character clob date decimal double float int integer interval large national nchar nclob numeric object precision real smallint time timestamp varchar varying ",Re="absolute action add after all allocate alter and any are as asc assertion at authorization before begin between both breadth by call cascade cascaded case cast catalog check close collate collation column commit condition connect connection constraint constraints constructor continue corresponding count create cross cube current current_date current_default_transform_group current_transform_group_for_type current_path current_role current_time current_timestamp current_user cursor cycle data day deallocate declare default deferrable deferred delete depth deref desc describe descriptor deterministic diagnostics disconnect distinct do domain drop dynamic each else elseif end end-exec equals escape except exception exec execute exists exit external fetch first for foreign found from free full function general get global go goto grant group grouping handle having hold hour identity if immediate in indicator initially inner inout input insert intersect into is isolation join key language last lateral leading leave left level like limit local localtime localtimestamp locator loop map match method minute modifies module month names natural nesting new next no none not of old on only open option or order ordinality out outer output overlaps pad parameter partial path prepare preserve primary prior privileges procedure public read reads recursive redo ref references referencing relative release repeat resignal restrict result return returns revoke right role rollback rollup routine row rows savepoint schema scroll search second section select session session_user set sets signal similar size some space specific specifictype sql sqlexception sqlstate sqlwarning start state static system_user table temporary then timezone_hour timezone_minute to trailing transaction translation treat trigger under undo union unique unnest until update usage user using value values view when whenever where while with without work write year zone ",de={backslashEscapes:!1,hashComments:!1,spaceAfterDashes:!1,slashComments:!1,doubleQuotedStrings:!1,doubleDollarQuotedStrings:!1,unquotedBitLiterals:!1,treatBitsAsBytes:!1,charSetCasts:!1,plsqlQuotingMechanism:!1,operatorChars:"*+-%<>!=&|~^/",specialVar:"?",identifierQuotes:'"',caseInsensitiveIdentifiers:!1,words:De(Re,Le)};function Jt(t,e,r,a){let s={};for(let n in de)s[n]=(t.hasOwnProperty(n)?t:de)[n];return e&&(s.words=De(e,r||"",a)),s}function Xe(t){return new bt(e=>{var r;let{next:a}=e;if(e.advance(),L(a,ne)){for(;L(e.next,ne);)e.advance();e.acceptToken(qt)}else if(a==36&&t.doubleDollarQuotedStrings){let s=ce(e,"");e.next==36&&(e.advance(),Gt(e,s),e.acceptToken(V))}else if(a==39||a==34&&t.doubleQuotedStrings)R(e,a,t.backslashEscapes),e.acceptToken(V);else if(a==35&&t.hashComments||a==47&&e.next==47&&t.slashComments)Pe(e),e.acceptToken(Qe);else if(a==45&&e.next==45&&(!t.spaceAfterDashes||e.peek(1)==32))Pe(e),e.acceptToken(Qe);else if(a==47&&e.next==42){e.advance();for(let s=1;;){let n=e.next;if(e.next<0)break;if(e.advance(),n==42&&e.next==47){if(s--,e.advance(),!s)break}else n==47&&e.next==42&&(s++,e.advance())}e.acceptToken(Ut)}else if((a==101||a==69)&&e.next==39)e.advance(),R(e,39,!0),e.acceptToken(V);else if((a==110||a==78)&&e.next==39&&t.charSetCasts)e.advance(),R(e,39,t.backslashEscapes),e.acceptToken(V);else if(a==95&&t.charSetCasts)for(let s=0;;s++){if(e.next==39&&s>1){e.advance(),R(e,39,t.backslashEscapes),e.acceptToken(V);break}if(!ie(e.next))break;e.advance()}else if(t.plsqlQuotingMechanism&&(a==113||a==81)&&e.next==39&&e.peek(1)>0&&!L(e.peek(1),ne)){let s=e.peek(1);e.advance(2),Yt(e,s),e.acceptToken(V)}else if(L(a,t.identifierQuotes)){const s=a==91?93:a;R(e,s,!1),e.acceptToken(At)}else if(a==40)e.acceptToken(Et);else if(a==41)e.acceptToken(It);else if(a==123)e.acceptToken(Dt);else if(a==125)e.acceptToken(Lt);else if(a==91)e.acceptToken(Rt);else if(a==93)e.acceptToken(Xt);else if(a==59)e.acceptToken(Nt);else if(t.unquotedBitLiterals&&a==48&&e.next==98)e.advance(),Se(e),e.acceptToken(Ce);else if((a==98||a==66)&&(e.next==39||e.next==34)){const s=e.next;e.advance(),t.treatBitsAsBytes?(R(e,s,t.backslashEscapes),e.acceptToken(Ft)):(Se(e,s),e.acceptToken(Ce))}else if(a==48&&(e.next==120||e.next==88)||(a==120||a==88)&&e.next==39){let s=e.next==39;for(e.advance();Kt(e.next);)e.advance();s&&e.next==39&&e.advance(),e.acceptToken(oe)}else if(a==46&&e.next>=48&&e.next<=57)we(e,!0),e.acceptToken(oe);else if(a==46)e.acceptToken(Zt);else if(a>=48&&a<=57)we(e,!1),e.acceptToken(oe);else if(L(a,t.operatorChars)){for(;L(e.next,t.operatorChars);)e.advance();e.acceptToken(zt)}else if(L(a,t.specialVar))e.next==a&&e.advance(),Ht(e),e.acceptToken(Mt);else if(a==58||a==44)e.acceptToken(Vt);else if(ie(a)){let s=ce(e,String.fromCharCode(a));e.acceptToken(e.next==46||e.peek(-s.length-1)==46?_e:(r=t.words[s.toLowerCase()])!==null&&r!==void 0?r:_e)}})}const Ne=Xe(de),$t=kt.deserialize({version:14,states:"%vQ]QQOOO#wQRO'#DSO$OQQO'#CwO%eQQO'#CxO%lQQO'#CyO%sQQO'#CzOOQQ'#DS'#DSOOQQ'#C}'#C}O'UQRO'#C{OOQQ'#Cv'#CvOOQQ'#C|'#C|Q]QQOOQOQQOOO'`QQO'#DOO(xQRO,59cO)PQQO,59cO)UQQO'#DSOOQQ,59d,59dO)cQQO,59dOOQQ,59e,59eO)jQQO,59eOOQQ,59f,59fO)qQQO,59fOOQQ-E6{-E6{OOQQ,59b,59bOOQQ-E6z-E6zOOQQ,59j,59jOOQQ-E6|-E6|O+VQRO1G.}O+^QQO,59cOOQQ1G/O1G/OOOQQ1G/P1G/POOQQ1G/Q1G/QP+kQQO'#C}O+rQQO1G.}O)PQQO,59cO,PQQO'#Cw",stateData:",[~OtOSPOSQOS~ORUOSUOTUOUUOVROXSOZTO]XO^QO_UO`UOaPObPOcPOdUOeUOfUOgUOhUO~O^]ORvXSvXTvXUvXVvXXvXZvX]vX_vX`vXavXbvXcvXdvXevXfvXgvXhvX~OsvX~P!jOa_Ob_Oc_O~ORUOSUOTUOUUOVROXSOZTO^tO_UO`UOa`Ob`Oc`OdUOeUOfUOgUOhUO~OWaO~P$ZOYcO~P$ZO[eO~P$ZORUOSUOTUOUUOVROXSOZTO^QO_UO`UOaPObPOcPOdUOeUOfUOgUOhUO~O]hOsoX~P%zOajObjOcjO~O^]ORkaSkaTkaUkaVkaXkaZka]ka_ka`kaakabkackadkaekafkagkahka~Oska~P'kO^]O~OWvXYvX[vX~P!jOWnO~P$ZOYoO~P$ZO[pO~P$ZO^]ORkiSkiTkiUkiVkiXkiZki]ki_ki`kiakibkickidkiekifkigkihki~Oski~P)xOWkaYka[ka~P'kO]hO~P$ZOWkiYki[ki~P)xOasObsOcsO~O",goto:"#hwPPPPPPPPPPPPPPPPPPPPPPPPPPx||||!Y!^!d!xPPP#[TYOZeUORSTWZbdfqT[OZQZORiZSWOZQbRQdSQfTZgWbdfqQ^PWk^lmrQl_Qm`RrseVORSTWZbdfq",nodeNames:"⚠ LineComment BlockComment String Number Bool Null ( ) { } [ ] ; . Operator Punctuation SpecialVar Identifier QuotedIdentifier Keyword Type Bits Bytes Builtin Script Statement CompositeIdentifier Parens Braces Brackets Statement",maxTerm:38,nodeProps:[["isolate",-4,1,2,3,19,""]],skippedNodes:[0,1,2],repeatNodeCount:3,tokenData:"RORO",tokenizers:[0,Ne],topRules:{Script:[0,25]},tokenPrec:0});function fe(t){let e=t.cursor().moveTo(t.from,-1);for(;/Comment/.test(e.name);)e.moveTo(e.from,-1);return e.node}function K(t,e){let r=t.sliceString(e.from,e.to),a=/^([`'"\[])(.*)([`'"\]])$/.exec(r);return a?a[2]:r}function ee(t){return t&&(t.name=="Identifier"||t.name=="QuotedIdentifier")}function ea(t,e){if(e.name=="CompositeIdentifier"){let r=[];for(let a=e.firstChild;a;a=a.nextSibling)ee(a)&&r.push(K(t,a));return r}return[K(t,e)]}function Te(t,e){for(let r=[];;){if(!e||e.name!=".")return r;let a=fe(e);if(!ee(a))return r;r.unshift(K(t,a)),e=fe(a)}}function ta(t,e){let r=pt(t).resolveInner(e,-1),a=ra(t.doc,r);return r.name=="Identifier"||r.name=="QuotedIdentifier"||r.name=="Keyword"?{from:r.from,quoted:r.name=="QuotedIdentifier"?t.doc.sliceString(r.from,r.from+1):null,parents:Te(t.doc,fe(r)),aliases:a}:r.name=="."?{from:e,quoted:null,parents:Te(t.doc,r),aliases:a}:{from:e,quoted:null,parents:[],empty:!0,aliases:a}}const aa=new Set("where group having order union intersect except all distinct limit offset fetch for".split(" "));function ra(t,e){let r;for(let s=e;!r;s=s.parent){if(!s)return null;s.name=="Statement"&&(r=s)}let a=null;for(let s=r.firstChild,n=!1,f=null;s;s=s.nextSibling){let l=s.name=="Keyword"?t.sliceString(s.from,s.to).toLowerCase():null,i=null;if(!n)n=l=="from";else if(l=="as"&&f&&ee(s.nextSibling))i=K(t,s.nextSibling);else{if(l&&aa.has(l))break;f&&ee(s)&&(i=K(t,s))}i&&(a||(a=Object.create(null)),a[i]=ea(t,f)),f=/Identifier$/.test(s.name)?s:null}return a}function sa(t,e,r){return r.map(a=>({...a,label:a.label[0]==t?a.label:t+a.label+e,apply:void 0}))}const oa=/^\w*$/,na=/^[`'"\[]?\w*[`'"\]]?$/;function qe(t){return t.self&&typeof t.self.label=="string"}class me{constructor(e,r){this.idQuote=e,this.idCaseInsensitive=r,this.list=[],this.children=void 0}child(e){let r=this.children||(this.children=Object.create(null)),a=r[e];return a||(e&&!this.list.some(s=>s.label==e)&&this.list.push(Ue(e,"type",this.idQuote,this.idCaseInsensitive)),r[e]=new me(this.idQuote,this.idCaseInsensitive))}maybeChild(e){return this.children?this.children[e]:null}addCompletion(e){let r=this.list.findIndex(a=>a.label==e.label);r>-1?this.list[r]=e:this.list.push(e)}addCompletions(e){for(let r of e)this.addCompletion(typeof r=="string"?Ue(r,"property",this.idQuote,this.idCaseInsensitive):r)}addNamespace(e){Array.isArray(e)?this.addCompletions(e):qe(e)?this.addNamespace(e.children):this.addNamespaceObject(e)}addNamespaceObject(e){for(let r of Object.keys(e)){let a=e[r],s=null,n=r.replace(/\\?\./g,l=>l=="."?"\0":l).split("\0"),f=this;qe(a)&&(s=a.self,a=a.children);for(let l=0;l<n.length;l++)s&&l==n.length-1&&f.addCompletion(s),f=f.child(n[l].replace(/\\\./g,"."));f.addNamespace(a)}}}function Ue(t,e,r,a){return new RegExp("^[a-z_][a-z_\\d]*$",a?"i":"").test(t)?{label:t,type:e}:{label:t,type:e,apply:r+t+Ze(r)}}function Ze(t){return t==="["?"]":t}function la(t,e,r,a,s,n){var f;let l=((f=n==null?void 0:n.spec.identifierQuotes)===null||f===void 0?void 0:f[0])||'"',i=new me(l,!!(n!=null&&n.spec.caseInsensitiveIdentifiers)),v=s?i.child(s):null;return i.addNamespace(t),e&&(v||i).addCompletions(e),r&&i.addCompletions(r),v&&i.addCompletions(v.list),a&&i.addCompletions((v||i).child(a).list),p=>{let{parents:O,from:y,quoted:T,empty:te,aliases:X}=ta(p.state,p.pos);if(te&&!p.explicit)return null;X&&O.length==1&&(O=X[O[0]]||O);let x=i;for(let S of O){for(;!x.children||!x.children[S];)if(x==i&&v)x=v;else if(x==v&&a)x=x.child(a);else return null;let q=x.maybeChild(S);if(!q)return null;x=q}let N=x.list;if(x==i&&X&&(N=N.concat(Object.keys(X).map(S=>({label:S,type:"constant"})))),T){let S=T[0],q=Ze(S),A=p.state.sliceDoc(p.pos,p.pos+1)==q;return{from:y,to:A?p.pos+1:void 0,options:sa(S,q,N),validFor:na}}else return{from:y,options:N,validFor:oa}}}function ia(t){return t==Ie?"type":t==Ee?"keyword":"variable"}function ca(t,e,r){let a=Object.keys(t).map(s=>r(e?s.toUpperCase():s,ia(t[s])));return mt(["QuotedIdentifier","String","LineComment","BlockComment","."],ut(a))}let da=$t.configure({props:[ht.add({Statement:vt()}),Ot.add({Statement(t,e){return{from:Math.min(t.from+100,e.doc.lineAt(t.from).to),to:t.to}},BlockComment(t){return{from:t.from+2,to:t.to-2}}}),gt({Keyword:m.keyword,Type:m.typeName,Builtin:m.standard(m.name),Bits:m.number,Bytes:m.string,Bool:m.bool,Null:m.null,Number:m.number,String:m.string,Identifier:m.name,QuotedIdentifier:m.special(m.string),SpecialVar:m.special(m.name),LineComment:m.lineComment,BlockComment:m.blockComment,Operator:m.operator,"Semi Punctuation":m.punctuation,"( )":m.paren,"{ }":m.brace,"[ ]":m.squareBracket})]});class G{constructor(e,r,a){this.dialect=e,this.language=r,this.spec=a}get extension(){return this.language.extension}configureLanguage(e,r){return new G(this.dialect,this.language.configure(e,r),this.spec)}static define(e){let r=Jt(e,e.keywords,e.types,e.builtin),a=ft.define({name:"sql",parser:da.configure({tokenizers:[{from:Ne,to:Xe(r)}]}),languageData:{commentTokens:{line:"--",block:{open:"/*",close:"*/"}},closeBrackets:{brackets:["(","[","{","'",'"',"`"]}}});return new G(r,a,e)}}function fa(t,e){return{label:t,type:e,boost:-1}}function ma(t,e=!1,r){return ca(t.dialect.words,e,r||fa)}function ua(t){return t.schema?la(t.schema,t.tables,t.schemas,t.defaultTable,t.defaultSchema,t.dialect||ue):()=>null}function ha(t){return t.schema?(t.dialect||ue).language.data.of({autocomplete:ua(t)}):[]}function va(t={}){let e=t.dialect||ue;return new dt(e.language,[ha(t),e.language.data.of({autocomplete:ma(e,t.upperCaseKeywords,t.keywordCompletion)})])}const ue=G.define({}),Oa=G.define({keywords:Re+"abort analyze attach autoincrement conflict database detach exclusive fail glob ignore index indexed instead isnull notnull offset plan pragma query raise regexp reindex rename replace temp vacuum virtual",types:Le+"bool blob long longblob longtext medium mediumblob mediumint mediumtext tinyblob tinyint tinytext text bigint int2 int8 unsigned signed real",builtin:"auth backup bail changes clone databases dbinfo dump echo eqp explain fullschema headers help import imposter indexes iotrace lint load log mode nullvalue once print prompt quit restore save scanstats separator shell show stats system tables testcase timeout timer trace vfsinfo vfslist vfsname width",operatorChars:"*+-%<>!=&|/~",identifierQuotes:'`"',specialVar:"@:?$"});var ga=P('<div class="sql-editor-wrap svelte-392xt8"></div>');function ba(t,e){je(e,!0);let r=xe(e,"placeholder",3,""),a=xe(e,"schema",19,()=>({})),s,n,f=M(!1);function l(){return document.documentElement.dataset.theme==="dark"||document.documentElement.dataset.theme!=="light"&&window.matchMedia("(prefers-color-scheme: dark)").matches}function i(){const O=[va({dialect:Oa,schema:a()}),yt(),Qt.of([..._t,Ct,{key:"Mod-Enter",run:()=>{var y;return(y=e.onExecute)==null||y.call(e),!0}}]),se.updateListener.of(y=>{if(y.docChanged){const T=y.state.doc.toString();e.onchange(T)}}),se.theme({"&":{fontSize:"13px",maxHeight:"300px"},".cm-scroller":{overflow:"auto",fontFamily:"var(--font-mono)"},".cm-content":{minHeight:"100px",padding:"8px 0"},"&.cm-focused":{outline:"none"}})];return r()&&O.push(St(r())),o(f)?O.push(wt):O.push(Pt(Tt)),O}function v(){n&&n.destroy(),n=new se({state:xt.create({doc:e.value,extensions:i()}),parent:s})}lt(()=>{k(f,l(),!0),v();const O=new MutationObserver(()=>{const y=l();if(y!==o(f)){k(f,y,!0);const T=(n==null?void 0:n.state.doc.toString())??e.value;v(),T!==e.value&&(n==null||n.dispatch({changes:{from:0,to:n.state.doc.length,insert:T}}))}});return O.observe(document.documentElement,{attributes:!0,attributeFilter:["data-theme"]}),()=>{O.disconnect(),n==null||n.destroy()}}),it(()=>{n==null||n.destroy()}),le(()=>{n&&e.value!==n.state.doc.toString()&&n.dispatch({changes:{from:0,to:n.state.doc.length,insert:e.value}})});var p=ga();ct(p,O=>s=O,()=>s),C(t,p),Be()}var ka=P('<div class="table-sql__target svelte-1syrthj"><span class="table-sql__target-label svelte-1syrthj"> </span> <code class="svelte-1syrthj"> </code></div>'),pa=P('<div><button type="button" class="table-sql__result-open svelte-1syrthj"><span> </span></button> <button type="button" class="table-sql__result-close svelte-1syrthj">×</button></div>'),xa=P('<span class="table-sql__result-error svelte-1syrthj"> </span>'),ya=P("<span> </span>"),Qa=P('<pre class="table-sql__error-block svelte-1syrthj"> </pre>'),_a=P('<div class="table-sql__empty svelte-1syrthj">Query returned no rows.</div>'),Ca=P('<div class="table-sql__result-panel svelte-1syrthj"><div class="table-sql__result-meta svelte-1syrthj"><!></div> <!></div>'),Sa=P('<div class="table-sql__result-tabs svelte-1syrthj"></div> <!>',1),wa=P('<div class="table-sql__empty svelte-1syrthj">Run a query against <code> </code> to inspect rows, joins, or aggregates for this target.</div>'),Pa=P('<div class="table-sql svelte-1syrthj"><div class="table-sql__toolbar svelte-1syrthj"><div class="table-sql__target svelte-1syrthj"><span class="table-sql__target-label svelte-1syrthj">Database</span> <code class="svelte-1syrthj"> </code></div> <!> <!> <span class="table-sql__shortcut svelte-1syrthj"></span></div> <!> <!></div>');function Ma(t,e){var be;je(e,!0);const r=()=>rt(ye,"$schemaStore",a),[a,s]=st();let n=M(""),f=M(!1),l=M(Ke([])),i=M(0),v=M(0),p=D(()=>r().schema[e.tableName]),O=D(()=>(()=>{const c={},d=r().schema;for(const[u,_]of Object.entries(d)){const I=_.fields;c[u]=I?Object.keys(I):[]}return c})()),y=D(()=>{var c;return(c=o(p))!=null&&c.dynamic?"Per-tenant DB":"Single DB"}),T=D(()=>{var c,d,u;return((u=(d=(c=o(p))==null?void 0:c.instanceDiscovery)==null?void 0:d.targetLabel)==null?void 0:u.trim())||"Target"}),te=D(()=>e.instanceId||"Not selected");function X(c){return`SELECT * FROM "${c}" LIMIT 100;`}le(()=>{k(n,X(e.tableName),!0)}),le(()=>{Object.keys(r().schema).length===0&&ye.loadSchema({silent:!0})});async function x(){if(o(n).trim()){k(f,!0);try{const c=await Je.fetch("data/sql",{method:"POST",body:{namespace:e.namespace,id:e.instanceId||void 0,sql:o(n).trim()}}),d=(c.columns??[]).map(u=>({key:u,label:u,type:"text",editable:!1}));k(v,o(v)+1),k(l,[...o(l),{id:o(v),sql:o(n).trim(),columns:d,rows:c.rows??[],rowCount:c.rowCount??0,time:c.time??0}],!0),k(i,o(l).length-1)}catch(c){const d=c instanceof Error?c.message:"Query failed";$e(d),k(v,o(v)+1),k(l,[...o(l),{id:o(v),sql:o(n).trim(),columns:[],rows:[],rowCount:0,time:0,error:d}],!0),k(i,o(l).length-1)}finally{k(f,!1)}}}function N(c){const d=o(l).filter((u,_)=>_!==c);o(i)>c?k(i,o(i)-1):o(i)===c&&k(i,Math.min(c,Math.max(0,d.length-1)),!0),k(l,d,!0)}var S=Pa(),q=g(S),A=g(q),he=w(g(A),2),ze=g(he,!0);h(he),h(A);var ve=w(A,2);{var Ve=c=>{var d=ka(),u=g(d),_=g(u,!0);h(u);var I=w(u,2),U=g(I,!0);h(I),h(d),E(()=>{B(_,o(T)),B(U,o(te))}),C(c,d)};W(ve,c=>{var d;(d=o(p))!=null&&d.dynamic&&c(Ve)})}var Oe=w(ve,2);{let c=D(()=>o(f)||!o(n).trim());ot(Oe,{variant:"primary",size:"sm",onclick:x,get loading(){return o(f)},get disabled(){return o(c)},children:(d,u)=>{ke();var _=He();E(()=>B(_,o(f)?"Executing...":"Execute")),C(d,_)},$$slots:{default:!0}})}var Me=w(Oe,2);Me.textContent=`${(be=navigator.platform)!=null&&be.includes("Mac")?"⌘":"Ctrl"}+Enter`,h(q);var ge=w(q,2);{let c=D(()=>`SELECT * FROM "${e.tableName}" LIMIT 100;`);ba(ge,{get value(){return o(n)},onchange:d=>k(n,d,!0),onExecute:x,get placeholder(){return o(c)},get schema(){return o(O)}})}var Ae=w(ge,2);{var Fe=c=>{var d=Sa(),u=Ge(d);et(u,23,()=>o(l),U=>U.id,(U,Y,j)=>{var Z=pa();let H;var z=g(Z),J=g(z),ae=g(J);h(J),h(z);var $=w(z,2);h(Z),E(()=>{H=tt(Z,1,"table-sql__result-tab svelte-1syrthj",null,H,{"table-sql__result-tab--active":o(j)===o(i)}),B(ae,`Result ${o(j)+1}`),at($,"aria-label",`Close result ${o(j)+1}`)}),pe("click",z,()=>k(i,o(j),!0)),pe("click",$,re=>{re.stopPropagation(),N(o(j))}),C(U,Z)}),h(u);var _=w(u,2);{var I=U=>{var Y=Ca(),j=g(Y),Z=g(j);{var H=b=>{var Q=xa(),F=g(Q,!0);h(Q),E(()=>B(F,o(l)[o(i)].error)),C(b,Q)},z=b=>{var Q=ya(),F=g(Q);h(Q),E(()=>B(F,`${o(l)[o(i)].rowCount??""} row${o(l)[o(i)].rowCount===1?"":"s"} · ${o(l)[o(i)].time??""}ms`)),C(b,Q)};W(Z,b=>{o(l)[o(i)].error?b(H):b(z,!1)})}h(j);var J=w(j,2);{var ae=b=>{var Q=Qa(),F=g(Q,!0);h(Q),E(()=>B(F,o(l)[o(i)].sql)),C(b,Q)},$=b=>{var Q=_a();C(b,Q)},re=b=>{nt(b,{get columns(){return o(l)[o(i)].columns},get rows(){return o(l)[o(i)].rows},readonly:!0})};W(J,b=>{o(l)[o(i)].error?b(ae):o(l)[o(i)].rows.length===0?b($,1):b(re,!1)})}h(Y),C(U,Y)};W(_,U=>{o(l)[o(i)]&&U(I)})}C(c,d)},We=c=>{var d=wa(),u=w(g(d)),_=g(u,!0);h(u),ke(),h(d),E(()=>B(_,e.tableName)),C(c,d)};W(Ae,c=>{o(l).length>0?c(Fe):c(We,!1)})}h(S),E(()=>B(ze,o(y))),C(t,S),Be(),s()}Ye(["click"]);export{Ma as default};
|