@edge-base/server 0.2.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/admin-build/_app/immutable/assets/19.4Si2ZFC_.css +1 -0
  2. package/admin-build/_app/immutable/assets/{3.Dg81Pgmd.css → 3.BtHYobTg.css} +1 -1
  3. package/admin-build/_app/immutable/assets/SqlEditor.Bbp1RIk0.css +1 -0
  4. package/admin-build/_app/immutable/assets/TableSqlTab.yeNZfhgG.css +1 -0
  5. package/admin-build/_app/immutable/chunks/B0QyxC2M.js +128 -0
  6. package/admin-build/_app/immutable/chunks/{DpuSetmN.js → BCKr7yKd.js} +1 -1
  7. package/admin-build/_app/immutable/chunks/{BSfSfeDG.js → BFs_qStz.js} +1 -1
  8. package/admin-build/_app/immutable/chunks/{D43CH5ty.js → BTJcQFEp.js} +1 -1
  9. package/admin-build/_app/immutable/chunks/BY07qVPA.js +1 -0
  10. package/admin-build/_app/immutable/chunks/{mD4EETH_.js → BcIUK2sk.js} +1 -1
  11. package/admin-build/_app/immutable/chunks/{DgxOZ3uv.js → BsFiK_FJ.js} +1 -1
  12. package/admin-build/_app/immutable/chunks/{CN6aakgF.js → CSGrwS7E.js} +1 -1
  13. package/admin-build/_app/immutable/chunks/{B14gOIqE.js → CqUxCvs_.js} +1 -1
  14. package/admin-build/_app/immutable/chunks/{BKLsgaNT.js → D-x55wdW.js} +1 -1
  15. package/admin-build/_app/immutable/chunks/{CfPHB4r5.js → D755Tqat.js} +1 -1
  16. package/admin-build/_app/immutable/chunks/{cqSkc6KP.js → DjOEv9M9.js} +1 -1
  17. package/admin-build/_app/immutable/chunks/{DP9kmlCd.js → DnLqc9L1.js} +1 -1
  18. package/admin-build/_app/immutable/chunks/{B-WlnirM.js → Dqk2TGNU.js} +1 -1
  19. package/admin-build/_app/immutable/chunks/{2nyN5wuZ.js → k0CIJkw4.js} +1 -1
  20. package/admin-build/_app/immutable/chunks/lSpxLU5p.js +2 -0
  21. package/admin-build/_app/immutable/chunks/{uboHVq-x.js → m9QZTyVV.js} +1 -1
  22. package/admin-build/_app/immutable/entry/{app.Dc071f6C.js → app.BTsq3_xq.js} +2 -2
  23. package/admin-build/_app/immutable/entry/start.zXCirpgY.js +1 -0
  24. package/admin-build/_app/immutable/nodes/0.BZ00WDYH.js +1 -0
  25. package/admin-build/_app/immutable/nodes/{1.rMaczUKT.js → 1.RzSJ3yyr.js} +1 -1
  26. package/admin-build/_app/immutable/nodes/{10.DIOlO4hv.js → 10.D-rsiquF.js} +1 -1
  27. package/admin-build/_app/immutable/nodes/{11.WxD9E0Eq.js → 11.l7-bgtFD.js} +1 -1
  28. package/admin-build/_app/immutable/nodes/{12.CNcefK3l.js → 12.Dkq0H7B5.js} +1 -1
  29. package/admin-build/_app/immutable/nodes/{13.aAWsqDdR.js → 13.DtK_4oRz.js} +1 -1
  30. package/admin-build/_app/immutable/nodes/{14.C9hdr3EN.js → 14.BKo7-AMx.js} +1 -1
  31. package/admin-build/_app/immutable/nodes/{15.43r5uVx5.js → 15.CQAj_6lq.js} +1 -1
  32. package/admin-build/_app/immutable/nodes/{16.D519948J.js → 16.XVIG-Ffr.js} +1 -1
  33. package/admin-build/_app/immutable/nodes/{17.ks4I4yoH.js → 17.g6raZLCM.js} +1 -1
  34. package/admin-build/_app/immutable/nodes/{18.ZuNm22dY.js → 18.IQz6a3T6.js} +1 -1
  35. package/admin-build/_app/immutable/nodes/19.CAAZ8i8h.js +2 -0
  36. package/admin-build/_app/immutable/nodes/{20.C9ASlwCn.js → 20.BPcX3KPj.js} +1 -1
  37. package/admin-build/_app/immutable/nodes/21.DoPabrY_.js +1 -0
  38. package/admin-build/_app/immutable/nodes/{22.6k8cg0Pr.js → 22.Br5AG_5Z.js} +1 -1
  39. package/admin-build/_app/immutable/nodes/{23.B9hcFTU-.js → 23.KjbrdXoE.js} +1 -1
  40. package/admin-build/_app/immutable/nodes/{24.OsQM9QtS.js → 24.C3n2-hgw.js} +1 -1
  41. package/admin-build/_app/immutable/nodes/{25.ClwkdaPp.js → 25.SFDSBzHd.js} +1 -1
  42. package/admin-build/_app/immutable/nodes/26.D95vui6E.js +1 -0
  43. package/admin-build/_app/immutable/nodes/{27.J1QASB3b.js → 27.FgLgdjwB.js} +1 -1
  44. package/admin-build/_app/immutable/nodes/{28.BKP1tVcZ.js → 28.B9sYYm1F.js} +1 -1
  45. package/admin-build/_app/immutable/nodes/{29.mqIe62On.js → 29.DyqZ_wbN.js} +1 -1
  46. package/admin-build/_app/immutable/nodes/3.Bzo2yVIO.js +2 -0
  47. package/admin-build/_app/immutable/nodes/{30.BRk-4B3j.js → 30.c1CiNwiS.js} +1 -1
  48. package/admin-build/_app/immutable/nodes/{31.BBqGNVXN.js → 31.CXty66Vh.js} +1 -1
  49. package/admin-build/_app/immutable/nodes/{4.Bi91lv2V.js → 4.BgQaXZ27.js} +1 -1
  50. package/admin-build/_app/immutable/nodes/{5.BumjsbNK.js → 5.BuJrHvxH.js} +1 -1
  51. package/admin-build/_app/immutable/nodes/{6.CMTP_7xN.js → 6.CkBBC94k.js} +1 -1
  52. package/admin-build/_app/immutable/nodes/{7.4T4wo7Kg.js → 7.D2YBvNFM.js} +1 -1
  53. package/admin-build/_app/immutable/nodes/{8.MUZQPNsN.js → 8.D8qQWo_z.js} +1 -1
  54. package/admin-build/_app/immutable/nodes/{9.3SV00WXe.js → 9.BLDLX5hV.js} +1 -1
  55. package/admin-build/_app/version.json +1 -1
  56. package/admin-build/index.html +7 -7
  57. package/package.json +2 -2
  58. package/src/__tests__/pagination.test.ts +12 -8
  59. package/src/__tests__/postgres-dialect.test.ts +2 -2
  60. package/src/__tests__/query.test.ts +7 -7
  61. package/src/durable-objects/database-do.ts +3 -3
  62. package/src/durable-objects/logs-do.ts +2 -2
  63. package/src/lib/auth-d1-service.ts +1 -1
  64. package/src/lib/auth-d1.ts +10 -0
  65. package/src/lib/d1-handler.ts +23 -4
  66. package/src/lib/pagination.ts +3 -3
  67. package/src/lib/postgres-handler.ts +2 -2
  68. package/src/lib/query-engine.ts +2 -2
  69. package/src/middleware/rate-limit.ts +11 -11
  70. package/src/routes/admin.ts +2 -2
  71. package/src/routes/auth.ts +7 -0
  72. package/admin-build/_app/immutable/assets/TableSqlTab.BHquaMBM.css +0 -1
  73. package/admin-build/_app/immutable/chunks/CkdaVlhQ.js +0 -2
  74. package/admin-build/_app/immutable/chunks/D8Nrx_IG.js +0 -128
  75. package/admin-build/_app/immutable/entry/start.Bhlxoqtt.js +0 -1
  76. package/admin-build/_app/immutable/nodes/0.CCfcYVV2.js +0 -1
  77. package/admin-build/_app/immutable/nodes/19.D519948J.js +0 -1
  78. package/admin-build/_app/immutable/nodes/21.BhSD2EfX.js +0 -1
  79. package/admin-build/_app/immutable/nodes/26._-65WG0q.js +0 -1
  80. package/admin-build/_app/immutable/nodes/3.WkDZWDQC.js +0 -2
@@ -5,12 +5,12 @@
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1" />
6
6
  <title>EdgeBase Admin</title>
7
7
  <link rel="icon" href="/admin/favicon.svg" type="image/svg+xml" />
8
- <link href="/admin/_app/immutable/entry/start.Bhlxoqtt.js" rel="modulepreload">
9
- <link href="/admin/_app/immutable/chunks/uboHVq-x.js" rel="modulepreload">
8
+ <link href="/admin/_app/immutable/entry/start.zXCirpgY.js" rel="modulepreload">
9
+ <link href="/admin/_app/immutable/chunks/m9QZTyVV.js" rel="modulepreload">
10
10
  <link href="/admin/_app/immutable/chunks/BdTBlfLy.js" rel="modulepreload">
11
11
  <link href="/admin/_app/immutable/chunks/Bn2NtlTj.js" rel="modulepreload">
12
- <link href="/admin/_app/immutable/chunks/CfPHB4r5.js" rel="modulepreload">
13
- <link href="/admin/_app/immutable/entry/app.Dc071f6C.js" rel="modulepreload">
12
+ <link href="/admin/_app/immutable/chunks/D755Tqat.js" rel="modulepreload">
13
+ <link href="/admin/_app/immutable/entry/app.BTsq3_xq.js" rel="modulepreload">
14
14
  <link href="/admin/_app/immutable/chunks/B2bEC_Hm.js" rel="modulepreload">
15
15
  <link href="/admin/_app/immutable/chunks/Bb0e0sAP.js" rel="modulepreload">
16
16
  <link href="/admin/_app/immutable/chunks/DtZk82gG.js" rel="modulepreload">
@@ -26,7 +26,7 @@
26
26
  <div style="display: contents">
27
27
  <script>
28
28
  {
29
- __sveltekit_18bu3q0 = {
29
+ __sveltekit_1vwf6db = {
30
30
  base: "/admin",
31
31
  assets: "/admin"
32
32
  };
@@ -34,8 +34,8 @@
34
34
  const element = document.currentScript.parentElement;
35
35
 
36
36
  Promise.all([
37
- import("/admin/_app/immutable/entry/start.Bhlxoqtt.js"),
38
- import("/admin/_app/immutable/entry/app.Dc071f6C.js")
37
+ import("/admin/_app/immutable/entry/start.zXCirpgY.js"),
38
+ import("/admin/_app/immutable/entry/app.BTsq3_xq.js")
39
39
  ]).then(([kit, app]) => {
40
40
  kit.start(app, element);
41
41
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@edge-base/server",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "EdgeBase runtime assets consumed by the EdgeBase CLI",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -34,7 +34,7 @@
34
34
  "jose": "^6.0.0",
35
35
  "pg": "^8.16.3",
36
36
  "zod": "^4.3.6",
37
- "@edge-base/shared": "0.2.0"
37
+ "@edge-base/shared": "0.2.1"
38
38
  },
39
39
  "devDependencies": {
40
40
  "@cloudflare/vitest-pool-workers": "^0.8.71",
@@ -10,7 +10,7 @@ import { parsePagination } from '../lib/pagination.js';
10
10
  describe('parsePagination', () => {
11
11
  // ── Defaults ──
12
12
  it('returns defaults when no params provided', () => {
13
- expect(parsePagination(undefined, undefined)).toEqual({ limit: 20, offset: 0 });
13
+ expect(parsePagination(undefined, undefined)).toEqual({ limit: 100, offset: 0 });
14
14
  });
15
15
 
16
16
  // ── Valid values ──
@@ -23,21 +23,25 @@ describe('parsePagination', () => {
23
23
  });
24
24
 
25
25
  // ── Limit clamping ──
26
- it('clamps limit to 100', () => {
27
- expect(parsePagination('999', '0')).toEqual({ limit: 100, offset: 0 });
26
+ it('clamps limit to 1000', () => {
27
+ expect(parsePagination('9999', '0')).toEqual({ limit: 1000, offset: 0 });
28
+ });
29
+
30
+ it('accepts limit within range (500)', () => {
31
+ expect(parsePagination('500', '0')).toEqual({ limit: 500, offset: 0 });
28
32
  });
29
33
 
30
34
  it('rejects limit=0 (falls back to default)', () => {
31
- expect(parsePagination('0', '0')).toEqual({ limit: 20, offset: 0 });
35
+ expect(parsePagination('0', '0')).toEqual({ limit: 100, offset: 0 });
32
36
  });
33
37
 
34
38
  // ── REGRESSION: negative and NaN values ──
35
39
  it('rejects negative limit', () => {
36
- expect(parsePagination('-5', '0')).toEqual({ limit: 20, offset: 0 });
40
+ expect(parsePagination('-5', '0')).toEqual({ limit: 100, offset: 0 });
37
41
  });
38
42
 
39
43
  it('rejects NaN limit', () => {
40
- expect(parsePagination('abc', '0')).toEqual({ limit: 20, offset: 0 });
44
+ expect(parsePagination('abc', '0')).toEqual({ limit: 100, offset: 0 });
41
45
  });
42
46
 
43
47
  it('rejects negative offset', () => {
@@ -49,11 +53,11 @@ describe('parsePagination', () => {
49
53
  });
50
54
 
51
55
  it('rejects Infinity limit', () => {
52
- expect(parsePagination('Infinity', '0')).toEqual({ limit: 20, offset: 0 });
56
+ expect(parsePagination('Infinity', '0')).toEqual({ limit: 100, offset: 0 });
53
57
  });
54
58
 
55
59
  // ── Empty string (same as undefined) ──
56
60
  it('treats empty strings as defaults', () => {
57
- expect(parsePagination('', '')).toEqual({ limit: 20, offset: 0 });
61
+ expect(parsePagination('', '')).toEqual({ limit: 100, offset: 0 });
58
62
  });
59
63
  });
@@ -43,7 +43,7 @@ describe('PostgreSQL dialect — bind params', () => {
43
43
  const { sql, params } = buildListQuery('products', {}, 'postgres');
44
44
  expect(sql).toContain('LIMIT $1');
45
45
  expect(sql).not.toContain('?');
46
- expect(params).toEqual([20]);
46
+ expect(params).toEqual([100]);
47
47
  });
48
48
 
49
49
  it('buildListQuery with offset → $1 OFFSET $2', () => {
@@ -71,7 +71,7 @@ describe('PostgreSQL dialect — bind params', () => {
71
71
  expect(sql).toContain('"status" = $1');
72
72
  expect(sql).toContain('"price" > $2');
73
73
  expect(sql).toContain('LIMIT $3');
74
- expect(params).toEqual(['active', 100, 20]);
74
+ expect(params).toEqual(['active', 100, 100]);
75
75
  });
76
76
 
77
77
  it('buildListQuery cursor after → $1 for cursor, $2 for limit', () => {
@@ -79,10 +79,10 @@ describe('buildListQuery — no filters', () => {
79
79
  expect(sql).toContain('LIMIT');
80
80
  });
81
81
 
82
- it('default limit is 20', () => {
82
+ it('default limit is 100', () => {
83
83
  const { params } = buildListQuery('posts', {});
84
- // params should contain 20 as default limit
85
- expect(params).toContain(20);
84
+ // params should contain 100 as default limit
85
+ expect(params).toContain(100);
86
86
  });
87
87
 
88
88
  it('generates countSql for non-cursor pagination', () => {
@@ -313,9 +313,9 @@ describe('buildSearchQuery', () => {
313
313
  expect(sql).toContain('"posts_fts"');
314
314
  });
315
315
 
316
- it('default limit 20, offset 0', () => {
316
+ it('default limit 100, offset 0', () => {
317
317
  const { params } = buildSearchQuery('posts', 'q');
318
- expect(params[1]).toBe(20);
318
+ expect(params[1]).toBe(100);
319
319
  expect(params[2]).toBeUndefined();
320
320
  });
321
321
 
@@ -560,7 +560,7 @@ describe('3-way sync: QUERY_PARAM_KEYS ↔ Zod queryParamsSchema', () => {
560
560
  describe('buildListQuery — exact params verification', () => {
561
561
  it('no filters → params contains only default limit', () => {
562
562
  const { params } = buildListQuery('t', {});
563
- expect(params).toEqual([20]);
563
+ expect(params).toEqual([100]);
564
564
  });
565
565
 
566
566
  it('no filters → countParams is empty array', () => {
@@ -722,7 +722,7 @@ describe('buildSubstringSearchQuery', () => {
722
722
  const { sql, params } = buildSubstringSearchQuery('posts', '준규', { fields: ['title', 'content'] });
723
723
  expect(sql).toContain('instr(lower(CAST("title" AS TEXT)), lower(?)) > 0');
724
724
  expect(sql).toContain('instr(lower(CAST("content" AS TEXT)), lower(?)) > 0');
725
- expect(params).toEqual(['준규', '준규', 20]);
725
+ expect(params).toEqual(['준규', '준규', 100]);
726
726
  });
727
727
 
728
728
  it('passes the raw term through the SQLite instr() fallback', () => {
@@ -470,7 +470,7 @@ export class DatabaseDO extends DurableObject<DOEnv> {
470
470
  if (countSql && countParams) {
471
471
  const countResult = [...this.sql(countSql, ...countParams)];
472
472
  const total = (countResult[0]?.total as number) ?? 0;
473
- const perPage = options.pagination?.perPage ?? options.pagination?.limit ?? 20;
473
+ const perPage = options.pagination?.perPage ?? options.pagination?.limit ?? 100;
474
474
  response.total = total;
475
475
  response.page = options.pagination?.page ?? 1;
476
476
  response.perPage = perPage;
@@ -478,7 +478,7 @@ export class DatabaseDO extends DurableObject<DOEnv> {
478
478
 
479
479
  // Cursor pagination: always include cursor and hasMore when items exist
480
480
  // so clients can start cursor-based pagination from any page (including the first)
481
- const limit = options.pagination?.limit ?? options.pagination?.perPage ?? 20;
481
+ const limit = options.pagination?.limit ?? options.pagination?.perPage ?? 100;
482
482
  const hasMore = normalizedRows.length === limit;
483
483
  response.hasMore = hasMore;
484
484
  if (normalizedRows.length > 0) {
@@ -516,7 +516,7 @@ export class DatabaseDO extends DurableObject<DOEnv> {
516
516
  return c.json({ items: [] });
517
517
  }
518
518
 
519
- const limit = options.pagination?.limit ?? options.pagination?.perPage ?? 20;
519
+ const limit = options.pagination?.limit ?? options.pagination?.perPage ?? 100;
520
520
  const offset = options.pagination?.offset ?? ((options.pagination?.page ?? 1) - 1) * limit;
521
521
 
522
522
  const tableConfig = this.getTableConfig(name);
@@ -484,10 +484,10 @@ export class LogsDO extends DurableObject<LogsDOEnv> {
484
484
  whereParts.push('status >= ?');
485
485
  params.push(SERVER_ERROR_STATUS);
486
486
  } else if (level === 'warn') {
487
- whereParts.push('status >= ? AND status < ?');
487
+ whereParts.push('(status >= ? AND status < ? AND status != 304)');
488
488
  params.push(300, SERVER_ERROR_STATUS);
489
489
  } else if (level === 'info') {
490
- whereParts.push('status >= ? AND status < ?');
490
+ whereParts.push('(status >= ? AND status < ? OR status = 304)');
491
491
  params.push(200, 300);
492
492
  }
493
493
 
@@ -194,7 +194,7 @@ export async function updateUser(
194
194
  'email', 'passwordHash', 'displayName', 'avatarUrl', 'emailVisibility',
195
195
  'role', 'status', 'verified', 'isAnonymous', 'locale', 'metadata', 'appMetadata',
196
196
  'customClaims', 'phone', 'phoneVerified', 'disabled', 'bannedUntil',
197
- 'lastSignInAt', 'updatedAt',
197
+ 'lastSignInAt', 'lastSignedInAt', 'updatedAt',
198
198
  ]);
199
199
 
200
200
  const sets: string[] = [];
@@ -125,6 +125,7 @@ CREATE TABLE IF NOT EXISTS _users (
125
125
  disabled INTEGER DEFAULT 0,
126
126
  status TEXT DEFAULT 'active',
127
127
  locale TEXT DEFAULT 'en',
128
+ lastSignedInAt TEXT,
128
129
  createdAt TEXT NOT NULL,
129
130
  updatedAt TEXT NOT NULL
130
131
  );
@@ -309,6 +310,7 @@ CREATE TABLE IF NOT EXISTS _users (
309
310
  disabled INTEGER DEFAULT 0,
310
311
  status TEXT DEFAULT 'active',
311
312
  locale TEXT DEFAULT 'en',
313
+ lastSignedInAt TEXT,
312
314
  createdAt TEXT NOT NULL,
313
315
  updatedAt TEXT NOT NULL
314
316
  );
@@ -403,6 +405,14 @@ export async function ensureAuthSchema(db: AuthDb): Promise<void> {
403
405
  .filter((s) => s.length > 0);
404
406
 
405
407
  await db.batch(statements.map((sql) => ({ sql })));
408
+
409
+ // Migrate existing _users tables: add lastSignedInAt if missing
410
+ try {
411
+ await db.run('ALTER TABLE _users ADD COLUMN lastSignedInAt TEXT', []);
412
+ } catch {
413
+ // Column already exists — safe to ignore
414
+ }
415
+
406
416
  schemaInitialized = true;
407
417
  }
408
418
 
@@ -399,8 +399,27 @@ async function handleList(
399
399
  }
400
400
 
401
401
  const queryOpts = parseQueryParams(Object.fromEntries(new URL(c.req.url).searchParams));
402
- const { sql, params, countSql, countParams } = buildListQuery(tableName, queryOpts, 'sqlite');
403
- const result = await executeD1Query(resolved.db, sql, params);
402
+ let query = buildListQuery(tableName, queryOpts, 'sqlite');
403
+ let result;
404
+ try {
405
+ result = await executeD1Query(resolved.db, query.sql, query.params);
406
+ } catch {
407
+ // FTS table may not exist — fall back to substring search
408
+ if (queryOpts.search) {
409
+ const searchFields = tableConfig.schema ? Object.keys(tableConfig.schema).filter(k => tableConfig.schema![k] !== false) : ['id'];
410
+ query = buildSubstringSearchQuery(tableName, queryOpts.search, {
411
+ pagination: queryOpts.pagination,
412
+ filters: queryOpts.filters,
413
+ orFilters: queryOpts.orFilters,
414
+ sort: queryOpts.sort,
415
+ fields: searchFields,
416
+ }, 'sqlite');
417
+ result = await executeD1Query(resolved.db, query.sql, query.params);
418
+ } else {
419
+ throw new Error('Query failed');
420
+ }
421
+ }
422
+ const { countSql, countParams } = query;
404
423
 
405
424
  // Apply read rules per row + normalize booleans/JSON
406
425
  let items = result.rows.map(r => normalizeRow(stripInternalFields(r), tableConfig));
@@ -435,7 +454,7 @@ async function handleList(
435
454
  total = Number(countResult.rows[0]?.total ?? 0);
436
455
  }
437
456
 
438
- const perPage = queryOpts.pagination?.limit ?? queryOpts.pagination?.perPage ?? 20;
457
+ const perPage = queryOpts.pagination?.limit ?? queryOpts.pagination?.perPage ?? 100;
439
458
  const page = queryOpts.pagination?.page ?? 1;
440
459
  // Always include cursor/hasMore like DO does — clients can start cursor pagination from any page
441
460
  const hasMore = items.length === perPage;
@@ -497,7 +516,7 @@ async function handleSearch(
497
516
 
498
517
  let items: Record<string, unknown>[];
499
518
  let total = 0;
500
- const limit = queryOpts.pagination?.limit ?? queryOpts.pagination?.perPage ?? 20;
519
+ const limit = queryOpts.pagination?.limit ?? queryOpts.pagination?.perPage ?? 100;
501
520
  const offset = queryOpts.pagination?.offset ?? ((queryOpts.pagination?.page ?? 1) - 1) * limit;
502
521
  const searchQuery = buildSearchQuery(tableName, searchTerm, {
503
522
  pagination: queryOpts.pagination,
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Pagination parameter validation.
3
3
  *
4
- * Clamps limit to 1..100 (default 20) and offset to ≥0 (default 0).
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 || '20', 10);
13
- const limit = Number.isFinite(rawLimit) && rawLimit > 0 ? Math.min(rawLimit, 100) : 20;
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;
@@ -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 ?? 20;
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 ?? 20;
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,
@@ -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: [20] }; // Default limit
660
+ return { limitClause: `LIMIT ${_bt.next()}`, limitParams: [100] }; // Default limit
661
661
  }
662
662
 
663
- const limit = pagination.limit ?? pagination.perPage ?? 20;
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: 10x higher to accommodate React strict mode double-rendering,
54
- // hot-reload page refreshes, and onSnapshot polling during development.
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: 1000, windowSec: 60 },
58
- storage: { requests: 500, windowSec: 60 },
59
- functions: { requests: 500, windowSec: 60 },
60
- auth: { requests: 300, windowSec: 60 },
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: 1000, windowSec: 60 },
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
  }
@@ -240,8 +240,8 @@ function getLogStatusCode(log: Record<string, unknown>): number {
240
240
  function matchesLogLevel(status: number, level: string): boolean {
241
241
  const normalized = level.toLowerCase();
242
242
  if (normalized === 'error') return status >= 500;
243
- if (normalized === 'warn') return status >= 300 && status < 500;
244
- if (normalized === 'info') return status >= 200 && status < 300;
243
+ if (normalized === 'warn') return (status >= 300 && status < 500 && status !== 304);
244
+ if (normalized === 'info') return (status >= 200 && status < 300) || status === 304;
245
245
  return true;
246
246
  }
247
247
 
@@ -509,6 +509,13 @@ async function createSessionAndTokens(
509
509
  metadata,
510
510
  });
511
511
 
512
+ // Update lastSignedInAt on the user record
513
+ try {
514
+ await db.run('UPDATE _users SET lastSignedInAt = ? WHERE id = ?', [now, userId]);
515
+ } catch {
516
+ // Non-critical: don't block sign-in if this column doesn't exist yet
517
+ }
518
+
512
519
  return { accessToken, refreshToken, sessionId };
513
520
  }
514
521
 
@@ -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">&times;</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};