d1s 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (408) hide show
  1. package/README.md +7 -0
  2. package/dist/.next/.next/BUILD_ID +1 -0
  3. package/dist/.next/.next/app-build-manifest.json +109 -0
  4. package/dist/.next/.next/app-path-routes-manifest.json +1 -0
  5. package/dist/.next/.next/build-manifest.json +33 -0
  6. package/dist/.next/.next/cache/.rscinfo +1 -0
  7. package/dist/.next/.next/cache/.tsbuildinfo +1 -0
  8. package/dist/.next/.next/cache/webpack/client-production/0.pack +0 -0
  9. package/dist/.next/.next/cache/webpack/client-production/1.pack +0 -0
  10. package/dist/.next/.next/cache/webpack/client-production/2.pack +0 -0
  11. package/dist/.next/.next/cache/webpack/client-production/index.pack +0 -0
  12. package/dist/.next/.next/cache/webpack/client-production/index.pack.old +0 -0
  13. package/dist/.next/.next/cache/webpack/edge-server-production/0.pack +0 -0
  14. package/dist/.next/.next/cache/webpack/edge-server-production/index.pack +0 -0
  15. package/dist/.next/.next/cache/webpack/server-production/0.pack +0 -0
  16. package/dist/.next/.next/cache/webpack/server-production/1.pack +0 -0
  17. package/dist/.next/.next/cache/webpack/server-production/index.pack +0 -0
  18. package/dist/.next/.next/cache/webpack/server-production/index.pack.old +0 -0
  19. package/dist/.next/.next/diagnostics/build-diagnostics.json +6 -0
  20. package/dist/.next/.next/diagnostics/framework.json +1 -0
  21. package/dist/.next/.next/export-marker.json +1 -0
  22. package/dist/.next/.next/images-manifest.json +1 -0
  23. package/dist/.next/.next/next-minimal-server.js.nft.json +1 -0
  24. package/dist/.next/.next/next-server.js.nft.json +1 -0
  25. package/dist/.next/.next/package.json +1 -0
  26. package/dist/.next/.next/prerender-manifest.json +1 -0
  27. package/dist/.next/.next/react-loadable-manifest.json +1 -0
  28. package/dist/.next/.next/required-server-files.json +1 -0
  29. package/dist/.next/.next/routes-manifest.json +1 -0
  30. package/dist/.next/.next/server/app/_not-found/page.js +1 -0
  31. package/dist/.next/.next/server/app/_not-found/page.js.nft.json +1 -0
  32. package/dist/.next/.next/server/app/_not-found/page_client-reference-manifest.js +1 -0
  33. package/dist/.next/.next/server/app/_not-found.html +1 -0
  34. package/dist/.next/.next/server/app/_not-found.meta +8 -0
  35. package/dist/.next/.next/server/app/_not-found.rsc +16 -0
  36. package/dist/.next/.next/server/app/api/cloudflare/route.js +1 -0
  37. package/dist/.next/.next/server/app/api/cloudflare/route.js.nft.json +1 -0
  38. package/dist/.next/.next/server/app/api/cloudflare/route_client-reference-manifest.js +1 -0
  39. package/dist/.next/.next/server/app/api/databases/route.js +1 -0
  40. package/dist/.next/.next/server/app/api/databases/route.js.nft.json +1 -0
  41. package/dist/.next/.next/server/app/api/databases/route_client-reference-manifest.js +1 -0
  42. package/dist/.next/.next/server/app/api/migrations/sync/route.js +12 -0
  43. package/dist/.next/.next/server/app/api/migrations/sync/route.js.nft.json +1 -0
  44. package/dist/.next/.next/server/app/api/migrations/sync/route_client-reference-manifest.js +1 -0
  45. package/dist/.next/.next/server/app/api/migrations/sync-files/route.js +1 -0
  46. package/dist/.next/.next/server/app/api/migrations/sync-files/route.js.nft.json +1 -0
  47. package/dist/.next/.next/server/app/api/migrations/sync-files/route_client-reference-manifest.js +1 -0
  48. package/dist/.next/.next/server/app/api/pull-remote/confirm/route.js +1 -0
  49. package/dist/.next/.next/server/app/api/pull-remote/confirm/route.js.nft.json +1 -0
  50. package/dist/.next/.next/server/app/api/pull-remote/confirm/route_client-reference-manifest.js +1 -0
  51. package/dist/.next/.next/server/app/api/pull-remote/preview/route.js +1 -0
  52. package/dist/.next/.next/server/app/api/pull-remote/preview/route.js.nft.json +1 -0
  53. package/dist/.next/.next/server/app/api/pull-remote/preview/route_client-reference-manifest.js +1 -0
  54. package/dist/.next/.next/server/app/api/push-remote/confirm/route.js +14 -0
  55. package/dist/.next/.next/server/app/api/push-remote/confirm/route.js.nft.json +1 -0
  56. package/dist/.next/.next/server/app/api/push-remote/confirm/route_client-reference-manifest.js +1 -0
  57. package/dist/.next/.next/server/app/api/push-remote/preview/route.js +14 -0
  58. package/dist/.next/.next/server/app/api/push-remote/preview/route.js.nft.json +1 -0
  59. package/dist/.next/.next/server/app/api/push-remote/preview/route_client-reference-manifest.js +1 -0
  60. package/dist/.next/.next/server/app/api/query/route.js +8 -0
  61. package/dist/.next/.next/server/app/api/query/route.js.nft.json +1 -0
  62. package/dist/.next/.next/server/app/api/query/route_client-reference-manifest.js +1 -0
  63. package/dist/.next/.next/server/app/api/tables/[name]/route.js +5 -0
  64. package/dist/.next/.next/server/app/api/tables/[name]/route.js.nft.json +1 -0
  65. package/dist/.next/.next/server/app/api/tables/[name]/route_client-reference-manifest.js +1 -0
  66. package/dist/.next/.next/server/app/api/tables/route.js +7 -0
  67. package/dist/.next/.next/server/app/api/tables/route.js.nft.json +1 -0
  68. package/dist/.next/.next/server/app/api/tables/route_client-reference-manifest.js +1 -0
  69. package/dist/.next/.next/server/app/index.html +3 -0
  70. package/dist/.next/.next/server/app/index.meta +7 -0
  71. package/dist/.next/.next/server/app/index.rsc +20 -0
  72. package/dist/.next/.next/server/app/page.js +58 -0
  73. package/dist/.next/.next/server/app/page.js.nft.json +1 -0
  74. package/dist/.next/.next/server/app/page_client-reference-manifest.js +1 -0
  75. package/dist/.next/.next/server/app-paths-manifest.json +15 -0
  76. package/dist/.next/.next/server/chunks/336.js +1 -0
  77. package/dist/.next/.next/server/chunks/627.js +6 -0
  78. package/dist/.next/.next/server/chunks/638.js +13 -0
  79. package/dist/.next/.next/server/chunks/801.js +55 -0
  80. package/dist/.next/.next/server/chunks/973.js +2 -0
  81. package/dist/.next/.next/server/chunks/992.js +3 -0
  82. package/dist/.next/.next/server/functions-config-manifest.json +1 -0
  83. package/dist/.next/.next/server/interception-route-rewrite-manifest.js +1 -0
  84. package/dist/.next/.next/server/middleware-build-manifest.js +1 -0
  85. package/dist/.next/.next/server/middleware-manifest.json +6 -0
  86. package/dist/.next/.next/server/middleware-react-loadable-manifest.js +1 -0
  87. package/dist/.next/.next/server/next-font-manifest.js +1 -0
  88. package/dist/.next/.next/server/next-font-manifest.json +1 -0
  89. package/dist/.next/.next/server/pages/404.html +1 -0
  90. package/dist/.next/.next/server/pages/500.html +1 -0
  91. package/dist/.next/.next/server/pages/_app.js +1 -0
  92. package/dist/.next/.next/server/pages/_app.js.nft.json +1 -0
  93. package/dist/.next/.next/server/pages/_document.js +1 -0
  94. package/dist/.next/.next/server/pages/_document.js.nft.json +1 -0
  95. package/dist/.next/.next/server/pages/_error.js +1 -0
  96. package/dist/.next/.next/server/pages/_error.js.nft.json +1 -0
  97. package/dist/.next/.next/server/pages-manifest.json +1 -0
  98. package/dist/.next/.next/server/server-reference-manifest.js +1 -0
  99. package/dist/.next/.next/server/server-reference-manifest.json +1 -0
  100. package/dist/.next/.next/server/webpack-runtime.js +1 -0
  101. package/dist/.next/.next/static/ODMSSwVqLoDcBgbFHUjr8/_buildManifest.js +1 -0
  102. package/dist/.next/.next/static/ODMSSwVqLoDcBgbFHUjr8/_ssgManifest.js +1 -0
  103. package/dist/.next/.next/static/chunks/422-6fa3c14fc64ad67b.js +1 -0
  104. package/dist/.next/.next/static/chunks/4bd1b696-8c908eb707f85a27.js +1 -0
  105. package/dist/.next/.next/static/chunks/517-3b698a5d3da06ff7.js +2 -0
  106. package/dist/.next/.next/static/chunks/692-ede418e1d28a1394.js +1 -0
  107. package/dist/.next/.next/static/chunks/735-c9144179c6bd7d06.js +1 -0
  108. package/dist/.next/.next/static/chunks/92-c4466e0f1ca8a3a8.js +1 -0
  109. package/dist/.next/.next/static/chunks/app/_not-found/page-b786c3dd79ad15a5.js +1 -0
  110. package/dist/.next/.next/static/chunks/app/api/cloudflare/route-3458d78022185d7f.js +1 -0
  111. package/dist/.next/.next/static/chunks/app/api/databases/route-64255424877a9f72.js +1 -0
  112. package/dist/.next/.next/static/chunks/app/api/migrations/sync/route-03766b3afcf043ba.js +1 -0
  113. package/dist/.next/.next/static/chunks/app/api/migrations/sync-files/route-02fa291c8000dadf.js +1 -0
  114. package/dist/.next/.next/static/chunks/app/api/pull-remote/confirm/route-7e05bb8920127abe.js +1 -0
  115. package/dist/.next/.next/static/chunks/app/api/pull-remote/preview/route-0fa15f783e8a306c.js +1 -0
  116. package/dist/.next/.next/static/chunks/app/api/push-remote/confirm/route-96691f1880e4ed14.js +1 -0
  117. package/dist/.next/.next/static/chunks/app/api/push-remote/preview/route-a798679c67374552.js +1 -0
  118. package/dist/.next/.next/static/chunks/app/api/query/route-e90d0030a5083e20.js +1 -0
  119. package/dist/.next/.next/static/chunks/app/api/tables/[name]/route-1efe63e73b480e58.js +1 -0
  120. package/dist/.next/.next/static/chunks/app/api/tables/route-3772b4f480c4b4a4.js +1 -0
  121. package/dist/.next/.next/static/chunks/app/layout-8360fab69b848283.js +1 -0
  122. package/dist/.next/.next/static/chunks/app/page-75081ac7a88cb706.js +1 -0
  123. package/dist/.next/.next/static/chunks/framework-d29117d969504448.js +1 -0
  124. package/dist/.next/.next/static/chunks/main-8d0ab17774ffa031.js +1 -0
  125. package/dist/.next/.next/static/chunks/main-app-d36cdfb402b40f13.js +1 -0
  126. package/dist/.next/.next/static/chunks/pages/_app-d23763e3e6c904ff.js +1 -0
  127. package/dist/.next/.next/static/chunks/pages/_error-9b7125ad1a1e68fa.js +1 -0
  128. package/dist/.next/.next/static/chunks/polyfills-42372ed130431b0a.js +1 -0
  129. package/dist/.next/.next/static/chunks/webpack-c76ac1e586b2802a.js +1 -0
  130. package/dist/.next/.next/static/css/c51a7ef325e30c16.css +3 -0
  131. package/dist/.next/.next/static/media/569ce4b8f30dc480-s.p.woff2 +0 -0
  132. package/dist/.next/.next/static/media/747892c23ea88013-s.woff2 +0 -0
  133. package/dist/.next/.next/static/media/93f479601ee12b01-s.p.woff2 +0 -0
  134. package/dist/.next/.next/static/media/ba015fad6dcf6784-s.woff2 +0 -0
  135. package/dist/.next/.next/trace +3 -0
  136. package/dist/.next/.next/types/app/api/cloudflare/route.ts +347 -0
  137. package/dist/.next/.next/types/app/api/databases/route.ts +347 -0
  138. package/dist/.next/.next/types/app/api/migrations/sync/route.ts +347 -0
  139. package/dist/.next/.next/types/app/api/migrations/sync-files/route.ts +347 -0
  140. package/dist/.next/.next/types/app/api/pull-remote/confirm/route.ts +347 -0
  141. package/dist/.next/.next/types/app/api/pull-remote/preview/route.ts +347 -0
  142. package/dist/.next/.next/types/app/api/push-remote/confirm/route.ts +347 -0
  143. package/dist/.next/.next/types/app/api/push-remote/preview/route.ts +347 -0
  144. package/dist/.next/.next/types/app/api/query/route.ts +347 -0
  145. package/dist/.next/.next/types/app/api/tables/[name]/route.ts +347 -0
  146. package/dist/.next/.next/types/app/api/tables/route.ts +347 -0
  147. package/dist/.next/.next/types/app/page.ts +84 -0
  148. package/dist/.next/.next/types/cache-life.d.ts +141 -0
  149. package/dist/.next/.next/types/package.json +1 -0
  150. package/dist/.next/BUILD_ID +1 -0
  151. package/dist/.next/app-build-manifest.json +109 -0
  152. package/dist/.next/app-path-routes-manifest.json +1 -0
  153. package/dist/.next/build-manifest.json +33 -0
  154. package/dist/.next/cache/.rscinfo +1 -0
  155. package/dist/.next/cache/.tsbuildinfo +1 -0
  156. package/dist/.next/cache/webpack/client-production/0.pack +0 -0
  157. package/dist/.next/cache/webpack/client-production/index.pack +0 -0
  158. package/dist/.next/cache/webpack/edge-server-production/0.pack +0 -0
  159. package/dist/.next/cache/webpack/edge-server-production/index.pack +0 -0
  160. package/dist/.next/cache/webpack/server-production/0.pack +0 -0
  161. package/dist/.next/cache/webpack/server-production/index.pack +0 -0
  162. package/dist/.next/diagnostics/build-diagnostics.json +6 -0
  163. package/dist/.next/diagnostics/framework.json +1 -0
  164. package/dist/.next/export-marker.json +1 -0
  165. package/dist/.next/images-manifest.json +1 -0
  166. package/dist/.next/next-minimal-server.js.nft.json +1 -0
  167. package/dist/.next/next-server.js.nft.json +1 -0
  168. package/dist/.next/package.json +1 -0
  169. package/dist/.next/prerender-manifest.json +1 -0
  170. package/dist/.next/react-loadable-manifest.json +1 -0
  171. package/dist/.next/required-server-files.json +1 -0
  172. package/dist/.next/routes-manifest.json +1 -0
  173. package/dist/.next/server/app/_not-found/page.js +1 -0
  174. package/dist/.next/server/app/_not-found/page.js.nft.json +1 -0
  175. package/dist/.next/server/app/_not-found/page_client-reference-manifest.js +1 -0
  176. package/dist/.next/server/app/_not-found.html +1 -0
  177. package/dist/.next/server/app/_not-found.meta +8 -0
  178. package/dist/.next/server/app/_not-found.rsc +16 -0
  179. package/dist/.next/server/app/api/cloudflare/route.js +1 -0
  180. package/dist/.next/server/app/api/cloudflare/route.js.nft.json +1 -0
  181. package/dist/.next/server/app/api/cloudflare/route_client-reference-manifest.js +1 -0
  182. package/dist/.next/server/app/api/databases/route.js +1 -0
  183. package/dist/.next/server/app/api/databases/route.js.nft.json +1 -0
  184. package/dist/.next/server/app/api/databases/route_client-reference-manifest.js +1 -0
  185. package/dist/.next/server/app/api/migrations/sync/route.js +12 -0
  186. package/dist/.next/server/app/api/migrations/sync/route.js.nft.json +1 -0
  187. package/dist/.next/server/app/api/migrations/sync/route_client-reference-manifest.js +1 -0
  188. package/dist/.next/server/app/api/migrations/sync-files/route.js +1 -0
  189. package/dist/.next/server/app/api/migrations/sync-files/route.js.nft.json +1 -0
  190. package/dist/.next/server/app/api/migrations/sync-files/route_client-reference-manifest.js +1 -0
  191. package/dist/.next/server/app/api/pull-remote/confirm/route.js +1 -0
  192. package/dist/.next/server/app/api/pull-remote/confirm/route.js.nft.json +1 -0
  193. package/dist/.next/server/app/api/pull-remote/confirm/route_client-reference-manifest.js +1 -0
  194. package/dist/.next/server/app/api/pull-remote/preview/route.js +1 -0
  195. package/dist/.next/server/app/api/pull-remote/preview/route.js.nft.json +1 -0
  196. package/dist/.next/server/app/api/pull-remote/preview/route_client-reference-manifest.js +1 -0
  197. package/dist/.next/server/app/api/push-remote/confirm/route.js +14 -0
  198. package/dist/.next/server/app/api/push-remote/confirm/route.js.nft.json +1 -0
  199. package/dist/.next/server/app/api/push-remote/confirm/route_client-reference-manifest.js +1 -0
  200. package/dist/.next/server/app/api/push-remote/preview/route.js +14 -0
  201. package/dist/.next/server/app/api/push-remote/preview/route.js.nft.json +1 -0
  202. package/dist/.next/server/app/api/push-remote/preview/route_client-reference-manifest.js +1 -0
  203. package/dist/.next/server/app/api/query/route.js +8 -0
  204. package/dist/.next/server/app/api/query/route.js.nft.json +1 -0
  205. package/dist/.next/server/app/api/query/route_client-reference-manifest.js +1 -0
  206. package/dist/.next/server/app/api/tables/[name]/route.js +5 -0
  207. package/dist/.next/server/app/api/tables/[name]/route.js.nft.json +1 -0
  208. package/dist/.next/server/app/api/tables/[name]/route_client-reference-manifest.js +1 -0
  209. package/dist/.next/server/app/api/tables/route.js +7 -0
  210. package/dist/.next/server/app/api/tables/route.js.nft.json +1 -0
  211. package/dist/.next/server/app/api/tables/route_client-reference-manifest.js +1 -0
  212. package/dist/.next/server/app/index.html +3 -0
  213. package/dist/.next/server/app/index.meta +7 -0
  214. package/dist/.next/server/app/index.rsc +20 -0
  215. package/dist/.next/server/app/page.js +58 -0
  216. package/dist/.next/server/app/page.js.nft.json +1 -0
  217. package/dist/.next/server/app/page_client-reference-manifest.js +1 -0
  218. package/dist/.next/server/app-paths-manifest.json +15 -0
  219. package/dist/.next/server/chunks/336.js +1 -0
  220. package/dist/.next/server/chunks/627.js +6 -0
  221. package/dist/.next/server/chunks/638.js +13 -0
  222. package/dist/.next/server/chunks/801.js +55 -0
  223. package/dist/.next/server/chunks/973.js +2 -0
  224. package/dist/.next/server/chunks/992.js +3 -0
  225. package/dist/.next/server/functions-config-manifest.json +1 -0
  226. package/dist/.next/server/interception-route-rewrite-manifest.js +1 -0
  227. package/dist/.next/server/middleware-build-manifest.js +1 -0
  228. package/dist/.next/server/middleware-manifest.json +6 -0
  229. package/dist/.next/server/middleware-react-loadable-manifest.js +1 -0
  230. package/dist/.next/server/next-font-manifest.js +1 -0
  231. package/dist/.next/server/next-font-manifest.json +1 -0
  232. package/dist/.next/server/pages/404.html +1 -0
  233. package/dist/.next/server/pages/500.html +1 -0
  234. package/dist/.next/server/pages/_app.js +1 -0
  235. package/dist/.next/server/pages/_app.js.nft.json +1 -0
  236. package/dist/.next/server/pages/_document.js +1 -0
  237. package/dist/.next/server/pages/_document.js.nft.json +1 -0
  238. package/dist/.next/server/pages/_error.js +1 -0
  239. package/dist/.next/server/pages/_error.js.nft.json +1 -0
  240. package/dist/.next/server/pages-manifest.json +1 -0
  241. package/dist/.next/server/server-reference-manifest.js +1 -0
  242. package/dist/.next/server/server-reference-manifest.json +1 -0
  243. package/dist/.next/server/webpack-runtime.js +1 -0
  244. package/dist/.next/static/OmPVuV0d1lrcjSBQzxkdH/_buildManifest.js +1 -0
  245. package/dist/.next/static/OmPVuV0d1lrcjSBQzxkdH/_ssgManifest.js +1 -0
  246. package/dist/.next/static/chunks/422-6fa3c14fc64ad67b.js +1 -0
  247. package/dist/.next/static/chunks/4bd1b696-8c908eb707f85a27.js +1 -0
  248. package/dist/.next/static/chunks/517-3b698a5d3da06ff7.js +2 -0
  249. package/dist/.next/static/chunks/692-ede418e1d28a1394.js +1 -0
  250. package/dist/.next/static/chunks/735-c9144179c6bd7d06.js +1 -0
  251. package/dist/.next/static/chunks/92-c4466e0f1ca8a3a8.js +1 -0
  252. package/dist/.next/static/chunks/app/_not-found/page-b786c3dd79ad15a5.js +1 -0
  253. package/dist/.next/static/chunks/app/api/cloudflare/route-3458d78022185d7f.js +1 -0
  254. package/dist/.next/static/chunks/app/api/databases/route-64255424877a9f72.js +1 -0
  255. package/dist/.next/static/chunks/app/api/migrations/sync/route-03766b3afcf043ba.js +1 -0
  256. package/dist/.next/static/chunks/app/api/migrations/sync-files/route-02fa291c8000dadf.js +1 -0
  257. package/dist/.next/static/chunks/app/api/pull-remote/confirm/route-7e05bb8920127abe.js +1 -0
  258. package/dist/.next/static/chunks/app/api/pull-remote/preview/route-0fa15f783e8a306c.js +1 -0
  259. package/dist/.next/static/chunks/app/api/push-remote/confirm/route-96691f1880e4ed14.js +1 -0
  260. package/dist/.next/static/chunks/app/api/push-remote/preview/route-a798679c67374552.js +1 -0
  261. package/dist/.next/static/chunks/app/api/query/route-e90d0030a5083e20.js +1 -0
  262. package/dist/.next/static/chunks/app/api/tables/[name]/route-1efe63e73b480e58.js +1 -0
  263. package/dist/.next/static/chunks/app/api/tables/route-3772b4f480c4b4a4.js +1 -0
  264. package/dist/.next/static/chunks/app/layout-8360fab69b848283.js +1 -0
  265. package/dist/.next/static/chunks/app/page-75081ac7a88cb706.js +1 -0
  266. package/dist/.next/static/chunks/framework-d29117d969504448.js +1 -0
  267. package/dist/.next/static/chunks/main-8d0ab17774ffa031.js +1 -0
  268. package/dist/.next/static/chunks/main-app-d36cdfb402b40f13.js +1 -0
  269. package/dist/.next/static/chunks/pages/_app-d23763e3e6c904ff.js +1 -0
  270. package/dist/.next/static/chunks/pages/_error-9b7125ad1a1e68fa.js +1 -0
  271. package/dist/.next/static/chunks/polyfills-42372ed130431b0a.js +1 -0
  272. package/dist/.next/static/chunks/webpack-c76ac1e586b2802a.js +1 -0
  273. package/dist/.next/static/css/c51a7ef325e30c16.css +3 -0
  274. package/dist/.next/static/media/569ce4b8f30dc480-s.p.woff2 +0 -0
  275. package/dist/.next/static/media/747892c23ea88013-s.woff2 +0 -0
  276. package/dist/.next/static/media/93f479601ee12b01-s.p.woff2 +0 -0
  277. package/dist/.next/static/media/ba015fad6dcf6784-s.woff2 +0 -0
  278. package/dist/.next/trace +13 -0
  279. package/dist/.next/types/app/api/cloudflare/route.ts +347 -0
  280. package/dist/.next/types/app/api/databases/route.ts +347 -0
  281. package/dist/.next/types/app/api/migrations/sync/route.ts +347 -0
  282. package/dist/.next/types/app/api/migrations/sync-files/route.ts +347 -0
  283. package/dist/.next/types/app/api/pull-remote/confirm/route.ts +347 -0
  284. package/dist/.next/types/app/api/pull-remote/preview/route.ts +347 -0
  285. package/dist/.next/types/app/api/push-remote/confirm/route.ts +347 -0
  286. package/dist/.next/types/app/api/push-remote/preview/route.ts +347 -0
  287. package/dist/.next/types/app/api/query/route.ts +347 -0
  288. package/dist/.next/types/app/api/tables/[name]/route.ts +347 -0
  289. package/dist/.next/types/app/api/tables/route.ts +347 -0
  290. package/dist/.next/types/app/page.ts +84 -0
  291. package/dist/.next/types/cache-life.d.ts +141 -0
  292. package/dist/.next/types/package.json +1 -0
  293. package/dist/app/api/cloudflare/route.js +146 -0
  294. package/dist/app/api/databases/route.js +72 -0
  295. package/dist/app/api/migrations/sync/route.js +172 -0
  296. package/dist/app/api/migrations/sync-files/route.js +172 -0
  297. package/dist/app/api/pull-remote/confirm/route.js +277 -0
  298. package/dist/app/api/pull-remote/preview/route.js +143 -0
  299. package/dist/app/api/push-remote/confirm/route.js +196 -0
  300. package/dist/app/api/push-remote/preview/route.js +178 -0
  301. package/dist/app/api/query/route.js +160 -0
  302. package/dist/app/api/tables/[name]/route.js +173 -0
  303. package/dist/app/api/tables/route.js +174 -0
  304. package/dist/app/app/api/cloudflare/route.js +146 -0
  305. package/dist/app/app/api/databases/route.js +72 -0
  306. package/dist/app/app/api/migrations/sync/route.js +172 -0
  307. package/dist/app/app/api/migrations/sync-files/route.js +172 -0
  308. package/dist/app/app/api/pull-remote/confirm/route.js +277 -0
  309. package/dist/app/app/api/pull-remote/preview/route.js +143 -0
  310. package/dist/app/app/api/push-remote/confirm/route.js +196 -0
  311. package/dist/app/app/api/push-remote/preview/route.js +178 -0
  312. package/dist/app/app/api/query/route.js +160 -0
  313. package/dist/app/app/api/tables/[name]/route.js +173 -0
  314. package/dist/app/app/api/tables/route.js +174 -0
  315. package/dist/app/app/globals.css +93 -0
  316. package/dist/app/app/layout.jsx +35 -0
  317. package/dist/app/app/page.jsx +37 -0
  318. package/dist/app/globals.css +93 -0
  319. package/dist/app/layout.jsx +35 -0
  320. package/dist/app/page.jsx +37 -0
  321. package/dist/d1-studio.js +344 -0
  322. package/dist/lib/database-queue.js +33 -0
  323. package/dist/lib/error.js +20 -0
  324. package/dist/lib/find-wrangler-config.js +67 -0
  325. package/dist/lib/license.js +99 -0
  326. package/dist/lib/migrations.js +415 -0
  327. package/dist/lib/parse-sql-error.js +200 -0
  328. package/dist/lib/request-deduplication.js +24 -0
  329. package/dist/lib/schema-operations.js +103 -0
  330. package/dist/lib/sql-error-types.js +14 -0
  331. package/dist/lib/sql-operations.js +557 -0
  332. package/dist/lib/utils.js +6 -0
  333. package/next.config.mjs +18 -0
  334. package/package.json +97 -0
  335. package/postcss.config.mjs +8 -0
  336. package/scripts/studio.js +344 -0
  337. package/scripts/test.js +168 -0
  338. package/src/app/api/cloudflare/route.js +146 -0
  339. package/src/app/api/databases/route.js +72 -0
  340. package/src/app/api/migrations/sync/route.js +172 -0
  341. package/src/app/api/migrations/sync-files/route.js +172 -0
  342. package/src/app/api/pull-remote/confirm/route.js +277 -0
  343. package/src/app/api/pull-remote/preview/route.js +143 -0
  344. package/src/app/api/push-remote/confirm/route.js +196 -0
  345. package/src/app/api/push-remote/preview/route.js +178 -0
  346. package/src/app/api/query/route.js +160 -0
  347. package/src/app/api/tables/[name]/route.js +173 -0
  348. package/src/app/api/tables/route.js +174 -0
  349. package/src/app/globals.css +93 -0
  350. package/src/app/layout.jsx +35 -0
  351. package/src/app/page.jsx +37 -0
  352. package/src/components/cloudflare-credentials-modal.jsx +94 -0
  353. package/src/components/column-selector.jsx +133 -0
  354. package/src/components/column-sorting.jsx +65 -0
  355. package/src/components/delete-records-dialog.jsx +64 -0
  356. package/src/components/download-button.jsx +205 -0
  357. package/src/components/edit-error-alert.jsx +30 -0
  358. package/src/components/editable-cell.jsx +163 -0
  359. package/src/components/editable-row.jsx +169 -0
  360. package/src/components/environment-handler.jsx +278 -0
  361. package/src/components/environment-select.jsx +59 -0
  362. package/src/components/pull-preview-toast.jsx +188 -0
  363. package/src/components/push-error-alert.jsx +72 -0
  364. package/src/components/push-preview-toast.jsx +183 -0
  365. package/src/components/query-results.jsx +112 -0
  366. package/src/components/refresh-button.jsx +61 -0
  367. package/src/components/resize-columns.jsx +101 -0
  368. package/src/components/sidebar.jsx +236 -0
  369. package/src/components/sql-editor.jsx +411 -0
  370. package/src/components/sql-error-display.jsx +167 -0
  371. package/src/components/sync-migrations-button.jsx +87 -0
  372. package/src/components/table-error-dialog.jsx +65 -0
  373. package/src/components/table-toolbar.jsx +285 -0
  374. package/src/components/table-view.jsx +843 -0
  375. package/src/components/ui/alert.jsx +47 -0
  376. package/src/components/ui/button.jsx +48 -0
  377. package/src/components/ui/card.jsx +50 -0
  378. package/src/components/ui/checkbox.jsx +24 -0
  379. package/src/components/ui/collapsible.jsx +11 -0
  380. package/src/components/ui/dialog.jsx +96 -0
  381. package/src/components/ui/dropdown-menu.jsx +158 -0
  382. package/src/components/ui/input.jsx +19 -0
  383. package/src/components/ui/scroll-area.jsx +40 -0
  384. package/src/components/ui/select.jsx +121 -0
  385. package/src/components/ui/separator.jsx +25 -0
  386. package/src/components/ui/sheet.jsx +109 -0
  387. package/src/components/ui/sidebar.jsx +620 -0
  388. package/src/components/ui/skeleton.jsx +14 -0
  389. package/src/components/ui/table.jsx +86 -0
  390. package/src/components/ui/tabs.jsx +43 -0
  391. package/src/components/ui/toast.jsx +86 -0
  392. package/src/components/ui/toaster.jsx +35 -0
  393. package/src/components/ui/tooltip.jsx +28 -0
  394. package/src/context/database-context.js +510 -0
  395. package/src/hooks/use-mobile.jsx +19 -0
  396. package/src/hooks/use-sql-error.ts +23 -0
  397. package/src/hooks/use-toast.js +155 -0
  398. package/src/lib/database-queue.js +33 -0
  399. package/src/lib/error.js +20 -0
  400. package/src/lib/find-wrangler-config.js +67 -0
  401. package/src/lib/license.js +99 -0
  402. package/src/lib/migrations.js +415 -0
  403. package/src/lib/parse-sql-error.js +200 -0
  404. package/src/lib/request-deduplication.js +24 -0
  405. package/src/lib/schema-operations.js +103 -0
  406. package/src/lib/sql-error-types.js +14 -0
  407. package/src/lib/sql-operations.js +557 -0
  408. package/src/lib/utils.js +6 -0
@@ -0,0 +1,133 @@
1
+ // components/column-selector.jsx
2
+ import React, { useState, useEffect } from 'react';
3
+ import {
4
+ DropdownMenu,
5
+ DropdownMenuContent,
6
+ DropdownMenuTrigger
7
+ } from "@/components/ui/dropdown-menu";
8
+ import { Button } from "@/components/ui/button";
9
+ import { Checkbox } from "@/components/ui/checkbox";
10
+ import { Input } from "@/components/ui/input";
11
+ import { Columns } from 'lucide-react';
12
+
13
+ export function ColumnSelector({ schema = [], visibleColumns = [], onColumnToggle }) {
14
+ const [searchTerm, setSearchTerm] = useState('');
15
+
16
+ // Initialize visible columns with all columns from schema
17
+ useEffect(() => {
18
+ if (!schema || schema.length === 0) return;
19
+
20
+ // Get all column names from schema
21
+ const allColumns = schema.map(col => col.name);
22
+
23
+ // If visibleColumns is empty, make all columns visible
24
+ if (visibleColumns.length === 0) {
25
+ allColumns.forEach(col => onColumnToggle(col));
26
+ }
27
+ }, [schema, visibleColumns.length, onColumnToggle]);
28
+
29
+ // Filter columns based on search term
30
+ const filteredColumns = schema.filter(col =>
31
+ col.name.toLowerCase().includes(searchTerm.toLowerCase())
32
+ );
33
+ const filteredColumnNames = filteredColumns.map(col => col.name);
34
+
35
+ // Determine if all filtered columns are selected
36
+ const allFilteredSelected =
37
+ filteredColumnNames.length > 0 &&
38
+ filteredColumnNames.every(name => visibleColumns.includes(name));
39
+
40
+ // Handle individual checkbox change
41
+ const handleCheckboxChange = (columnName) => {
42
+ onColumnToggle(columnName);
43
+ };
44
+
45
+ // Handle the "Select All" checkbox change for the filtered list
46
+ const handleSelectAllChange = (checked) => {
47
+ if (checked) {
48
+ // For every filtered column that is not visible, toggle it on
49
+ filteredColumns.forEach(col => {
50
+ if (!visibleColumns.includes(col.name)) {
51
+ onColumnToggle(col.name);
52
+ }
53
+ });
54
+ } else {
55
+ // For every filtered column that is visible, toggle it off
56
+ filteredColumns.forEach(col => {
57
+ if (visibleColumns.includes(col.name)) {
58
+ onColumnToggle(col.name);
59
+ }
60
+ });
61
+ }
62
+ };
63
+
64
+ return (
65
+ <DropdownMenu>
66
+ <DropdownMenuTrigger asChild>
67
+ <Button
68
+ size="sm"
69
+ variant="outline"
70
+ className="font-semibold"
71
+ >
72
+ <Columns className="h-4 w-4" />
73
+ Columns ({visibleColumns.length})
74
+ </Button>
75
+ </DropdownMenuTrigger>
76
+ <DropdownMenuContent align="end" className="w-64 font-sans">
77
+ <div className="p-2">
78
+ <Input
79
+ placeholder="Search columns..."
80
+ value={searchTerm}
81
+ onChange={(e) => setSearchTerm(e.target.value)}
82
+ className="h-8"
83
+ />
84
+ </div>
85
+
86
+ {/* Select All Option */}
87
+ <div className="flex items-center space-x-2 px-2 py-1.5 hover:bg-accent rounded-md">
88
+ <Checkbox
89
+ id="select-all-columns"
90
+ checked={allFilteredSelected}
91
+ onCheckedChange={handleSelectAllChange}
92
+ className="shrink-0"
93
+ />
94
+ <label
95
+ htmlFor="select-all-columns"
96
+ className="flex-1 cursor-pointer text-sm font-medium"
97
+ >
98
+ Select All {searchTerm && '(Filtered)'}
99
+ </label>
100
+ </div>
101
+
102
+ <div className="max-h-[300px] overflow-y-auto">
103
+ {filteredColumns.map((column) => (
104
+ <div
105
+ key={column.name}
106
+ className="flex items-start space-x-2 px-2 py-1.5 hover:bg-accent rounded-md"
107
+ >
108
+ <Checkbox
109
+ id={`column-${column.name}`}
110
+ checked={visibleColumns.includes(column.name)}
111
+ onCheckedChange={() => handleCheckboxChange(column.name)}
112
+ className="mt-1"
113
+ />
114
+ <label
115
+ htmlFor={`column-${column.name}`}
116
+ className="flex-1 cursor-pointer"
117
+ >
118
+ <div className="text-sm font-medium">
119
+ {column.name}
120
+ </div>
121
+ <div className="text-xs text-muted-foreground">
122
+ {column.type.toLowerCase()}
123
+ </div>
124
+ </label>
125
+ </div>
126
+ ))}
127
+ </div>
128
+ </DropdownMenuContent>
129
+ </DropdownMenu>
130
+ );
131
+ }
132
+
133
+ export default ColumnSelector;
@@ -0,0 +1,65 @@
1
+ // components/column-sorting.jsx
2
+ 'use client';
3
+
4
+ import { ArrowUpDown, ArrowUp, ArrowDown } from 'lucide-react';
5
+ import { Button } from "@/components/ui/button";
6
+
7
+ export function SortableHeader({
8
+ column,
9
+ sortConfig,
10
+ onSort,
11
+ children
12
+ }) {
13
+ const direction = sortConfig[column];
14
+
15
+ return (
16
+ <div className="flex items-center w-full">
17
+ <Button
18
+ variant="ghost"
19
+ size="sm"
20
+ className="h-8 hover:bg-neutral-100 w-full justify-between"
21
+ onClick={() => {
22
+ const nextDirection = !direction
23
+ ? 'asc'
24
+ : direction === 'asc'
25
+ ? 'desc'
26
+ : null;
27
+ onSort(column, nextDirection);
28
+ }}
29
+ >
30
+ <span className="flex items-center gap-1 font-mono">
31
+ {children}
32
+ </span>
33
+ <span className="shrink-0">
34
+ {direction === 'asc' && <ArrowUp className="h-4 w-4" />}
35
+ {direction === 'desc' && <ArrowDown className="h-4 w-4" />}
36
+ {!direction && <ArrowUpDown className="h-4 w-4" />}
37
+ </span>
38
+ </Button>
39
+ </div>
40
+ );
41
+ }
42
+
43
+ export function sortData(data, column, direction) {
44
+ if (!direction || !data.length) return data;
45
+
46
+ return [...data].sort((a, b) => {
47
+ const aVal = a[column];
48
+ const bVal = b[column];
49
+
50
+ // Handle null values
51
+ if (aVal == null && bVal == null) return 0;
52
+ if (aVal == null) return 1;
53
+ if (bVal == null) return -1;
54
+
55
+ // Compare based on type
56
+ if (typeof aVal === 'number' && typeof bVal === 'number') {
57
+ return direction === 'asc' ? aVal - bVal : bVal - aVal;
58
+ }
59
+
60
+ // String comparison for everything else
61
+ const aStr = String(aVal).toLowerCase();
62
+ const bStr = String(bVal).toLowerCase();
63
+ return direction === 'asc' ? aStr.localeCompare(bStr) : bStr.localeCompare(aStr);
64
+ });
65
+ }
@@ -0,0 +1,64 @@
1
+ // components/delete-records-dialog.jsx
2
+ 'use client';
3
+
4
+ import React from 'react';
5
+ import { AlertCircle } from 'lucide-react';
6
+ import {
7
+ Dialog,
8
+ DialogContent,
9
+ DialogDescription,
10
+ DialogHeader,
11
+ DialogTitle,
12
+ DialogFooter,
13
+ } from "@/components/ui/dialog";
14
+ import { Button } from "@/components/ui/button";
15
+ import { Alert, AlertDescription } from "@/components/ui/alert";
16
+
17
+ export function DeleteRecordsDialog({
18
+ isOpen,
19
+ onClose,
20
+ onConfirm,
21
+ selectedCount,
22
+ tableName,
23
+ isDeleting,
24
+ error
25
+ }) {
26
+ return (
27
+ <Dialog open={isOpen} onOpenChange={onClose}>
28
+ <DialogContent className="sm:max-w-md font-sans">
29
+ <DialogHeader>
30
+ <DialogTitle className="mb-2">Delete {selectedCount} {selectedCount === 1 ? 'Record' : 'Records'}?</DialogTitle>
31
+ <DialogDescription className="text-neutral-600 font-medium">
32
+ You're about to delete {selectedCount} {selectedCount === 1 ? 'record' : 'records'} from <span className="font-sans font-bold text-neutral-900">{tableName}</span>.
33
+ </DialogDescription>
34
+ </DialogHeader>
35
+
36
+ {error && (
37
+ <Alert variant="destructive">
38
+ <AlertCircle className="h-4 w-4" />
39
+ <AlertDescription>{error}</AlertDescription>
40
+ </Alert>
41
+ )}
42
+
43
+ <DialogFooter className="flex gap-1 mt-2 sm:justify-end font-sans">
44
+ <Button
45
+ variant="outline"
46
+ onClick={onClose}
47
+ disabled={isDeleting}
48
+ >
49
+ Cancel
50
+ </Button>
51
+ <Button
52
+ variant="destructive"
53
+ onClick={onConfirm}
54
+ disabled={isDeleting}
55
+ >
56
+ {isDeleting ? 'Deleting...' : 'Delete'}
57
+ </Button>
58
+ </DialogFooter>
59
+ </DialogContent>
60
+ </Dialog>
61
+ );
62
+ }
63
+
64
+ export default DeleteRecordsDialog;
@@ -0,0 +1,205 @@
1
+ // components/download-button.jsx
2
+ 'use client';
3
+
4
+ import React, { memo, useState } from 'react';
5
+ import { Download, FileJson, FileSpreadsheet, FileCode, Loader2 } from 'lucide-react';
6
+ import { Button } from "@/components/ui/button";
7
+ import {
8
+ DropdownMenu,
9
+ DropdownMenuContent,
10
+ DropdownMenuItem,
11
+ DropdownMenuTrigger,
12
+ } from "@/components/ui/dropdown-menu";
13
+ import {
14
+ Tooltip,
15
+ TooltipContent,
16
+ TooltipProvider,
17
+ TooltipTrigger,
18
+ } from "@/components/ui/tooltip";
19
+ import { useToast } from "@/hooks/use-toast";
20
+
21
+ const DownloadButton = memo(({
22
+ tableName,
23
+ onDownloadStart,
24
+ onDownloadComplete,
25
+ disabled
26
+ }) => {
27
+ const [isDownloading, setIsDownloading] = useState(false);
28
+ const { toast } = useToast();
29
+
30
+ const downloadAsFile = (data, filename) => {
31
+ try {
32
+ const blob = new Blob([data], { type: "application/octet-stream" });
33
+ const url = window.URL.createObjectURL(blob);
34
+
35
+ const link = document.createElement("a");
36
+ link.href = url;
37
+ link.download = filename;
38
+ document.body.appendChild(link);
39
+ link.click();
40
+ document.body.removeChild(link);
41
+ window.URL.revokeObjectURL(url);
42
+ } catch (error) {
43
+ console.error("Error during file download:", error);
44
+ throw error;
45
+ }
46
+ };
47
+
48
+ const handleDownload = async (format) => {
49
+ if (disabled) return;
50
+
51
+ try {
52
+ setIsDownloading(true);
53
+ onDownloadStart?.();
54
+
55
+ const response = await fetch(`/api/tables/${tableName}`);
56
+ const result = await response.json();
57
+
58
+ if (!response.ok) {
59
+ throw new Error(result.error || 'Failed to fetch data');
60
+ }
61
+
62
+ const { data, schema } = result;
63
+
64
+ if (!data?.length) {
65
+ toast({
66
+ title: "No Data",
67
+ description: "The table is empty.",
68
+ variant: "destructive",
69
+ });
70
+ return;
71
+ }
72
+
73
+ const timestamp = new Date().toISOString().split("T")[0];
74
+ const filename = `${tableName}_${timestamp}.${format}`;
75
+
76
+ switch (format) {
77
+ case "json": {
78
+ const jsonStr = JSON.stringify(data, null, 2);
79
+ downloadAsFile(jsonStr, filename);
80
+ break;
81
+ }
82
+ case "csv": {
83
+ const headers = Object.keys(data[0]);
84
+ const csvRows = [
85
+ headers.join(","),
86
+ ...data.map((row) =>
87
+ headers.map((header) => {
88
+ const value = row[header];
89
+ if (value === null || value === undefined) return "";
90
+ if (typeof value === "string") {
91
+ const escaped = value.replace(/"/g, '""');
92
+ return `"${escaped}"`;
93
+ }
94
+ return value;
95
+ }).join(",")
96
+ ),
97
+ ];
98
+ const csvStr = csvRows.join("\n");
99
+ downloadAsFile(csvStr, filename);
100
+ break;
101
+ }
102
+ case "sql": {
103
+ // Generate CREATE TABLE statement
104
+ const createTable = `CREATE TABLE IF NOT EXISTS ${tableName} (\n` +
105
+ schema.map(col => {
106
+ const constraints = [];
107
+ if (col.pk) constraints.push('PRIMARY KEY');
108
+ if (!col.notnull) constraints.push('NOT NULL');
109
+
110
+ return ` ${col.name} ${col.type}${constraints.length ? ` ${constraints.join(' ')}` : ''}`;
111
+ }).join(',\n') +
112
+ '\n);\n\n';
113
+
114
+ // Generate INSERT statements
115
+ const insertStatements = data.map(row => {
116
+ const columns = Object.keys(row);
117
+ const values = columns.map(col => {
118
+ const value = row[col];
119
+ if (value === null) return 'NULL';
120
+ if (typeof value === 'string') return `'${value.replace(/'/g, "''")}'`;
121
+ return value;
122
+ });
123
+
124
+ return `INSERT INTO ${tableName} (${columns.join(', ')})\nVALUES (${values.join(', ')});`;
125
+ }).join('\n');
126
+
127
+ const sqlContent = createTable + insertStatements;
128
+ downloadAsFile(sqlContent, filename);
129
+ break;
130
+ }
131
+ }
132
+
133
+ toast({
134
+ title: "Download Complete",
135
+ description: `${data.length} rows exported as ${format.toUpperCase()}.`,
136
+ });
137
+ onDownloadComplete?.();
138
+
139
+ } catch (error) {
140
+ console.error("Download error:", error);
141
+ toast({
142
+ variant: "destructive",
143
+ title: "Download Failed",
144
+ description: error.message,
145
+ });
146
+ } finally {
147
+ setIsDownloading(false);
148
+ }
149
+ };
150
+
151
+ return (
152
+ <DropdownMenu>
153
+ <TooltipProvider>
154
+ <Tooltip>
155
+ <TooltipTrigger asChild>
156
+ <DropdownMenuTrigger asChild>
157
+ <Button
158
+ variant="outline"
159
+ size="icon"
160
+ className="h-8"
161
+ disabled={isDownloading || disabled}
162
+ >
163
+ {isDownloading ? (
164
+ <Loader2 className="h-4 w-4 animate-spin" />
165
+ ) : (
166
+ <Download className="h-4 w-4" />
167
+ )}
168
+ </Button>
169
+ </DropdownMenuTrigger>
170
+ </TooltipTrigger>
171
+ <TooltipContent>
172
+ <p>Download table data</p>
173
+ </TooltipContent>
174
+ </Tooltip>
175
+ </TooltipProvider>
176
+ <DropdownMenuContent align="end">
177
+ <DropdownMenuItem
178
+ onClick={() => handleDownload('json')}
179
+ disabled={disabled}
180
+ >
181
+ <FileJson className="mr-2 h-4 w-4" />
182
+ <span>Download JSON</span>
183
+ </DropdownMenuItem>
184
+ <DropdownMenuItem
185
+ onClick={() => handleDownload('csv')}
186
+ disabled={disabled}
187
+ >
188
+ <FileSpreadsheet className="mr-2 h-4 w-4" />
189
+ <span>Download CSV</span>
190
+ </DropdownMenuItem>
191
+ <DropdownMenuItem
192
+ onClick={() => handleDownload('sql')}
193
+ disabled={disabled}
194
+ >
195
+ <FileCode className="mr-2 h-4 w-4" />
196
+ <span>Download SQL</span>
197
+ </DropdownMenuItem>
198
+ </DropdownMenuContent>
199
+ </DropdownMenu>
200
+ );
201
+ });
202
+
203
+ DownloadButton.displayName = 'DownloadButton';
204
+
205
+ export default DownloadButton;
@@ -0,0 +1,30 @@
1
+ // components/edit-error-alert.jsx
2
+ 'use client';
3
+
4
+ import React from 'react';
5
+ import { AlertCircle, X } from 'lucide-react';
6
+ import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
7
+
8
+ export function EditErrorAlert({ error, onDismiss }) {
9
+ if (!error) return null;
10
+
11
+ return (
12
+ <Alert variant="destructive" className="mb-4">
13
+ <AlertCircle className="h-4 w-4" />
14
+ <AlertTitle className="flex items-center justify-between">
15
+ <span>Failed to save changes</span>
16
+ {onDismiss && (
17
+ <button
18
+ onClick={onDismiss}
19
+ className="p-1 hover:bg-destructive/10 rounded-full"
20
+ >
21
+ <X className="h-4 w-4" />
22
+ </button>
23
+ )}
24
+ </AlertTitle>
25
+ <AlertDescription>{error.message}</AlertDescription>
26
+ </Alert>
27
+ );
28
+ }
29
+
30
+ export default EditErrorAlert;
@@ -0,0 +1,163 @@
1
+ // components/editable-cell.jsx
2
+
3
+ 'use client';
4
+
5
+ import React, { useState, useEffect, useRef, useCallback, useMemo } from 'react';
6
+ import { TableCell } from '@/components/ui/table';
7
+ import { Input } from '@/components/ui/input';
8
+ import {
9
+ Select,
10
+ SelectContent,
11
+ SelectItem,
12
+ SelectTrigger,
13
+ SelectValue,
14
+ } from "@/components/ui/select";
15
+
16
+ export function EditableCell({
17
+ value: initialValue,
18
+ row: _row,
19
+ column,
20
+ schema,
21
+ onChange,
22
+ onStartEdit,
23
+ isEditing
24
+ }) {
25
+ const cleanValue = typeof initialValue === 'string' ?
26
+ initialValue.replace(/^'|'$/g, '') :
27
+ initialValue;
28
+
29
+ const [value, setValue] = useState(cleanValue);
30
+ const [width, setWidth] = useState('auto');
31
+ const cellRef = useRef(null);
32
+ const inputRef = useRef(null);
33
+
34
+ // Find column schema and extract column type and constraints
35
+ const columnSchema = schema.find(col => col.name === column);
36
+ const allowedValues = useMemo(() => columnSchema?.check || null, [columnSchema]);
37
+ const isBoolean = useMemo(() => {
38
+ const type = columnSchema?.type?.toLowerCase() || '';
39
+ return type === 'boolean' || type === 'bool' || (type === 'integer' && column.toLowerCase().startsWith('is_'));
40
+ }, [columnSchema, column]);
41
+
42
+ useEffect(() => {
43
+ setValue(cleanValue);
44
+ }, [cleanValue]);
45
+
46
+ useEffect(() => {
47
+ if (cellRef.current && !isEditing) {
48
+ const cellWidth = cellRef.current.offsetWidth;
49
+ setWidth(`${cellWidth}px`);
50
+ }
51
+ }, [isEditing]);
52
+
53
+ useEffect(() => {
54
+ if (isEditing && inputRef.current) {
55
+ inputRef.current.focus();
56
+ inputRef.current.select();
57
+ }
58
+ }, [isEditing]);
59
+
60
+ // Allow editing of primary key now.
61
+ const isPrimaryKey = columnSchema?.pk === 1;
62
+
63
+ const handleChange = useCallback((newValue) => {
64
+ // Convert boolean values to 1/0 for storage if it's a boolean field
65
+ const processedValue = isBoolean ?
66
+ (newValue === 'true' ? 1 : newValue === 'false' ? 0 : newValue) :
67
+ newValue;
68
+
69
+ setValue(newValue);
70
+ onChange?.(processedValue);
71
+ }, [onChange, isBoolean]);
72
+
73
+ const handleCellClick = useCallback(() => {
74
+ // Removed isPrimaryKey check so that even primary key cells can be edited
75
+ if (!isEditing && onStartEdit) {
76
+ onStartEdit(cleanValue);
77
+ }
78
+ }, [isEditing, onStartEdit, cleanValue]);
79
+
80
+ const baseClasses = "border-x border-neutral-200 px-3 py-2.5 text-xs font-mono whitespace-nowrap";
81
+
82
+ // Display formatting for cell value when not editing
83
+ const displayValue = useMemo(() => {
84
+ if (cleanValue === null || cleanValue === undefined) return 'null';
85
+ if (isBoolean) {
86
+ return cleanValue === 1 || cleanValue === '1' || cleanValue === 'true' ? 'true' : 'false';
87
+ }
88
+ return cleanValue.toString();
89
+ }, [cleanValue, isBoolean]);
90
+
91
+ if (!isEditing) {
92
+ return (
93
+ <TableCell
94
+ ref={cellRef}
95
+ className={`${baseClasses} cursor-pointer hover:bg-muted/50`}
96
+ onClick={handleCellClick}
97
+ >
98
+ {displayValue}
99
+ </TableCell>
100
+ );
101
+ }
102
+
103
+ // Render boolean dropdown
104
+ if (isBoolean) {
105
+ return (
106
+ <TableCell className={`${baseClasses} p-0`} style={{ width }}>
107
+ <div className="w-full h-full">
108
+ <Select
109
+ value={displayValue}
110
+ onValueChange={handleChange}
111
+ defaultOpen={isEditing}
112
+ >
113
+ <SelectTrigger className="w-full h-9 min-w-0 rounded-none border-0 bg-orange-50 text-orange-900">
114
+ <SelectValue placeholder="Select value" />
115
+ </SelectTrigger>
116
+ <SelectContent className="min-w-[8rem]">
117
+ <SelectItem value="true">true</SelectItem>
118
+ <SelectItem value="false">false</SelectItem>
119
+ </SelectContent>
120
+ </Select>
121
+ </div>
122
+ </TableCell>
123
+ );
124
+ }
125
+
126
+ // Render check constraint dropdown
127
+ if (allowedValues?.length > 0) {
128
+ return (
129
+ <TableCell className={`${baseClasses} p-0`} style={{ width }}>
130
+ <div className="w-full h-full">
131
+ <Select
132
+ value={value ?? allowedValues[0]}
133
+ onValueChange={handleChange}
134
+ defaultOpen={isEditing}
135
+ >
136
+ <SelectTrigger className="w-full h-9 min-w-0 rounded-none border-0 bg-orange-50 text-orange-900">
137
+ <SelectValue placeholder={`Select ${column}`} />
138
+ </SelectTrigger>
139
+ <SelectContent className="min-w-[8rem]">
140
+ {allowedValues.map(allowedValue => (
141
+ <SelectItem key={allowedValue} value={allowedValue}>
142
+ {allowedValue}
143
+ </SelectItem>
144
+ ))}
145
+ </SelectContent>
146
+ </Select>
147
+ </div>
148
+ </TableCell>
149
+ );
150
+ }
151
+
152
+ // Default input for other fields
153
+ return (
154
+ <TableCell className={`${baseClasses} p-0`} style={{ width }}>
155
+ <Input
156
+ ref={inputRef}
157
+ value={value ?? ''}
158
+ onChange={(e) => handleChange(e.target.value)}
159
+ className="w-full min-w-0 rounded-none border-0 bg-orange-50 text-orange-900"
160
+ />
161
+ </TableCell>
162
+ );
163
+ }