@agent-native/core 0.86.0 → 0.86.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 (183) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +9 -0
  3. package/corpus/core/package.json +2 -1
  4. package/corpus/core/src/client/AgentPanel.tsx +10 -0
  5. package/corpus/core/src/client/AssistantChat.tsx +91 -27
  6. package/corpus/core/src/client/ErrorBoundary.tsx +67 -12
  7. package/corpus/core/src/client/ErrorReportActions.tsx +69 -0
  8. package/corpus/core/src/client/FeedbackButton.tsx +8 -4
  9. package/corpus/core/src/client/db-admin/DbAdminPage.tsx +41 -13
  10. package/corpus/core/src/client/db-admin/SqlEditor.tsx +10 -3
  11. package/corpus/core/src/client/db-admin/TableEditor.tsx +12 -5
  12. package/corpus/core/src/client/db-admin/useAgentSync.ts +10 -3
  13. package/corpus/core/src/client/db-admin/useDbAdmin.ts +65 -16
  14. package/corpus/core/src/client/error-reporting.ts +100 -0
  15. package/corpus/core/src/client/index.ts +11 -0
  16. package/corpus/core/src/client/org/RequireActiveOrg.tsx +12 -0
  17. package/corpus/core/src/client/visual-style-controls.tsx +615 -2
  18. package/corpus/core/src/db-admin/index.ts +26 -0
  19. package/corpus/core/src/db-admin/operations.ts +87 -49
  20. package/corpus/core/src/localization/default-messages.ts +4 -0
  21. package/corpus/core/src/server/builder-design-systems.ts +328 -9
  22. package/corpus/core/src/server/index.ts +15 -0
  23. package/corpus/core/src/templates/default/app/root.tsx +47 -0
  24. package/corpus/templates/analytics/AGENTS.md +6 -4
  25. package/corpus/templates/analytics/actions/delete-db-admin-connection.ts +19 -0
  26. package/corpus/templates/analytics/actions/list-db-admin-connections.ts +18 -0
  27. package/corpus/templates/analytics/actions/navigate.ts +17 -3
  28. package/corpus/templates/analytics/actions/save-db-admin-connection.ts +33 -0
  29. package/corpus/templates/analytics/actions/view-screen.ts +11 -3
  30. package/corpus/templates/analytics/app/hooks/use-navigation-state.ts +11 -2
  31. package/corpus/templates/analytics/app/i18n/zh-TW.ts +23 -2
  32. package/corpus/templates/analytics/app/i18n-data.ts +230 -20
  33. package/corpus/templates/analytics/app/pages/Agents.tsx +398 -4
  34. package/corpus/templates/analytics/changelog/2026-07-03-connect-other-app-databases-from-analytics.md +6 -0
  35. package/corpus/templates/analytics/server/db/schema.ts +27 -0
  36. package/corpus/templates/analytics/server/lib/db-admin-connections.ts +458 -0
  37. package/corpus/templates/analytics/server/plugins/db.ts +35 -0
  38. package/corpus/templates/analytics/server/routes/[base]/_agent-native/analytics-db-admin/[...path].ts +1 -0
  39. package/corpus/templates/analytics/server/routes/_agent-native/analytics-db-admin/[...path].ts +160 -0
  40. package/corpus/templates/content/app/root.tsx +9 -0
  41. package/corpus/templates/content/changelog/2026-07-03-error-screens-now-include-a-feedback-button-with-debug-info.md +6 -0
  42. package/corpus/templates/design/AGENTS.md +13 -7
  43. package/corpus/templates/design/actions/get-design-system.ts +21 -0
  44. package/corpus/templates/design/actions/index-design-system-with-builder.ts +14 -37
  45. package/corpus/templates/design/app/components/design/code-workbench/CodeWorkbench.tsx +3 -3
  46. package/corpus/templates/design/app/components/design/code-workbench/SideBar.tsx +70 -9
  47. package/corpus/templates/design/app/components/design/code-workbench/editor/EditorTabs.tsx +11 -2
  48. package/corpus/templates/design/app/components/design/code-workbench/editor/MonacoHost.tsx +1 -1
  49. package/corpus/templates/design/app/components/design/code-workbench/editor/StatusBar.tsx +1 -1
  50. package/corpus/templates/design/app/components/design/code-workbench/explorer/ExplorerView.tsx +8 -2
  51. package/corpus/templates/design/app/components/design/code-workbench/explorer/FileTree.tsx +7 -3
  52. package/corpus/templates/design/app/components/design/code-workbench/store.tsx +48 -0
  53. package/corpus/templates/design/app/hooks/useDesignHotkeys.ts +6 -0
  54. package/corpus/templates/design/app/i18n/zh-TW.ts +15 -14
  55. package/corpus/templates/design/app/i18n-data.ts +154 -142
  56. package/corpus/templates/design/app/pages/DesignSystemSetup.tsx +32 -14
  57. package/corpus/templates/design/changelog/2026-07-03-design-system-setup-now-indexes-figma-code-and-design-md-sou.md +6 -0
  58. package/corpus/templates/design/changelog/2026-07-03-the-code-editor-is-easier-to-use-with-top-sidebar-tabs-clear.md +6 -0
  59. package/corpus/templates/design/server/lib/builder-design-system-proxy.ts +16 -106
  60. package/corpus/templates/mail/app/root.tsx +60 -1
  61. package/corpus/templates/mail/changelog/2026-07-03-error-screens-now-include-a-feedback-button-with-debug-info.md +6 -0
  62. package/corpus/templates/plan/app/i18n/ar-SA.ts +3 -0
  63. package/corpus/templates/plan/app/i18n/de-DE.ts +4 -0
  64. package/corpus/templates/plan/app/i18n/en-US.ts +4 -0
  65. package/corpus/templates/plan/app/i18n/es-ES.ts +4 -0
  66. package/corpus/templates/plan/app/i18n/fr-FR.ts +4 -0
  67. package/corpus/templates/plan/app/i18n/hi-IN.ts +3 -0
  68. package/corpus/templates/plan/app/i18n/ja-JP.ts +4 -0
  69. package/corpus/templates/plan/app/i18n/ko-KR.ts +4 -0
  70. package/corpus/templates/plan/app/i18n/pt-BR.ts +4 -0
  71. package/corpus/templates/plan/app/i18n/zh-CN.ts +3 -0
  72. package/corpus/templates/plan/app/i18n/zh-TW.ts +3 -0
  73. package/corpus/templates/plan/app/pages/PlansPage.tsx +74 -3
  74. package/corpus/templates/plan/changelog/2026-07-03-error-screens-now-include-a-feedback-button-with-debug-info.md +6 -0
  75. package/corpus/templates/slides/AGENTS.md +7 -3
  76. package/corpus/templates/slides/actions/get-design-system.ts +21 -0
  77. package/corpus/templates/slides/actions/import-file.ts +15 -7
  78. package/corpus/templates/slides/actions/index-design-system-with-builder.ts +14 -37
  79. package/corpus/templates/slides/app/components/design-system/DesignSystemSetup.tsx +32 -8
  80. package/corpus/templates/slides/app/components/editor/EditorSidebar.tsx +2 -2
  81. package/corpus/templates/slides/app/components/editor/EditorToolbar.tsx +2 -4
  82. package/corpus/templates/slides/app/components/editor/SlideEditor.tsx +163 -154
  83. package/corpus/templates/slides/app/components/editor/SlideStyleInspector.tsx +19 -15
  84. package/corpus/templates/slides/app/components/editor/SpeakerNotesPanel.tsx +56 -6
  85. package/corpus/templates/slides/app/components/layout/Layout.tsx +6 -1
  86. package/corpus/templates/slides/app/i18n/ar-SA.ts +8 -7
  87. package/corpus/templates/slides/app/i18n/de-DE.ts +7 -8
  88. package/corpus/templates/slides/app/i18n/en-US.ts +8 -7
  89. package/corpus/templates/slides/app/i18n/es-ES.ts +7 -8
  90. package/corpus/templates/slides/app/i18n/fr-FR.ts +7 -8
  91. package/corpus/templates/slides/app/i18n/hi-IN.ts +8 -7
  92. package/corpus/templates/slides/app/i18n/ja-JP.ts +7 -8
  93. package/corpus/templates/slides/app/i18n/ko-KR.ts +7 -7
  94. package/corpus/templates/slides/app/i18n/pt-BR.ts +7 -8
  95. package/corpus/templates/slides/app/i18n/zh-CN.ts +8 -7
  96. package/corpus/templates/slides/app/i18n/zh-TW.ts +8 -7
  97. package/corpus/templates/slides/app/lib/canvas-zoom.ts +16 -1
  98. package/corpus/templates/slides/app/pages/DeckEditor.tsx +3 -3
  99. package/corpus/templates/slides/changelog/2026-07-03-design-system-setup-now-indexes-figma-code-and-design-md-sou.md +6 -0
  100. package/corpus/templates/slides/changelog/2026-07-03-slide-editing-now-keeps-thumbnails-speaker-notes-styling-and.md +6 -0
  101. package/corpus/templates/slides/server/lib/builder-design-system-proxy.ts +16 -104
  102. package/dist/client/AgentPanel.d.ts.map +1 -1
  103. package/dist/client/AgentPanel.js +2 -1
  104. package/dist/client/AgentPanel.js.map +1 -1
  105. package/dist/client/AssistantChat.d.ts.map +1 -1
  106. package/dist/client/AssistantChat.js +77 -25
  107. package/dist/client/AssistantChat.js.map +1 -1
  108. package/dist/client/ErrorBoundary.d.ts.map +1 -1
  109. package/dist/client/ErrorBoundary.js +37 -2
  110. package/dist/client/ErrorBoundary.js.map +1 -1
  111. package/dist/client/ErrorReportActions.d.ts +13 -0
  112. package/dist/client/ErrorReportActions.d.ts.map +1 -0
  113. package/dist/client/ErrorReportActions.js +14 -0
  114. package/dist/client/ErrorReportActions.js.map +1 -0
  115. package/dist/client/FeedbackButton.d.ts +3 -1
  116. package/dist/client/FeedbackButton.d.ts.map +1 -1
  117. package/dist/client/FeedbackButton.js +6 -5
  118. package/dist/client/FeedbackButton.js.map +1 -1
  119. package/dist/client/db-admin/DbAdminPage.d.ts +9 -1
  120. package/dist/client/db-admin/DbAdminPage.d.ts.map +1 -1
  121. package/dist/client/db-admin/DbAdminPage.js +17 -13
  122. package/dist/client/db-admin/DbAdminPage.js.map +1 -1
  123. package/dist/client/db-admin/SqlEditor.d.ts +3 -1
  124. package/dist/client/db-admin/SqlEditor.d.ts.map +1 -1
  125. package/dist/client/db-admin/SqlEditor.js +3 -3
  126. package/dist/client/db-admin/SqlEditor.js.map +1 -1
  127. package/dist/client/db-admin/TableEditor.d.ts +3 -1
  128. package/dist/client/db-admin/TableEditor.d.ts.map +1 -1
  129. package/dist/client/db-admin/TableEditor.js +6 -6
  130. package/dist/client/db-admin/TableEditor.js.map +1 -1
  131. package/dist/client/db-admin/useAgentSync.d.ts +3 -2
  132. package/dist/client/db-admin/useAgentSync.d.ts.map +1 -1
  133. package/dist/client/db-admin/useAgentSync.js +8 -4
  134. package/dist/client/db-admin/useAgentSync.js.map +1 -1
  135. package/dist/client/db-admin/useDbAdmin.d.ts +11 -7
  136. package/dist/client/db-admin/useDbAdmin.d.ts.map +1 -1
  137. package/dist/client/db-admin/useDbAdmin.js +45 -20
  138. package/dist/client/db-admin/useDbAdmin.js.map +1 -1
  139. package/dist/client/error-reporting.d.ts +19 -0
  140. package/dist/client/error-reporting.d.ts.map +1 -0
  141. package/dist/client/error-reporting.js +71 -0
  142. package/dist/client/error-reporting.js.map +1 -0
  143. package/dist/client/index.d.ts +3 -1
  144. package/dist/client/index.d.ts.map +1 -1
  145. package/dist/client/index.js +3 -1
  146. package/dist/client/index.js.map +1 -1
  147. package/dist/client/org/RequireActiveOrg.d.ts.map +1 -1
  148. package/dist/client/org/RequireActiveOrg.js +2 -1
  149. package/dist/client/org/RequireActiveOrg.js.map +1 -1
  150. package/dist/client/visual-style-controls.d.ts +11 -0
  151. package/dist/client/visual-style-controls.d.ts.map +1 -1
  152. package/dist/client/visual-style-controls.js +350 -1
  153. package/dist/client/visual-style-controls.js.map +1 -1
  154. package/dist/collab/routes.d.ts +1 -1
  155. package/dist/collab/struct-routes.d.ts +1 -1
  156. package/dist/db-admin/index.d.ts +3 -0
  157. package/dist/db-admin/index.d.ts.map +1 -0
  158. package/dist/db-admin/index.js +2 -0
  159. package/dist/db-admin/index.js.map +1 -0
  160. package/dist/db-admin/operations.d.ts +26 -5
  161. package/dist/db-admin/operations.d.ts.map +1 -1
  162. package/dist/db-admin/operations.js +66 -55
  163. package/dist/db-admin/operations.js.map +1 -1
  164. package/dist/localization/default-messages.d.ts +3 -0
  165. package/dist/localization/default-messages.d.ts.map +1 -1
  166. package/dist/localization/default-messages.js +3 -0
  167. package/dist/localization/default-messages.js.map +1 -1
  168. package/dist/notifications/routes.d.ts +1 -1
  169. package/dist/provider-api/corpus-jobs.d.ts +2 -2
  170. package/dist/resources/handlers.d.ts +1 -1
  171. package/dist/secrets/routes.d.ts +9 -9
  172. package/dist/server/builder-design-systems.d.ts +61 -0
  173. package/dist/server/builder-design-systems.d.ts.map +1 -1
  174. package/dist/server/builder-design-systems.js +219 -14
  175. package/dist/server/builder-design-systems.js.map +1 -1
  176. package/dist/server/index.d.ts +1 -1
  177. package/dist/server/index.d.ts.map +1 -1
  178. package/dist/server/index.js +1 -1
  179. package/dist/server/index.js.map +1 -1
  180. package/dist/server/transcribe-voice.d.ts +1 -1
  181. package/dist/templates/default/app/root.tsx +47 -0
  182. package/package.json +2 -1
  183. package/src/templates/default/app/root.tsx +47 -0
@@ -1,18 +1,24 @@
1
1
  /**
2
- * Dev-mode database admin operations.
2
+ * Database admin operations.
3
3
  *
4
4
  * Pure, dialect-agnostic, RAW/UNSCOPED helpers backing the Supabase-Studio-like
5
5
  * DB admin. These run the FULL database with no per-user `accessFilter`
6
- * scoping they are a developer tool, gated to dev + localhost at the route
7
- * and agent-tool layers. Do NOT call these from any production-reachable
8
- * surface.
6
+ * scoping. Callers MUST gate access before invoking them. The built-in core
7
+ * route gates this to dev + localhost; production-reachable surfaces must pass
8
+ * an explicit runtime for the target database and enforce their own admin-only
9
+ * checks before reading or mutating.
9
10
  *
10
11
  * All access goes through the unified `getDbExec()` client, which uses `?`
11
12
  * placeholders (auto-converted to `$1,$2,…` for Postgres) and returns rows
12
13
  * keyed by column name. Identifiers are validated against a strict pattern and
13
14
  * always double-quoted; values are ALWAYS parameterized — never interpolated.
14
15
  */
15
- import { getDbExec, getDialect, isPostgres } from "../db/client.js";
16
+ import {
17
+ getDbExec,
18
+ getDialect,
19
+ type DbExec,
20
+ type Dialect,
21
+ } from "../db/client.js";
16
22
  import { notifyActionChange } from "../server/action-change.js";
17
23
  import type {
18
24
  DbAdminColumn,
@@ -35,6 +41,12 @@ import type {
35
41
 
36
42
  const IDENT_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
37
43
 
44
+ export interface DbAdminRuntime {
45
+ db?: DbExec;
46
+ dialect?: Dialect;
47
+ notifyChange?: () => Promise<void>;
48
+ }
49
+
38
50
  /** Throw on any identifier that isn't a plain `[A-Za-z_][A-Za-z0-9_]*`. */
39
51
  function assertIdent(name: string, kind = "identifier"): string {
40
52
  if (typeof name !== "string" || !IDENT_RE.test(name)) {
@@ -48,15 +60,27 @@ function quoteIdent(name: string): string {
48
60
  return `"${assertIdent(name)}"`;
49
61
  }
50
62
 
51
- function dialect(): DbAdminDialect {
52
- return getDialect();
63
+ function db(runtime?: DbAdminRuntime): DbExec {
64
+ return runtime?.db ?? getDbExec();
65
+ }
66
+
67
+ function dialect(runtime?: DbAdminRuntime): DbAdminDialect {
68
+ return (runtime?.dialect ?? getDialect()) as DbAdminDialect;
69
+ }
70
+
71
+ function isPostgresRuntime(runtime?: DbAdminRuntime): boolean {
72
+ return dialect(runtime) === "postgres";
53
73
  }
54
74
 
55
75
  // ---------------------------------------------------------------------------
56
76
  // Notify the UI after a real mutation so polling refetches.
57
77
  // ---------------------------------------------------------------------------
58
78
 
59
- async function notifyDbAdminChange(): Promise<void> {
79
+ async function notifyDbAdminChange(runtime?: DbAdminRuntime): Promise<void> {
80
+ if (runtime?.notifyChange) {
81
+ await runtime.notifyChange();
82
+ return;
83
+ }
60
84
  // The UI keys on useChangeVersions(["db-admin","action"]). notifyActionChange
61
85
  // records a "db-admin" change AND a marker; the action route layer's generic
62
86
  // "action" source is covered by passing the db-admin action name through the
@@ -68,15 +92,15 @@ async function notifyDbAdminChange(): Promise<void> {
68
92
  // listTables
69
93
  // ---------------------------------------------------------------------------
70
94
 
71
- export async function listTables(): Promise<{
95
+ export async function listTables(runtime?: DbAdminRuntime): Promise<{
72
96
  dialect: DbAdminDialect;
73
97
  tables: DbAdminTableSummary[];
74
98
  }> {
75
- const db = getDbExec();
99
+ const client = db(runtime);
76
100
  const summaries: DbAdminTableSummary[] = [];
77
101
 
78
- if (isPostgres()) {
79
- const res = await db.execute(
102
+ if (isPostgresRuntime(runtime)) {
103
+ const res = await client.execute(
80
104
  `SELECT table_name AS name, table_type AS type
81
105
  FROM information_schema.tables
82
106
  WHERE table_schema = 'public'
@@ -89,11 +113,11 @@ export async function listTables(): Promise<{
89
113
  summaries.push({
90
114
  name,
91
115
  type,
92
- rowCount: type === "view" ? null : await safeRowCount(name),
116
+ rowCount: type === "view" ? null : await safeRowCount(name, runtime),
93
117
  });
94
118
  }
95
119
  } else {
96
- const res = await db.execute(
120
+ const res = await client.execute(
97
121
  `SELECT name, type FROM sqlite_master
98
122
  WHERE type IN ('table', 'view')
99
123
  AND name NOT LIKE 'sqlite_%'
@@ -105,18 +129,21 @@ export async function listTables(): Promise<{
105
129
  summaries.push({
106
130
  name,
107
131
  type,
108
- rowCount: type === "view" ? null : await safeRowCount(name),
132
+ rowCount: type === "view" ? null : await safeRowCount(name, runtime),
109
133
  });
110
134
  }
111
135
  }
112
136
 
113
- return { dialect: dialect(), tables: summaries };
137
+ return { dialect: dialect(runtime), tables: summaries };
114
138
  }
115
139
 
116
- async function safeRowCount(table: string): Promise<number | null> {
140
+ async function safeRowCount(
141
+ table: string,
142
+ runtime?: DbAdminRuntime,
143
+ ): Promise<number | null> {
117
144
  try {
118
- const db = getDbExec();
119
- const res = await db.execute(
145
+ const client = db(runtime);
146
+ const res = await client.execute(
120
147
  `SELECT COUNT(*) AS c FROM ${quoteIdent(table)}`,
121
148
  );
122
149
  const c = (res.rows[0] as any)?.c;
@@ -133,26 +160,28 @@ async function safeRowCount(table: string): Promise<number | null> {
133
160
 
134
161
  export async function getTableSchema(
135
162
  table: string,
163
+ runtime?: DbAdminRuntime,
136
164
  ): Promise<DbAdminTableSchema> {
137
165
  assertIdent(table, "table name");
138
- return isPostgres()
139
- ? getTableSchemaPostgres(table)
140
- : getTableSchemaSqlite(table);
166
+ return isPostgresRuntime(runtime)
167
+ ? getTableSchemaPostgres(table, runtime)
168
+ : getTableSchemaSqlite(table, runtime);
141
169
  }
142
170
 
143
171
  async function getTableSchemaPostgres(
144
172
  table: string,
173
+ runtime?: DbAdminRuntime,
145
174
  ): Promise<DbAdminTableSchema> {
146
- const db = getDbExec();
175
+ const client = db(runtime);
147
176
 
148
- const typeRes = await db.execute({
177
+ const typeRes = await client.execute({
149
178
  sql: `SELECT table_type AS type FROM information_schema.tables
150
179
  WHERE table_schema = 'public' AND table_name = ?`,
151
180
  args: [table],
152
181
  });
153
182
  const type = (typeRes.rows[0] as any)?.type === "VIEW" ? "view" : "table";
154
183
 
155
- const colRes = await db.execute({
184
+ const colRes = await client.execute({
156
185
  sql: `SELECT
157
186
  column_name AS name,
158
187
  data_type AS type,
@@ -164,7 +193,7 @@ async function getTableSchemaPostgres(
164
193
  args: [table],
165
194
  });
166
195
 
167
- const pkRes = await db.execute({
196
+ const pkRes = await client.execute({
168
197
  sql: `SELECT kcu.column_name AS col
169
198
  FROM information_schema.table_constraints tc
170
199
  JOIN information_schema.key_column_usage kcu
@@ -179,7 +208,7 @@ async function getTableSchemaPostgres(
179
208
  const primaryKey = pkRes.rows.map((r) => String((r as any).col));
180
209
  const pkSet = new Set(primaryKey);
181
210
 
182
- const fkRes = await db.execute({
211
+ const fkRes = await client.execute({
183
212
  sql: `SELECT
184
213
  kcu.column_name AS col,
185
214
  ccu.table_name AS ref_table,
@@ -202,7 +231,7 @@ async function getTableSchemaPostgres(
202
231
  refColumn: String((r as any).ref_col),
203
232
  }));
204
233
 
205
- const idxRes = await db.execute({
234
+ const idxRes = await client.execute({
206
235
  sql: `SELECT indexname AS name, indexdef AS def
207
236
  FROM pg_indexes
208
237
  WHERE schemaname = 'public' AND tablename = ?`,
@@ -248,22 +277,25 @@ async function getTableSchemaPostgres(
248
277
  primaryKey,
249
278
  foreignKeys,
250
279
  indexes,
251
- rowCount: type === "view" ? null : await safeRowCount(table),
280
+ rowCount: type === "view" ? null : await safeRowCount(table, runtime),
252
281
  };
253
282
  }
254
283
 
255
284
  async function getTableSchemaSqlite(
256
285
  table: string,
286
+ runtime?: DbAdminRuntime,
257
287
  ): Promise<DbAdminTableSchema> {
258
- const db = getDbExec();
288
+ const client = db(runtime);
259
289
 
260
- const typeRes = await db.execute({
290
+ const typeRes = await client.execute({
261
291
  sql: `SELECT type FROM sqlite_master WHERE name = ? AND type IN ('table','view')`,
262
292
  args: [table],
263
293
  });
264
294
  const type = (typeRes.rows[0] as any)?.type === "view" ? "view" : "table";
265
295
 
266
- const colRes = await db.execute(`PRAGMA table_info(${quoteIdent(table)})`);
296
+ const colRes = await client.execute(
297
+ `PRAGMA table_info(${quoteIdent(table)})`,
298
+ );
267
299
  const columns: DbAdminColumn[] = colRes.rows.map((r) => {
268
300
  const name = String((r as any).name);
269
301
  const dflt = (r as any).dflt_value;
@@ -290,7 +322,7 @@ async function getTableSchemaSqlite(
290
322
  }
291
323
  }
292
324
 
293
- const fkRes = await db.execute(
325
+ const fkRes = await client.execute(
294
326
  `PRAGMA foreign_key_list(${quoteIdent(table)})`,
295
327
  );
296
328
  const foreignKeys: DbAdminForeignKey[] = fkRes.rows.map((r) => ({
@@ -299,14 +331,14 @@ async function getTableSchemaSqlite(
299
331
  refColumn: String((r as any).to),
300
332
  }));
301
333
 
302
- const idxListRes = await db.execute(
334
+ const idxListRes = await client.execute(
303
335
  `PRAGMA index_list(${quoteIdent(table)})`,
304
336
  );
305
337
  const indexes: DbAdminIndex[] = [];
306
338
  for (const idx of idxListRes.rows) {
307
339
  const idxName = String((idx as any).name);
308
340
  if (idxName.startsWith("sqlite_")) continue;
309
- const infoRes = await db.execute(
341
+ const infoRes = await client.execute(
310
342
  `PRAGMA index_info(${quoteIdent(idxName)})`,
311
343
  );
312
344
  indexes.push({
@@ -325,7 +357,7 @@ async function getTableSchemaSqlite(
325
357
  primaryKey,
326
358
  foreignKeys,
327
359
  indexes,
328
- rowCount: type === "view" ? null : await safeRowCount(table),
360
+ rowCount: type === "view" ? null : await safeRowCount(table, runtime),
329
361
  };
330
362
  }
331
363
 
@@ -358,7 +390,10 @@ const OP_SQL: Record<string, string> = {
358
390
  };
359
391
 
360
392
  /** Build a parameterized WHERE clause + args from filters. */
361
- function buildWhere(filters: DbAdminFilter[] | undefined): {
393
+ function buildWhere(
394
+ filters: DbAdminFilter[] | undefined,
395
+ runtime?: DbAdminRuntime,
396
+ ): {
362
397
  clause: string;
363
398
  args: unknown[];
364
399
  } {
@@ -391,7 +426,7 @@ function buildWhere(filters: DbAdminFilter[] | undefined): {
391
426
  case "ilike": {
392
427
  // SQLite LIKE is case-insensitive for ASCII by default; Postgres has
393
428
  // a dedicated ILIKE operator.
394
- if (isPostgres()) {
429
+ if (isPostgresRuntime(runtime)) {
395
430
  parts.push(`${col} ILIKE ?`);
396
431
  } else {
397
432
  parts.push(`${col} LIKE ?`);
@@ -421,26 +456,27 @@ function buildOrderBy(sort: DbAdminRowsRequest["sort"]): string {
421
456
  export async function getRows(
422
457
  table: string,
423
458
  req: DbAdminRowsRequest,
459
+ runtime?: DbAdminRuntime,
424
460
  ): Promise<DbAdminRowsResult> {
425
461
  assertIdent(table, "table name");
426
- const db = getDbExec();
427
- const schema = await getTableSchema(table);
462
+ const client = db(runtime);
463
+ const schema = await getTableSchema(table, runtime);
428
464
 
429
465
  const page = Math.max(1, Math.floor(req.page) || 1);
430
466
  const pageSize = Math.min(1000, Math.max(1, Math.floor(req.pageSize) || 50));
431
467
  const offset = (page - 1) * pageSize;
432
468
 
433
- const where = buildWhere(req.filters);
469
+ const where = buildWhere(req.filters, runtime);
434
470
  const orderBy = buildOrderBy(req.sort);
435
471
  const quoted = quoteIdent(table);
436
472
 
437
- const countRes = await db.execute({
473
+ const countRes = await client.execute({
438
474
  sql: `SELECT COUNT(*) AS c FROM ${quoted}${where.clause}`,
439
475
  args: where.args,
440
476
  });
441
477
  const total = Number((countRes.rows[0] as any)?.c ?? 0) || 0;
442
478
 
443
- const rowsRes = await db.execute({
479
+ const rowsRes = await client.execute({
444
480
  sql: `SELECT * FROM ${quoted}${where.clause}${orderBy} LIMIT ? OFFSET ?`,
445
481
  args: [...where.args, pageSize, offset],
446
482
  });
@@ -512,6 +548,7 @@ function buildDelete(
512
548
  export async function applyMutations(
513
549
  table: string,
514
550
  m: DbAdminMutation,
551
+ runtime?: DbAdminRuntime,
515
552
  ): Promise<DbAdminMutationResult> {
516
553
  assertIdent(table, "table name");
517
554
 
@@ -540,13 +577,13 @@ export async function applyMutations(
540
577
  // sequentially. A failure mid-batch surfaces as a thrown error with the
541
578
  // counts accumulated so far; callers should treat a partial batch as a
542
579
  // failure and re-run with a corrected payload.
543
- const db = getDbExec();
580
+ const client = db(runtime);
544
581
  const insertCount = m.inserts?.length ?? 0;
545
582
  const updateCount = m.updates?.length ?? 0;
546
583
 
547
584
  let executed = 0;
548
585
  for (const stmt of statements) {
549
- const res = await db.execute({ sql: stmt.sql, args: stmt.args });
586
+ const res = await client.execute({ sql: stmt.sql, args: stmt.args });
550
587
  if (executed < insertCount) {
551
588
  result.inserted += 1;
552
589
  } else if (executed < insertCount + updateCount) {
@@ -557,7 +594,7 @@ export async function applyMutations(
557
594
  executed += 1;
558
595
  }
559
596
 
560
- if (statements.length > 0) await notifyDbAdminChange();
597
+ if (statements.length > 0) await notifyDbAdminChange(runtime);
561
598
  return result;
562
599
  }
563
600
 
@@ -611,6 +648,7 @@ export async function runSql(
611
648
  sql: string,
612
649
  params: unknown[] | undefined,
613
650
  opts: { confirmDestructive?: boolean } = {},
651
+ runtime?: DbAdminRuntime,
614
652
  ): Promise<DbAdminQueryResult> {
615
653
  if (typeof sql !== "string" || !sql.trim()) {
616
654
  throw new Error("SQL is required");
@@ -629,9 +667,9 @@ export async function runSql(
629
667
  finalSql = `${finalSql} LIMIT 100`;
630
668
  }
631
669
 
632
- const db = getDbExec();
670
+ const client = db(runtime);
633
671
  const started = Date.now();
634
- const res = await db.execute(
672
+ const res = await client.execute(
635
673
  params && params.length > 0 ? { sql: finalSql, args: params } : finalSql,
636
674
  );
637
675
  const durationMs = Date.now() - started;
@@ -642,7 +680,7 @@ export async function runSql(
642
680
  ? Object.keys(rows[0])
643
681
  : [];
644
682
 
645
- if (isMutatingSql(finalSql)) await notifyDbAdminChange();
683
+ if (isMutatingSql(finalSql)) await notifyDbAdminChange(runtime);
646
684
 
647
685
  return {
648
686
  columns,
@@ -362,6 +362,10 @@ const messages = {
362
362
  loadErrorTitle: "Couldn't load organization",
363
363
  loadErrorFallback: "Couldn't load organization.",
364
364
  tryAgain: "Try again",
365
+ sendFeedback: "Send feedback",
366
+ feedbackPlaceholder:
367
+ "Describe what happened before this organization error appeared.",
368
+ openGitHubIssue: "Open GitHub issue",
365
369
  yourOrganization: "Your organization",
366
370
  joinYourTeam: "Join your team",
367
371
  openToDomainEmails: "Open to @{{domain}} emails",