@agent-native/core 0.26.8 → 0.27.0

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 (218) hide show
  1. package/dist/agent/run-ownership.d.ts +12 -0
  2. package/dist/agent/run-ownership.d.ts.map +1 -0
  3. package/dist/agent/run-ownership.js +39 -0
  4. package/dist/agent/run-ownership.js.map +1 -0
  5. package/dist/cli/index.js +2 -2
  6. package/dist/cli/index.js.map +1 -1
  7. package/dist/cli/skills.d.ts.map +1 -1
  8. package/dist/cli/skills.js +108 -3
  9. package/dist/cli/skills.js.map +1 -1
  10. package/dist/client/db-admin/DataGrid.d.ts +42 -0
  11. package/dist/client/db-admin/DataGrid.d.ts.map +1 -0
  12. package/dist/client/db-admin/DataGrid.js +204 -0
  13. package/dist/client/db-admin/DataGrid.js.map +1 -0
  14. package/dist/client/db-admin/DbAdminPage.d.ts +2 -0
  15. package/dist/client/db-admin/DbAdminPage.d.ts.map +1 -0
  16. package/dist/client/db-admin/DbAdminPage.js +72 -0
  17. package/dist/client/db-admin/DbAdminPage.js.map +1 -0
  18. package/dist/client/db-admin/DevDatabaseLink.d.ts +19 -0
  19. package/dist/client/db-admin/DevDatabaseLink.d.ts.map +1 -0
  20. package/dist/client/db-admin/DevDatabaseLink.js +25 -0
  21. package/dist/client/db-admin/DevDatabaseLink.js.map +1 -0
  22. package/dist/client/db-admin/EditableCell.d.ts +26 -0
  23. package/dist/client/db-admin/EditableCell.d.ts.map +1 -0
  24. package/dist/client/db-admin/EditableCell.js +150 -0
  25. package/dist/client/db-admin/EditableCell.js.map +1 -0
  26. package/dist/client/db-admin/FilterBar.d.ts +8 -0
  27. package/dist/client/db-admin/FilterBar.d.ts.map +1 -0
  28. package/dist/client/db-admin/FilterBar.js +68 -0
  29. package/dist/client/db-admin/FilterBar.js.map +1 -0
  30. package/dist/client/db-admin/ResultsGrid.d.ts +6 -0
  31. package/dist/client/db-admin/ResultsGrid.d.ts.map +1 -0
  32. package/dist/client/db-admin/ResultsGrid.js +41 -0
  33. package/dist/client/db-admin/ResultsGrid.js.map +1 -0
  34. package/dist/client/db-admin/RowSidePanel.d.ts +18 -0
  35. package/dist/client/db-admin/RowSidePanel.d.ts.map +1 -0
  36. package/dist/client/db-admin/RowSidePanel.js +104 -0
  37. package/dist/client/db-admin/RowSidePanel.js.map +1 -0
  38. package/dist/client/db-admin/SqlEditor.d.ts +8 -0
  39. package/dist/client/db-admin/SqlEditor.d.ts.map +1 -0
  40. package/dist/client/db-admin/SqlEditor.js +350 -0
  41. package/dist/client/db-admin/SqlEditor.js.map +1 -0
  42. package/dist/client/db-admin/TableBrowser.d.ts +10 -0
  43. package/dist/client/db-admin/TableBrowser.d.ts.map +1 -0
  44. package/dist/client/db-admin/TableBrowser.js +61 -0
  45. package/dist/client/db-admin/TableBrowser.js.map +1 -0
  46. package/dist/client/db-admin/TableEditor.d.ts +9 -0
  47. package/dist/client/db-admin/TableEditor.d.ts.map +1 -0
  48. package/dist/client/db-admin/TableEditor.js +254 -0
  49. package/dist/client/db-admin/TableEditor.js.map +1 -0
  50. package/dist/client/db-admin/cell-format.d.ts +55 -0
  51. package/dist/client/db-admin/cell-format.d.ts.map +1 -0
  52. package/dist/client/db-admin/cell-format.js +223 -0
  53. package/dist/client/db-admin/cell-format.js.map +1 -0
  54. package/dist/client/db-admin/changeset.d.ts +74 -0
  55. package/dist/client/db-admin/changeset.d.ts.map +1 -0
  56. package/dist/client/db-admin/changeset.js +169 -0
  57. package/dist/client/db-admin/changeset.js.map +1 -0
  58. package/dist/client/db-admin/export-utils.d.ts +15 -0
  59. package/dist/client/db-admin/export-utils.d.ts.map +1 -0
  60. package/dist/client/db-admin/export-utils.js +62 -0
  61. package/dist/client/db-admin/export-utils.js.map +1 -0
  62. package/dist/client/db-admin/index.d.ts +7 -0
  63. package/dist/client/db-admin/index.d.ts.map +1 -0
  64. package/dist/client/db-admin/index.js +8 -0
  65. package/dist/client/db-admin/index.js.map +1 -0
  66. package/dist/client/db-admin/sql-storage.d.ts +35 -0
  67. package/dist/client/db-admin/sql-storage.d.ts.map +1 -0
  68. package/dist/client/db-admin/sql-storage.js +117 -0
  69. package/dist/client/db-admin/sql-storage.js.map +1 -0
  70. package/dist/client/db-admin/storage.d.ts +24 -0
  71. package/dist/client/db-admin/storage.d.ts.map +1 -0
  72. package/dist/client/db-admin/storage.js +50 -0
  73. package/dist/client/db-admin/storage.js.map +1 -0
  74. package/dist/client/db-admin/useAgentSync.d.ts +22 -0
  75. package/dist/client/db-admin/useAgentSync.d.ts.map +1 -0
  76. package/dist/client/db-admin/useAgentSync.js +120 -0
  77. package/dist/client/db-admin/useAgentSync.js.map +1 -0
  78. package/dist/client/db-admin/useDbAdmin.d.ts +20 -0
  79. package/dist/client/db-admin/useDbAdmin.d.ts.map +1 -0
  80. package/dist/client/db-admin/useDbAdmin.js +154 -0
  81. package/dist/client/db-admin/useDbAdmin.js.map +1 -0
  82. package/dist/client/index.d.ts +1 -0
  83. package/dist/client/index.d.ts.map +1 -1
  84. package/dist/client/index.js +1 -0
  85. package/dist/client/index.js.map +1 -1
  86. package/dist/credentials/index.d.ts.map +1 -1
  87. package/dist/credentials/index.js +25 -5
  88. package/dist/credentials/index.js.map +1 -1
  89. package/dist/db-admin/agent-tools.d.ts +15 -0
  90. package/dist/db-admin/agent-tools.d.ts.map +1 -0
  91. package/dist/db-admin/agent-tools.js +147 -0
  92. package/dist/db-admin/agent-tools.js.map +1 -0
  93. package/dist/db-admin/operations.d.ts +17 -0
  94. package/dist/db-admin/operations.d.ts.map +1 -0
  95. package/dist/db-admin/operations.js +541 -0
  96. package/dist/db-admin/operations.js.map +1 -0
  97. package/dist/db-admin/routes.d.ts +5 -0
  98. package/dist/db-admin/routes.d.ts.map +1 -0
  99. package/dist/db-admin/routes.js +134 -0
  100. package/dist/db-admin/routes.js.map +1 -0
  101. package/dist/db-admin/types.d.ts +85 -0
  102. package/dist/db-admin/types.d.ts.map +1 -0
  103. package/dist/db-admin/types.js +9 -0
  104. package/dist/db-admin/types.js.map +1 -0
  105. package/dist/extensions/url-safety.d.ts +20 -0
  106. package/dist/extensions/url-safety.d.ts.map +1 -1
  107. package/dist/extensions/url-safety.js +43 -0
  108. package/dist/extensions/url-safety.js.map +1 -1
  109. package/dist/file-upload/actions/upload-image.d.ts.map +1 -1
  110. package/dist/file-upload/actions/upload-image.js +6 -1
  111. package/dist/file-upload/actions/upload-image.js.map +1 -1
  112. package/dist/integrations/adapters/email.d.ts.map +1 -1
  113. package/dist/integrations/adapters/email.js +112 -0
  114. package/dist/integrations/adapters/email.js.map +1 -1
  115. package/dist/integrations/types.d.ts +11 -0
  116. package/dist/integrations/types.d.ts.map +1 -1
  117. package/dist/integrations/types.js.map +1 -1
  118. package/dist/scripts/db/exec.d.ts.map +1 -1
  119. package/dist/scripts/db/exec.js +2 -1
  120. package/dist/scripts/db/exec.js.map +1 -1
  121. package/dist/scripts/db/index.d.ts.map +1 -1
  122. package/dist/scripts/db/index.js +1 -0
  123. package/dist/scripts/db/index.js.map +1 -1
  124. package/dist/scripts/db/migrate-encrypt-credentials.d.ts +28 -0
  125. package/dist/scripts/db/migrate-encrypt-credentials.d.ts.map +1 -0
  126. package/dist/scripts/db/migrate-encrypt-credentials.js +190 -0
  127. package/dist/scripts/db/migrate-encrypt-credentials.js.map +1 -0
  128. package/dist/scripts/db/query.d.ts.map +1 -1
  129. package/dist/scripts/db/query.js +2 -1
  130. package/dist/scripts/db/query.js.map +1 -1
  131. package/dist/scripts/db/safety.d.ts +1 -0
  132. package/dist/scripts/db/safety.d.ts.map +1 -1
  133. package/dist/scripts/db/safety.js +32 -0
  134. package/dist/scripts/db/safety.js.map +1 -1
  135. package/dist/scripts/db/scoping.d.ts.map +1 -1
  136. package/dist/scripts/db/scoping.js +11 -1
  137. package/dist/scripts/db/scoping.js.map +1 -1
  138. package/dist/secrets/crypto.d.ts +28 -0
  139. package/dist/secrets/crypto.d.ts.map +1 -0
  140. package/dist/secrets/crypto.js +81 -0
  141. package/dist/secrets/crypto.js.map +1 -0
  142. package/dist/secrets/storage.d.ts.map +1 -1
  143. package/dist/secrets/storage.js +3 -61
  144. package/dist/secrets/storage.js.map +1 -1
  145. package/dist/server/action-discovery.d.ts.map +1 -1
  146. package/dist/server/action-discovery.js +5 -2
  147. package/dist/server/action-discovery.js.map +1 -1
  148. package/dist/server/action-routes.d.ts.map +1 -1
  149. package/dist/server/action-routes.js +24 -7
  150. package/dist/server/action-routes.js.map +1 -1
  151. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  152. package/dist/server/agent-chat-plugin.js +39 -0
  153. package/dist/server/agent-chat-plugin.js.map +1 -1
  154. package/dist/server/auth.d.ts +1 -1
  155. package/dist/server/auth.d.ts.map +1 -1
  156. package/dist/server/auth.js.map +1 -1
  157. package/dist/server/better-auth-instance.js +3 -3
  158. package/dist/server/better-auth-instance.js.map +1 -1
  159. package/dist/server/core-routes-plugin.d.ts.map +1 -1
  160. package/dist/server/core-routes-plugin.js +5 -0
  161. package/dist/server/core-routes-plugin.js.map +1 -1
  162. package/dist/server/csrf.d.ts.map +1 -1
  163. package/dist/server/csrf.js +9 -1
  164. package/dist/server/csrf.js.map +1 -1
  165. package/dist/server/design-token-utils.d.ts +8 -1
  166. package/dist/server/design-token-utils.d.ts.map +1 -1
  167. package/dist/server/design-token-utils.js +12 -4
  168. package/dist/server/design-token-utils.js.map +1 -1
  169. package/dist/templates/default/AGENTS.md +4 -4
  170. package/dist/templates/default/app/routes/database.tsx +13 -0
  171. package/dist/templates/workspace-core/.agents/skills/authentication/SKILL.md +9 -2
  172. package/dist/templates/workspace-core/.agents/skills/sharing/SKILL.md +7 -1
  173. package/dist/vite/client.d.ts.map +1 -1
  174. package/dist/vite/client.js +4 -0
  175. package/dist/vite/client.js.map +1 -1
  176. package/docs/content/a2a-protocol.md +2 -2
  177. package/docs/content/actions.md +2 -54
  178. package/docs/content/agent-mentions.md +1 -1
  179. package/docs/content/agent-teams.md +1 -1
  180. package/docs/content/authentication.md +2 -2
  181. package/docs/content/cli-adapters.md +33 -17
  182. package/docs/content/client.md +11 -20
  183. package/docs/content/code-agents-ui.md +19 -6
  184. package/docs/content/context-awareness.md +36 -20
  185. package/docs/content/database.md +3 -3
  186. package/docs/content/deployment.md +8 -8
  187. package/docs/content/dispatch.md +1 -1
  188. package/docs/content/external-agents.md +5 -1
  189. package/docs/content/faq.md +1 -0
  190. package/docs/content/frames.md +110 -30
  191. package/docs/content/getting-started.md +15 -14
  192. package/docs/content/mcp-clients.md +1 -1
  193. package/docs/content/mcp-protocol.md +11 -88
  194. package/docs/content/messaging.md +1 -1
  195. package/docs/content/migration-workbench.md +13 -87
  196. package/docs/content/multi-app-workspace.md +2 -38
  197. package/docs/content/multi-tenancy.md +3 -26
  198. package/docs/content/onboarding.md +10 -3
  199. package/docs/content/recurring-jobs.md +2 -2
  200. package/docs/content/security.md +33 -1
  201. package/docs/content/server.md +1 -1
  202. package/docs/content/skills-guide.md +7 -4
  203. package/docs/content/template-assets.md +9 -9
  204. package/docs/content/template-brain.md +114 -388
  205. package/docs/content/template-clips.md +42 -2
  206. package/docs/content/template-content.md +1 -1
  207. package/docs/content/template-design.md +38 -0
  208. package/docs/content/template-dispatch.md +3 -3
  209. package/docs/content/template-forms.md +6 -6
  210. package/docs/content/template-starter.md +2 -2
  211. package/docs/content/using-your-agent.md +56 -0
  212. package/docs/content/workspace-management.md +6 -6
  213. package/docs/content/workspace.md +19 -0
  214. package/package.json +10 -3
  215. package/src/templates/default/AGENTS.md +4 -4
  216. package/src/templates/default/app/routes/database.tsx +13 -0
  217. package/src/templates/workspace-core/.agents/skills/authentication/SKILL.md +9 -2
  218. package/src/templates/workspace-core/.agents/skills/sharing/SKILL.md +7 -1
@@ -0,0 +1,223 @@
1
+ /** Sentinel meaning "store SQL NULL". */
2
+ export const NULL_VALUE = null;
3
+ const NUMBER_TYPES = [
4
+ "int",
5
+ "integer",
6
+ "smallint",
7
+ "bigint",
8
+ "serial",
9
+ "bigserial",
10
+ "smallserial",
11
+ "decimal",
12
+ "numeric",
13
+ "real",
14
+ "double",
15
+ "float",
16
+ "money",
17
+ ];
18
+ const BOOLEAN_TYPES = ["bool", "boolean"];
19
+ const JSON_TYPES = ["json", "jsonb"];
20
+ const TIMESTAMP_TYPES = [
21
+ "timestamp",
22
+ "timestamptz",
23
+ "datetime",
24
+ "date",
25
+ "time",
26
+ "timetz",
27
+ ];
28
+ const UUID_TYPES = ["uuid", "guid"];
29
+ function normalizeType(col) {
30
+ return (col.type || "").toString().trim().toLowerCase();
31
+ }
32
+ /**
33
+ * Try to pull allowed enum values out of a column definition.
34
+ *
35
+ * The base contract column shape (`DbAdminColumn`) only carries a `type`
36
+ * string, but introspection may attach extra fields per dialect. We probe a
37
+ * few likely shapes and also parse a Postgres/MySQL-style inline list embedded
38
+ * in the type string, e.g. `enum('a','b')`.
39
+ */
40
+ export function inferEnumValues(col) {
41
+ const anyCol = col;
42
+ const candidates = [anyCol.enumValues, anyCol.values, anyCol.options];
43
+ for (const candidate of candidates) {
44
+ if (Array.isArray(candidate) && candidate.length > 0) {
45
+ return candidate.map((v) => String(v));
46
+ }
47
+ }
48
+ const type = (col.type || "").toString();
49
+ const match = type.match(/^\s*(?:enum|set)\s*\((.+)\)\s*$/i);
50
+ if (match) {
51
+ const items = match[1]
52
+ .split(",")
53
+ .map((s) => s.trim().replace(/^['"]|['"]$/g, ""))
54
+ .filter((s) => s.length > 0);
55
+ if (items.length > 0)
56
+ return items;
57
+ }
58
+ return null;
59
+ }
60
+ /** Infer which editor UI a column should use. */
61
+ export function inferEditorKind(col) {
62
+ const type = normalizeType(col);
63
+ if (inferEnumValues(col))
64
+ return "enum";
65
+ if (UUID_TYPES.some((t) => type.includes(t)))
66
+ return "uuid";
67
+ if (BOOLEAN_TYPES.some((t) => type === t || type.includes(t)))
68
+ return "boolean";
69
+ if (JSON_TYPES.some((t) => type === t || type.includes(t)))
70
+ return "json";
71
+ if (TIMESTAMP_TYPES.some((t) => type.includes(t)))
72
+ return "timestamp";
73
+ if (NUMBER_TYPES.some((t) => type.includes(t)))
74
+ return "number";
75
+ return "text";
76
+ }
77
+ /** Whether a value is SQL NULL (vs empty string, 0, false, etc). */
78
+ export function isNull(value) {
79
+ return value === null || value === undefined;
80
+ }
81
+ /**
82
+ * Format a DB value for compact in-cell display. Returns a marker the cell uses
83
+ * to render NULL distinctly; for plain string consumers the text is "NULL".
84
+ */
85
+ export function formatCellValue(value, kind) {
86
+ if (isNull(value))
87
+ return { text: "NULL", isNull: true };
88
+ switch (kind) {
89
+ case "boolean":
90
+ return { text: value === true ? "true" : "false", isNull: false };
91
+ case "json":
92
+ return { text: formatJsonCompact(value), isNull: false };
93
+ case "timestamp":
94
+ return { text: formatTimestamp(value), isNull: false };
95
+ case "number":
96
+ return { text: String(value), isNull: false };
97
+ default:
98
+ return { text: String(value), isNull: false };
99
+ }
100
+ }
101
+ /** Compact single-line JSON for cell display. */
102
+ export function formatJsonCompact(value) {
103
+ if (typeof value === "string") {
104
+ try {
105
+ return JSON.stringify(JSON.parse(value));
106
+ }
107
+ catch {
108
+ return value;
109
+ }
110
+ }
111
+ try {
112
+ return JSON.stringify(value);
113
+ }
114
+ catch {
115
+ return String(value);
116
+ }
117
+ }
118
+ /** Pretty multi-line JSON for the expanded editor. */
119
+ export function formatJsonPretty(value) {
120
+ if (isNull(value))
121
+ return "";
122
+ if (typeof value === "string") {
123
+ try {
124
+ return JSON.stringify(JSON.parse(value), null, 2);
125
+ }
126
+ catch {
127
+ return value;
128
+ }
129
+ }
130
+ try {
131
+ return JSON.stringify(value, null, 2);
132
+ }
133
+ catch {
134
+ return String(value);
135
+ }
136
+ }
137
+ /** Human-readable timestamp; tolerant of strings, numbers, and Dates. */
138
+ export function formatTimestamp(value) {
139
+ if (isNull(value))
140
+ return "";
141
+ const date = value instanceof Date
142
+ ? value
143
+ : typeof value === "number"
144
+ ? new Date(value)
145
+ : new Date(String(value));
146
+ if (Number.isNaN(date.getTime()))
147
+ return String(value);
148
+ const pad = (n) => String(n).padStart(2, "0");
149
+ return (`${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ` +
150
+ `${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`);
151
+ }
152
+ /** Convert a DB value to the string an editor input should start with. */
153
+ export function valueToEditString(value, kind) {
154
+ if (isNull(value))
155
+ return "";
156
+ if (kind === "json")
157
+ return formatJsonPretty(value);
158
+ if (kind === "timestamp")
159
+ return formatTimestamp(value);
160
+ if (kind === "boolean")
161
+ return value === true ? "true" : "false";
162
+ return String(value);
163
+ }
164
+ export class ParseError extends Error {
165
+ }
166
+ /**
167
+ * Parse an edited string back into the JS value sent in the mutation payload.
168
+ *
169
+ * `allowEmptyString` distinguishes "" → empty string from "" → NULL. For most
170
+ * types empty means NULL; for text the editor decides.
171
+ */
172
+ export function parseEditValue(raw, kind, opts = {}) {
173
+ if (raw === "") {
174
+ if (kind === "text" && opts.allowEmptyString)
175
+ return "";
176
+ return NULL_VALUE;
177
+ }
178
+ const trimmed = raw.trim();
179
+ switch (kind) {
180
+ case "number": {
181
+ const n = Number(trimmed);
182
+ if (trimmed === "" || Number.isNaN(n)) {
183
+ throw new ParseError(`"${raw}" is not a valid number`);
184
+ }
185
+ return n;
186
+ }
187
+ case "boolean": {
188
+ const v = trimmed.toLowerCase();
189
+ if (["true", "t", "1", "yes", "y"].includes(v))
190
+ return true;
191
+ if (["false", "f", "0", "no", "n"].includes(v))
192
+ return false;
193
+ if (v === "null")
194
+ return NULL_VALUE;
195
+ throw new ParseError(`"${raw}" is not a valid boolean`);
196
+ }
197
+ case "json": {
198
+ // Accept ANY valid JSON value, including scalars.
199
+ try {
200
+ return JSON.parse(trimmed);
201
+ }
202
+ catch (err) {
203
+ throw new ParseError(`Invalid JSON: ${err instanceof Error ? err.message : String(err)}`);
204
+ }
205
+ }
206
+ case "timestamp":
207
+ case "uuid":
208
+ case "enum":
209
+ case "text":
210
+ default:
211
+ // Preserve intentional spaces for text; trim structured types.
212
+ return kind === "text" ? raw : trimmed;
213
+ }
214
+ }
215
+ /** Cycle a tri-state boolean: null → true → false → null. */
216
+ export function cycleTriStateBoolean(value) {
217
+ if (value === null || value === undefined)
218
+ return true;
219
+ if (value === true)
220
+ return false;
221
+ return null;
222
+ }
223
+ //# sourceMappingURL=cell-format.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cell-format.js","sourceRoot":"","sources":["../../../src/client/db-admin/cell-format.ts"],"names":[],"mappings":"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","sourcesContent":["import type { DbAdminColumn } from \"../../db-admin/types.js\";\n\n/**\n * Type-aware cell formatting and parsing helpers for the DB admin grid.\n *\n * These are intentionally dialect-agnostic: they look at the column's `type`\n * string and normalize it into one of a small set of editor \"kinds\" that drive\n * which editor UI is rendered and how values are parsed back into the mutation\n * payload.\n */\n\nexport type EditorKind =\n | \"text\"\n | \"number\"\n | \"boolean\"\n | \"json\"\n | \"timestamp\"\n | \"enum\"\n | \"uuid\";\n\n/** Sentinel meaning \"store SQL NULL\". */\nexport const NULL_VALUE = null;\n\nconst NUMBER_TYPES = [\n \"int\",\n \"integer\",\n \"smallint\",\n \"bigint\",\n \"serial\",\n \"bigserial\",\n \"smallserial\",\n \"decimal\",\n \"numeric\",\n \"real\",\n \"double\",\n \"float\",\n \"money\",\n];\n\nconst BOOLEAN_TYPES = [\"bool\", \"boolean\"];\nconst JSON_TYPES = [\"json\", \"jsonb\"];\nconst TIMESTAMP_TYPES = [\n \"timestamp\",\n \"timestamptz\",\n \"datetime\",\n \"date\",\n \"time\",\n \"timetz\",\n];\nconst UUID_TYPES = [\"uuid\", \"guid\"];\n\nfunction normalizeType(col: DbAdminColumn): string {\n return (col.type || \"\").toString().trim().toLowerCase();\n}\n\n/**\n * Try to pull allowed enum values out of a column definition.\n *\n * The base contract column shape (`DbAdminColumn`) only carries a `type`\n * string, but introspection may attach extra fields per dialect. We probe a\n * few likely shapes and also parse a Postgres/MySQL-style inline list embedded\n * in the type string, e.g. `enum('a','b')`.\n */\nexport function inferEnumValues(col: DbAdminColumn): string[] | null {\n const anyCol = col as unknown as Record<string, unknown>;\n const candidates = [anyCol.enumValues, anyCol.values, anyCol.options];\n for (const candidate of candidates) {\n if (Array.isArray(candidate) && candidate.length > 0) {\n return candidate.map((v) => String(v));\n }\n }\n const type = (col.type || \"\").toString();\n const match = type.match(/^\\s*(?:enum|set)\\s*\\((.+)\\)\\s*$/i);\n if (match) {\n const items = match[1]\n .split(\",\")\n .map((s) => s.trim().replace(/^['\"]|['\"]$/g, \"\"))\n .filter((s) => s.length > 0);\n if (items.length > 0) return items;\n }\n return null;\n}\n\n/** Infer which editor UI a column should use. */\nexport function inferEditorKind(col: DbAdminColumn): EditorKind {\n const type = normalizeType(col);\n\n if (inferEnumValues(col)) return \"enum\";\n if (UUID_TYPES.some((t) => type.includes(t))) return \"uuid\";\n if (BOOLEAN_TYPES.some((t) => type === t || type.includes(t)))\n return \"boolean\";\n if (JSON_TYPES.some((t) => type === t || type.includes(t))) return \"json\";\n if (TIMESTAMP_TYPES.some((t) => type.includes(t))) return \"timestamp\";\n if (NUMBER_TYPES.some((t) => type.includes(t))) return \"number\";\n return \"text\";\n}\n\n/** Whether a value is SQL NULL (vs empty string, 0, false, etc). */\nexport function isNull(value: unknown): boolean {\n return value === null || value === undefined;\n}\n\n/**\n * Format a DB value for compact in-cell display. Returns a marker the cell uses\n * to render NULL distinctly; for plain string consumers the text is \"NULL\".\n */\nexport function formatCellValue(\n value: unknown,\n kind: EditorKind,\n): { text: string; isNull: boolean } {\n if (isNull(value)) return { text: \"NULL\", isNull: true };\n\n switch (kind) {\n case \"boolean\":\n return { text: value === true ? \"true\" : \"false\", isNull: false };\n case \"json\":\n return { text: formatJsonCompact(value), isNull: false };\n case \"timestamp\":\n return { text: formatTimestamp(value), isNull: false };\n case \"number\":\n return { text: String(value), isNull: false };\n default:\n return { text: String(value), isNull: false };\n }\n}\n\n/** Compact single-line JSON for cell display. */\nexport function formatJsonCompact(value: unknown): string {\n if (typeof value === \"string\") {\n try {\n return JSON.stringify(JSON.parse(value));\n } catch {\n return value;\n }\n }\n try {\n return JSON.stringify(value);\n } catch {\n return String(value);\n }\n}\n\n/** Pretty multi-line JSON for the expanded editor. */\nexport function formatJsonPretty(value: unknown): string {\n if (isNull(value)) return \"\";\n if (typeof value === \"string\") {\n try {\n return JSON.stringify(JSON.parse(value), null, 2);\n } catch {\n return value;\n }\n }\n try {\n return JSON.stringify(value, null, 2);\n } catch {\n return String(value);\n }\n}\n\n/** Human-readable timestamp; tolerant of strings, numbers, and Dates. */\nexport function formatTimestamp(value: unknown): string {\n if (isNull(value)) return \"\";\n const date =\n value instanceof Date\n ? value\n : typeof value === \"number\"\n ? new Date(value)\n : new Date(String(value));\n if (Number.isNaN(date.getTime())) return String(value);\n const pad = (n: number) => String(n).padStart(2, \"0\");\n return (\n `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ` +\n `${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`\n );\n}\n\n/** Convert a DB value to the string an editor input should start with. */\nexport function valueToEditString(value: unknown, kind: EditorKind): string {\n if (isNull(value)) return \"\";\n if (kind === \"json\") return formatJsonPretty(value);\n if (kind === \"timestamp\") return formatTimestamp(value);\n if (kind === \"boolean\") return value === true ? \"true\" : \"false\";\n return String(value);\n}\n\nexport class ParseError extends Error {}\n\n/**\n * Parse an edited string back into the JS value sent in the mutation payload.\n *\n * `allowEmptyString` distinguishes \"\" → empty string from \"\" → NULL. For most\n * types empty means NULL; for text the editor decides.\n */\nexport function parseEditValue(\n raw: string,\n kind: EditorKind,\n opts: { allowEmptyString?: boolean } = {},\n): unknown {\n if (raw === \"\") {\n if (kind === \"text\" && opts.allowEmptyString) return \"\";\n return NULL_VALUE;\n }\n\n const trimmed = raw.trim();\n\n switch (kind) {\n case \"number\": {\n const n = Number(trimmed);\n if (trimmed === \"\" || Number.isNaN(n)) {\n throw new ParseError(`\"${raw}\" is not a valid number`);\n }\n return n;\n }\n case \"boolean\": {\n const v = trimmed.toLowerCase();\n if ([\"true\", \"t\", \"1\", \"yes\", \"y\"].includes(v)) return true;\n if ([\"false\", \"f\", \"0\", \"no\", \"n\"].includes(v)) return false;\n if (v === \"null\") return NULL_VALUE;\n throw new ParseError(`\"${raw}\" is not a valid boolean`);\n }\n case \"json\": {\n // Accept ANY valid JSON value, including scalars.\n try {\n return JSON.parse(trimmed);\n } catch (err) {\n throw new ParseError(\n `Invalid JSON: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n case \"timestamp\":\n case \"uuid\":\n case \"enum\":\n case \"text\":\n default:\n // Preserve intentional spaces for text; trim structured types.\n return kind === \"text\" ? raw : trimmed;\n }\n}\n\n/** Cycle a tri-state boolean: null → true → false → null. */\nexport function cycleTriStateBoolean(value: unknown): boolean | null {\n if (value === null || value === undefined) return true;\n if (value === true) return false;\n return null;\n}\n"]}
@@ -0,0 +1,74 @@
1
+ import type { DbAdminTableSchema, DbAdminMutation } from "../../db-admin/types.js";
2
+ /**
3
+ * The staged-changeset model — the production-grade core of the table editor.
4
+ *
5
+ * Edits are NOT committed on blur. Instead every cell edit, new row, and
6
+ * deletion accumulates here until the user explicitly commits (Cmd/Ctrl+S or
7
+ * the Commit button), at which point {@link buildMutation} maps the staged
8
+ * state into a single {@link DbAdminMutation}. Until then the grid renders the
9
+ * staged values overlaid on the fetched rows, and the user can discard
10
+ * everything.
11
+ *
12
+ * Rows are keyed by a stable primary-key string (the table's PK column values
13
+ * joined). If a table has no primary key, edits target a full-row `where`
14
+ * match instead, and the consumer should warn / disable editing.
15
+ */
16
+ /** New rows get a temporary client id so the grid can track them pre-insert. */
17
+ export interface NewRow {
18
+ /** Stable client-only id, e.g. `new:0`. Never sent to the server. */
19
+ _localId: string;
20
+ values: Record<string, unknown>;
21
+ }
22
+ export interface Changeset {
23
+ /** rowPkString → { column → newValue }. */
24
+ edits: Map<string, Record<string, unknown>>;
25
+ /** Staged inserts. */
26
+ newRows: NewRow[];
27
+ /** rowPkString of rows staged for deletion. */
28
+ deletedKeys: Set<string>;
29
+ }
30
+ export interface UseChangesetResult {
31
+ edits: Map<string, Record<string, unknown>>;
32
+ newRows: NewRow[];
33
+ deletedKeys: Set<string>;
34
+ /** Whether editing is possible (requires a primary key on the table). */
35
+ canEdit: boolean;
36
+ /** Stage a single cell edit on an existing row. */
37
+ setCell: (pk: string, col: string, value: unknown) => void;
38
+ /** Stage many cell edits on one existing row at once. */
39
+ setCells: (pk: string, values: Record<string, unknown>) => void;
40
+ /** Append a blank new row (optionally seeded) and return its local id. */
41
+ addRow: (seed?: Record<string, unknown>) => string;
42
+ /** Patch a staged new row's values. */
43
+ setNewRowCell: (localId: string, col: string, value: unknown) => void;
44
+ /** Remove a staged new row entirely. */
45
+ removeNewRow: (localId: string) => void;
46
+ /** Stage existing rows for deletion (by pk string). Toggles off if re-staged. */
47
+ deleteRows: (pks: string[]) => void;
48
+ /** Un-stage a deletion. */
49
+ undeleteRows: (pks: string[]) => void;
50
+ /** Clear a single staged cell edit (revert to original). */
51
+ revertCell: (pk: string, col: string) => void;
52
+ /** Drop everything. */
53
+ discardAll: () => void;
54
+ /** Whether a given existing-row cell is dirty. */
55
+ isCellDirty: (pk: string, col: string) => boolean;
56
+ /** The staged value for a cell, if any. */
57
+ getStagedCell: (pk: string, col: string) => {
58
+ value: unknown;
59
+ } | undefined;
60
+ /** Whether an existing row is staged for deletion. */
61
+ isDeleted: (pk: string) => boolean;
62
+ isDirty: boolean;
63
+ /** Total count of pending changes (edited rows + new rows + deletions). */
64
+ pendingCount: number;
65
+ /**
66
+ * Build the mutation payload. `originalRows` maps pk string → the original
67
+ * fetched row, used to construct the `where` clause for updates/deletes.
68
+ */
69
+ buildMutation: (originalRows: Map<string, Record<string, unknown>>, dryRun?: boolean) => DbAdminMutation;
70
+ }
71
+ /** Compute the stable pk string for a row given the schema's primary key. */
72
+ export declare function pkStringFor(schema: DbAdminTableSchema | undefined, row: Record<string, unknown>): string;
73
+ export declare function useChangeset(schema: DbAdminTableSchema | undefined): UseChangesetResult;
74
+ //# sourceMappingURL=changeset.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"changeset.d.ts","sourceRoot":"","sources":["../../../src/client/db-admin/changeset.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,kBAAkB,EAClB,eAAe,EAChB,MAAM,yBAAyB,CAAC;AAEjC;;;;;;;;;;;;;GAaG;AAEH,gFAAgF;AAChF,MAAM,WAAW,MAAM;IACrB,qEAAqE;IACrE,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC;AAED,MAAM,WAAW,SAAS;IACxB,2CAA2C;IAC3C,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAC5C,sBAAsB;IACtB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,+CAA+C;IAC/C,WAAW,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CAC1B;AAED,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAC5C,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,WAAW,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAEzB,yEAAyE;IACzE,OAAO,EAAE,OAAO,CAAC;IAEjB,mDAAmD;IACnD,OAAO,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IAC3D,yDAAyD;IACzD,QAAQ,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;IAChE,0EAA0E;IAC1E,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,MAAM,CAAC;IACnD,uCAAuC;IACvC,aAAa,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IACtE,wCAAwC;IACxC,YAAY,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,iFAAiF;IACjF,UAAU,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACpC,2BAA2B;IAC3B,YAAY,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACtC,4DAA4D;IAC5D,UAAU,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9C,uBAAuB;IACvB,UAAU,EAAE,MAAM,IAAI,CAAC;IAEvB,kDAAkD;IAClD,WAAW,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC;IAClD,2CAA2C;IAC3C,aAAa,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,KAAK;QAAE,KAAK,EAAE,OAAO,CAAA;KAAE,GAAG,SAAS,CAAC;IAC3E,sDAAsD;IACtD,SAAS,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC;IAEnC,OAAO,EAAE,OAAO,CAAC;IACjB,2EAA2E;IAC3E,YAAY,EAAE,MAAM,CAAC;IAErB;;;OAGG;IACH,aAAa,EAAE,CACb,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EAClD,MAAM,CAAC,EAAE,OAAO,KACb,eAAe,CAAC;CACtB;AAED,6EAA6E;AAC7E,wBAAgB,WAAW,CACzB,MAAM,EAAE,kBAAkB,GAAG,SAAS,EACtC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC3B,MAAM,CAOR;AAgBD,wBAAgB,YAAY,CAC1B,MAAM,EAAE,kBAAkB,GAAG,SAAS,GACrC,kBAAkB,CAoLpB"}
@@ -0,0 +1,169 @@
1
+ import { useCallback, useMemo, useState } from "react";
2
+ /** Compute the stable pk string for a row given the schema's primary key. */
3
+ export function pkStringFor(schema, row) {
4
+ const cols = schema && schema.primaryKey.length > 0
5
+ ? schema.primaryKey
6
+ : // No PK: fall back to a full-row signature so each row is distinct.
7
+ Object.keys(row).sort();
8
+ return JSON.stringify(cols.map((c) => row[c] ?? null));
9
+ }
10
+ /** Build the `where` object that uniquely identifies an existing row. */
11
+ function whereFor(schema, row) {
12
+ if (schema && schema.primaryKey.length > 0) {
13
+ const where = {};
14
+ for (const col of schema.primaryKey)
15
+ where[col] = row[col] ?? null;
16
+ return where;
17
+ }
18
+ // No PK — match the full original row.
19
+ return { ...row };
20
+ }
21
+ export function useChangeset(schema) {
22
+ const [edits, setEdits] = useState(() => new Map());
23
+ const [newRows, setNewRows] = useState([]);
24
+ const [deletedKeys, setDeletedKeys] = useState(() => new Set());
25
+ const canEdit = !!schema && schema.primaryKey.length > 0;
26
+ const setCell = useCallback((pk, col, value) => {
27
+ setEdits((prev) => {
28
+ const next = new Map(prev);
29
+ const row = { ...(next.get(pk) ?? {}) };
30
+ row[col] = value;
31
+ next.set(pk, row);
32
+ return next;
33
+ });
34
+ }, []);
35
+ const setCells = useCallback((pk, values) => {
36
+ setEdits((prev) => {
37
+ const next = new Map(prev);
38
+ const row = { ...(next.get(pk) ?? {}), ...values };
39
+ next.set(pk, row);
40
+ return next;
41
+ });
42
+ }, []);
43
+ const revertCell = useCallback((pk, col) => {
44
+ setEdits((prev) => {
45
+ if (!prev.has(pk))
46
+ return prev;
47
+ const next = new Map(prev);
48
+ const row = { ...next.get(pk) };
49
+ delete row[col];
50
+ if (Object.keys(row).length === 0)
51
+ next.delete(pk);
52
+ else
53
+ next.set(pk, row);
54
+ return next;
55
+ });
56
+ }, []);
57
+ const addRow = useCallback((seed) => {
58
+ const localId = `new:${Math.random().toString(36).slice(2)}`;
59
+ setNewRows((prev) => [...prev, { _localId: localId, values: seed ?? {} }]);
60
+ return localId;
61
+ }, []);
62
+ const setNewRowCell = useCallback((localId, col, value) => {
63
+ setNewRows((prev) => prev.map((r) => r._localId === localId
64
+ ? { ...r, values: { ...r.values, [col]: value } }
65
+ : r));
66
+ }, []);
67
+ const removeNewRow = useCallback((localId) => {
68
+ setNewRows((prev) => prev.filter((r) => r._localId !== localId));
69
+ }, []);
70
+ const deleteRows = useCallback((pks) => {
71
+ setDeletedKeys((prev) => {
72
+ const next = new Set(prev);
73
+ for (const pk of pks) {
74
+ if (next.has(pk))
75
+ next.delete(pk);
76
+ else
77
+ next.add(pk);
78
+ }
79
+ return next;
80
+ });
81
+ }, []);
82
+ const undeleteRows = useCallback((pks) => {
83
+ setDeletedKeys((prev) => {
84
+ const next = new Set(prev);
85
+ for (const pk of pks)
86
+ next.delete(pk);
87
+ return next;
88
+ });
89
+ }, []);
90
+ const discardAll = useCallback(() => {
91
+ setEdits(new Map());
92
+ setNewRows([]);
93
+ setDeletedKeys(new Set());
94
+ }, []);
95
+ const isCellDirty = useCallback((pk, col) => edits.has(pk) && Object.prototype.hasOwnProperty.call(edits.get(pk), col), [edits]);
96
+ const getStagedCell = useCallback((pk, col) => {
97
+ const row = edits.get(pk);
98
+ if (row && Object.prototype.hasOwnProperty.call(row, col)) {
99
+ return { value: row[col] };
100
+ }
101
+ return undefined;
102
+ }, [edits]);
103
+ const isDeleted = useCallback((pk) => deletedKeys.has(pk), [deletedKeys]);
104
+ const pendingCount = useMemo(() => {
105
+ // An edited row that is also deleted only counts once (as a deletion).
106
+ let editedNotDeleted = 0;
107
+ for (const pk of edits.keys()) {
108
+ if (!deletedKeys.has(pk))
109
+ editedNotDeleted += 1;
110
+ }
111
+ return editedNotDeleted + newRows.length + deletedKeys.size;
112
+ }, [edits, newRows, deletedKeys]);
113
+ const isDirty = pendingCount > 0;
114
+ const buildMutation = useCallback((originalRows, dryRun) => {
115
+ const inserts = newRows
116
+ .map((r) => r.values)
117
+ .filter((v) => Object.keys(v).length > 0);
118
+ const updates = [];
119
+ for (const [pk, set] of edits.entries()) {
120
+ if (deletedKeys.has(pk))
121
+ continue; // deletion supersedes edit
122
+ const original = originalRows.get(pk);
123
+ if (!original)
124
+ continue;
125
+ if (Object.keys(set).length === 0)
126
+ continue;
127
+ updates.push({ where: whereFor(schema, original), set });
128
+ }
129
+ const deletes = [];
130
+ for (const pk of deletedKeys) {
131
+ const original = originalRows.get(pk);
132
+ if (!original)
133
+ continue;
134
+ deletes.push(whereFor(schema, original));
135
+ }
136
+ const mutation = {};
137
+ if (inserts.length)
138
+ mutation.inserts = inserts;
139
+ if (updates.length)
140
+ mutation.updates = updates;
141
+ if (deletes.length)
142
+ mutation.deletes = deletes;
143
+ if (dryRun)
144
+ mutation.dryRun = true;
145
+ return mutation;
146
+ }, [edits, newRows, deletedKeys, schema]);
147
+ return {
148
+ edits,
149
+ newRows,
150
+ deletedKeys,
151
+ canEdit,
152
+ setCell,
153
+ setCells,
154
+ addRow,
155
+ setNewRowCell,
156
+ removeNewRow,
157
+ deleteRows,
158
+ undeleteRows,
159
+ revertCell,
160
+ discardAll,
161
+ isCellDirty,
162
+ getStagedCell,
163
+ isDeleted,
164
+ isDirty,
165
+ pendingCount,
166
+ buildMutation,
167
+ };
168
+ }
169
+ //# sourceMappingURL=changeset.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"changeset.js","sourceRoot":"","sources":["../../../src/client/db-admin/changeset.ts"],"names":[],"mappings":"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","sourcesContent":["import { useCallback, useMemo, useState } from \"react\";\nimport type {\n DbAdminTableSchema,\n DbAdminMutation,\n} from \"../../db-admin/types.js\";\n\n/**\n * The staged-changeset model — the production-grade core of the table editor.\n *\n * Edits are NOT committed on blur. Instead every cell edit, new row, and\n * deletion accumulates here until the user explicitly commits (Cmd/Ctrl+S or\n * the Commit button), at which point {@link buildMutation} maps the staged\n * state into a single {@link DbAdminMutation}. Until then the grid renders the\n * staged values overlaid on the fetched rows, and the user can discard\n * everything.\n *\n * Rows are keyed by a stable primary-key string (the table's PK column values\n * joined). If a table has no primary key, edits target a full-row `where`\n * match instead, and the consumer should warn / disable editing.\n */\n\n/** New rows get a temporary client id so the grid can track them pre-insert. */\nexport interface NewRow {\n /** Stable client-only id, e.g. `new:0`. Never sent to the server. */\n _localId: string;\n values: Record<string, unknown>;\n}\n\nexport interface Changeset {\n /** rowPkString → { column → newValue }. */\n edits: Map<string, Record<string, unknown>>;\n /** Staged inserts. */\n newRows: NewRow[];\n /** rowPkString of rows staged for deletion. */\n deletedKeys: Set<string>;\n}\n\nexport interface UseChangesetResult {\n edits: Map<string, Record<string, unknown>>;\n newRows: NewRow[];\n deletedKeys: Set<string>;\n\n /** Whether editing is possible (requires a primary key on the table). */\n canEdit: boolean;\n\n /** Stage a single cell edit on an existing row. */\n setCell: (pk: string, col: string, value: unknown) => void;\n /** Stage many cell edits on one existing row at once. */\n setCells: (pk: string, values: Record<string, unknown>) => void;\n /** Append a blank new row (optionally seeded) and return its local id. */\n addRow: (seed?: Record<string, unknown>) => string;\n /** Patch a staged new row's values. */\n setNewRowCell: (localId: string, col: string, value: unknown) => void;\n /** Remove a staged new row entirely. */\n removeNewRow: (localId: string) => void;\n /** Stage existing rows for deletion (by pk string). Toggles off if re-staged. */\n deleteRows: (pks: string[]) => void;\n /** Un-stage a deletion. */\n undeleteRows: (pks: string[]) => void;\n /** Clear a single staged cell edit (revert to original). */\n revertCell: (pk: string, col: string) => void;\n /** Drop everything. */\n discardAll: () => void;\n\n /** Whether a given existing-row cell is dirty. */\n isCellDirty: (pk: string, col: string) => boolean;\n /** The staged value for a cell, if any. */\n getStagedCell: (pk: string, col: string) => { value: unknown } | undefined;\n /** Whether an existing row is staged for deletion. */\n isDeleted: (pk: string) => boolean;\n\n isDirty: boolean;\n /** Total count of pending changes (edited rows + new rows + deletions). */\n pendingCount: number;\n\n /**\n * Build the mutation payload. `originalRows` maps pk string → the original\n * fetched row, used to construct the `where` clause for updates/deletes.\n */\n buildMutation: (\n originalRows: Map<string, Record<string, unknown>>,\n dryRun?: boolean,\n ) => DbAdminMutation;\n}\n\n/** Compute the stable pk string for a row given the schema's primary key. */\nexport function pkStringFor(\n schema: DbAdminTableSchema | undefined,\n row: Record<string, unknown>,\n): string {\n const cols =\n schema && schema.primaryKey.length > 0\n ? schema.primaryKey\n : // No PK: fall back to a full-row signature so each row is distinct.\n Object.keys(row).sort();\n return JSON.stringify(cols.map((c) => row[c] ?? null));\n}\n\n/** Build the `where` object that uniquely identifies an existing row. */\nfunction whereFor(\n schema: DbAdminTableSchema | undefined,\n row: Record<string, unknown>,\n): Record<string, unknown> {\n if (schema && schema.primaryKey.length > 0) {\n const where: Record<string, unknown> = {};\n for (const col of schema.primaryKey) where[col] = row[col] ?? null;\n return where;\n }\n // No PK — match the full original row.\n return { ...row };\n}\n\nexport function useChangeset(\n schema: DbAdminTableSchema | undefined,\n): UseChangesetResult {\n const [edits, setEdits] = useState<Map<string, Record<string, unknown>>>(\n () => new Map(),\n );\n const [newRows, setNewRows] = useState<NewRow[]>([]);\n const [deletedKeys, setDeletedKeys] = useState<Set<string>>(() => new Set());\n\n const canEdit = !!schema && schema.primaryKey.length > 0;\n\n const setCell = useCallback((pk: string, col: string, value: unknown) => {\n setEdits((prev) => {\n const next = new Map(prev);\n const row = { ...(next.get(pk) ?? {}) };\n row[col] = value;\n next.set(pk, row);\n return next;\n });\n }, []);\n\n const setCells = useCallback(\n (pk: string, values: Record<string, unknown>) => {\n setEdits((prev) => {\n const next = new Map(prev);\n const row = { ...(next.get(pk) ?? {}), ...values };\n next.set(pk, row);\n return next;\n });\n },\n [],\n );\n\n const revertCell = useCallback((pk: string, col: string) => {\n setEdits((prev) => {\n if (!prev.has(pk)) return prev;\n const next = new Map(prev);\n const row = { ...next.get(pk)! };\n delete row[col];\n if (Object.keys(row).length === 0) next.delete(pk);\n else next.set(pk, row);\n return next;\n });\n }, []);\n\n const addRow = useCallback((seed?: Record<string, unknown>) => {\n const localId = `new:${Math.random().toString(36).slice(2)}`;\n setNewRows((prev) => [...prev, { _localId: localId, values: seed ?? {} }]);\n return localId;\n }, []);\n\n const setNewRowCell = useCallback(\n (localId: string, col: string, value: unknown) => {\n setNewRows((prev) =>\n prev.map((r) =>\n r._localId === localId\n ? { ...r, values: { ...r.values, [col]: value } }\n : r,\n ),\n );\n },\n [],\n );\n\n const removeNewRow = useCallback((localId: string) => {\n setNewRows((prev) => prev.filter((r) => r._localId !== localId));\n }, []);\n\n const deleteRows = useCallback((pks: string[]) => {\n setDeletedKeys((prev) => {\n const next = new Set(prev);\n for (const pk of pks) {\n if (next.has(pk)) next.delete(pk);\n else next.add(pk);\n }\n return next;\n });\n }, []);\n\n const undeleteRows = useCallback((pks: string[]) => {\n setDeletedKeys((prev) => {\n const next = new Set(prev);\n for (const pk of pks) next.delete(pk);\n return next;\n });\n }, []);\n\n const discardAll = useCallback(() => {\n setEdits(new Map());\n setNewRows([]);\n setDeletedKeys(new Set());\n }, []);\n\n const isCellDirty = useCallback(\n (pk: string, col: string) =>\n edits.has(pk) && Object.prototype.hasOwnProperty.call(edits.get(pk), col),\n [edits],\n );\n\n const getStagedCell = useCallback(\n (pk: string, col: string) => {\n const row = edits.get(pk);\n if (row && Object.prototype.hasOwnProperty.call(row, col)) {\n return { value: row[col] };\n }\n return undefined;\n },\n [edits],\n );\n\n const isDeleted = useCallback(\n (pk: string) => deletedKeys.has(pk),\n [deletedKeys],\n );\n\n const pendingCount = useMemo(() => {\n // An edited row that is also deleted only counts once (as a deletion).\n let editedNotDeleted = 0;\n for (const pk of edits.keys()) {\n if (!deletedKeys.has(pk)) editedNotDeleted += 1;\n }\n return editedNotDeleted + newRows.length + deletedKeys.size;\n }, [edits, newRows, deletedKeys]);\n\n const isDirty = pendingCount > 0;\n\n const buildMutation = useCallback(\n (\n originalRows: Map<string, Record<string, unknown>>,\n dryRun?: boolean,\n ): DbAdminMutation => {\n const inserts: Record<string, unknown>[] = newRows\n .map((r) => r.values)\n .filter((v) => Object.keys(v).length > 0);\n\n const updates: DbAdminMutation[\"updates\"] = [];\n for (const [pk, set] of edits.entries()) {\n if (deletedKeys.has(pk)) continue; // deletion supersedes edit\n const original = originalRows.get(pk);\n if (!original) continue;\n if (Object.keys(set).length === 0) continue;\n updates.push({ where: whereFor(schema, original), set });\n }\n\n const deletes: Record<string, unknown>[] = [];\n for (const pk of deletedKeys) {\n const original = originalRows.get(pk);\n if (!original) continue;\n deletes.push(whereFor(schema, original));\n }\n\n const mutation: DbAdminMutation = {};\n if (inserts.length) mutation.inserts = inserts;\n if (updates.length) mutation.updates = updates;\n if (deletes.length) mutation.deletes = deletes;\n if (dryRun) mutation.dryRun = true;\n return mutation;\n },\n [edits, newRows, deletedKeys, schema],\n );\n\n return {\n edits,\n newRows,\n deletedKeys,\n canEdit,\n setCell,\n setCells,\n addRow,\n setNewRowCell,\n removeNewRow,\n deleteRows,\n undeleteRows,\n revertCell,\n discardAll,\n isCellDirty,\n getStagedCell,\n isDeleted,\n isDirty,\n pendingCount,\n buildMutation,\n };\n}\n"]}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Serialization + download helpers for exporting SQL editor results.
3
+ *
4
+ * Kept dependency-free and SSR-safe: `downloadFile` no-ops outside the browser.
5
+ */
6
+ /** Render rows as RFC-4180-style CSV with a header row of the given columns. */
7
+ export declare function toCSV(columns: string[], rows: Record<string, unknown>[]): string;
8
+ /** Render rows as a pretty-printed JSON array. */
9
+ export declare function toJSON(rows: Record<string, unknown>[]): string;
10
+ /**
11
+ * Trigger a client-side download of `content` as a file named `name` with the
12
+ * given MIME type. No-ops during SSR.
13
+ */
14
+ export declare function downloadFile(name: string, mime: string, content: string): void;
15
+ //# sourceMappingURL=export-utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"export-utils.d.ts","sourceRoot":"","sources":["../../../src/client/db-admin/export-utils.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAsBH,gFAAgF;AAChF,wBAAgB,KAAK,CACnB,OAAO,EAAE,MAAM,EAAE,EACjB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAC9B,MAAM,CAMR;AAED,kDAAkD;AAClD,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,MAAM,CAE9D;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAC1B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,GACd,IAAI,CAiBN"}
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Serialization + download helpers for exporting SQL editor results.
3
+ *
4
+ * Kept dependency-free and SSR-safe: `downloadFile` no-ops outside the browser.
5
+ */
6
+ function cellToCSV(value) {
7
+ if (value === null || value === undefined)
8
+ return "";
9
+ let str;
10
+ if (typeof value === "object") {
11
+ try {
12
+ str = JSON.stringify(value);
13
+ }
14
+ catch {
15
+ str = String(value);
16
+ }
17
+ }
18
+ else {
19
+ str = String(value);
20
+ }
21
+ // Quote when the value contains a comma, quote, CR, or LF. Escape embedded
22
+ // double-quotes by doubling them (RFC 4180).
23
+ if (/[",\r\n]/.test(str)) {
24
+ return `"${str.replace(/"/g, '""')}"`;
25
+ }
26
+ return str;
27
+ }
28
+ /** Render rows as RFC-4180-style CSV with a header row of the given columns. */
29
+ export function toCSV(columns, rows) {
30
+ const header = columns.map(cellToCSV).join(",");
31
+ const body = rows.map((row) => columns.map((col) => cellToCSV(row[col])).join(","));
32
+ return [header, ...body].join("\r\n");
33
+ }
34
+ /** Render rows as a pretty-printed JSON array. */
35
+ export function toJSON(rows) {
36
+ return JSON.stringify(rows, null, 2);
37
+ }
38
+ /**
39
+ * Trigger a client-side download of `content` as a file named `name` with the
40
+ * given MIME type. No-ops during SSR.
41
+ */
42
+ export function downloadFile(name, mime, content) {
43
+ if (typeof window === "undefined" || typeof document === "undefined")
44
+ return;
45
+ try {
46
+ const blob = new Blob([content], { type: mime });
47
+ const url = URL.createObjectURL(blob);
48
+ const anchor = document.createElement("a");
49
+ anchor.href = url;
50
+ anchor.download = name;
51
+ anchor.style.display = "none";
52
+ document.body.appendChild(anchor);
53
+ anchor.click();
54
+ document.body.removeChild(anchor);
55
+ // Revoke on the next tick so the click has a chance to start the download.
56
+ setTimeout(() => URL.revokeObjectURL(url), 0);
57
+ }
58
+ catch {
59
+ // Best-effort — nothing actionable if the browser blocks the download.
60
+ }
61
+ }
62
+ //# sourceMappingURL=export-utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"export-utils.js","sourceRoot":"","sources":["../../../src/client/db-admin/export-utils.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,SAAS,SAAS,CAAC,KAAc;IAC/B,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,EAAE,CAAC;IACrD,IAAI,GAAW,CAAC;IAChB,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,IAAI,CAAC;YACH,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QAC9B,CAAC;QAAC,MAAM,CAAC;YACP,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;QACtB,CAAC;IACH,CAAC;SAAM,CAAC;QACN,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IACtB,CAAC;IACD,2EAA2E;IAC3E,6CAA6C;IAC7C,IAAI,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QACzB,OAAO,IAAI,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC;IACxC,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,gFAAgF;AAChF,MAAM,UAAU,KAAK,CACnB,OAAiB,EACjB,IAA+B;IAE/B,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAChD,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAC5B,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CACpD,CAAC;IACF,OAAO,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AACxC,CAAC;AAED,kDAAkD;AAClD,MAAM,UAAU,MAAM,CAAC,IAA+B;IACpD,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;AACvC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,YAAY,CAC1B,IAAY,EACZ,IAAY,EACZ,OAAe;IAEf,IAAI,OAAO,MAAM,KAAK,WAAW,IAAI,OAAO,QAAQ,KAAK,WAAW;QAAE,OAAO;IAC7E,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,CAAC,OAAO,CAAC,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;QACjD,MAAM,GAAG,GAAG,GAAG,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;QACtC,MAAM,MAAM,GAAG,QAAQ,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC;QAC3C,MAAM,CAAC,IAAI,GAAG,GAAG,CAAC;QAClB,MAAM,CAAC,QAAQ,GAAG,IAAI,CAAC;QACvB,MAAM,CAAC,KAAK,CAAC,OAAO,GAAG,MAAM,CAAC;QAC9B,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;QAClC,MAAM,CAAC,KAAK,EAAE,CAAC;QACf,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;QAClC,2EAA2E;QAC3E,UAAU,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,eAAe,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;IAChD,CAAC;IAAC,MAAM,CAAC;QACP,uEAAuE;IACzE,CAAC;AACH,CAAC","sourcesContent":["/**\n * Serialization + download helpers for exporting SQL editor results.\n *\n * Kept dependency-free and SSR-safe: `downloadFile` no-ops outside the browser.\n */\n\nfunction cellToCSV(value: unknown): string {\n if (value === null || value === undefined) return \"\";\n let str: string;\n if (typeof value === \"object\") {\n try {\n str = JSON.stringify(value);\n } catch {\n str = String(value);\n }\n } else {\n str = String(value);\n }\n // Quote when the value contains a comma, quote, CR, or LF. Escape embedded\n // double-quotes by doubling them (RFC 4180).\n if (/[\",\\r\\n]/.test(str)) {\n return `\"${str.replace(/\"/g, '\"\"')}\"`;\n }\n return str;\n}\n\n/** Render rows as RFC-4180-style CSV with a header row of the given columns. */\nexport function toCSV(\n columns: string[],\n rows: Record<string, unknown>[],\n): string {\n const header = columns.map(cellToCSV).join(\",\");\n const body = rows.map((row) =>\n columns.map((col) => cellToCSV(row[col])).join(\",\"),\n );\n return [header, ...body].join(\"\\r\\n\");\n}\n\n/** Render rows as a pretty-printed JSON array. */\nexport function toJSON(rows: Record<string, unknown>[]): string {\n return JSON.stringify(rows, null, 2);\n}\n\n/**\n * Trigger a client-side download of `content` as a file named `name` with the\n * given MIME type. No-ops during SSR.\n */\nexport function downloadFile(\n name: string,\n mime: string,\n content: string,\n): void {\n if (typeof window === \"undefined\" || typeof document === \"undefined\") return;\n try {\n const blob = new Blob([content], { type: mime });\n const url = URL.createObjectURL(blob);\n const anchor = document.createElement(\"a\");\n anchor.href = url;\n anchor.download = name;\n anchor.style.display = \"none\";\n document.body.appendChild(anchor);\n anchor.click();\n document.body.removeChild(anchor);\n // Revoke on the next tick so the click has a chance to start the download.\n setTimeout(() => URL.revokeObjectURL(url), 0);\n } catch {\n // Best-effort — nothing actionable if the browser blocks the download.\n }\n}\n"]}
@@ -0,0 +1,7 @@
1
+ export { DbAdminPage } from "./DbAdminPage.js";
2
+ export { DevDatabaseLink, type DevDatabaseLinkProps, } from "./DevDatabaseLink.js";
3
+ export { dbAdminBasePath, dbAdminGet, dbAdminPost, useOverview, useTableSchema, useTableRows, mutateTable, runQuery, type DbAdminOverview, type DbAdminQueryState, } from "./useDbAdmin.js";
4
+ export { loadGridState, saveGridState, getLS, setLS, removeLS, type GridState, } from "./storage.js";
5
+ export { useDbAdminAgentSync, useNavigateConsumer, type DbAdminNavigationState, } from "./useAgentSync.js";
6
+ export { TableBrowser, type TableBrowserProps } from "./TableBrowser.js";
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/client/db-admin/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EACL,eAAe,EACf,KAAK,oBAAoB,GAC1B,MAAM,sBAAsB,CAAC;AAG9B,OAAO,EACL,eAAe,EACf,UAAU,EACV,WAAW,EACX,WAAW,EACX,cAAc,EACd,YAAY,EACZ,WAAW,EACX,QAAQ,EACR,KAAK,eAAe,EACpB,KAAK,iBAAiB,GACvB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,aAAa,EACb,aAAa,EACb,KAAK,EACL,KAAK,EACL,QAAQ,EACR,KAAK,SAAS,GACf,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,mBAAmB,EACnB,mBAAmB,EACnB,KAAK,sBAAsB,GAC5B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,YAAY,EAAE,KAAK,iBAAiB,EAAE,MAAM,mBAAmB,CAAC"}