d1s 0.2.11 → 0.2.13

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 (318) hide show
  1. package/dist/.next/.next/BUILD_ID +1 -1
  2. package/dist/.next/.next/app-build-manifest.json +28 -28
  3. package/dist/.next/.next/app-path-routes-manifest.json +1 -1
  4. package/dist/.next/.next/build-manifest.json +3 -3
  5. package/dist/.next/.next/cache/.rscinfo +1 -1
  6. package/dist/.next/.next/cache/.tsbuildinfo +1 -1
  7. package/dist/.next/.next/cache/webpack/client-production/0.pack +0 -0
  8. package/dist/.next/.next/cache/webpack/client-production/1.pack +0 -0
  9. package/dist/.next/.next/cache/webpack/client-production/10.pack +0 -0
  10. package/dist/.next/.next/cache/webpack/client-production/11.pack +0 -0
  11. package/dist/.next/.next/cache/webpack/client-production/12.pack +0 -0
  12. package/dist/.next/.next/cache/webpack/client-production/2.pack +0 -0
  13. package/dist/.next/.next/cache/webpack/client-production/3.pack +0 -0
  14. package/dist/.next/.next/cache/webpack/client-production/4.pack +0 -0
  15. package/dist/.next/.next/cache/webpack/client-production/5.pack +0 -0
  16. package/dist/.next/.next/cache/webpack/client-production/6.pack +0 -0
  17. package/dist/.next/.next/cache/webpack/client-production/7.pack +0 -0
  18. package/dist/.next/.next/cache/webpack/client-production/8.pack +0 -0
  19. package/dist/.next/.next/cache/webpack/client-production/9.pack +0 -0
  20. package/dist/.next/.next/cache/webpack/client-production/index.pack +0 -0
  21. package/dist/.next/.next/cache/webpack/client-production/index.pack.old +0 -0
  22. package/dist/.next/.next/cache/webpack/edge-server-production/index.pack +0 -0
  23. package/dist/.next/.next/cache/webpack/server-production/0.pack +0 -0
  24. package/dist/.next/.next/cache/webpack/server-production/1.pack +0 -0
  25. package/dist/.next/.next/cache/webpack/server-production/2.pack +0 -0
  26. package/dist/.next/.next/cache/webpack/server-production/3.pack +0 -0
  27. package/dist/.next/.next/cache/webpack/server-production/index.pack +0 -0
  28. package/dist/.next/.next/cache/webpack/server-production/index.pack.old +0 -0
  29. package/dist/.next/.next/next-minimal-server.js.nft.json +1 -1
  30. package/dist/.next/.next/next-server.js.nft.json +1 -1
  31. package/dist/.next/.next/prerender-manifest.json +1 -1
  32. package/dist/.next/.next/required-server-files.json +1 -1
  33. package/dist/.next/.next/server/app/_not-found/page.js +1 -1
  34. package/dist/.next/.next/server/app/_not-found/page.js.nft.json +1 -1
  35. package/dist/.next/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  36. package/dist/.next/.next/server/app/_not-found.html +1 -1
  37. package/dist/.next/.next/server/app/_not-found.rsc +4 -4
  38. package/dist/.next/.next/server/app/api/cloudflare/route.js +1 -1
  39. package/dist/.next/.next/server/app/api/cloudflare/route_client-reference-manifest.js +1 -1
  40. package/dist/.next/.next/server/app/api/databases/route.js +1 -1
  41. package/dist/.next/.next/server/app/api/databases/route_client-reference-manifest.js +1 -1
  42. package/dist/.next/.next/server/app/api/migrations/sync/route.js +5 -5
  43. package/dist/.next/.next/server/app/api/migrations/sync/route_client-reference-manifest.js +1 -1
  44. package/dist/.next/.next/server/app/api/migrations/sync-files/route.js +3 -3
  45. package/dist/.next/.next/server/app/api/migrations/sync-files/route_client-reference-manifest.js +1 -1
  46. package/dist/.next/.next/server/app/api/pull-data/confirm/route.js +1 -1
  47. package/dist/.next/.next/server/app/api/pull-data/confirm/route_client-reference-manifest.js +1 -1
  48. package/dist/.next/.next/server/app/api/pull-remote/confirm/route.js +2 -2
  49. package/dist/.next/.next/server/app/api/pull-remote/confirm/route_client-reference-manifest.js +1 -1
  50. package/dist/.next/.next/server/app/api/pull-remote/preview/route.js +4 -4
  51. package/dist/.next/.next/server/app/api/pull-remote/preview/route_client-reference-manifest.js +1 -1
  52. package/dist/.next/.next/server/app/api/push-remote/confirm/route.js +5 -5
  53. package/dist/.next/.next/server/app/api/push-remote/confirm/route_client-reference-manifest.js +1 -1
  54. package/dist/.next/.next/server/app/api/push-remote/preview/route.js +4 -4
  55. package/dist/.next/.next/server/app/api/push-remote/preview/route_client-reference-manifest.js +1 -1
  56. package/dist/.next/.next/server/app/api/query/route.js +3 -3
  57. package/dist/.next/.next/server/app/api/query/route_client-reference-manifest.js +1 -1
  58. package/dist/.next/.next/server/app/api/tables/[name]/route.js +5 -5
  59. package/dist/.next/.next/server/app/api/tables/[name]/route_client-reference-manifest.js +1 -1
  60. package/dist/.next/.next/server/app/api/tables/route.js +2 -2
  61. package/dist/.next/.next/server/app/api/tables/route_client-reference-manifest.js +1 -1
  62. package/dist/.next/.next/server/app/api/update/route.js +1 -1
  63. package/dist/.next/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  64. package/dist/.next/.next/server/app/index.html +2 -2
  65. package/dist/.next/.next/server/app/index.rsc +5 -5
  66. package/dist/.next/.next/server/app/page.js +7 -7
  67. package/dist/.next/.next/server/app/page.js.nft.json +1 -1
  68. package/dist/.next/.next/server/app/page_client-reference-manifest.js +1 -1
  69. package/dist/.next/.next/server/app-paths-manifest.json +1 -1
  70. package/dist/.next/.next/server/chunks/226.js +12 -12
  71. package/dist/.next/.next/server/chunks/391.js +1 -1
  72. package/dist/.next/.next/server/chunks/572.js +1 -0
  73. package/dist/.next/.next/server/chunks/992.js +3 -3
  74. package/dist/.next/.next/server/middleware-build-manifest.js +1 -1
  75. package/dist/.next/.next/server/next-font-manifest.js +1 -1
  76. package/dist/.next/.next/server/next-font-manifest.json +1 -1
  77. package/dist/.next/.next/server/pages/404.html +1 -1
  78. package/dist/.next/.next/server/pages/500.html +1 -1
  79. package/dist/.next/.next/server/server-reference-manifest.json +1 -1
  80. package/dist/.next/.next/static/chunks/{576-c4daf274bb6469a1.js → 576-18a2209e1ed26aad.js} +1 -1
  81. package/dist/.next/.next/static/chunks/{92-c4466e0f1ca8a3a8.js → 92-5f7522943fcb72a8.js} +1 -1
  82. package/dist/.next/.next/static/chunks/app/{layout-be6ee67cf0c92654.js → layout-40ec07d04681ba81.js} +1 -1
  83. package/dist/.next/.next/static/chunks/app/page-f05cd0fc436bf9bc.js +1 -0
  84. package/dist/.next/.next/static/chunks/app/page-f2bc307c0d8acdaa.js +1 -0
  85. package/dist/.next/.next/static/chunks/{main-app-fa35024de9bd9284.js → main-app-4506e88db72db4b7.js} +1 -1
  86. package/dist/.next/.next/static/css/{9f6c25c5400f83d3.css → 7c16f57d325d0d7d.css} +1 -1
  87. package/dist/.next/.next/static/ejYPqJ2kVicVp5EFWOZIC/_buildManifest.js +1 -0
  88. package/dist/.next/.next/static/ejYPqJ2kVicVp5EFWOZIC/_ssgManifest.js +1 -0
  89. package/dist/.next/.next/static/gABGrAoO8IPArDo_Ns_7g/_buildManifest.js +1 -0
  90. package/dist/.next/.next/static/gABGrAoO8IPArDo_Ns_7g/_ssgManifest.js +1 -0
  91. package/dist/.next/.next/static/gh-QfIUVo4FTTduYCVKT6/_buildManifest.js +1 -0
  92. package/dist/.next/.next/static/gh-QfIUVo4FTTduYCVKT6/_ssgManifest.js +1 -0
  93. package/dist/.next/.next/static/media/8d697b304b401681-s.woff2 +0 -0
  94. package/dist/.next/.next/static/media/9610d9e46709d722-s.woff2 +0 -0
  95. package/dist/.next/.next/static/thaCy2qVeNqYYhdayr13C/_buildManifest.js +1 -0
  96. package/dist/.next/.next/static/thaCy2qVeNqYYhdayr13C/_ssgManifest.js +1 -0
  97. package/dist/.next/.next/static/ybCx6L6gHqtODbKmlhU-d/_buildManifest.js +1 -0
  98. package/dist/.next/.next/static/ybCx6L6gHqtODbKmlhU-d/_ssgManifest.js +1 -0
  99. package/dist/.next/.next/trace +3 -3
  100. package/dist/.next/.next/types/app/api/cloudflare/route.ts +1 -1
  101. package/dist/.next/.next/types/app/api/databases/route.ts +1 -1
  102. package/dist/.next/.next/types/app/api/migrations/sync/route.ts +1 -1
  103. package/dist/.next/.next/types/app/api/migrations/sync-files/route.ts +1 -1
  104. package/dist/.next/.next/types/app/api/pull-data/confirm/route.ts +1 -1
  105. package/dist/.next/.next/types/app/api/pull-remote/confirm/route.ts +1 -1
  106. package/dist/.next/.next/types/app/api/pull-remote/preview/route.ts +1 -1
  107. package/dist/.next/.next/types/app/api/push-remote/confirm/route.ts +1 -1
  108. package/dist/.next/.next/types/app/api/push-remote/preview/route.ts +1 -1
  109. package/dist/.next/.next/types/app/api/query/route.ts +1 -1
  110. package/dist/.next/.next/types/app/api/tables/[name]/route.ts +1 -1
  111. package/dist/.next/.next/types/app/api/tables/route.ts +1 -1
  112. package/dist/.next/.next/types/app/api/update/route.ts +1 -1
  113. package/dist/.next/.next/types/app/page.ts +1 -1
  114. package/dist/.next/BUILD_ID +1 -1
  115. package/dist/.next/app-build-manifest.json +28 -28
  116. package/dist/.next/app-path-routes-manifest.json +1 -1
  117. package/dist/.next/build-manifest.json +3 -3
  118. package/dist/.next/cache/.rscinfo +1 -1
  119. package/dist/.next/cache/.tsbuildinfo +1 -1
  120. package/dist/.next/cache/webpack/client-production/0.pack +0 -0
  121. package/dist/.next/cache/webpack/client-production/1.pack +0 -0
  122. package/dist/.next/cache/webpack/client-production/2.pack +0 -0
  123. package/dist/.next/cache/webpack/client-production/index.pack +0 -0
  124. package/dist/.next/cache/webpack/client-production/index.pack.old +0 -0
  125. package/dist/.next/cache/webpack/edge-server-production/index.pack +0 -0
  126. package/dist/.next/cache/webpack/server-production/0.pack +0 -0
  127. package/dist/.next/cache/webpack/server-production/index.pack +0 -0
  128. package/dist/.next/next-minimal-server.js.nft.json +1 -1
  129. package/dist/.next/next-server.js.nft.json +1 -1
  130. package/dist/.next/prerender-manifest.json +1 -1
  131. package/dist/.next/required-server-files.json +1 -1
  132. package/dist/.next/server/app/_not-found/page.js +1 -1
  133. package/dist/.next/server/app/_not-found/page.js.nft.json +1 -1
  134. package/dist/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  135. package/dist/.next/server/app/_not-found.html +1 -1
  136. package/dist/.next/server/app/_not-found.rsc +4 -4
  137. package/dist/.next/server/app/api/cloudflare/route.js +1 -1
  138. package/dist/.next/server/app/api/cloudflare/route_client-reference-manifest.js +1 -1
  139. package/dist/.next/server/app/api/databases/route.js +1 -1
  140. package/dist/.next/server/app/api/databases/route_client-reference-manifest.js +1 -1
  141. package/dist/.next/server/app/api/migrations/sync/route.js +5 -5
  142. package/dist/.next/server/app/api/migrations/sync/route_client-reference-manifest.js +1 -1
  143. package/dist/.next/server/app/api/migrations/sync-files/route.js +3 -3
  144. package/dist/.next/server/app/api/migrations/sync-files/route_client-reference-manifest.js +1 -1
  145. package/dist/.next/server/app/api/pull-data/confirm/route.js +1 -1
  146. package/dist/.next/server/app/api/pull-data/confirm/route_client-reference-manifest.js +1 -1
  147. package/dist/.next/server/app/api/pull-remote/confirm/route.js +2 -2
  148. package/dist/.next/server/app/api/pull-remote/confirm/route_client-reference-manifest.js +1 -1
  149. package/dist/.next/server/app/api/pull-remote/preview/route.js +4 -4
  150. package/dist/.next/server/app/api/pull-remote/preview/route_client-reference-manifest.js +1 -1
  151. package/dist/.next/server/app/api/push-remote/confirm/route.js +5 -5
  152. package/dist/.next/server/app/api/push-remote/confirm/route_client-reference-manifest.js +1 -1
  153. package/dist/.next/server/app/api/push-remote/preview/route.js +4 -4
  154. package/dist/.next/server/app/api/push-remote/preview/route_client-reference-manifest.js +1 -1
  155. package/dist/.next/server/app/api/query/route.js +3 -3
  156. package/dist/.next/server/app/api/query/route_client-reference-manifest.js +1 -1
  157. package/dist/.next/server/app/api/tables/[name]/route.js +5 -5
  158. package/dist/.next/server/app/api/tables/[name]/route_client-reference-manifest.js +1 -1
  159. package/dist/.next/server/app/api/tables/route.js +2 -2
  160. package/dist/.next/server/app/api/tables/route_client-reference-manifest.js +1 -1
  161. package/dist/.next/server/app/api/update/route.js +1 -1
  162. package/dist/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  163. package/dist/.next/server/app/index.html +2 -2
  164. package/dist/.next/server/app/index.rsc +5 -5
  165. package/dist/.next/server/app/page.js +7 -7
  166. package/dist/.next/server/app/page.js.nft.json +1 -1
  167. package/dist/.next/server/app/page_client-reference-manifest.js +1 -1
  168. package/dist/.next/server/app-paths-manifest.json +1 -1
  169. package/dist/.next/server/chunks/226.js +12 -12
  170. package/dist/.next/server/chunks/391.js +1 -1
  171. package/dist/.next/server/chunks/572.js +1 -0
  172. package/dist/.next/server/chunks/992.js +3 -3
  173. package/dist/.next/server/middleware-build-manifest.js +1 -1
  174. package/dist/.next/server/next-font-manifest.js +1 -1
  175. package/dist/.next/server/next-font-manifest.json +1 -1
  176. package/dist/.next/server/pages/404.html +1 -1
  177. package/dist/.next/server/pages/500.html +1 -1
  178. package/dist/.next/server/server-reference-manifest.json +1 -1
  179. package/dist/.next/static/IX-QLbm7scYnyqWeeimal/_buildManifest.js +1 -0
  180. package/dist/.next/static/IX-QLbm7scYnyqWeeimal/_ssgManifest.js +1 -0
  181. package/dist/.next/static/chunks/{576-c4daf274bb6469a1.js → 576-18a2209e1ed26aad.js} +1 -1
  182. package/dist/.next/static/chunks/{92-c4466e0f1ca8a3a8.js → 92-5f7522943fcb72a8.js} +1 -1
  183. package/dist/.next/static/chunks/app/{layout-be6ee67cf0c92654.js → layout-40ec07d04681ba81.js} +1 -1
  184. package/dist/.next/static/chunks/app/page-f05cd0fc436bf9bc.js +1 -0
  185. package/dist/.next/static/chunks/{main-app-fa35024de9bd9284.js → main-app-4506e88db72db4b7.js} +1 -1
  186. package/dist/.next/static/css/{9f6c25c5400f83d3.css → 7c16f57d325d0d7d.css} +1 -1
  187. package/dist/.next/static/media/8d697b304b401681-s.woff2 +0 -0
  188. package/dist/.next/static/media/9610d9e46709d722-s.woff2 +0 -0
  189. package/dist/.next/trace +3 -14
  190. package/dist/.next/types/app/api/cloudflare/route.ts +1 -1
  191. package/dist/.next/types/app/api/databases/route.ts +1 -1
  192. package/dist/.next/types/app/api/migrations/sync/route.ts +1 -1
  193. package/dist/.next/types/app/api/migrations/sync-files/route.ts +1 -1
  194. package/dist/.next/types/app/api/pull-data/confirm/route.ts +1 -1
  195. package/dist/.next/types/app/api/pull-remote/confirm/route.ts +1 -1
  196. package/dist/.next/types/app/api/pull-remote/preview/route.ts +1 -1
  197. package/dist/.next/types/app/api/push-remote/confirm/route.ts +1 -1
  198. package/dist/.next/types/app/api/push-remote/preview/route.ts +1 -1
  199. package/dist/.next/types/app/api/query/route.ts +1 -1
  200. package/dist/.next/types/app/api/tables/[name]/route.ts +1 -1
  201. package/dist/.next/types/app/api/tables/route.ts +1 -1
  202. package/dist/.next/types/app/api/update/route.ts +1 -1
  203. package/dist/.next/types/app/page.ts +1 -1
  204. package/dist/app/api/tables/[name]/route.js +22 -10
  205. package/dist/app/globals.css +39 -0
  206. package/dist/d1-studio.js +2 -2
  207. package/dist/lib/data-type-handlers.js +426 -0
  208. package/dist/lib/sql-operations.js +32 -8
  209. package/dist/lib/sql-sanitizer.js +233 -0
  210. package/package.json +3 -9
  211. package/dist/.next/.next/server/chunks/90.js +0 -1
  212. package/dist/.next/.next/static/chunks/app/page-36ed30b2266617f3.js +0 -1
  213. package/dist/.next/server/chunks/90.js +0 -1
  214. package/dist/.next/static/chunks/app/page-36ed30b2266617f3.js +0 -1
  215. package/dist/app/app/api/cloudflare/route.js +0 -150
  216. package/dist/app/app/api/databases/route.js +0 -71
  217. package/dist/app/app/api/migrations/sync/route.js +0 -174
  218. package/dist/app/app/api/migrations/sync-files/route.js +0 -172
  219. package/dist/app/app/api/pull-data/confirm/route.js +0 -230
  220. package/dist/app/app/api/pull-remote/confirm/route.js +0 -278
  221. package/dist/app/app/api/pull-remote/preview/route.js +0 -144
  222. package/dist/app/app/api/push-remote/confirm/route.js +0 -196
  223. package/dist/app/app/api/push-remote/preview/route.js +0 -179
  224. package/dist/app/app/api/query/route.js +0 -168
  225. package/dist/app/app/api/tables/[name]/route.js +0 -174
  226. package/dist/app/app/api/tables/route.js +0 -178
  227. package/dist/app/app/api/update/route.js +0 -45
  228. package/dist/app/app/globals.css +0 -93
  229. package/dist/app/app/layout.jsx +0 -35
  230. package/dist/app/app/page.jsx +0 -34
  231. package/next.config.mjs +0 -18
  232. package/postcss.config.mjs +0 -8
  233. package/scripts/studio.js +0 -199
  234. package/scripts/test.js +0 -366
  235. package/src/app/api/cloudflare/route.js +0 -150
  236. package/src/app/api/databases/route.js +0 -71
  237. package/src/app/api/migrations/sync/route.js +0 -174
  238. package/src/app/api/migrations/sync-files/route.js +0 -172
  239. package/src/app/api/pull-data/confirm/route.js +0 -230
  240. package/src/app/api/pull-remote/confirm/route.js +0 -278
  241. package/src/app/api/pull-remote/preview/route.js +0 -144
  242. package/src/app/api/push-remote/confirm/route.js +0 -196
  243. package/src/app/api/push-remote/preview/route.js +0 -179
  244. package/src/app/api/query/route.js +0 -168
  245. package/src/app/api/tables/[name]/route.js +0 -174
  246. package/src/app/api/tables/route.js +0 -178
  247. package/src/app/api/update/route.js +0 -45
  248. package/src/app/globals.css +0 -93
  249. package/src/app/layout.jsx +0 -35
  250. package/src/app/page.jsx +0 -34
  251. package/src/components/cloudflare-credentials-modal.jsx +0 -94
  252. package/src/components/column-selector.jsx +0 -133
  253. package/src/components/column-sorting.jsx +0 -65
  254. package/src/components/delete-records-dialog.jsx +0 -64
  255. package/src/components/download-button.jsx +0 -205
  256. package/src/components/edit-error-alert.jsx +0 -30
  257. package/src/components/editable-cell.jsx +0 -163
  258. package/src/components/editable-row.jsx +0 -169
  259. package/src/components/environment-handler.jsx +0 -332
  260. package/src/components/environment-select.jsx +0 -62
  261. package/src/components/pull-preview-toast.jsx +0 -215
  262. package/src/components/push-error-alert.jsx +0 -72
  263. package/src/components/push-preview-toast.jsx +0 -183
  264. package/src/components/query-results.jsx +0 -112
  265. package/src/components/refresh-button.jsx +0 -61
  266. package/src/components/resize-columns.jsx +0 -101
  267. package/src/components/sidebar.jsx +0 -254
  268. package/src/components/sql-editor.jsx +0 -411
  269. package/src/components/sql-error-display.jsx +0 -167
  270. package/src/components/sync-migrations-button.jsx +0 -87
  271. package/src/components/table-error-dialog.jsx +0 -65
  272. package/src/components/table-toolbar.jsx +0 -285
  273. package/src/components/table-view.jsx +0 -843
  274. package/src/components/ui/alert.jsx +0 -47
  275. package/src/components/ui/button.jsx +0 -48
  276. package/src/components/ui/card.jsx +0 -50
  277. package/src/components/ui/checkbox.jsx +0 -24
  278. package/src/components/ui/collapsible.jsx +0 -11
  279. package/src/components/ui/dialog.jsx +0 -96
  280. package/src/components/ui/dropdown-menu.jsx +0 -158
  281. package/src/components/ui/input.jsx +0 -19
  282. package/src/components/ui/scroll-area.jsx +0 -40
  283. package/src/components/ui/select.jsx +0 -121
  284. package/src/components/ui/separator.jsx +0 -25
  285. package/src/components/ui/sheet.jsx +0 -109
  286. package/src/components/ui/sidebar.jsx +0 -620
  287. package/src/components/ui/skeleton.jsx +0 -14
  288. package/src/components/ui/table.jsx +0 -86
  289. package/src/components/ui/tabs.jsx +0 -43
  290. package/src/components/ui/toast.jsx +0 -86
  291. package/src/components/ui/toaster.jsx +0 -35
  292. package/src/components/ui/tooltip.jsx +0 -28
  293. package/src/components/update-banner.jsx +0 -93
  294. package/src/context/database-context.js +0 -510
  295. package/src/hooks/use-mobile.jsx +0 -19
  296. package/src/hooks/use-sql-error.ts +0 -23
  297. package/src/hooks/use-toast.js +0 -155
  298. package/src/lib/database-queue.js +0 -37
  299. package/src/lib/error.js +0 -20
  300. package/src/lib/find-wrangler-config.js +0 -74
  301. package/src/lib/license.js +0 -99
  302. package/src/lib/logger.js +0 -58
  303. package/src/lib/migrations.js +0 -415
  304. package/src/lib/parse-sql-error.js +0 -200
  305. package/src/lib/request-deduplication.js +0 -24
  306. package/src/lib/schema-operations.js +0 -106
  307. package/src/lib/sql-error-types.js +0 -14
  308. package/src/lib/sql-operations.js +0 -647
  309. package/src/lib/utils.js +0 -6
  310. package/src/lib/version-utils.js +0 -34
  311. /package/dist/.next/.next/static/{OUHnbB-64afrrZQL0Srn5 → FEsQ9jwPUQv5A3fwg6Opl}/_buildManifest.js +0 -0
  312. /package/dist/.next/.next/static/{OUHnbB-64afrrZQL0Srn5 → FEsQ9jwPUQv5A3fwg6Opl}/_ssgManifest.js +0 -0
  313. /package/dist/.next/.next/static/{ZBTCAyp1kO5FdEHMU-Dw2 → Y9mYu4WBghepP5oT_3OdR}/_buildManifest.js +0 -0
  314. /package/dist/.next/.next/static/{ZBTCAyp1kO5FdEHMU-Dw2 → Y9mYu4WBghepP5oT_3OdR}/_ssgManifest.js +0 -0
  315. /package/dist/.next/.next/static/{bHYW7fgIBDF8-Q33_WPoE → ae3gNmoSGm-R5LJC4UagI}/_buildManifest.js +0 -0
  316. /package/dist/.next/.next/static/{bHYW7fgIBDF8-Q33_WPoE → ae3gNmoSGm-R5LJC4UagI}/_ssgManifest.js +0 -0
  317. /package/dist/.next/{static/ZBTCAyp1kO5FdEHMU-Dw2 → .next/static/bKfUJeuvAQlBmR3TjrfkH}/_buildManifest.js +0 -0
  318. /package/dist/.next/{static/ZBTCAyp1kO5FdEHMU-Dw2 → .next/static/bKfUJeuvAQlBmR3TjrfkH}/_ssgManifest.js +0 -0
@@ -1,4 +1,4 @@
1
- // File: /Users/kona/Desktop/d1studio/src/app/api/cloudflare/route.js
1
+ // File: /Volumes/ProjectSpace/_wip/d1studio/src/app/api/cloudflare/route.js
2
2
  import * as entry from '../../../../../src/app/api/cloudflare/route.js'
3
3
  import type { NextRequest } from 'next/server.js'
4
4
 
@@ -1,4 +1,4 @@
1
- // File: /Users/kona/Desktop/d1studio/src/app/api/databases/route.js
1
+ // File: /Volumes/ProjectSpace/_wip/d1studio/src/app/api/databases/route.js
2
2
  import * as entry from '../../../../../src/app/api/databases/route.js'
3
3
  import type { NextRequest } from 'next/server.js'
4
4
 
@@ -1,4 +1,4 @@
1
- // File: /Users/kona/Desktop/d1studio/src/app/api/migrations/sync/route.js
1
+ // File: /Volumes/ProjectSpace/_wip/d1studio/src/app/api/migrations/sync/route.js
2
2
  import * as entry from '../../../../../../src/app/api/migrations/sync/route.js'
3
3
  import type { NextRequest } from 'next/server.js'
4
4
 
@@ -1,4 +1,4 @@
1
- // File: /Users/kona/Desktop/d1studio/src/app/api/migrations/sync-files/route.js
1
+ // File: /Volumes/ProjectSpace/_wip/d1studio/src/app/api/migrations/sync-files/route.js
2
2
  import * as entry from '../../../../../../src/app/api/migrations/sync-files/route.js'
3
3
  import type { NextRequest } from 'next/server.js'
4
4
 
@@ -1,4 +1,4 @@
1
- // File: /Users/kona/Desktop/d1studio/src/app/api/pull-data/confirm/route.js
1
+ // File: /Volumes/ProjectSpace/_wip/d1studio/src/app/api/pull-data/confirm/route.js
2
2
  import * as entry from '../../../../../../src/app/api/pull-data/confirm/route.js'
3
3
  import type { NextRequest } from 'next/server.js'
4
4
 
@@ -1,4 +1,4 @@
1
- // File: /Users/kona/Desktop/d1studio/src/app/api/pull-remote/confirm/route.js
1
+ // File: /Volumes/ProjectSpace/_wip/d1studio/src/app/api/pull-remote/confirm/route.js
2
2
  import * as entry from '../../../../../../src/app/api/pull-remote/confirm/route.js'
3
3
  import type { NextRequest } from 'next/server.js'
4
4
 
@@ -1,4 +1,4 @@
1
- // File: /Users/kona/Desktop/d1studio/src/app/api/pull-remote/preview/route.js
1
+ // File: /Volumes/ProjectSpace/_wip/d1studio/src/app/api/pull-remote/preview/route.js
2
2
  import * as entry from '../../../../../../src/app/api/pull-remote/preview/route.js'
3
3
  import type { NextRequest } from 'next/server.js'
4
4
 
@@ -1,4 +1,4 @@
1
- // File: /Users/kona/Desktop/d1studio/src/app/api/push-remote/confirm/route.js
1
+ // File: /Volumes/ProjectSpace/_wip/d1studio/src/app/api/push-remote/confirm/route.js
2
2
  import * as entry from '../../../../../../src/app/api/push-remote/confirm/route.js'
3
3
  import type { NextRequest } from 'next/server.js'
4
4
 
@@ -1,4 +1,4 @@
1
- // File: /Users/kona/Desktop/d1studio/src/app/api/push-remote/preview/route.js
1
+ // File: /Volumes/ProjectSpace/_wip/d1studio/src/app/api/push-remote/preview/route.js
2
2
  import * as entry from '../../../../../../src/app/api/push-remote/preview/route.js'
3
3
  import type { NextRequest } from 'next/server.js'
4
4
 
@@ -1,4 +1,4 @@
1
- // File: /Users/kona/Desktop/d1studio/src/app/api/query/route.js
1
+ // File: /Volumes/ProjectSpace/_wip/d1studio/src/app/api/query/route.js
2
2
  import * as entry from '../../../../../src/app/api/query/route.js'
3
3
  import type { NextRequest } from 'next/server.js'
4
4
 
@@ -1,4 +1,4 @@
1
- // File: /Users/kona/Desktop/d1studio/src/app/api/tables/[name]/route.js
1
+ // File: /Volumes/ProjectSpace/_wip/d1studio/src/app/api/tables/[name]/route.js
2
2
  import * as entry from '../../../../../../src/app/api/tables/[name]/route.js'
3
3
  import type { NextRequest } from 'next/server.js'
4
4
 
@@ -1,4 +1,4 @@
1
- // File: /Users/kona/Desktop/d1studio/src/app/api/tables/route.js
1
+ // File: /Volumes/ProjectSpace/_wip/d1studio/src/app/api/tables/route.js
2
2
  import * as entry from '../../../../../src/app/api/tables/route.js'
3
3
  import type { NextRequest } from 'next/server.js'
4
4
 
@@ -1,4 +1,4 @@
1
- // File: /Users/kona/Desktop/d1studio/src/app/api/update/route.js
1
+ // File: /Volumes/ProjectSpace/_wip/d1studio/src/app/api/update/route.js
2
2
  import * as entry from '../../../../../src/app/api/update/route.js'
3
3
  import type { NextRequest } from 'next/server.js'
4
4
 
@@ -1,4 +1,4 @@
1
- // File: /Users/kona/Desktop/d1studio/src/app/page.jsx
1
+ // File: /Volumes/ProjectSpace/_wip/d1studio/src/app/page.jsx
2
2
  import * as entry from '../../../src/app/page.js'
3
3
  import type { ResolvingMetadata, ResolvingViewport } from 'next/dist/lib/metadata/types/metadata-interface.js'
4
4
 
@@ -6,6 +6,7 @@ import { exec } from 'child_process';
6
6
  import { findWranglerConfig } from '@/lib/find-wrangler-config.js';
7
7
  import { dbQueue } from '@/lib/database-queue';
8
8
  import logger from '@/lib/logger';
9
+ import { sanitizeTableName, sanitizeColumnName } from '@/lib/sql-sanitizer.js';
9
10
 
10
11
  const execAsync = promisify(exec);
11
12
 
@@ -98,13 +99,18 @@ export async function GET(request, context) {
98
99
  // Get the first D1 database name from the configuration
99
100
  const databaseName = config.d1_databases[0].database_name;
100
101
 
101
- // Get table schema using PRAGMA query
102
- const schemaQuery = `PRAGMA table_info(${name});`;
102
+ // Validate and sanitize table name to prevent SQL injection
103
+ const sanitizedTableName = sanitizeTableName(name);
104
+
105
+ // Get table schema using PRAGMA query (PRAGMA is safe from injection when table name is sanitized)
106
+ const schemaQuery = `PRAGMA table_info(${sanitizedTableName});`;
103
107
  const schema = await executeD1Query(schemaQuery, projectDir, databaseName);
104
108
 
105
- // Get the CREATE TABLE statement from sqlite_master
106
- const createTableQuery = `SELECT sql FROM sqlite_master WHERE type='table' AND name='${name}';`;
107
- const tableDefinition = await executeD1Query(createTableQuery, projectDir, databaseName);
109
+ // Get the CREATE TABLE statement from sqlite_master using parameterized query approach
110
+ const createTableQuery = `SELECT sql FROM sqlite_master WHERE type='table' AND name = ?;`;
111
+ // Note: executeD1Query would need to support parameters, for now we sanitize the table name
112
+ const createTableQuerySafe = `SELECT sql FROM sqlite_master WHERE type='table' AND name='${name.replace(/'/g, "''")}';`;
113
+ const tableDefinition = await executeD1Query(createTableQuerySafe, projectDir, databaseName);
108
114
  const createTableSQL = tableDefinition[0]?.sql || '';
109
115
 
110
116
  // Extract CHECK constraints from the CREATE TABLE statement
@@ -116,17 +122,23 @@ export async function GET(request, context) {
116
122
  check: checkConstraints[column.name] || null
117
123
  }));
118
124
 
119
- // Get total row count for the table
120
- const countQuery = `SELECT COUNT(*) as total FROM ${name};`;
125
+ // Get total row count for the table (using sanitized table name)
126
+ const countQuery = `SELECT COUNT(*) as total FROM ${sanitizedTableName};`;
121
127
  const countResult = await executeD1Query(countQuery, projectDir, databaseName);
122
128
  const totalRows = countResult[0]?.total || 0;
123
129
 
124
130
  // Fetch paginated data using the primary key column for ordering
125
131
  const primaryKeyColumn = schema.find(col => col.pk === 1)?.name || schema[0]?.name;
132
+ const sanitizedPrimaryKey = primaryKeyColumn ? sanitizeColumnName(primaryKeyColumn) : '*';
133
+
134
+ // Validate limit and offset to prevent injection through URL params
135
+ const safeLimitNum = Math.max(1, Math.min(parseInt(limit) || 50, 1000)); // Cap at 1000 rows
136
+ const safeOffsetNum = Math.max(0, parseInt(offset) || 0);
137
+
126
138
  const dataQuery = `
127
- SELECT * FROM ${name}
128
- ORDER BY ${primaryKeyColumn} DESC
129
- LIMIT ${limit} OFFSET ${offset};
139
+ SELECT * FROM ${sanitizedTableName}
140
+ ORDER BY ${sanitizedPrimaryKey} DESC
141
+ LIMIT ${safeLimitNum} OFFSET ${safeOffsetNum};
130
142
  `;
131
143
  const data = await executeD1Query(dataQuery, projectDir, databaseName);
132
144
 
@@ -91,3 +91,42 @@ body {
91
91
  table-layout: fixed;
92
92
  width: 100%;
93
93
  }
94
+
95
+ /* Custom gray utility classes */
96
+ @layer utilities {
97
+ .bg-gray-custom-50 { background-color: var(--gray-50); }
98
+ .bg-gray-custom-100 { background-color: var(--gray-100); }
99
+ .bg-gray-custom-200 { background-color: var(--gray-200); }
100
+ .bg-gray-custom-300 { background-color: var(--gray-300); }
101
+ .bg-gray-custom-400 { background-color: var(--gray-400); }
102
+ .bg-gray-custom-500 { background-color: var(--gray-500); }
103
+ .bg-gray-custom-600 { background-color: var(--gray-600); }
104
+ .bg-gray-custom-700 { background-color: var(--gray-700); }
105
+ .bg-gray-custom-800 { background-color: var(--gray-800); }
106
+ .bg-gray-custom-900 { background-color: var(--gray-900); }
107
+ .bg-gray-custom-950 { background-color: var(--gray-950); }
108
+
109
+ .text-gray-custom-50 { color: var(--gray-50); }
110
+ .text-gray-custom-100 { color: var(--gray-100); }
111
+ .text-gray-custom-200 { color: var(--gray-200); }
112
+ .text-gray-custom-300 { color: var(--gray-300); }
113
+ .text-gray-custom-400 { color: var(--gray-400); }
114
+ .text-gray-custom-500 { color: var(--gray-500); }
115
+ .text-gray-custom-600 { color: var(--gray-600); }
116
+ .text-gray-custom-700 { color: var(--gray-700); }
117
+ .text-gray-custom-800 { color: var(--gray-800); }
118
+ .text-gray-custom-900 { color: var(--gray-900); }
119
+ .text-gray-custom-950 { color: var(--gray-950); }
120
+
121
+ .border-gray-custom-50 { border-color: var(--gray-50); }
122
+ .border-gray-custom-100 { border-color: var(--gray-100); }
123
+ .border-gray-custom-200 { border-color: var(--gray-200); }
124
+ .border-gray-custom-300 { border-color: var(--gray-300); }
125
+ .border-gray-custom-400 { border-color: var(--gray-400); }
126
+ .border-gray-custom-500 { border-color: var(--gray-500); }
127
+ .border-gray-custom-600 { border-color: var(--gray-600); }
128
+ .border-gray-custom-700 { border-color: var(--gray-700); }
129
+ .border-gray-custom-800 { border-color: var(--gray-800); }
130
+ .border-gray-custom-900 { border-color: var(--gray-900); }
131
+ .border-gray-custom-950 { border-color: var(--gray-950); }
132
+ }
package/dist/d1-studio.js CHANGED
@@ -6,8 +6,8 @@ import { dirname, join } from 'path';
6
6
  import express from 'express';
7
7
  import { createServer } from 'http';
8
8
  import next from 'next';
9
- import { findWranglerConfig } from '../src/lib/find-wrangler-config.js';
10
- import logger from '../src/lib/logger.js';
9
+ import { findWranglerConfig } from './lib/find-wrangler-config.js';
10
+ import logger from './lib/logger.js';
11
11
  import updateNotifier from 'update-notifier';
12
12
  import pkg from '../package.json' with { type: 'json' };
13
13
 
@@ -0,0 +1,426 @@
1
+ /**
2
+ * Data Type Handlers for Enhanced Database Operations
3
+ * Provides validation, formatting, and display logic for various data types
4
+ */
5
+
6
+ /**
7
+ * UUID validation regex - supports all UUID versions (1-5)
8
+ */
9
+ const UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
10
+
11
+ /**
12
+ * Data type handlers with validation, formatting, and display logic
13
+ */
14
+ export const DataTypeHandlers = {
15
+ uuid: {
16
+ validate: (value) => {
17
+ if (!value || typeof value !== 'string') return false;
18
+ return UUID_REGEX.test(value);
19
+ },
20
+ format: (value) => {
21
+ if (!value) return null;
22
+ return value.toLowerCase().trim();
23
+ },
24
+ display: (value) => {
25
+ if (!value) return '';
26
+ if (value.length <= 16) return value;
27
+ return value.substring(0, 8) + '...' + value.substring(value.length - 8);
28
+ },
29
+ editComponent: 'input',
30
+ editProps: {
31
+ type: 'text',
32
+ placeholder: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
33
+ pattern: UUID_REGEX.source,
34
+ title: 'Enter a valid UUID (e.g., 123e4567-e89b-12d3-a456-426614174000)'
35
+ }
36
+ },
37
+
38
+ text: {
39
+ validate: (value) => {
40
+ return typeof value === 'string' || value === null || value === undefined;
41
+ },
42
+ format: (value) => {
43
+ if (value === null || value === undefined) return null;
44
+ return String(value);
45
+ },
46
+ display: (value) => {
47
+ if (!value) return '';
48
+ if (value.length <= 50) return value;
49
+ return value.substring(0, 50) + '...';
50
+ },
51
+ editComponent: 'input',
52
+ editProps: { type: 'text' }
53
+ },
54
+
55
+ longText: {
56
+ validate: (value) => {
57
+ return typeof value === 'string' || value === null || value === undefined;
58
+ },
59
+ format: (value) => {
60
+ if (value === null || value === undefined) return null;
61
+ return String(value);
62
+ },
63
+ display: (value) => {
64
+ if (!value) return '';
65
+ if (value.length <= 100) return value;
66
+ return value.substring(0, 100) + '...';
67
+ },
68
+ editComponent: 'textarea',
69
+ editProps: {
70
+ rows: 4,
71
+ placeholder: 'Enter long text content...'
72
+ }
73
+ },
74
+
75
+ json: {
76
+ validate: (value) => {
77
+ if (value === null || value === undefined) return true;
78
+ if (typeof value === 'string') {
79
+ try {
80
+ JSON.parse(value);
81
+ return true;
82
+ } catch {
83
+ return false;
84
+ }
85
+ }
86
+ return typeof value === 'object';
87
+ },
88
+ format: (value) => {
89
+ if (value === null || value === undefined) return null;
90
+ if (typeof value === 'string') {
91
+ try {
92
+ // Validate JSON by parsing, then return original string
93
+ JSON.parse(value);
94
+ return value;
95
+ } catch {
96
+ throw new Error('Invalid JSON format');
97
+ }
98
+ }
99
+ return JSON.stringify(value);
100
+ },
101
+ display: (value) => {
102
+ if (!value) return '';
103
+ const formatted = typeof value === 'string' ? value : JSON.stringify(value);
104
+ if (formatted.length <= 50) return formatted;
105
+ return formatted.substring(0, 50) + '...';
106
+ },
107
+ editComponent: 'textarea',
108
+ editProps: {
109
+ rows: 6,
110
+ placeholder: 'Enter valid JSON...',
111
+ className: 'font-mono'
112
+ }
113
+ },
114
+
115
+ integer: {
116
+ validate: (value) => {
117
+ if (value === null || value === undefined) return true;
118
+ return Number.isInteger(Number(value));
119
+ },
120
+ format: (value) => {
121
+ if (value === null || value === undefined) return null;
122
+ const num = Number(value);
123
+ if (!Number.isInteger(num)) {
124
+ throw new Error('Value must be an integer');
125
+ }
126
+ return num;
127
+ },
128
+ display: (value) => {
129
+ if (value === null || value === undefined) return '';
130
+ return String(value);
131
+ },
132
+ editComponent: 'input',
133
+ editProps: {
134
+ type: 'number',
135
+ step: '1',
136
+ pattern: '[0-9-]+'
137
+ }
138
+ },
139
+
140
+ real: {
141
+ validate: (value) => {
142
+ if (value === null || value === undefined) return true;
143
+ return !isNaN(Number(value)) && isFinite(Number(value));
144
+ },
145
+ format: (value) => {
146
+ if (value === null || value === undefined) return null;
147
+ const num = Number(value);
148
+ if (isNaN(num) || !isFinite(num)) {
149
+ throw new Error('Value must be a valid number');
150
+ }
151
+ return num;
152
+ },
153
+ display: (value) => {
154
+ if (value === null || value === undefined) return '';
155
+ return String(value);
156
+ },
157
+ editComponent: 'input',
158
+ editProps: {
159
+ type: 'number',
160
+ step: 'any'
161
+ }
162
+ },
163
+
164
+ boolean: {
165
+ validate: (value) => {
166
+ if (value === null || value === undefined) return true;
167
+ return typeof value === 'boolean' || value === 'true' || value === 'false' || value === 1 || value === 0;
168
+ },
169
+ format: (value) => {
170
+ if (value === null || value === undefined) return null;
171
+ if (typeof value === 'boolean') return value;
172
+ if (value === 'true' || value === 1) return true;
173
+ if (value === 'false' || value === 0) return false;
174
+ throw new Error('Value must be a boolean');
175
+ },
176
+ display: (value) => {
177
+ if (value === null || value === undefined) return '';
178
+ return value ? 'true' : 'false';
179
+ },
180
+ editComponent: 'select',
181
+ editProps: {
182
+ options: [
183
+ { value: '', label: 'NULL' },
184
+ { value: 'true', label: 'True' },
185
+ { value: 'false', label: 'False' }
186
+ ]
187
+ }
188
+ },
189
+
190
+ date: {
191
+ validate: (value) => {
192
+ if (value === null || value === undefined) return true;
193
+ return !isNaN(Date.parse(value));
194
+ },
195
+ format: (value) => {
196
+ if (value === null || value === undefined) return null;
197
+ const date = new Date(value);
198
+ if (isNaN(date.getTime())) {
199
+ throw new Error('Value must be a valid date');
200
+ }
201
+ return date.toISOString().split('T')[0];
202
+ },
203
+ display: (value) => {
204
+ if (!value) return '';
205
+ return value;
206
+ },
207
+ editComponent: 'input',
208
+ editProps: { type: 'date' }
209
+ },
210
+
211
+ datetime: {
212
+ validate: (value) => {
213
+ if (value === null || value === undefined) return true;
214
+ return !isNaN(Date.parse(value));
215
+ },
216
+ format: (value) => {
217
+ if (value === null || value === undefined) return null;
218
+ const date = new Date(value);
219
+ if (isNaN(date.getTime())) {
220
+ throw new Error('Value must be a valid datetime');
221
+ }
222
+ return date.toISOString();
223
+ },
224
+ display: (value) => {
225
+ if (!value) return '';
226
+ return new Date(value).toLocaleString();
227
+ },
228
+ editComponent: 'input',
229
+ editProps: { type: 'datetime-local' }
230
+ },
231
+
232
+ blob: {
233
+ validate: (value) => {
234
+ // For blob data, we typically handle as base64 strings or Buffer objects
235
+ if (value === null || value === undefined) return true;
236
+ return typeof value === 'string' || Buffer.isBuffer(value);
237
+ },
238
+ format: (value) => {
239
+ if (value === null || value === undefined) return null;
240
+ return value; // Keep as-is for blob data
241
+ },
242
+ display: (value) => {
243
+ if (!value) return '';
244
+ if (typeof value === 'string') {
245
+ return `<BLOB: ${value.length} chars>`;
246
+ }
247
+ if (Buffer.isBuffer(value)) {
248
+ return `<BLOB: ${value.length} bytes>`;
249
+ }
250
+ return '<BLOB>';
251
+ },
252
+ editComponent: 'input',
253
+ editProps: {
254
+ type: 'file',
255
+ accept: '*/*'
256
+ }
257
+ }
258
+ };
259
+
260
+ /**
261
+ * Detects the data type of a value based on its content
262
+ * @param {any} value - The value to analyze
263
+ * @returns {string} - The detected data type
264
+ */
265
+ export function detectDataType(value) {
266
+ if (value === null || value === undefined) return 'text';
267
+
268
+ if (typeof value === 'string') {
269
+ // Check for UUID pattern
270
+ if (UUID_REGEX.test(value)) return 'uuid';
271
+
272
+ // Check for JSON
273
+ try {
274
+ JSON.parse(value);
275
+ return 'json';
276
+ } catch {
277
+ // Not JSON, continue checking
278
+ }
279
+
280
+ // Check for date/datetime
281
+ if (!isNaN(Date.parse(value))) {
282
+ // Simple heuristic: if it looks like a full datetime, classify as datetime
283
+ if (value.includes('T') || value.includes(' ')) return 'datetime';
284
+ return 'date';
285
+ }
286
+
287
+ // Check for boolean
288
+ if (value === 'true' || value === 'false') return 'boolean';
289
+
290
+ // Check for number
291
+ if (!isNaN(Number(value)) && isFinite(Number(value))) {
292
+ return Number.isInteger(Number(value)) ? 'integer' : 'real';
293
+ }
294
+
295
+ // Long text heuristic
296
+ if (value.length > 255) return 'longText';
297
+
298
+ return 'text';
299
+ }
300
+
301
+ if (typeof value === 'number') {
302
+ return Number.isInteger(value) ? 'integer' : 'real';
303
+ }
304
+
305
+ if (typeof value === 'boolean') return 'boolean';
306
+
307
+ if (typeof value === 'object') return 'json';
308
+
309
+ if (Buffer.isBuffer(value)) return 'blob';
310
+
311
+ return 'text';
312
+ }
313
+
314
+ /**
315
+ * Gets the appropriate data type handler for a value
316
+ * @param {any} value - The value to get a handler for
317
+ * @returns {Object} - The data type handler
318
+ */
319
+ export function getDataTypeHandler(value) {
320
+ const type = detectDataType(value);
321
+ return DataTypeHandlers[type] || DataTypeHandlers.text;
322
+ }
323
+
324
+ /**
325
+ * Validates a value against its detected or specified data type
326
+ * @param {any} value - The value to validate
327
+ * @param {string} dataType - Optional explicit data type
328
+ * @returns {boolean} - True if valid
329
+ */
330
+ export function validateValue(value, dataType = null) {
331
+ const type = dataType || detectDataType(value);
332
+ const handler = DataTypeHandlers[type];
333
+
334
+ if (!handler) {
335
+ throw new Error(`Unknown data type: ${type}`);
336
+ }
337
+
338
+ return handler.validate(value);
339
+ }
340
+
341
+ /**
342
+ * Formats a value according to its data type
343
+ * @param {any} value - The value to format
344
+ * @param {string} dataType - Optional explicit data type
345
+ * @returns {any} - The formatted value
346
+ */
347
+ export function formatValue(value, dataType = null) {
348
+ const type = dataType || detectDataType(value);
349
+ const handler = DataTypeHandlers[type];
350
+
351
+ if (!handler) {
352
+ throw new Error(`Unknown data type: ${type}`);
353
+ }
354
+
355
+ return handler.format(value);
356
+ }
357
+
358
+ /**
359
+ * Gets display representation of a value
360
+ * @param {any} value - The value to display
361
+ * @param {string} dataType - Optional explicit data type
362
+ * @returns {string} - The display string
363
+ */
364
+ export function getDisplayValue(value, dataType = null) {
365
+ const type = dataType || detectDataType(value);
366
+ const handler = DataTypeHandlers[type];
367
+
368
+ if (!handler) {
369
+ return String(value || '');
370
+ }
371
+
372
+ return handler.display(value);
373
+ }
374
+
375
+ /**
376
+ * Enhanced WHERE clause builder with UUID support
377
+ * @param {Object} conditions - Conditions object
378
+ * @param {Object} options - Options for comparison operators
379
+ * @returns {Object} - WHERE clause and parameters
380
+ */
381
+ export function buildEnhancedWhereClause(conditions, options = {}) {
382
+ if (!conditions || typeof conditions !== 'object') {
383
+ throw new Error('Conditions must be an object');
384
+ }
385
+
386
+ const entries = Object.entries(conditions);
387
+ if (entries.length === 0) {
388
+ return { whereClause: '', params: [] };
389
+ }
390
+
391
+ const clauses = [];
392
+ const params = [];
393
+
394
+ for (const [column, value] of entries) {
395
+ const operator = options.operators?.[column] || '=';
396
+ const dataType = options.dataTypes?.[column] || detectDataType(value);
397
+
398
+ // Handle different operators
399
+ if (operator === 'LIKE') {
400
+ clauses.push(`${column} LIKE ?`);
401
+ params.push(`%${value}%`);
402
+ } else if (operator === 'IN') {
403
+ if (!Array.isArray(value)) {
404
+ throw new Error(`IN operator requires an array value for column ${column}`);
405
+ }
406
+ const placeholders = value.map(() => '?').join(', ');
407
+ clauses.push(`${column} IN (${placeholders})`);
408
+ params.push(...value);
409
+ } else if (operator === 'BETWEEN') {
410
+ if (!Array.isArray(value) || value.length !== 2) {
411
+ throw new Error(`BETWEEN operator requires an array of 2 values for column ${column}`);
412
+ }
413
+ clauses.push(`${column} BETWEEN ? AND ?`);
414
+ params.push(value[0], value[1]);
415
+ } else {
416
+ // Standard operators: =, !=, <, >, <=, >=
417
+ clauses.push(`${column} ${operator} ?`);
418
+ params.push(formatValue(value, dataType));
419
+ }
420
+ }
421
+
422
+ return {
423
+ whereClause: clauses.join(' AND '),
424
+ params: params
425
+ };
426
+ }