@tulip-systems/core 0.5.7 → 0.5.9

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 (304) hide show
  1. package/dist/components/client.mjs +7 -7
  2. package/dist/components/common/icons.d.mts +52 -52
  3. package/dist/components/common/icons.d.mts.map +1 -1
  4. package/dist/components/common/status.d.mts +3 -3
  5. package/dist/components/common/status.d.mts.map +1 -1
  6. package/dist/components/editor/components/content.client.d.mts +2 -2
  7. package/dist/components/editor/components/content.client.d.mts.map +1 -1
  8. package/dist/components/editor/components/editor.client.d.mts +6 -6
  9. package/dist/components/editor/components/editor.client.d.mts.map +1 -1
  10. package/dist/components/editor/components/menu.client.d.mts +3 -3
  11. package/dist/components/editor/components/menu.client.d.mts.map +1 -1
  12. package/dist/components/editor/components/menu.client.mjs +1 -1
  13. package/dist/components/header/back-button.client.d.mts +2 -2
  14. package/dist/components/header/back-button.client.d.mts.map +1 -1
  15. package/dist/components/header/bottom-bar.client.d.mts +3 -3
  16. package/dist/components/header/bottom-bar.client.d.mts.map +1 -1
  17. package/dist/components/header/bottom-bar.client.mjs +1 -1
  18. package/dist/components/header/breadcrumbs.client.d.mts +7 -7
  19. package/dist/components/header/breadcrumbs.client.d.mts.map +1 -1
  20. package/dist/components/header/breadcrumbs.client.mjs +1 -1
  21. package/dist/components/header/header.client.d.mts +2 -2
  22. package/dist/components/header/mobile-nav-switcher.client.d.mts +2 -2
  23. package/dist/components/header/top-bar.client.d.mts +4 -4
  24. package/dist/components/header/top-bar.client.mjs +1 -1
  25. package/dist/components/layouts/admin-content.client.d.mts +2 -2
  26. package/dist/components/layouts/admin-error-pages.d.mts +23 -0
  27. package/dist/components/layouts/admin-error-pages.d.mts.map +1 -0
  28. package/dist/components/layouts/admin-error-pages.mjs +60 -0
  29. package/dist/components/layouts/admin-error-pages.mjs.map +1 -0
  30. package/dist/components/layouts/admin-layout.d.mts +2 -2
  31. package/dist/components/layouts/admin-layout.d.mts.map +1 -1
  32. package/dist/components/layouts/admin-loading.d.mts +2 -2
  33. package/dist/components/layouts/admin-loading.d.mts.map +1 -1
  34. package/dist/components/layouts/empty-page.d.mts +4 -4
  35. package/dist/components/layouts/empty-page.d.mts.map +1 -1
  36. package/dist/components/layouts/empty-page.mjs.map +1 -1
  37. package/dist/components/layouts/error-page.d.mts +35 -10
  38. package/dist/components/layouts/error-page.d.mts.map +1 -1
  39. package/dist/components/layouts/error-page.mjs +36 -40
  40. package/dist/components/layouts/error-page.mjs.map +1 -1
  41. package/dist/components/layouts/error-sections.d.mts +29 -0
  42. package/dist/components/layouts/error-sections.d.mts.map +1 -0
  43. package/dist/components/layouts/error-sections.mjs +47 -0
  44. package/dist/components/layouts/error-sections.mjs.map +1 -0
  45. package/dist/components/layouts/list-layout.d.mts +2 -2
  46. package/dist/components/layouts/list-layout.d.mts.map +1 -1
  47. package/dist/components/layouts/providers.client.d.mts +2 -2
  48. package/dist/components/layouts/root-error-pages.d.mts +10 -0
  49. package/dist/components/layouts/root-error-pages.d.mts.map +1 -0
  50. package/dist/components/layouts/root-error-pages.mjs +17 -0
  51. package/dist/components/layouts/root-error-pages.mjs.map +1 -0
  52. package/dist/components/layouts/root-layout.server.d.mts +2 -2
  53. package/dist/components/layouts/root-layout.server.d.mts.map +1 -1
  54. package/dist/components/layouts/root-loading.d.mts +2 -2
  55. package/dist/components/layouts/root-loading.d.mts.map +1 -1
  56. package/dist/components/layouts/tab-layout.d.mts +2 -2
  57. package/dist/components/layouts/tab-layout.d.mts.map +1 -1
  58. package/dist/components/layouts/tab-layout.mjs +1 -1
  59. package/dist/components/lists/data-list.d.mts +5 -5
  60. package/dist/components/lists/data-list.d.mts.map +1 -1
  61. package/dist/components/lists/data-stack.d.mts +8 -8
  62. package/dist/components/lists/data-stack.d.mts.map +1 -1
  63. package/dist/components/navigation/admin-sidebar-header.client.mjs +2 -2
  64. package/dist/components/navigation/admin-sidebar-paths.client.d.mts +10 -10
  65. package/dist/components/navigation/admin-sidebar-paths.client.mjs +1 -1
  66. package/dist/components/navigation/admin-sidebar-skeleton.mjs +1 -1
  67. package/dist/components/ui/accordion.d.mts +5 -5
  68. package/dist/components/ui/accordion.d.mts.map +1 -1
  69. package/dist/components/ui/alert-dialog.d.mts +12 -12
  70. package/dist/components/ui/alert-dialog.d.mts.map +1 -1
  71. package/dist/components/ui/alert.d.mts +6 -6
  72. package/dist/components/ui/alert.d.mts.map +1 -1
  73. package/dist/components/ui/aspect-ratio.d.mts +2 -2
  74. package/dist/components/ui/aspect-ratio.d.mts.map +1 -1
  75. package/dist/components/ui/avatar.client.d.mts +4 -4
  76. package/dist/components/ui/badge.d.mts +4 -4
  77. package/dist/components/ui/badge.d.mts.map +1 -1
  78. package/dist/components/ui/breadcrumb.d.mts +8 -8
  79. package/dist/components/ui/breadcrumb.d.mts.map +1 -1
  80. package/dist/components/ui/button.d.mts +5 -5
  81. package/dist/components/ui/calendar.d.mts +3 -3
  82. package/dist/components/ui/card.d.mts +7 -7
  83. package/dist/components/ui/carousel.d.mts +6 -6
  84. package/dist/components/ui/chart.client.d.mts +5 -5
  85. package/dist/components/ui/checkbox.d.mts +2 -2
  86. package/dist/components/ui/collapsible.client.d.mts +4 -4
  87. package/dist/components/ui/color-picker.client.d.mts +2 -2
  88. package/dist/components/ui/combobox-dropdown.client.d.mts +2 -2
  89. package/dist/components/ui/combobox-dropdown.client.mjs +1 -1
  90. package/dist/components/ui/combobox.client.d.mts +2 -2
  91. package/dist/components/ui/combobox.client.mjs +1 -1
  92. package/dist/components/ui/command.d.mts +10 -10
  93. package/dist/components/ui/context-menu.d.mts +16 -16
  94. package/dist/components/ui/date-picker.client.d.mts +2 -2
  95. package/dist/components/ui/date-picker.client.mjs +1 -1
  96. package/dist/components/ui/dialog.client.d.mts +11 -11
  97. package/dist/components/ui/drawer.client.d.mts +11 -11
  98. package/dist/components/ui/dropdown-menu.d.mts +18 -18
  99. package/dist/components/ui/dropdown-menu.d.mts.map +1 -1
  100. package/dist/components/ui/dropdown-menu.mjs +2 -2
  101. package/dist/components/ui/dropdown-menu.mjs.map +1 -1
  102. package/dist/components/ui/form.client.d.mts +7 -7
  103. package/dist/components/ui/hover-card.client.d.mts +4 -4
  104. package/dist/components/ui/input-recipient.d.mts +2 -2
  105. package/dist/components/ui/input.d.mts +2 -2
  106. package/dist/components/ui/label.d.mts +2 -2
  107. package/dist/components/ui/navigation-menu.d.mts +11 -11
  108. package/dist/components/ui/pagination.d.mts +8 -8
  109. package/dist/components/ui/popover.d.mts +5 -5
  110. package/dist/components/ui/progress.client.d.mts +2 -2
  111. package/dist/components/ui/radio-group.d.mts +3 -3
  112. package/dist/components/ui/resizable.client.d.mts +4 -4
  113. package/dist/components/ui/scroll-area.d.mts +3 -3
  114. package/dist/components/ui/select.client.d.mts +11 -11
  115. package/dist/components/ui/separator.d.mts +2 -2
  116. package/dist/components/ui/sheet.client.d.mts +9 -9
  117. package/dist/components/ui/sidebar.client.d.mts +26 -26
  118. package/dist/components/ui/sidebar.client.mjs +2 -2
  119. package/dist/components/ui/skeleton.d.mts +2 -2
  120. package/dist/components/ui/slider.d.mts +2 -2
  121. package/dist/components/ui/sonner.client.d.mts +2 -2
  122. package/dist/components/ui/switch.d.mts +2 -2
  123. package/dist/components/ui/tabs.d.mts +5 -5
  124. package/dist/components/ui/textarea.d.mts +2 -2
  125. package/dist/components/ui/time-input.client.d.mts +2 -2
  126. package/dist/components/ui/toggle-group.client.d.mts +3 -3
  127. package/dist/components/ui/toggle.d.mts +2 -2
  128. package/dist/components/ui/toggle.d.mts.map +1 -1
  129. package/dist/components/ui/tooltip.client.d.mts +5 -5
  130. package/dist/components.d.mts +5 -4
  131. package/dist/components.mjs +18 -17
  132. package/dist/data-tables/client.d.mts +2 -6
  133. package/dist/data-tables/client.mjs +2 -6
  134. package/dist/lib/hooks/use-indicator.d.mts +2 -2
  135. package/dist/lib.mjs +1 -1
  136. package/dist/modules/auth/components/allowed.client.d.mts +2 -2
  137. package/dist/modules/auth/components/auth-layout.server.d.mts +2 -2
  138. package/dist/modules/auth/components/auth-loading.d.mts +2 -2
  139. package/dist/modules/auth/components/auth-loading.d.mts.map +1 -1
  140. package/dist/modules/auth/components/create-first-user-page.client.d.mts +2 -2
  141. package/dist/modules/auth/components/create-first-user-page.client.mjs +1 -1
  142. package/dist/modules/auth/components/forget-password-page.client.d.mts +2 -2
  143. package/dist/modules/auth/components/guard-first-user.server.d.mts +2 -2
  144. package/dist/modules/auth/components/guard.server.d.mts +2 -2
  145. package/dist/modules/auth/components/login-page.client.d.mts +2 -2
  146. package/dist/modules/auth/components/login-page.client.mjs +1 -1
  147. package/dist/modules/auth/components/reset-password-page.client.d.mts +2 -2
  148. package/dist/modules/auth/components/reset-password-page.client.mjs +1 -1
  149. package/dist/modules/auth/components/update-password-command.d.mts +2 -2
  150. package/dist/modules/auth/db/schema.d.mts +73 -73
  151. package/dist/modules/auth/db/schema.d.mts.map +1 -1
  152. package/dist/modules/auth/handler/client.client.d.mts +4 -4
  153. package/dist/modules/auth/hooks/use-permission.d.mts +3 -3
  154. package/dist/modules/auth/hooks/use-session.d.mts +4 -4
  155. package/dist/modules/auth/lib/helpers.server.d.mts +2 -2
  156. package/dist/modules/auth/lib/helpers.server.d.mts.map +1 -1
  157. package/dist/modules/commands/components/alert-dialog-command.client.d.mts +10 -10
  158. package/dist/modules/commands/components/alert-dialog-command.client.d.mts.map +1 -1
  159. package/dist/modules/commands/components/click-command.client.d.mts +2 -2
  160. package/dist/modules/commands/components/click-command.client.d.mts.map +1 -1
  161. package/dist/modules/commands/components/command-trigger.client.d.mts +6 -6
  162. package/dist/modules/commands/components/command-trigger.client.d.mts.map +1 -1
  163. package/dist/modules/commands/components/command-trigger.client.mjs +1 -1
  164. package/dist/modules/commands/components/dialog-command.client.d.mts +8 -8
  165. package/dist/modules/commands/components/dialog-command.client.d.mts.map +1 -1
  166. package/dist/modules/commands/components/dialog-command.client.mjs +1 -1
  167. package/dist/modules/commands/components/dropdown-command.client.d.mts +5 -5
  168. package/dist/modules/commands/components/dropdown-command.client.d.mts.map +1 -1
  169. package/dist/modules/commands/components/empty-command.client.d.mts +2 -2
  170. package/dist/modules/commands/components/empty-command.client.d.mts.map +1 -1
  171. package/dist/modules/commands/components/form-dialog-command.client.d.mts +11 -11
  172. package/dist/modules/commands/components/form-dialog-command.client.d.mts.map +1 -1
  173. package/dist/modules/commands/components/form-dialog-command.client.mjs +1 -1
  174. package/dist/modules/commands/hooks/use-command-mutation.client.d.mts +3 -3
  175. package/dist/modules/commands/menus/context-menu.client.d.mts +2 -2
  176. package/dist/modules/commands/menus/context-menu.client.d.mts.map +1 -1
  177. package/dist/modules/commands/menus/dropdown-menu.client.d.mts +3 -3
  178. package/dist/modules/commands/menus/dropdown-menu.client.d.mts.map +1 -1
  179. package/dist/modules/commands/menus/dropdown-menu.client.mjs +1 -1
  180. package/dist/modules/commands/menus/inline-menu.client.d.mts +3 -3
  181. package/dist/modules/commands/menus/inline-menu.client.d.mts.map +1 -1
  182. package/dist/modules/commands/menus/responsive-menu.client.d.mts +3 -3
  183. package/dist/modules/commands/menus/responsive-menu.client.d.mts.map +1 -1
  184. package/dist/modules/commands/utils/archive-command.client.d.mts +3 -3
  185. package/dist/modules/commands/utils/archive-command.client.d.mts.map +1 -1
  186. package/dist/modules/commands/utils/delete-command.client.d.mts +3 -3
  187. package/dist/modules/commands/utils/delete-command.client.d.mts.map +1 -1
  188. package/dist/modules/config/db/helpers.d.mts +5 -5
  189. package/dist/modules/config/db/helpers.d.mts.map +1 -1
  190. package/dist/modules/data-tables/components/cell/common.client.d.mts +5 -5
  191. package/dist/modules/data-tables/components/column-header.d.mts +2 -2
  192. package/dist/modules/data-tables/components/filters/combobox.client.d.mts +2 -2
  193. package/dist/modules/data-tables/components/filters/combobox.client.mjs +1 -1
  194. package/dist/modules/data-tables/components/filters/slider.client.d.mts +2 -2
  195. package/dist/modules/data-tables/components/filters/slider.client.mjs +1 -1
  196. package/dist/modules/data-tables/components/header.d.mts +4 -4
  197. package/dist/modules/data-tables/components/layout.d.mts +2 -2
  198. package/dist/modules/data-tables/components/search-input.client.d.mts +2 -2
  199. package/dist/modules/data-tables/components/skeleton.d.mts +2 -2
  200. package/dist/modules/data-tables/components/table.d.mts +7 -7
  201. package/dist/modules/data-tables/components/toolbar.d.mts +3 -3
  202. package/dist/modules/data-tables/hooks/use-context.client.d.mts +2 -2
  203. package/dist/modules/data-tables/lib/converters/search.mjs +2 -2
  204. package/dist/modules/data-tables/lib/converters/search.mjs.map +1 -1
  205. package/dist/modules/data-tables/tables/data-table/components/table.d.mts +2 -2
  206. package/dist/modules/data-tables/tables/inline-table/components/cells/common.d.mts +2 -2
  207. package/dist/modules/data-tables/tables/inline-table/components/cells/common.d.mts.map +1 -1
  208. package/dist/modules/data-tables/tables/inline-table/components/cells/drag-handle.client.d.mts +2 -2
  209. package/dist/modules/data-tables/tables/inline-table/components/{inputs → cells}/read-only.d.mts +3 -3
  210. package/dist/modules/data-tables/tables/inline-table/components/cells/read-only.d.mts.map +1 -0
  211. package/dist/modules/data-tables/tables/inline-table/components/{inputs → cells}/read-only.mjs +1 -1
  212. package/dist/modules/data-tables/tables/inline-table/components/cells/read-only.mjs.map +1 -0
  213. package/dist/modules/data-tables/tables/inline-table/components/table.d.mts +2 -2
  214. package/dist/modules/data-tables/tables/inline-table/components/table.mjs +1 -1
  215. package/dist/modules/data-tables/tables/inline-table/hooks/context.client.d.mts +2 -2
  216. package/dist/modules/data-tables/tables/inline-table/hooks/context.client.mjs +1 -1
  217. package/dist/modules/inline-edit/components/combobox-dropdown.client.d.mts +2 -2
  218. package/dist/modules/inline-edit/components/combobox.client.d.mts +2 -2
  219. package/dist/modules/inline-edit/components/date-input.client.d.mts +2 -2
  220. package/dist/modules/inline-edit/components/date-input.client.mjs +1 -1
  221. package/dist/modules/inline-edit/components/date-picker.client.d.mts +2 -2
  222. package/dist/modules/inline-edit/components/date-picker.client.mjs +1 -1
  223. package/dist/modules/inline-edit/components/editor.client.d.mts +2 -2
  224. package/dist/modules/inline-edit/components/input-recipient.client.d.mts +2 -2
  225. package/dist/modules/inline-edit/components/input-toggle.client.d.mts +2 -2
  226. package/dist/modules/inline-edit/components/input.client.d.mts +4 -4
  227. package/dist/modules/inline-edit/components/select.client.d.mts +6 -6
  228. package/dist/modules/inline-edit/components/switch.client.d.mts +2 -2
  229. package/dist/modules/inline-edit/components/toggle.client.d.mts +2 -2
  230. package/dist/modules/inline-edit/hooks/context.client.d.mts +2 -2
  231. package/dist/modules/router/handler/init.server.d.mts +6 -6
  232. package/dist/modules/router/handler/init.server.d.mts.map +1 -1
  233. package/dist/modules/router/lib/query-client.server.d.mts +2 -2
  234. package/dist/modules/router/lib/query-client.server.d.mts.map +1 -1
  235. package/dist/modules/storage/components/dropzone-context.client.d.mts +2 -2
  236. package/dist/modules/storage/components/dropzone-context.client.d.mts.map +1 -1
  237. package/dist/modules/storage/components/dropzone.client.d.mts +5 -5
  238. package/dist/modules/storage/components/dropzone.client.d.mts.map +1 -1
  239. package/dist/modules/storage/components/image-grid.client.d.mts +3 -3
  240. package/dist/modules/storage/components/image-grid.client.d.mts.map +1 -1
  241. package/dist/modules/storage/components/image-grid.client.mjs +3 -3
  242. package/dist/modules/storage/components/upload-zone.client.d.mts +2 -2
  243. package/dist/modules/storage/components/upload-zone.client.d.mts.map +1 -1
  244. package/dist/modules/storage/lib/router.server.d.mts +2342 -2342
  245. package/dist/modules/storage/lib/router.server.d.mts.map +1 -1
  246. package/dist/modules/storage/lib/schema.d.mts +92 -92
  247. package/dist/modules/storage/lib/schema.d.mts.map +1 -1
  248. package/dist/modules/storage/lib/schema.mjs +1 -1
  249. package/dist/modules/storage/lib/service.server.d.mts +15 -15
  250. package/dist/modules/storage/lib/service.server.mjs +2 -2
  251. package/dist/modules/storage/lib/service.server.mjs.map +1 -1
  252. package/dist/modules/storage/lib/validators.d.mts +85 -85
  253. package/dist/modules/storage/lib/validators.d.mts.map +1 -1
  254. package/package.json +1 -1
  255. package/src/components/entry.ts +3 -2
  256. package/src/components/layouts/admin-error-pages.tsx +109 -0
  257. package/src/components/layouts/empty-page.tsx +0 -17
  258. package/src/components/layouts/error-page.tsx +58 -44
  259. package/src/components/layouts/error-sections.tsx +52 -0
  260. package/src/components/layouts/root-error-pages.tsx +12 -0
  261. package/src/modules/data-tables/entry.client.ts +1 -5
  262. package/src/modules/data-tables/lib/converters/search.ts +2 -2
  263. package/src/modules/storage/lib/service.server.ts +1 -1
  264. package/dist/components/layouts/not-allowed-page.d.mts +0 -22
  265. package/dist/components/layouts/not-allowed-page.d.mts.map +0 -1
  266. package/dist/components/layouts/not-allowed-page.mjs +0 -25
  267. package/dist/components/layouts/not-allowed-page.mjs.map +0 -1
  268. package/dist/components/layouts/not-found-page.d.mts +0 -8
  269. package/dist/components/layouts/not-found-page.d.mts.map +0 -1
  270. package/dist/components/layouts/not-found-page.mjs +0 -20
  271. package/dist/components/layouts/not-found-page.mjs.map +0 -1
  272. package/dist/components/layouts/not-found-section.mjs +0 -30
  273. package/dist/components/layouts/not-found-section.mjs.map +0 -1
  274. package/dist/modules/data-tables/tables/inline-table/components/inputs/advanced-select.client.d.mts +0 -29
  275. package/dist/modules/data-tables/tables/inline-table/components/inputs/advanced-select.client.d.mts.map +0 -1
  276. package/dist/modules/data-tables/tables/inline-table/components/inputs/advanced-select.client.mjs +0 -52
  277. package/dist/modules/data-tables/tables/inline-table/components/inputs/advanced-select.client.mjs.map +0 -1
  278. package/dist/modules/data-tables/tables/inline-table/components/inputs/combobox.client.d.mts +0 -27
  279. package/dist/modules/data-tables/tables/inline-table/components/inputs/combobox.client.d.mts.map +0 -1
  280. package/dist/modules/data-tables/tables/inline-table/components/inputs/combobox.client.mjs +0 -29
  281. package/dist/modules/data-tables/tables/inline-table/components/inputs/combobox.client.mjs.map +0 -1
  282. package/dist/modules/data-tables/tables/inline-table/components/inputs/input.client.d.mts +0 -39
  283. package/dist/modules/data-tables/tables/inline-table/components/inputs/input.client.d.mts.map +0 -1
  284. package/dist/modules/data-tables/tables/inline-table/components/inputs/input.client.mjs +0 -71
  285. package/dist/modules/data-tables/tables/inline-table/components/inputs/input.client.mjs.map +0 -1
  286. package/dist/modules/data-tables/tables/inline-table/components/inputs/read-only.d.mts.map +0 -1
  287. package/dist/modules/data-tables/tables/inline-table/components/inputs/read-only.mjs.map +0 -1
  288. package/dist/modules/data-tables/tables/inline-table/components/inputs/select.client.d.mts +0 -33
  289. package/dist/modules/data-tables/tables/inline-table/components/inputs/select.client.d.mts.map +0 -1
  290. package/dist/modules/data-tables/tables/inline-table/components/inputs/select.client.mjs +0 -52
  291. package/dist/modules/data-tables/tables/inline-table/components/inputs/select.client.mjs.map +0 -1
  292. package/dist/modules/data-tables/tables/inline-table/hooks/use-input.client.d.mts +0 -17
  293. package/dist/modules/data-tables/tables/inline-table/hooks/use-input.client.d.mts.map +0 -1
  294. package/dist/modules/data-tables/tables/inline-table/hooks/use-input.client.mjs +0 -53
  295. package/dist/modules/data-tables/tables/inline-table/hooks/use-input.client.mjs.map +0 -1
  296. package/src/components/layouts/not-allowed-page.tsx +0 -44
  297. package/src/components/layouts/not-found-page.tsx +0 -17
  298. package/src/components/layouts/not-found-section.tsx +0 -26
  299. package/src/modules/data-tables/tables/inline-table/components/inputs/advanced-select.client.tsx +0 -90
  300. package/src/modules/data-tables/tables/inline-table/components/inputs/combobox.client.tsx +0 -109
  301. package/src/modules/data-tables/tables/inline-table/components/inputs/input.client.tsx +0 -108
  302. package/src/modules/data-tables/tables/inline-table/components/inputs/select.client.tsx +0 -102
  303. package/src/modules/data-tables/tables/inline-table/hooks/use-input.client.ts +0 -65
  304. /package/src/modules/data-tables/tables/inline-table/components/{inputs → cells}/read-only.tsx +0 -0
@@ -91,19 +91,19 @@ declare class StorageService<TSchema extends TDatabaseSchema> {
91
91
  * Upload file to S3 and add it to the database
92
92
  **/
93
93
  uploadFile(input: UploadFileSchema & Pick<PutObjectInput, "body">): Promise<{
94
- size: number | null;
95
- readonly: boolean | null;
96
94
  id: string;
95
+ readonly: boolean | null;
96
+ type: "file" | "folder" | null;
97
+ size: number | null;
98
+ isPending: boolean;
97
99
  createdAt: Date;
98
100
  updatedAt: Date;
99
101
  name: string;
100
- type: "file" | "folder" | null;
101
- isPending: boolean;
102
102
  mode: "private" | "public" | null;
103
- hidden: boolean | null;
104
103
  namespace: string;
105
104
  subtype: "image" | "document" | "spreadsheet" | "video" | "audio" | "archive" | "other";
106
105
  contentType: string | null;
106
+ hidden: boolean | null;
107
107
  createdBy: string | null;
108
108
  isDeleted: boolean;
109
109
  orphanedAt: Date | null;
@@ -116,19 +116,19 @@ declare class StorageService<TSchema extends TDatabaseSchema> {
116
116
  id: string;
117
117
  presignedUrl: string;
118
118
  node: {
119
- size: number | null;
120
- readonly: boolean | null;
121
119
  id: string;
120
+ readonly: boolean | null;
121
+ type: "file" | "folder" | null;
122
+ size: number | null;
123
+ isPending: boolean;
122
124
  createdAt: Date;
123
125
  updatedAt: Date;
124
126
  name: string;
125
- type: "file" | "folder" | null;
126
- isPending: boolean;
127
127
  mode: "private" | "public" | null;
128
- hidden: boolean | null;
129
128
  namespace: string;
130
129
  subtype: "image" | "document" | "spreadsheet" | "video" | "audio" | "archive" | "other";
131
130
  contentType: string | null;
131
+ hidden: boolean | null;
132
132
  createdBy: string | null;
133
133
  isDeleted: boolean;
134
134
  orphanedAt: Date | null;
@@ -151,19 +151,19 @@ declare class StorageService<TSchema extends TDatabaseSchema> {
151
151
  * Create a new folder
152
152
  */
153
153
  createFolder(input: CreateFolderNodeSchema): Promise<{
154
- size: number | null;
155
- readonly: boolean | null;
156
154
  id: string;
155
+ readonly: boolean | null;
156
+ type: "file" | "folder" | null;
157
+ size: number | null;
158
+ isPending: boolean;
157
159
  createdAt: Date;
158
160
  updatedAt: Date;
159
161
  name: string;
160
- type: "file" | "folder" | null;
161
- isPending: boolean;
162
162
  mode: "private" | "public" | null;
163
- hidden: boolean | null;
164
163
  namespace: string;
165
164
  subtype: "image" | "document" | "spreadsheet" | "video" | "audio" | "archive" | "other";
166
165
  contentType: string | null;
166
+ hidden: boolean | null;
167
167
  createdBy: string | null;
168
168
  isDeleted: boolean;
169
169
  orphanedAt: Date | null;
@@ -1,7 +1,7 @@
1
1
  import { ServerError } from "../../router/lib/error.server.mjs";
2
- import { generateDefaultUUID } from "../../config/db/helpers.mjs";
3
2
  import { BUCKET_NAME } from "../../../lib/config/constants.mjs";
4
3
  import { getDriveBucketKey, inferNodeSubtype, isFile, isFolder } from "./helpers.mjs";
4
+ import { generateDefaultUUID } from "../../config/db/helpers.mjs";
5
5
  import { convertSearchToQueryParams } from "../../data-tables/lib/converters/search.mjs";
6
6
  import { convertOrderByToQueryParams } from "../../data-tables/lib/converters/sorting.mjs";
7
7
  import { deviceSizes } from "./constants.mjs";
@@ -135,7 +135,7 @@ var StorageService = class {
135
135
  * Upload file to S3 and add it to the database
136
136
  **/
137
137
  async uploadFile(input) {
138
- const id = generateDefaultUUID();
138
+ const id = input.id ?? generateDefaultUUID();
139
139
  return await this.#db.transaction(async (tx) => {
140
140
  const [result] = await tx.insert(nodes).values({
141
141
  id,
@@ -1 +1 @@
1
- {"version":3,"file":"service.server.mjs","names":["#db","#blob","#createGetCommand","#putObject","#createPutCommand"],"sources":["../../../../src/modules/storage/lib/service.server.ts"],"sourcesContent":["import { BUCKET_NAME } from \"@/lib/config/constants\";\nimport { generateDefaultUUID, TDatabaseSchema } from \"@/modules/config/entry\";\nimport { DatabaseClient } from \"@/modules/config/entry.server\";\nimport {\n convertOrderByToQueryParams,\n convertSearchToQueryParams,\n} from \"@/modules/data-tables/entry.server\";\nimport { BulkActionSchema } from \"@/modules/router/entry\";\nimport { ServerError } from \"@/modules/router/lib/error.server\";\nimport {\n DeleteObjectsCommand,\n GetObjectCommand,\n PutObjectCommand,\n S3Client,\n S3ClientConfig,\n} from \"@aws-sdk/client-s3\";\nimport { getSignedUrl } from \"@aws-sdk/s3-request-presigner\";\nimport { addSeconds } from \"date-fns\";\nimport { and, asc, eq, inArray, isNotNull, isNull, SQL } from \"drizzle-orm\";\nimport { after } from \"next/server\";\nimport { deviceSizes } from \"./constants\";\nimport { getDriveBucketKey, inferNodeSubtype, isFile, isFolder } from \"./helpers\";\nimport { nodePresignedUrls, nodes, nodeVariants } from \"./schema\";\nimport {\n CreateFolderNodeSchema,\n FileNode,\n GetFileURLSchema,\n getFileURLSchemaDefaults,\n GetNodesByParentIdInput,\n GetObjectInput,\n getObjectSchema,\n Node,\n PresignFileSchema,\n PutObjectInput,\n putObjectSchema,\n UpdateNodeSchema,\n UploadFileSchema,\n} from \"./validators\";\n\n/**\n * Storage Service Config\n */\nexport type StorageServiceConfig<TSchema extends TDatabaseSchema> = {\n db: DatabaseClient<TSchema>;\n config: S3ClientConfig;\n};\n\n/**\n * Storage Service\n */\nexport class StorageService<TSchema extends TDatabaseSchema> {\n /**\n * S3 Client\n */\n #blob: S3Client;\n #db: DatabaseClient<TSchema>;\n\n /**\n * Constructor\n */\n constructor({ db, config }: StorageServiceConfig<TSchema>) {\n this.#db = db;\n this.#blob = new S3Client(config);\n }\n\n /**\n * Get Blob\n */\n blob() {\n return this.#blob;\n }\n\n /**\n * Create get command\n */\n #createGetCommand(props: GetObjectInput) {\n const input = getObjectSchema.parse(props);\n\n return new GetObjectCommand({\n Bucket: BUCKET_NAME,\n Key: getDriveBucketKey(input.id, input.variant),\n ResponseContentDisposition: input.disposition,\n });\n }\n\n /**\n * Get object\n */\n async getObject(id: string, options: GetFileURLSchema = getFileURLSchemaDefaults) {\n const getCommand = this.#createGetCommand({ ...options, id });\n\n return await this.#blob.send(getCommand);\n }\n\n /**\n * Create put command\n */\n #createPutCommand(props: PutObjectInput) {\n const input = putObjectSchema.parse(props);\n\n return new PutObjectCommand({\n Bucket: BUCKET_NAME,\n Key: getDriveBucketKey(input.id, input.variant),\n Body: input.body,\n ContentType: input.contentType ?? undefined,\n ContentLength: input.size ?? undefined,\n Metadata: {\n nodeId: input.id,\n },\n });\n }\n\n /**\n * Put object\n */\n async #putObject(props: PutObjectInput) {\n const putCommand = this.#createPutCommand(props);\n return await this.#blob.send(putCommand);\n }\n\n /**\n * Get node by id\n */\n async getNodeById(id: string) {\n return this.#db.select().from(nodes).where(eq(nodes.id, id));\n }\n\n /**\n * Get nodes by parent id\n */\n async getNodesByParentId({ filters, ...query }: GetNodesByParentIdInput) {\n const orderBy = convertOrderByToQueryParams(query, nodes, asc(nodes.createdAt));\n const search = convertSearchToQueryParams(query, [nodes.name]);\n\n return this.#db\n .select()\n .from(nodes)\n .where(\n and(\n filters.nodeIds != null ? inArray(nodes.id, filters.nodeIds) : undefined,\n filters.types != null ? inArray(nodes.type, filters.types) : undefined,\n filters.isDeleted != null ? eq(nodes.isDeleted, filters.isDeleted) : undefined,\n filters.isOrphaned === true\n ? isNotNull(nodes.orphanedAt)\n : filters.isOrphaned === false\n ? isNull(nodes.orphanedAt)\n : undefined,\n filters.hidden != null ? eq(nodes.hidden, filters.hidden) : undefined,\n filters.parentId ? eq(nodes.parentId, filters.parentId) : isNull(nodes.parentId),\n eq(nodes.namespace, filters.namespace),\n search,\n ),\n )\n .orderBy(orderBy as SQL);\n }\n\n /**\n * Get file url\n */\n async getSignedURL(node: Node, options: GetFileURLSchema = getFileURLSchemaDefaults) {\n const [presignedUrl] = await this.#db\n .select({ url: nodePresignedUrls.url, expiresAt: nodePresignedUrls.expiresAt })\n .from(nodePresignedUrls)\n .where(\n and(\n eq(nodePresignedUrls.nodeId, node.id),\n eq(nodePresignedUrls.variant, options.variant),\n eq(nodePresignedUrls.disposition, options.disposition),\n ),\n );\n\n if (presignedUrl && presignedUrl.expiresAt > new Date()) return presignedUrl.url;\n\n const expiresIn = 3600 * 24;\n\n // Get the variants\n const variants = await this.#db\n .select()\n .from(nodeVariants)\n .where(eq(nodeVariants.nodeId, node.id));\n\n // If the requested variant does not exist, fallback to main\n const variantExists = variants.find((v) => v.variant === options.variant);\n const variant = variantExists ? options.variant : \"main\";\n\n console.info(\n `Generating new signed url for file: ${node.id} with variant: ${variant} and disposition: ${options.disposition}`,\n );\n\n // Generate the get command\n const getCommand = this.#createGetCommand({\n id: node.id,\n variant,\n disposition: `${options.disposition}; filename=\"${node.name}\"`,\n });\n\n // Generate the presigned url that expires in 24 hours\n const url = await getSignedUrl(this.#blob, getCommand, { expiresIn });\n\n // Add the presigned url to the database\n after(async () => {\n await this.#db\n .insert(nodePresignedUrls)\n .values({\n nodeId: node.id,\n url,\n variant,\n disposition: options.disposition,\n expiresAt: addSeconds(new Date(), expiresIn),\n })\n .onConflictDoUpdate({\n target: [\n nodePresignedUrls.nodeId,\n nodePresignedUrls.variant,\n nodePresignedUrls.disposition,\n ],\n set: { url, expiresAt: addSeconds(new Date(), expiresIn) },\n });\n });\n\n return url;\n }\n\n /**\n * Upload file to S3 and add it to the database\n **/\n async uploadFile(input: UploadFileSchema & Pick<PutObjectInput, \"body\">) {\n const id = generateDefaultUUID();\n\n return await this.#db.transaction(async (tx) => {\n const [result] = await tx\n .insert(nodes)\n .values({\n id,\n type: \"file\",\n name: input.name,\n namespace: input.namespace,\n parentId: input.parentId,\n size: input.size,\n contentType: input.contentType,\n mode: input.mode,\n subtype: inferNodeSubtype(input),\n })\n .returning();\n\n if (!result) {\n throw new ServerError(\"INTERNAL_SERVER_ERROR\", {\n message: \"Oep! Er is iets fout gegaan\",\n });\n }\n\n await this.#putObject({\n id,\n body: input.body,\n variant: \"main\",\n name: input.name,\n contentType: input.contentType,\n size: input.size,\n });\n\n return result;\n });\n }\n\n /**\n * Presign a new upload\n */\n async presignUpload(input: PresignFileSchema) {\n // Generate the put command\n const putCommand = this.#createPutCommand({\n id: input.id,\n name: input.name,\n variant: \"main\",\n contentType: input.contentType,\n size: input.size,\n });\n\n // Generate the presigned url\n const presignedUrl = await getSignedUrl(this.#blob, putCommand, { expiresIn: 3600 });\n\n const [node] = await this.#db\n .insert(nodes)\n .values({\n ...input,\n subtype: inferNodeSubtype(input),\n isPending: true,\n type: \"file\",\n id: input.id,\n })\n .returning();\n\n if (!node) {\n throw new ServerError(\"INTERNAL_SERVER_ERROR\", {\n message: \"Oep! Er is iets fout gegaan\",\n });\n }\n\n // Return the result\n return { id: input.id, presignedUrl, node };\n }\n\n /**\n * Confirm a new upload\n */\n async confirmUpload(input: { id: string }) {\n const [result] = await this.#db\n .update(nodes)\n .set({ isPending: false })\n .where(eq(nodes.id, input.id))\n .returning();\n\n if (!result) {\n throw new ServerError(\"NOT_FOUND\", { message: \"File not found\" });\n }\n\n /**\n * Generate the preview version of the file\n */\n // after(async () => {});\n await this.generatePreviews(input);\n\n return result as FileNode;\n }\n\n /**\n * Generate preview version of the file\n */\n async generatePreviews(input: { id: string }) {\n /**\n * Get the main version of the file\n */\n const getCommand = this.#createGetCommand({ id: input.id, variant: \"main\" });\n\n const response = await this.#blob.send(getCommand);\n const contentType = response.ContentType;\n if (!response.Body) {\n throw new ServerError(\"INTERNAL_SERVER_ERROR\", {\n message: \"Oep! Er is iets fout gegaan\",\n });\n }\n\n /**\n * Transform the main version of the file to a buffer\n */\n const byteArray = await response.Body.transformToByteArray();\n const buffer = Buffer.from(byteArray);\n\n /**\n * Generate the preview versions for images\n */\n if (contentType?.startsWith(\"image/\")) {\n const sharp = await import(\"sharp\");\n\n // Generate the preview versions\n await Promise.allSettled(\n deviceSizes.flatMap(async (width) => {\n // Generate the preview\n const preview = await sharp.default(buffer).resize({ width }).webp().toBuffer();\n\n // Upload the preview and add the variant to the database\n return this.#db.transaction(async (tx) => {\n await this.#putObject({\n id: input.id,\n body: preview,\n variant: `preview-${width}`,\n contentType: \"image/webp\",\n size: preview.byteLength,\n });\n\n await tx.insert(nodeVariants).values({\n nodeId: input.id,\n variant: `preview-${width}`,\n width,\n });\n });\n }),\n );\n }\n }\n\n /**\n * Create a new folder\n */\n async createFolder(input: CreateFolderNodeSchema) {\n const [parent] = input.parentId\n ? await this.#db.select().from(nodes).where(eq(nodes.id, input.parentId))\n : [];\n\n /**\n * Validate\n */\n if (input.parentId && !parent) {\n throw new ServerError(\"BAD_REQUEST\", { message: \"Parent not found\" });\n }\n\n if (parent && !isFolder(parent)) {\n throw new ServerError(\"BAD_REQUEST\", { message: \"Parent is not a folder\" });\n }\n\n if (parent && parent.namespace !== input.namespace) {\n throw new ServerError(\"BAD_REQUEST\", {\n message: \"Parent is not in the same namespace\",\n });\n }\n\n /**\n * Create the folder\n */\n const [result] = await this.#db\n .insert(nodes)\n .values({ ...input, type: \"folder\" })\n .returning();\n\n if (!result) {\n throw new ServerError(\"INTERNAL_SERVER_ERROR\", {\n message: \"Folder kon niet worden aangemaakt\",\n });\n }\n\n return result;\n }\n\n /**\n * Update a node\n */\n async updateNode(input: { id: string; data: UpdateNodeSchema }) {\n const [node] = await this.#db\n .select({ readonly: nodes.readonly })\n .from(nodes)\n .where(eq(nodes.id, input.id));\n\n if (node?.readonly) {\n throw new ServerError(\"BAD_REQUEST\", { message: \"Node is readonly\" });\n }\n\n const [result] = await this.#db\n .update(nodes)\n .set(input.data)\n .where(eq(nodes.id, input.id))\n .returning();\n\n if (!result) {\n throw new ServerError(\"INTERNAL_SERVER_ERROR\", {\n message: \"Node kon niet worden gewijzigd\",\n });\n }\n\n return result;\n }\n\n /**\n * Delete nodes\n */\n async deleteNodes(input: BulkActionSchema) {\n const items = await this.#db\n .select({ id: nodes.id, type: nodes.type, readonly: nodes.readonly })\n .from(nodes)\n .where(inArray(nodes.id, input.ids));\n\n // Check if the nodes are readonly\n if (items.some((item) => item.readonly)) {\n throw new ServerError(\"BAD_REQUEST\", { message: \"Nodes are readonly\" });\n }\n\n // Split the nodes into folders and files\n const folders = items.filter(isFolder).map((folder) => folder.id);\n const files = items.filter(isFile).map((file) => file.id);\n\n // Delete command for S3\n const deleteCommand =\n files.length > 0\n ? new DeleteObjectsCommand({\n Bucket: BUCKET_NAME,\n Delete: {\n Objects: files.map((id) => ({ Key: id })),\n },\n })\n : undefined;\n\n /**\n * Delete files and folders in a transaction\n */\n await this.#db.transaction(async (tx) => {\n await tx.delete(nodes).where(inArray(nodes.id, folders));\n await tx.delete(nodes).where(inArray(nodes.id, files));\n\n if (deleteCommand) await this.#blob.send(deleteCommand);\n });\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAkDA,IAAa,iBAAb,MAA6D;;;;CAI3D;CACA;;;;CAKA,YAAY,EAAE,IAAI,UAAyC;AACzD,QAAKA,KAAM;AACX,QAAKC,OAAQ,IAAI,SAAS,OAAO;;;;;CAMnC,OAAO;AACL,SAAO,MAAKA;;;;;CAMd,kBAAkB,OAAuB;EACvC,MAAM,QAAQ,gBAAgB,MAAM,MAAM;AAE1C,SAAO,IAAI,iBAAiB;GAC1B,QAAQ;GACR,KAAK,kBAAkB,MAAM,IAAI,MAAM,QAAQ;GAC/C,4BAA4B,MAAM;GACnC,CAAC;;;;;CAMJ,MAAM,UAAU,IAAY,UAA4B,0BAA0B;EAChF,MAAM,aAAa,MAAKC,iBAAkB;GAAE,GAAG;GAAS;GAAI,CAAC;AAE7D,SAAO,MAAM,MAAKD,KAAM,KAAK,WAAW;;;;;CAM1C,kBAAkB,OAAuB;EACvC,MAAM,QAAQ,gBAAgB,MAAM,MAAM;AAE1C,SAAO,IAAI,iBAAiB;GAC1B,QAAQ;GACR,KAAK,kBAAkB,MAAM,IAAI,MAAM,QAAQ;GAC/C,MAAM,MAAM;GACZ,aAAa,MAAM,eAAe;GAClC,eAAe,MAAM,QAAQ;GAC7B,UAAU,EACR,QAAQ,MAAM,IACf;GACF,CAAC;;;;;CAMJ,OAAME,UAAW,OAAuB;EACtC,MAAM,aAAa,MAAKC,iBAAkB,MAAM;AAChD,SAAO,MAAM,MAAKH,KAAM,KAAK,WAAW;;;;;CAM1C,MAAM,YAAY,IAAY;AAC5B,SAAO,MAAKD,GAAI,QAAQ,CAAC,KAAK,MAAM,CAAC,MAAM,GAAG,MAAM,IAAI,GAAG,CAAC;;;;;CAM9D,MAAM,mBAAmB,EAAE,SAAS,GAAG,SAAkC;EACvE,MAAM,UAAU,4BAA4B,OAAO,OAAO,IAAI,MAAM,UAAU,CAAC;EAC/E,MAAM,SAAS,2BAA2B,OAAO,CAAC,MAAM,KAAK,CAAC;AAE9D,SAAO,MAAKA,GACT,QAAQ,CACR,KAAK,MAAM,CACX,MACC,IACE,QAAQ,WAAW,OAAO,QAAQ,MAAM,IAAI,QAAQ,QAAQ,GAAG,QAC/D,QAAQ,SAAS,OAAO,QAAQ,MAAM,MAAM,QAAQ,MAAM,GAAG,QAC7D,QAAQ,aAAa,OAAO,GAAG,MAAM,WAAW,QAAQ,UAAU,GAAG,QACrE,QAAQ,eAAe,OACnB,UAAU,MAAM,WAAW,GAC3B,QAAQ,eAAe,QACrB,OAAO,MAAM,WAAW,GACxB,QACN,QAAQ,UAAU,OAAO,GAAG,MAAM,QAAQ,QAAQ,OAAO,GAAG,QAC5D,QAAQ,WAAW,GAAG,MAAM,UAAU,QAAQ,SAAS,GAAG,OAAO,MAAM,SAAS,EAChF,GAAG,MAAM,WAAW,QAAQ,UAAU,EACtC,OACD,CACF,CACA,QAAQ,QAAe;;;;;CAM5B,MAAM,aAAa,MAAY,UAA4B,0BAA0B;EACnF,MAAM,CAAC,gBAAgB,MAAM,MAAKA,GAC/B,OAAO;GAAE,KAAK,kBAAkB;GAAK,WAAW,kBAAkB;GAAW,CAAC,CAC9E,KAAK,kBAAkB,CACvB,MACC,IACE,GAAG,kBAAkB,QAAQ,KAAK,GAAG,EACrC,GAAG,kBAAkB,SAAS,QAAQ,QAAQ,EAC9C,GAAG,kBAAkB,aAAa,QAAQ,YAAY,CACvD,CACF;AAEH,MAAI,gBAAgB,aAAa,4BAAY,IAAI,MAAM,CAAE,QAAO,aAAa;EAE7E,MAAM,YAAY,OAAO;EAUzB,MAAM,WAPW,MAAM,MAAKA,GACzB,QAAQ,CACR,KAAK,aAAa,CAClB,MAAM,GAAG,aAAa,QAAQ,KAAK,GAAG,CAAC,EAGX,MAAM,MAAM,EAAE,YAAY,QAAQ,QAAQ,GACzC,QAAQ,UAAU;AAElD,UAAQ,KACN,uCAAuC,KAAK,GAAG,iBAAiB,QAAQ,oBAAoB,QAAQ,cACrG;EAGD,MAAM,aAAa,MAAKE,iBAAkB;GACxC,IAAI,KAAK;GACT;GACA,aAAa,GAAG,QAAQ,YAAY,cAAc,KAAK,KAAK;GAC7D,CAAC;EAGF,MAAM,MAAM,MAAM,aAAa,MAAKD,MAAO,YAAY,EAAE,WAAW,CAAC;AAGrE,QAAM,YAAY;AAChB,SAAM,MAAKD,GACR,OAAO,kBAAkB,CACzB,OAAO;IACN,QAAQ,KAAK;IACb;IACA;IACA,aAAa,QAAQ;IACrB,WAAW,2BAAW,IAAI,MAAM,EAAE,UAAU;IAC7C,CAAC,CACD,mBAAmB;IAClB,QAAQ;KACN,kBAAkB;KAClB,kBAAkB;KAClB,kBAAkB;KACnB;IACD,KAAK;KAAE;KAAK,WAAW,2BAAW,IAAI,MAAM,EAAE,UAAU;KAAE;IAC3D,CAAC;IACJ;AAEF,SAAO;;;;;CAMT,MAAM,WAAW,OAAwD;EACvE,MAAM,KAAK,qBAAqB;AAEhC,SAAO,MAAM,MAAKA,GAAI,YAAY,OAAO,OAAO;GAC9C,MAAM,CAAC,UAAU,MAAM,GACpB,OAAO,MAAM,CACb,OAAO;IACN;IACA,MAAM;IACN,MAAM,MAAM;IACZ,WAAW,MAAM;IACjB,UAAU,MAAM;IAChB,MAAM,MAAM;IACZ,aAAa,MAAM;IACnB,MAAM,MAAM;IACZ,SAAS,iBAAiB,MAAM;IACjC,CAAC,CACD,WAAW;AAEd,OAAI,CAAC,OACH,OAAM,IAAI,YAAY,yBAAyB,EAC7C,SAAS,+BACV,CAAC;AAGJ,SAAM,MAAKG,UAAW;IACpB;IACA,MAAM,MAAM;IACZ,SAAS;IACT,MAAM,MAAM;IACZ,aAAa,MAAM;IACnB,MAAM,MAAM;IACb,CAAC;AAEF,UAAO;IACP;;;;;CAMJ,MAAM,cAAc,OAA0B;EAE5C,MAAM,aAAa,MAAKC,iBAAkB;GACxC,IAAI,MAAM;GACV,MAAM,MAAM;GACZ,SAAS;GACT,aAAa,MAAM;GACnB,MAAM,MAAM;GACb,CAAC;EAGF,MAAM,eAAe,MAAM,aAAa,MAAKH,MAAO,YAAY,EAAE,WAAW,MAAM,CAAC;EAEpF,MAAM,CAAC,QAAQ,MAAM,MAAKD,GACvB,OAAO,MAAM,CACb,OAAO;GACN,GAAG;GACH,SAAS,iBAAiB,MAAM;GAChC,WAAW;GACX,MAAM;GACN,IAAI,MAAM;GACX,CAAC,CACD,WAAW;AAEd,MAAI,CAAC,KACH,OAAM,IAAI,YAAY,yBAAyB,EAC7C,SAAS,+BACV,CAAC;AAIJ,SAAO;GAAE,IAAI,MAAM;GAAI;GAAc;GAAM;;;;;CAM7C,MAAM,cAAc,OAAuB;EACzC,MAAM,CAAC,UAAU,MAAM,MAAKA,GACzB,OAAO,MAAM,CACb,IAAI,EAAE,WAAW,OAAO,CAAC,CACzB,MAAM,GAAG,MAAM,IAAI,MAAM,GAAG,CAAC,CAC7B,WAAW;AAEd,MAAI,CAAC,OACH,OAAM,IAAI,YAAY,aAAa,EAAE,SAAS,kBAAkB,CAAC;;;;AAOnE,QAAM,KAAK,iBAAiB,MAAM;AAElC,SAAO;;;;;CAMT,MAAM,iBAAiB,OAAuB;;;;EAI5C,MAAM,aAAa,MAAKE,iBAAkB;GAAE,IAAI,MAAM;GAAI,SAAS;GAAQ,CAAC;EAE5E,MAAM,WAAW,MAAM,MAAKD,KAAM,KAAK,WAAW;EAClD,MAAM,cAAc,SAAS;AAC7B,MAAI,CAAC,SAAS,KACZ,OAAM,IAAI,YAAY,yBAAyB,EAC7C,SAAS,+BACV,CAAC;;;;EAMJ,MAAM,YAAY,MAAM,SAAS,KAAK,sBAAsB;EAC5D,MAAM,SAAS,OAAO,KAAK,UAAU;;;;AAKrC,MAAI,aAAa,WAAW,SAAS,EAAE;GACrC,MAAM,QAAQ,MAAM,OAAO;AAG3B,SAAM,QAAQ,WACZ,YAAY,QAAQ,OAAO,UAAU;IAEnC,MAAM,UAAU,MAAM,MAAM,QAAQ,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,MAAM,CAAC,UAAU;AAG/E,WAAO,MAAKD,GAAI,YAAY,OAAO,OAAO;AACxC,WAAM,MAAKG,UAAW;MACpB,IAAI,MAAM;MACV,MAAM;MACN,SAAS,WAAW;MACpB,aAAa;MACb,MAAM,QAAQ;MACf,CAAC;AAEF,WAAM,GAAG,OAAO,aAAa,CAAC,OAAO;MACnC,QAAQ,MAAM;MACd,SAAS,WAAW;MACpB;MACD,CAAC;MACF;KACF,CACH;;;;;;CAOL,MAAM,aAAa,OAA+B;EAChD,MAAM,CAAC,UAAU,MAAM,WACnB,MAAM,MAAKH,GAAI,QAAQ,CAAC,KAAK,MAAM,CAAC,MAAM,GAAG,MAAM,IAAI,MAAM,SAAS,CAAC,GACvE,EAAE;;;;AAKN,MAAI,MAAM,YAAY,CAAC,OACrB,OAAM,IAAI,YAAY,eAAe,EAAE,SAAS,oBAAoB,CAAC;AAGvE,MAAI,UAAU,CAAC,SAAS,OAAO,CAC7B,OAAM,IAAI,YAAY,eAAe,EAAE,SAAS,0BAA0B,CAAC;AAG7E,MAAI,UAAU,OAAO,cAAc,MAAM,UACvC,OAAM,IAAI,YAAY,eAAe,EACnC,SAAS,uCACV,CAAC;;;;EAMJ,MAAM,CAAC,UAAU,MAAM,MAAKA,GACzB,OAAO,MAAM,CACb,OAAO;GAAE,GAAG;GAAO,MAAM;GAAU,CAAC,CACpC,WAAW;AAEd,MAAI,CAAC,OACH,OAAM,IAAI,YAAY,yBAAyB,EAC7C,SAAS,qCACV,CAAC;AAGJ,SAAO;;;;;CAMT,MAAM,WAAW,OAA+C;EAC9D,MAAM,CAAC,QAAQ,MAAM,MAAKA,GACvB,OAAO,EAAE,UAAU,MAAM,UAAU,CAAC,CACpC,KAAK,MAAM,CACX,MAAM,GAAG,MAAM,IAAI,MAAM,GAAG,CAAC;AAEhC,MAAI,MAAM,SACR,OAAM,IAAI,YAAY,eAAe,EAAE,SAAS,oBAAoB,CAAC;EAGvE,MAAM,CAAC,UAAU,MAAM,MAAKA,GACzB,OAAO,MAAM,CACb,IAAI,MAAM,KAAK,CACf,MAAM,GAAG,MAAM,IAAI,MAAM,GAAG,CAAC,CAC7B,WAAW;AAEd,MAAI,CAAC,OACH,OAAM,IAAI,YAAY,yBAAyB,EAC7C,SAAS,kCACV,CAAC;AAGJ,SAAO;;;;;CAMT,MAAM,YAAY,OAAyB;EACzC,MAAM,QAAQ,MAAM,MAAKA,GACtB,OAAO;GAAE,IAAI,MAAM;GAAI,MAAM,MAAM;GAAM,UAAU,MAAM;GAAU,CAAC,CACpE,KAAK,MAAM,CACX,MAAM,QAAQ,MAAM,IAAI,MAAM,IAAI,CAAC;AAGtC,MAAI,MAAM,MAAM,SAAS,KAAK,SAAS,CACrC,OAAM,IAAI,YAAY,eAAe,EAAE,SAAS,sBAAsB,CAAC;EAIzE,MAAM,UAAU,MAAM,OAAO,SAAS,CAAC,KAAK,WAAW,OAAO,GAAG;EACjE,MAAM,QAAQ,MAAM,OAAO,OAAO,CAAC,KAAK,SAAS,KAAK,GAAG;EAGzD,MAAM,gBACJ,MAAM,SAAS,IACX,IAAI,qBAAqB;GACvB,QAAQ;GACR,QAAQ,EACN,SAAS,MAAM,KAAK,QAAQ,EAAE,KAAK,IAAI,EAAE,EAC1C;GACF,CAAC,GACF;;;;AAKN,QAAM,MAAKA,GAAI,YAAY,OAAO,OAAO;AACvC,SAAM,GAAG,OAAO,MAAM,CAAC,MAAM,QAAQ,MAAM,IAAI,QAAQ,CAAC;AACxD,SAAM,GAAG,OAAO,MAAM,CAAC,MAAM,QAAQ,MAAM,IAAI,MAAM,CAAC;AAEtD,OAAI,cAAe,OAAM,MAAKC,KAAM,KAAK,cAAc;IACvD"}
1
+ {"version":3,"file":"service.server.mjs","names":["#db","#blob","#createGetCommand","#putObject","#createPutCommand"],"sources":["../../../../src/modules/storage/lib/service.server.ts"],"sourcesContent":["import { BUCKET_NAME } from \"@/lib/config/constants\";\nimport { generateDefaultUUID, TDatabaseSchema } from \"@/modules/config/entry\";\nimport { DatabaseClient } from \"@/modules/config/entry.server\";\nimport {\n convertOrderByToQueryParams,\n convertSearchToQueryParams,\n} from \"@/modules/data-tables/entry.server\";\nimport { BulkActionSchema } from \"@/modules/router/entry\";\nimport { ServerError } from \"@/modules/router/lib/error.server\";\nimport {\n DeleteObjectsCommand,\n GetObjectCommand,\n PutObjectCommand,\n S3Client,\n S3ClientConfig,\n} from \"@aws-sdk/client-s3\";\nimport { getSignedUrl } from \"@aws-sdk/s3-request-presigner\";\nimport { addSeconds } from \"date-fns\";\nimport { and, asc, eq, inArray, isNotNull, isNull, SQL } from \"drizzle-orm\";\nimport { after } from \"next/server\";\nimport { deviceSizes } from \"./constants\";\nimport { getDriveBucketKey, inferNodeSubtype, isFile, isFolder } from \"./helpers\";\nimport { nodePresignedUrls, nodes, nodeVariants } from \"./schema\";\nimport {\n CreateFolderNodeSchema,\n FileNode,\n GetFileURLSchema,\n getFileURLSchemaDefaults,\n GetNodesByParentIdInput,\n GetObjectInput,\n getObjectSchema,\n Node,\n PresignFileSchema,\n PutObjectInput,\n putObjectSchema,\n UpdateNodeSchema,\n UploadFileSchema,\n} from \"./validators\";\n\n/**\n * Storage Service Config\n */\nexport type StorageServiceConfig<TSchema extends TDatabaseSchema> = {\n db: DatabaseClient<TSchema>;\n config: S3ClientConfig;\n};\n\n/**\n * Storage Service\n */\nexport class StorageService<TSchema extends TDatabaseSchema> {\n /**\n * S3 Client\n */\n #blob: S3Client;\n #db: DatabaseClient<TSchema>;\n\n /**\n * Constructor\n */\n constructor({ db, config }: StorageServiceConfig<TSchema>) {\n this.#db = db;\n this.#blob = new S3Client(config);\n }\n\n /**\n * Get Blob\n */\n blob() {\n return this.#blob;\n }\n\n /**\n * Create get command\n */\n #createGetCommand(props: GetObjectInput) {\n const input = getObjectSchema.parse(props);\n\n return new GetObjectCommand({\n Bucket: BUCKET_NAME,\n Key: getDriveBucketKey(input.id, input.variant),\n ResponseContentDisposition: input.disposition,\n });\n }\n\n /**\n * Get object\n */\n async getObject(id: string, options: GetFileURLSchema = getFileURLSchemaDefaults) {\n const getCommand = this.#createGetCommand({ ...options, id });\n\n return await this.#blob.send(getCommand);\n }\n\n /**\n * Create put command\n */\n #createPutCommand(props: PutObjectInput) {\n const input = putObjectSchema.parse(props);\n\n return new PutObjectCommand({\n Bucket: BUCKET_NAME,\n Key: getDriveBucketKey(input.id, input.variant),\n Body: input.body,\n ContentType: input.contentType ?? undefined,\n ContentLength: input.size ?? undefined,\n Metadata: {\n nodeId: input.id,\n },\n });\n }\n\n /**\n * Put object\n */\n async #putObject(props: PutObjectInput) {\n const putCommand = this.#createPutCommand(props);\n return await this.#blob.send(putCommand);\n }\n\n /**\n * Get node by id\n */\n async getNodeById(id: string) {\n return this.#db.select().from(nodes).where(eq(nodes.id, id));\n }\n\n /**\n * Get nodes by parent id\n */\n async getNodesByParentId({ filters, ...query }: GetNodesByParentIdInput) {\n const orderBy = convertOrderByToQueryParams(query, nodes, asc(nodes.createdAt));\n const search = convertSearchToQueryParams(query, [nodes.name]);\n\n return this.#db\n .select()\n .from(nodes)\n .where(\n and(\n filters.nodeIds != null ? inArray(nodes.id, filters.nodeIds) : undefined,\n filters.types != null ? inArray(nodes.type, filters.types) : undefined,\n filters.isDeleted != null ? eq(nodes.isDeleted, filters.isDeleted) : undefined,\n filters.isOrphaned === true\n ? isNotNull(nodes.orphanedAt)\n : filters.isOrphaned === false\n ? isNull(nodes.orphanedAt)\n : undefined,\n filters.hidden != null ? eq(nodes.hidden, filters.hidden) : undefined,\n filters.parentId ? eq(nodes.parentId, filters.parentId) : isNull(nodes.parentId),\n eq(nodes.namespace, filters.namespace),\n search,\n ),\n )\n .orderBy(orderBy as SQL);\n }\n\n /**\n * Get file url\n */\n async getSignedURL(node: Node, options: GetFileURLSchema = getFileURLSchemaDefaults) {\n const [presignedUrl] = await this.#db\n .select({ url: nodePresignedUrls.url, expiresAt: nodePresignedUrls.expiresAt })\n .from(nodePresignedUrls)\n .where(\n and(\n eq(nodePresignedUrls.nodeId, node.id),\n eq(nodePresignedUrls.variant, options.variant),\n eq(nodePresignedUrls.disposition, options.disposition),\n ),\n );\n\n if (presignedUrl && presignedUrl.expiresAt > new Date()) return presignedUrl.url;\n\n const expiresIn = 3600 * 24;\n\n // Get the variants\n const variants = await this.#db\n .select()\n .from(nodeVariants)\n .where(eq(nodeVariants.nodeId, node.id));\n\n // If the requested variant does not exist, fallback to main\n const variantExists = variants.find((v) => v.variant === options.variant);\n const variant = variantExists ? options.variant : \"main\";\n\n console.info(\n `Generating new signed url for file: ${node.id} with variant: ${variant} and disposition: ${options.disposition}`,\n );\n\n // Generate the get command\n const getCommand = this.#createGetCommand({\n id: node.id,\n variant,\n disposition: `${options.disposition}; filename=\"${node.name}\"`,\n });\n\n // Generate the presigned url that expires in 24 hours\n const url = await getSignedUrl(this.#blob, getCommand, { expiresIn });\n\n // Add the presigned url to the database\n after(async () => {\n await this.#db\n .insert(nodePresignedUrls)\n .values({\n nodeId: node.id,\n url,\n variant,\n disposition: options.disposition,\n expiresAt: addSeconds(new Date(), expiresIn),\n })\n .onConflictDoUpdate({\n target: [\n nodePresignedUrls.nodeId,\n nodePresignedUrls.variant,\n nodePresignedUrls.disposition,\n ],\n set: { url, expiresAt: addSeconds(new Date(), expiresIn) },\n });\n });\n\n return url;\n }\n\n /**\n * Upload file to S3 and add it to the database\n **/\n async uploadFile(input: UploadFileSchema & Pick<PutObjectInput, \"body\">) {\n const id = input.id ?? generateDefaultUUID();\n\n return await this.#db.transaction(async (tx) => {\n const [result] = await tx\n .insert(nodes)\n .values({\n id,\n type: \"file\",\n name: input.name,\n namespace: input.namespace,\n parentId: input.parentId,\n size: input.size,\n contentType: input.contentType,\n mode: input.mode,\n subtype: inferNodeSubtype(input),\n })\n .returning();\n\n if (!result) {\n throw new ServerError(\"INTERNAL_SERVER_ERROR\", {\n message: \"Oep! Er is iets fout gegaan\",\n });\n }\n\n await this.#putObject({\n id,\n body: input.body,\n variant: \"main\",\n name: input.name,\n contentType: input.contentType,\n size: input.size,\n });\n\n return result;\n });\n }\n\n /**\n * Presign a new upload\n */\n async presignUpload(input: PresignFileSchema) {\n // Generate the put command\n const putCommand = this.#createPutCommand({\n id: input.id,\n name: input.name,\n variant: \"main\",\n contentType: input.contentType,\n size: input.size,\n });\n\n // Generate the presigned url\n const presignedUrl = await getSignedUrl(this.#blob, putCommand, { expiresIn: 3600 });\n\n const [node] = await this.#db\n .insert(nodes)\n .values({\n ...input,\n subtype: inferNodeSubtype(input),\n isPending: true,\n type: \"file\",\n id: input.id,\n })\n .returning();\n\n if (!node) {\n throw new ServerError(\"INTERNAL_SERVER_ERROR\", {\n message: \"Oep! Er is iets fout gegaan\",\n });\n }\n\n // Return the result\n return { id: input.id, presignedUrl, node };\n }\n\n /**\n * Confirm a new upload\n */\n async confirmUpload(input: { id: string }) {\n const [result] = await this.#db\n .update(nodes)\n .set({ isPending: false })\n .where(eq(nodes.id, input.id))\n .returning();\n\n if (!result) {\n throw new ServerError(\"NOT_FOUND\", { message: \"File not found\" });\n }\n\n /**\n * Generate the preview version of the file\n */\n // after(async () => {});\n await this.generatePreviews(input);\n\n return result as FileNode;\n }\n\n /**\n * Generate preview version of the file\n */\n async generatePreviews(input: { id: string }) {\n /**\n * Get the main version of the file\n */\n const getCommand = this.#createGetCommand({ id: input.id, variant: \"main\" });\n\n const response = await this.#blob.send(getCommand);\n const contentType = response.ContentType;\n if (!response.Body) {\n throw new ServerError(\"INTERNAL_SERVER_ERROR\", {\n message: \"Oep! Er is iets fout gegaan\",\n });\n }\n\n /**\n * Transform the main version of the file to a buffer\n */\n const byteArray = await response.Body.transformToByteArray();\n const buffer = Buffer.from(byteArray);\n\n /**\n * Generate the preview versions for images\n */\n if (contentType?.startsWith(\"image/\")) {\n const sharp = await import(\"sharp\");\n\n // Generate the preview versions\n await Promise.allSettled(\n deviceSizes.flatMap(async (width) => {\n // Generate the preview\n const preview = await sharp.default(buffer).resize({ width }).webp().toBuffer();\n\n // Upload the preview and add the variant to the database\n return this.#db.transaction(async (tx) => {\n await this.#putObject({\n id: input.id,\n body: preview,\n variant: `preview-${width}`,\n contentType: \"image/webp\",\n size: preview.byteLength,\n });\n\n await tx.insert(nodeVariants).values({\n nodeId: input.id,\n variant: `preview-${width}`,\n width,\n });\n });\n }),\n );\n }\n }\n\n /**\n * Create a new folder\n */\n async createFolder(input: CreateFolderNodeSchema) {\n const [parent] = input.parentId\n ? await this.#db.select().from(nodes).where(eq(nodes.id, input.parentId))\n : [];\n\n /**\n * Validate\n */\n if (input.parentId && !parent) {\n throw new ServerError(\"BAD_REQUEST\", { message: \"Parent not found\" });\n }\n\n if (parent && !isFolder(parent)) {\n throw new ServerError(\"BAD_REQUEST\", { message: \"Parent is not a folder\" });\n }\n\n if (parent && parent.namespace !== input.namespace) {\n throw new ServerError(\"BAD_REQUEST\", {\n message: \"Parent is not in the same namespace\",\n });\n }\n\n /**\n * Create the folder\n */\n const [result] = await this.#db\n .insert(nodes)\n .values({ ...input, type: \"folder\" })\n .returning();\n\n if (!result) {\n throw new ServerError(\"INTERNAL_SERVER_ERROR\", {\n message: \"Folder kon niet worden aangemaakt\",\n });\n }\n\n return result;\n }\n\n /**\n * Update a node\n */\n async updateNode(input: { id: string; data: UpdateNodeSchema }) {\n const [node] = await this.#db\n .select({ readonly: nodes.readonly })\n .from(nodes)\n .where(eq(nodes.id, input.id));\n\n if (node?.readonly) {\n throw new ServerError(\"BAD_REQUEST\", { message: \"Node is readonly\" });\n }\n\n const [result] = await this.#db\n .update(nodes)\n .set(input.data)\n .where(eq(nodes.id, input.id))\n .returning();\n\n if (!result) {\n throw new ServerError(\"INTERNAL_SERVER_ERROR\", {\n message: \"Node kon niet worden gewijzigd\",\n });\n }\n\n return result;\n }\n\n /**\n * Delete nodes\n */\n async deleteNodes(input: BulkActionSchema) {\n const items = await this.#db\n .select({ id: nodes.id, type: nodes.type, readonly: nodes.readonly })\n .from(nodes)\n .where(inArray(nodes.id, input.ids));\n\n // Check if the nodes are readonly\n if (items.some((item) => item.readonly)) {\n throw new ServerError(\"BAD_REQUEST\", { message: \"Nodes are readonly\" });\n }\n\n // Split the nodes into folders and files\n const folders = items.filter(isFolder).map((folder) => folder.id);\n const files = items.filter(isFile).map((file) => file.id);\n\n // Delete command for S3\n const deleteCommand =\n files.length > 0\n ? new DeleteObjectsCommand({\n Bucket: BUCKET_NAME,\n Delete: {\n Objects: files.map((id) => ({ Key: id })),\n },\n })\n : undefined;\n\n /**\n * Delete files and folders in a transaction\n */\n await this.#db.transaction(async (tx) => {\n await tx.delete(nodes).where(inArray(nodes.id, folders));\n await tx.delete(nodes).where(inArray(nodes.id, files));\n\n if (deleteCommand) await this.#blob.send(deleteCommand);\n });\n }\n}\n"],"mappings":"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"}