@tulip-systems/core 0.7.0 → 0.8.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 (361) hide show
  1. package/dist/auth/server.d.mts +3 -3
  2. package/dist/auth/server.mjs +3 -3
  3. package/dist/components/editor/components/editor.client.d.mts +4 -3
  4. package/dist/components/editor/components/editor.client.d.mts.map +1 -1
  5. package/dist/components/editor/components/editor.client.mjs +5 -2
  6. package/dist/components/editor/components/editor.client.mjs.map +1 -1
  7. package/dist/components/editor/extensions/file-handler/extension.d.mts +4 -4
  8. package/dist/components/editor/extensions/file-handler/extension.d.mts.map +1 -1
  9. package/dist/components/editor/extensions/file-handler/extension.mjs.map +1 -1
  10. package/dist/components/editor/extensions/file-handler/strategy.d.mts +4 -6
  11. package/dist/components/editor/extensions/file-handler/strategy.d.mts.map +1 -1
  12. package/dist/components/editor/extensions/file-handler/strategy.mjs +11 -11
  13. package/dist/components/editor/extensions/file-handler/strategy.mjs.map +1 -1
  14. package/dist/components/editor/extensions/file-handler/utils.mjs +1 -1
  15. package/dist/components/editor/extensions/file-handler/utils.mjs.map +1 -1
  16. package/dist/components/editor/extensions/image/extension.mjs +9 -9
  17. package/dist/components/editor/extensions/image/extension.mjs.map +1 -1
  18. package/dist/components/editor/lib/constants.d.mts +1 -1
  19. package/dist/components/editor/lib/constants.mjs +1 -1
  20. package/dist/components/editor/lib/extensions.d.mts +1 -1
  21. package/dist/components/editor/lib/helpers.d.mts +11 -3
  22. package/dist/components/editor/lib/helpers.d.mts.map +1 -1
  23. package/dist/components/editor/lib/helpers.mjs +27 -13
  24. package/dist/components/editor/lib/helpers.mjs.map +1 -1
  25. package/dist/components/ui/combobox-dropdown.client.mjs +1 -0
  26. package/dist/components/ui/combobox-dropdown.client.mjs.map +1 -1
  27. package/dist/components/ui/combobox.client.mjs +1 -1
  28. package/dist/components/ui/combobox.client.mjs.map +1 -1
  29. package/dist/components.d.mts +2 -2
  30. package/dist/components.mjs +2 -2
  31. package/dist/config/server.d.mts +1 -3
  32. package/dist/config/server.mjs +1 -4
  33. package/dist/config.d.mts +2 -2
  34. package/dist/config.mjs +1 -1
  35. package/dist/data-tables/client.d.mts +2 -1
  36. package/dist/data-tables/client.mjs +2 -1
  37. package/dist/data-tables.d.mts +1 -1
  38. package/dist/database/client.d.mts +1 -0
  39. package/dist/database/client.mjs +1 -0
  40. package/dist/database/server.d.mts +2 -0
  41. package/dist/database/server.mjs +3 -0
  42. package/dist/database.d.mts +3 -0
  43. package/dist/database.mjs +3 -0
  44. package/dist/emails/client.d.mts +1 -0
  45. package/dist/emails/client.mjs +1 -0
  46. package/dist/emails/server.d.mts +2 -0
  47. package/dist/emails/server.mjs +3 -0
  48. package/dist/emails.d.mts +1 -0
  49. package/dist/emails.mjs +1 -0
  50. package/dist/lib/utils/markdown.d.mts +10 -0
  51. package/dist/lib/utils/markdown.d.mts.map +1 -0
  52. package/dist/lib/utils/markdown.mjs +15 -0
  53. package/dist/lib/utils/markdown.mjs.map +1 -0
  54. package/dist/lib/utils/url.mjs +2 -1
  55. package/dist/lib/utils/url.mjs.map +1 -1
  56. package/dist/lib/utils/user-agent.mjs +15 -0
  57. package/dist/lib/utils/user-agent.mjs.map +1 -1
  58. package/dist/lib.d.mts +2 -2
  59. package/dist/lib.mjs +2 -2
  60. package/dist/modules/auth/components/create-first-user-guard.server.d.mts +16 -0
  61. package/dist/modules/auth/components/create-first-user-guard.server.d.mts.map +1 -0
  62. package/dist/modules/auth/components/create-first-user-guard.server.mjs +16 -0
  63. package/dist/modules/auth/components/create-first-user-guard.server.mjs.map +1 -0
  64. package/dist/modules/auth/components/guard.server.d.mts +2 -2
  65. package/dist/modules/auth/components/guard.server.mjs +1 -1
  66. package/dist/modules/auth/components/guard.server.mjs.map +1 -1
  67. package/dist/modules/auth/db/schema.d.mts +1 -1
  68. package/dist/modules/auth/db/schema.mjs +2 -2
  69. package/dist/modules/auth/handler/create-client.client.d.mts +4838 -229
  70. package/dist/modules/auth/handler/create-client.client.d.mts.map +1 -1
  71. package/dist/modules/auth/handler/create-client.client.mjs.map +1 -1
  72. package/dist/modules/auth/handler/proxy.server.mjs +2 -2
  73. package/dist/modules/auth/handler/proxy.server.mjs.map +1 -1
  74. package/dist/modules/auth/handler/route.server.d.mts +2 -2
  75. package/dist/modules/auth/handler/route.server.d.mts.map +1 -1
  76. package/dist/modules/auth/handler/route.server.mjs.map +1 -1
  77. package/dist/modules/auth/handler/{init.d.mts → service.server.d.mts} +322 -90
  78. package/dist/modules/auth/handler/service.server.d.mts.map +1 -0
  79. package/dist/modules/auth/handler/{init.mjs → service.server.mjs} +19 -8
  80. package/dist/modules/auth/handler/service.server.mjs.map +1 -0
  81. package/dist/modules/auth/hooks/use-session.d.mts +9 -4
  82. package/dist/modules/auth/hooks/use-session.d.mts.map +1 -1
  83. package/dist/modules/auth/lib/helpers.server.d.mts +1 -1
  84. package/dist/modules/auth/lib/permissions.d.mts +1 -1
  85. package/dist/modules/auth/lib/validators.mjs +1 -1
  86. package/dist/modules/config/lib/context.d.mts +9 -10
  87. package/dist/modules/config/lib/context.d.mts.map +1 -1
  88. package/dist/modules/config/lib/context.mjs.map +1 -1
  89. package/dist/modules/data-tables/lib/converters/search.d.mts +1 -1
  90. package/dist/modules/data-tables/lib/converters/sorting.d.mts +1 -1
  91. package/dist/modules/data-tables/server/get-data.server.d.mts +3 -3
  92. package/dist/modules/data-tables/server/get-data.server.mjs +1 -1
  93. package/dist/modules/data-tables/server/get-data.server.mjs.map +1 -1
  94. package/dist/modules/data-tables/strategies/infinite/strategy.d.mts +1 -1
  95. package/dist/modules/data-tables/strategies/infinite/strategy.mjs +3 -0
  96. package/dist/modules/data-tables/strategies/infinite/strategy.mjs.map +1 -1
  97. package/dist/modules/data-tables/tables/data-table/components/row.mjs +5 -15
  98. package/dist/modules/data-tables/tables/data-table/components/row.mjs.map +1 -1
  99. package/dist/modules/data-tables/tables/inline-table/components/body.mjs +1 -1
  100. package/dist/modules/data-tables/tables/inline-table/components/body.mjs.map +1 -1
  101. package/dist/modules/data-tables/tables/inline-table/components/row.client.mjs +13 -23
  102. package/dist/modules/data-tables/tables/inline-table/components/row.client.mjs.map +1 -1
  103. package/dist/modules/data-tables/tables/inline-table/components/table.d.mts +1 -0
  104. package/dist/modules/data-tables/tables/inline-table/components/table.d.mts.map +1 -1
  105. package/dist/modules/data-tables/tables/inline-table/components/table.mjs +2 -1
  106. package/dist/modules/data-tables/tables/inline-table/components/table.mjs.map +1 -1
  107. package/dist/modules/data-tables/tables/inline-table/hooks/context.client.d.mts +5 -1
  108. package/dist/modules/data-tables/tables/inline-table/hooks/context.client.d.mts.map +1 -1
  109. package/dist/modules/data-tables/tables/inline-table/hooks/context.client.mjs +2 -1
  110. package/dist/modules/data-tables/tables/inline-table/hooks/context.client.mjs.map +1 -1
  111. package/dist/modules/data-tables/tables/inline-table/hooks/use-hotkeys.client.d.mts +30 -0
  112. package/dist/modules/data-tables/tables/inline-table/hooks/use-hotkeys.client.d.mts.map +1 -0
  113. package/dist/modules/data-tables/tables/inline-table/hooks/use-hotkeys.client.mjs +77 -9
  114. package/dist/modules/data-tables/tables/inline-table/hooks/use-hotkeys.client.mjs.map +1 -1
  115. package/dist/modules/{config/db → database/lib}/helpers.d.mts +2 -2
  116. package/dist/modules/database/lib/helpers.d.mts.map +1 -0
  117. package/dist/modules/{config/db → database/lib}/helpers.mjs +1 -1
  118. package/dist/modules/database/lib/helpers.mjs.map +1 -0
  119. package/dist/modules/database/lib/service.server.d.mts +34 -0
  120. package/dist/modules/database/lib/service.server.d.mts.map +1 -0
  121. package/dist/modules/database/lib/service.server.mjs +24 -0
  122. package/dist/modules/database/lib/service.server.mjs.map +1 -0
  123. package/dist/modules/{config/db → database/lib}/types.d.mts +1 -1
  124. package/dist/modules/database/lib/types.d.mts.map +1 -0
  125. package/dist/modules/emails/lib/service.server.d.mts +29 -0
  126. package/dist/modules/emails/lib/service.server.d.mts.map +1 -0
  127. package/dist/modules/emails/lib/service.server.mjs +21 -0
  128. package/dist/modules/emails/lib/service.server.mjs.map +1 -0
  129. package/dist/modules/inline-edit/components/date-input.client.mjs +1 -1
  130. package/dist/modules/inline-edit/components/date-input.client.mjs.map +1 -1
  131. package/dist/modules/inline-edit/components/date-picker.client.mjs +1 -0
  132. package/dist/modules/inline-edit/components/date-picker.client.mjs.map +1 -1
  133. package/dist/modules/inline-edit/components/date-time.client.mjs +1 -0
  134. package/dist/modules/inline-edit/components/date-time.client.mjs.map +1 -1
  135. package/dist/modules/inline-edit/components/editor.client.mjs +1 -0
  136. package/dist/modules/inline-edit/components/editor.client.mjs.map +1 -1
  137. package/dist/modules/inline-edit/components/input-recipient.client.mjs +1 -0
  138. package/dist/modules/inline-edit/components/input-recipient.client.mjs.map +1 -1
  139. package/dist/modules/inline-edit/components/input-toggle.client.mjs +1 -0
  140. package/dist/modules/inline-edit/components/input-toggle.client.mjs.map +1 -1
  141. package/dist/modules/inline-edit/components/input.client.d.mts.map +1 -1
  142. package/dist/modules/inline-edit/components/input.client.mjs +3 -0
  143. package/dist/modules/inline-edit/components/input.client.mjs.map +1 -1
  144. package/dist/modules/inline-edit/components/select.client.d.mts.map +1 -1
  145. package/dist/modules/inline-edit/components/select.client.mjs +1 -0
  146. package/dist/modules/inline-edit/components/select.client.mjs.map +1 -1
  147. package/dist/modules/inline-edit/components/switch.client.mjs +1 -0
  148. package/dist/modules/inline-edit/components/switch.client.mjs.map +1 -1
  149. package/dist/modules/inline-edit/components/toggle.client.mjs +1 -0
  150. package/dist/modules/inline-edit/components/toggle.client.mjs.map +1 -1
  151. package/dist/modules/router/handler/context.server.d.mts +12 -10
  152. package/dist/modules/router/handler/context.server.d.mts.map +1 -1
  153. package/dist/modules/router/handler/init.server.d.mts +13 -11
  154. package/dist/modules/router/handler/init.server.d.mts.map +1 -1
  155. package/dist/modules/router/handler/init.server.mjs +2 -2
  156. package/dist/modules/router/handler/init.server.mjs.map +1 -1
  157. package/dist/modules/router/handler/route.server.d.mts +1 -1
  158. package/dist/modules/storage/components/dropzone.client.d.mts +2 -2
  159. package/dist/modules/storage/components/dropzone.client.d.mts.map +1 -1
  160. package/dist/modules/storage/components/dropzone.client.mjs.map +1 -1
  161. package/dist/modules/storage/components/image-grid.client.d.mts +3 -3
  162. package/dist/modules/storage/components/image-grid.client.d.mts.map +1 -1
  163. package/dist/modules/storage/components/image-grid.client.mjs +20 -22
  164. package/dist/modules/storage/components/image-grid.client.mjs.map +1 -1
  165. package/dist/modules/storage/components/image.client.d.mts +8 -0
  166. package/dist/modules/storage/components/image.client.d.mts.map +1 -0
  167. package/dist/modules/storage/components/image.client.mjs +17 -0
  168. package/dist/modules/storage/components/image.client.mjs.map +1 -0
  169. package/dist/modules/storage/components/upload-button.client.d.mts +12 -0
  170. package/dist/modules/storage/components/upload-button.client.d.mts.map +1 -0
  171. package/dist/modules/storage/components/upload-button.client.mjs +34 -0
  172. package/dist/modules/storage/components/upload-button.client.mjs.map +1 -0
  173. package/dist/modules/storage/components/upload-zone-context.client.d.mts +5 -5
  174. package/dist/modules/storage/components/upload-zone-context.client.d.mts.map +1 -1
  175. package/dist/modules/storage/components/upload-zone-context.client.mjs +2 -2
  176. package/dist/modules/storage/components/upload-zone-context.client.mjs.map +1 -1
  177. package/dist/modules/storage/components/upload-zone.client.d.mts +4 -4
  178. package/dist/modules/storage/components/upload-zone.client.d.mts.map +1 -1
  179. package/dist/modules/storage/components/upload-zone.client.mjs +16 -9
  180. package/dist/modules/storage/components/upload-zone.client.mjs.map +1 -1
  181. package/dist/modules/storage/lib/constants.d.mts +1 -5
  182. package/dist/modules/storage/lib/constants.d.mts.map +1 -1
  183. package/dist/modules/storage/lib/constants.mjs +1 -13
  184. package/dist/modules/storage/lib/constants.mjs.map +1 -1
  185. package/dist/modules/storage/lib/helpers.d.mts +14 -28
  186. package/dist/modules/storage/lib/helpers.d.mts.map +1 -1
  187. package/dist/modules/storage/lib/helpers.mjs +17 -75
  188. package/dist/modules/storage/lib/helpers.mjs.map +1 -1
  189. package/dist/modules/storage/lib/procedures.server.d.mts +1991 -0
  190. package/dist/modules/{auth/handler/init.d.mts.map → storage/lib/procedures.server.d.mts.map} +1 -1
  191. package/dist/modules/storage/lib/procedures.server.mjs +22 -0
  192. package/dist/modules/storage/lib/procedures.server.mjs.map +1 -0
  193. package/dist/modules/storage/lib/router-handlers.server.d.mts +41 -0
  194. package/dist/modules/storage/lib/router-handlers.server.d.mts.map +1 -0
  195. package/dist/modules/storage/lib/router-handlers.server.mjs +124 -0
  196. package/dist/modules/storage/lib/router-handlers.server.mjs.map +1 -0
  197. package/dist/modules/storage/lib/schema.d.mts +68 -958
  198. package/dist/modules/storage/lib/schema.d.mts.map +1 -1
  199. package/dist/modules/storage/lib/schema.mjs +28 -65
  200. package/dist/modules/storage/lib/schema.mjs.map +1 -1
  201. package/dist/modules/storage/lib/service.server.d.mts +2155 -141
  202. package/dist/modules/storage/lib/service.server.d.mts.map +1 -1
  203. package/dist/modules/storage/lib/service.server.mjs +453 -242
  204. package/dist/modules/storage/lib/service.server.mjs.map +1 -1
  205. package/dist/modules/storage/lib/upload.client.d.mts +58 -0
  206. package/dist/modules/storage/lib/upload.client.d.mts.map +1 -0
  207. package/dist/modules/storage/lib/upload.client.mjs +87 -0
  208. package/dist/modules/storage/lib/upload.client.mjs.map +1 -0
  209. package/dist/modules/storage/lib/validators.d.mts +297 -835
  210. package/dist/modules/storage/lib/validators.d.mts.map +1 -1
  211. package/dist/modules/storage/lib/validators.mjs +32 -76
  212. package/dist/modules/storage/lib/validators.mjs.map +1 -1
  213. package/dist/modules/storage/providers/adapters/s3.server.d.mts +19 -0
  214. package/dist/modules/storage/providers/adapters/s3.server.d.mts.map +1 -0
  215. package/dist/modules/storage/providers/adapters/s3.server.mjs +173 -0
  216. package/dist/modules/storage/providers/adapters/s3.server.mjs.map +1 -0
  217. package/dist/modules/storage/providers/lib/constants.d.mts +6 -0
  218. package/dist/modules/storage/providers/lib/constants.d.mts.map +1 -0
  219. package/dist/modules/storage/providers/lib/constants.mjs +6 -0
  220. package/dist/modules/storage/providers/lib/constants.mjs.map +1 -0
  221. package/dist/modules/storage/providers/lib/errors.d.mts +12 -0
  222. package/dist/modules/storage/providers/lib/errors.d.mts.map +1 -0
  223. package/dist/modules/storage/providers/lib/errors.mjs +13 -0
  224. package/dist/modules/storage/providers/lib/errors.mjs.map +1 -0
  225. package/dist/modules/storage/providers/lib/types.d.mts +21 -0
  226. package/dist/modules/storage/providers/lib/types.d.mts.map +1 -0
  227. package/dist/modules/storage/providers/lib/validators.d.mts +112 -0
  228. package/dist/modules/storage/providers/lib/validators.d.mts.map +1 -0
  229. package/dist/modules/storage/providers/lib/validators.mjs +75 -0
  230. package/dist/modules/storage/providers/lib/validators.mjs.map +1 -0
  231. package/dist/router/server.d.mts +1 -1
  232. package/dist/storage/client.d.mts +4 -2
  233. package/dist/storage/client.mjs +4 -2
  234. package/dist/storage/server.d.mts +5 -4
  235. package/dist/storage/server.mjs +5 -4
  236. package/dist/storage.d.mts +9 -6
  237. package/dist/storage.mjs +8 -6
  238. package/package.json +18 -5
  239. package/src/components/editor/components/editor.client.tsx +9 -1
  240. package/src/components/editor/extensions/file-handler/extension.ts +4 -4
  241. package/src/components/editor/extensions/file-handler/strategy.ts +15 -40
  242. package/src/components/editor/extensions/file-handler/utils.ts +1 -1
  243. package/src/components/editor/extensions/image/extension.ts +10 -10
  244. package/src/components/editor/lib/helpers.ts +28 -11
  245. package/src/components/ui/combobox-dropdown.client.tsx +1 -0
  246. package/src/components/ui/combobox.client.tsx +1 -1
  247. package/src/entry.ts +12 -51
  248. package/src/lib/entry.ts +1 -5
  249. package/src/lib/utils/markdown.ts +10 -0
  250. package/src/lib/utils/url.ts +2 -1
  251. package/src/lib/utils/user-agent.ts +15 -0
  252. package/src/modules/auth/components/{guard-first-user.server.tsx → create-first-user-guard.server.tsx} +8 -8
  253. package/src/modules/auth/components/guard.server.tsx +1 -1
  254. package/src/modules/auth/entry.server.ts +4 -5
  255. package/src/modules/auth/handler/create-client.client.ts +2 -2
  256. package/src/modules/auth/handler/proxy.server.ts +1 -1
  257. package/src/modules/auth/handler/route.server.ts +2 -2
  258. package/src/modules/auth/handler/{init.ts → service.server.ts} +30 -9
  259. package/src/modules/config/entry.server.ts +0 -9
  260. package/src/modules/config/entry.ts +2 -2
  261. package/src/modules/config/lib/context.ts +9 -9
  262. package/src/modules/data-tables/entry.client.ts +1 -0
  263. package/src/modules/data-tables/server/get-data.server.ts +1 -1
  264. package/src/modules/data-tables/strategies/infinite/strategy.ts +4 -1
  265. package/src/modules/data-tables/tables/data-table/components/row.tsx +12 -21
  266. package/src/modules/data-tables/tables/inline-table/components/body.tsx +1 -1
  267. package/src/modules/data-tables/tables/inline-table/components/row.client.tsx +24 -30
  268. package/src/modules/data-tables/tables/inline-table/components/table.tsx +6 -1
  269. package/src/modules/data-tables/tables/inline-table/hooks/context.client.tsx +5 -0
  270. package/src/modules/data-tables/tables/inline-table/hooks/use-hotkeys.client.ts +119 -91
  271. package/src/modules/database/entry.client.ts +0 -0
  272. package/src/modules/database/entry.server.ts +4 -0
  273. package/src/modules/database/entry.ts +5 -0
  274. package/src/modules/database/lib/service.server.ts +33 -0
  275. package/src/modules/emails/entry.client.ts +0 -0
  276. package/src/modules/emails/entry.server.ts +4 -0
  277. package/src/modules/emails/entry.ts +0 -0
  278. package/src/modules/emails/lib/service.server.ts +29 -0
  279. package/src/modules/inline-edit/components/date-input.client.tsx +1 -1
  280. package/src/modules/inline-edit/components/date-picker.client.tsx +1 -0
  281. package/src/modules/inline-edit/components/date-time.client.tsx +1 -0
  282. package/src/modules/inline-edit/components/editor.client.tsx +3 -0
  283. package/src/modules/inline-edit/components/input-recipient.client.tsx +1 -0
  284. package/src/modules/inline-edit/components/input-toggle.client.tsx +1 -0
  285. package/src/modules/inline-edit/components/input.client.tsx +3 -0
  286. package/src/modules/inline-edit/components/select.client.tsx +5 -1
  287. package/src/modules/inline-edit/components/switch.client.tsx +1 -0
  288. package/src/modules/inline-edit/components/toggle.client.tsx +1 -0
  289. package/src/modules/router/handler/init.server.ts +2 -2
  290. package/src/modules/storage/components/dropzone.client.tsx +1 -1
  291. package/src/modules/storage/components/image-grid.client.tsx +23 -20
  292. package/src/modules/storage/components/image.client.tsx +8 -0
  293. package/src/modules/storage/components/upload-zone-context.client.tsx +11 -8
  294. package/src/modules/storage/components/upload-zone.client.tsx +22 -16
  295. package/src/modules/storage/entry.client.ts +3 -1
  296. package/src/modules/storage/entry.server.ts +9 -3
  297. package/src/modules/storage/entry.ts +13 -1
  298. package/src/modules/storage/lib/constants.ts +0 -11
  299. package/src/modules/storage/lib/helpers.ts +18 -65
  300. package/src/modules/storage/lib/procedures.server.ts +60 -0
  301. package/src/modules/storage/lib/router-handlers.server.ts +178 -0
  302. package/src/modules/storage/lib/schema.ts +26 -97
  303. package/src/modules/storage/lib/service.server.ts +636 -374
  304. package/src/modules/storage/lib/upload.client.ts +156 -0
  305. package/src/modules/storage/lib/validators.ts +50 -111
  306. package/src/modules/storage/providers/adapters/s3.server.ts +281 -0
  307. package/src/modules/storage/providers/lib/constants.ts +3 -0
  308. package/src/modules/storage/providers/lib/errors.ts +21 -0
  309. package/src/modules/storage/providers/lib/types.ts +28 -0
  310. package/src/modules/storage/providers/lib/validators.ts +122 -0
  311. package/dist/lib/config/constants.d.mts +0 -5
  312. package/dist/lib/config/constants.d.mts.map +0 -1
  313. package/dist/lib/config/constants.mjs +0 -6
  314. package/dist/lib/config/constants.mjs.map +0 -1
  315. package/dist/modules/auth/components/guard-first-user.server.d.mts +0 -18
  316. package/dist/modules/auth/components/guard-first-user.server.d.mts.map +0 -1
  317. package/dist/modules/auth/components/guard-first-user.server.mjs +0 -16
  318. package/dist/modules/auth/components/guard-first-user.server.mjs.map +0 -1
  319. package/dist/modules/auth/handler/init.mjs.map +0 -1
  320. package/dist/modules/config/db/helpers.d.mts.map +0 -1
  321. package/dist/modules/config/db/helpers.mjs.map +0 -1
  322. package/dist/modules/config/db/init.d.mts +0 -20
  323. package/dist/modules/config/db/init.d.mts.map +0 -1
  324. package/dist/modules/config/db/init.mjs +0 -15
  325. package/dist/modules/config/db/init.mjs.map +0 -1
  326. package/dist/modules/config/db/types.d.mts.map +0 -1
  327. package/dist/modules/config/providers/email.d.mts +0 -12
  328. package/dist/modules/config/providers/email.d.mts.map +0 -1
  329. package/dist/modules/config/providers/email.mjs +0 -11
  330. package/dist/modules/config/providers/email.mjs.map +0 -1
  331. package/dist/modules/storage/config/filters.d.mts +0 -17
  332. package/dist/modules/storage/config/filters.d.mts.map +0 -1
  333. package/dist/modules/storage/config/filters.mjs +0 -17
  334. package/dist/modules/storage/config/filters.mjs.map +0 -1
  335. package/dist/modules/storage/lib/create-client.server.d.mts +0 -11
  336. package/dist/modules/storage/lib/create-client.server.d.mts.map +0 -1
  337. package/dist/modules/storage/lib/create-client.server.mjs +0 -11
  338. package/dist/modules/storage/lib/create-client.server.mjs.map +0 -1
  339. package/dist/modules/storage/lib/create-upload.client.d.mts +0 -56
  340. package/dist/modules/storage/lib/create-upload.client.d.mts.map +0 -1
  341. package/dist/modules/storage/lib/create-upload.client.mjs +0 -98
  342. package/dist/modules/storage/lib/create-upload.client.mjs.map +0 -1
  343. package/dist/modules/storage/lib/proxy.server.d.mts +0 -21
  344. package/dist/modules/storage/lib/proxy.server.d.mts.map +0 -1
  345. package/dist/modules/storage/lib/proxy.server.mjs +0 -46
  346. package/dist/modules/storage/lib/proxy.server.mjs.map +0 -1
  347. package/dist/modules/storage/lib/router.server.d.mts +0 -31002
  348. package/dist/modules/storage/lib/router.server.d.mts.map +0 -1
  349. package/dist/modules/storage/lib/router.server.mjs +0 -86
  350. package/dist/modules/storage/lib/router.server.mjs.map +0 -1
  351. package/src/lib/config/constants.ts +0 -1
  352. package/src/lib/utils/time-picker.ts +0 -139
  353. package/src/modules/config/db/init.ts +0 -21
  354. package/src/modules/config/providers/email.ts +0 -13
  355. package/src/modules/storage/config/filters.ts +0 -12
  356. package/src/modules/storage/lib/create-client.server.ts +0 -14
  357. package/src/modules/storage/lib/create-upload.client.ts +0 -134
  358. package/src/modules/storage/lib/proxy.server.ts +0 -63
  359. package/src/modules/storage/lib/router.server.ts +0 -182
  360. /package/src/modules/{config/db → database/lib}/helpers.ts +0 -0
  361. /package/src/modules/{config/db → database/lib}/types.ts +0 -0
@@ -0,0 +1,156 @@
1
+ import type { StorageRouterInputs, StorageRouterOutputs } from "./procedures.server";
2
+ import type {
3
+ PresignUploadInput,
4
+ PresignUploadOutput,
5
+ SelectStorageAssetSchema,
6
+ } from "./validators";
7
+
8
+ /**
9
+ * Upload request
10
+ */
11
+ export type UploadFileRequest = PresignUploadInput & { file: File };
12
+ export type PrepareUploadInput = Omit<UploadFileRequest, "name" | "contentType" | "size">;
13
+ export type UploadHooks = {
14
+ beforePresign?: (input: UploadFileRequest) => Promise<void> | void;
15
+ afterPresign?: (presignResult: PresignUploadOutput) => Promise<void> | void;
16
+ beforeConfirm?: (presignResult: PresignUploadOutput) => Promise<void> | void;
17
+ afterConfirm?: (asset: SelectStorageAssetSchema) => Promise<void> | void;
18
+ };
19
+
20
+ /**
21
+ * Upload client
22
+ */
23
+ export type UploadClient = {
24
+ prepareUpload: (input: PrepareUploadInput) => UploadFileRequest;
25
+ upload: (input: UploadFileRequest, hooks?: UploadHooks) => Promise<SelectStorageAssetSchema>;
26
+ deleteAsset: (id: string) => Promise<SelectStorageAssetSchema | null>;
27
+ deleteAssets: (ids: string[]) => Promise<SelectStorageAssetSchema[]>;
28
+ restoreAsset: (id: string) => Promise<SelectStorageAssetSchema | null>;
29
+ restoreAssets: (ids: string[]) => Promise<SelectStorageAssetSchema[]>;
30
+ purgeAsset: (id: string) => Promise<SelectStorageAssetSchema | null>;
31
+ purgeAssets: (ids: string[]) => Promise<SelectStorageAssetSchema[]>;
32
+ };
33
+
34
+ /**
35
+ * Create upload client props
36
+ */
37
+ type CreateStorageClientProps = {
38
+ endpoints: {
39
+ presign: (input: StorageRouterInputs["presign"]) => Promise<StorageRouterOutputs["presign"]>;
40
+ confirm: (uploadId: StorageRouterInputs["confirm"]) => Promise<StorageRouterOutputs["confirm"]>;
41
+ deleteAssets: (
42
+ ids: StorageRouterInputs["deleteAssets"],
43
+ ) => Promise<StorageRouterOutputs["deleteAssets"]>;
44
+ deleteAsset: (
45
+ id: StorageRouterInputs["deleteAsset"],
46
+ ) => Promise<StorageRouterOutputs["deleteAsset"]>;
47
+ restoreAsset: (
48
+ id: StorageRouterInputs["restoreAsset"],
49
+ ) => Promise<StorageRouterOutputs["restoreAsset"]>;
50
+ restoreAssets: (
51
+ ids: StorageRouterInputs["restoreAssets"],
52
+ ) => Promise<StorageRouterOutputs["restoreAssets"]>;
53
+ purgeAsset: (
54
+ id: StorageRouterInputs["purgeAsset"],
55
+ ) => Promise<StorageRouterOutputs["purgeAsset"]>;
56
+ purgeAssets: (
57
+ ids: StorageRouterInputs["purgeAssets"],
58
+ ) => Promise<StorageRouterOutputs["purgeAssets"]>;
59
+ };
60
+ };
61
+
62
+ /**
63
+ * Creates an upload client for the storage module.
64
+ *
65
+ * Flow:
66
+ * - Prepare upload payload with generated id and resolved key
67
+ * - Request presigned upload URL from server
68
+ * - Upload file bytes directly to object storage
69
+ * - Confirm upload and receive finalized storage asset
70
+ */
71
+ export function createUploadClient(props: CreateStorageClientProps): UploadClient {
72
+ /**
73
+ * Create input schema for the upload method
74
+ * @param {PrepareUploadInput} input
75
+ * @returns {UploadFileRequest}
76
+ */
77
+ function prepareUpload(input: PrepareUploadInput): UploadFileRequest {
78
+ return {
79
+ ...input,
80
+ uploadId: input.uploadId ?? crypto.randomUUID(),
81
+ name: input.file.name,
82
+ size: input.file.size,
83
+ contentType: input.file.type || "application/octet-stream",
84
+ };
85
+ }
86
+
87
+ /**
88
+ * Upload file to the server
89
+ * @param {UploadFileRequest} input
90
+ * @returns {Promise<SelectStorageAssetSchema>}
91
+ */
92
+ async function upload(
93
+ input: UploadFileRequest,
94
+ hooks?: UploadHooks,
95
+ ): Promise<SelectStorageAssetSchema> {
96
+ let presignResult: PresignUploadOutput | null = null;
97
+
98
+ try {
99
+ /**
100
+ * Presign
101
+ */
102
+ await hooks?.beforePresign?.(input);
103
+ presignResult = await props.endpoints.presign(input);
104
+ await hooks?.afterPresign?.(presignResult);
105
+
106
+ /**
107
+ * Upload the file
108
+ */
109
+ const uploadResponse = await fetch(presignResult.presignedUrl, {
110
+ method: "PUT",
111
+ headers: { "Content-Type": input.contentType || "application/octet-stream" },
112
+ body: input.file,
113
+ });
114
+
115
+ if (!uploadResponse.ok) {
116
+ const message = await uploadResponse.text();
117
+ throw new Error(`Upload failed: ${message}`);
118
+ }
119
+
120
+ /**
121
+ * Confirm
122
+ */
123
+ await hooks?.beforeConfirm?.(presignResult);
124
+ const asset = await props.endpoints.confirm(presignResult.uploadId);
125
+ await hooks?.afterConfirm?.(asset);
126
+ /**
127
+ * Return
128
+ */
129
+ return asset;
130
+ } catch (err) {
131
+ console.error("Upload error: ", err);
132
+
133
+ /**
134
+ * Delete if upload failed
135
+ * */
136
+ if (presignResult) {
137
+ await props.endpoints.deleteAsset(presignResult.id).catch((deleteErr) => {
138
+ console.error("Failed to delete asset after upload error: ", deleteErr);
139
+ });
140
+ }
141
+
142
+ throw err;
143
+ }
144
+ }
145
+
146
+ return {
147
+ prepareUpload,
148
+ upload,
149
+ deleteAsset: props.endpoints.deleteAsset,
150
+ deleteAssets: props.endpoints.deleteAssets,
151
+ restoreAsset: props.endpoints.restoreAsset,
152
+ restoreAssets: props.endpoints.restoreAssets,
153
+ purgeAsset: props.endpoints.purgeAsset,
154
+ purgeAssets: props.endpoints.purgeAssets,
155
+ };
156
+ }
@@ -1,146 +1,85 @@
1
- import type { PutObjectCommandInput } from "@aws-sdk/client-s3";
2
1
  import { createInsertSchema, createSelectSchema, createUpdateSchema } from "drizzle-zod";
3
2
  import { z } from "zod";
4
- import { tableQuerySchema } from "@/modules/data-tables/entry";
5
- import { resolveFiltersSchema } from "@/modules/data-tables/lib/filters/resolvers";
6
- import { nodesTableFilters } from "../config/filters";
7
- import { imageDispositions, imageVariants } from "./constants";
8
- import { nodeModeEnum, nodes } from "./schema";
3
+ import { getObjectOptionsDefaults, objectBodyInputSchema } from "../providers/lib/validators";
4
+ import { imageDispositions } from "./constants";
5
+ import { storageAssets, storageAssetVisibilityEnum } from "./schema";
9
6
 
10
7
  /**
11
- * Nodes
8
+ * StorageAssets
12
9
  */
13
- export type Node = typeof nodes.$inferSelect;
14
- export type FileNode = typeof nodes.$inferSelect & { type: "file" };
15
- export type FolderNode = typeof nodes.$inferSelect & { type: "folder" };
10
+ export type StorageAsset = typeof storageAssets.$inferSelect;
16
11
 
17
12
  /**
18
- * Node mode
13
+ * StorageAsset visibility enum
19
14
  */
20
- export const nodeModeSchema = z.enum(nodeModeEnum.enumValues);
21
- export type NodeMode = z.infer<typeof nodeModeSchema>;
15
+ export const storageAssetVisibilitySchema = z.enum(storageAssetVisibilityEnum.enumValues);
16
+ export type StorageAssetVisibility = z.infer<typeof storageAssetVisibilitySchema>;
22
17
 
23
18
  /**
24
- * Create node
19
+ * Create storageAsset
25
20
  */
26
- export const createNodeSchema = createInsertSchema(nodes, {
27
- namespace: z.string(),
28
- });
21
+ export const createStorageAssetSchema = createInsertSchema(storageAssets);
29
22
 
30
- export type CreateNodeInput = z.input<typeof createNodeSchema>;
31
- export type CreateNodeSchema = z.infer<typeof createNodeSchema>;
23
+ export type CreateStorageAssetInput = z.input<typeof createStorageAssetSchema>;
24
+ export type CreateStorageAssetSchema = z.infer<typeof createStorageAssetSchema>;
32
25
 
33
26
  /**
34
- * Update node
27
+ * Update storageAsset
35
28
  */
36
- export const updateNodeSchema = createUpdateSchema(nodes);
29
+ export const updateStorageAssetSchema = createUpdateSchema(storageAssets);
37
30
 
38
- export type UpdateNodeInput = z.input<typeof updateNodeSchema>;
39
- export type UpdateNodeSchema = z.infer<typeof updateNodeSchema>;
31
+ export type UpdateStorageAssetInput = z.input<typeof updateStorageAssetSchema>;
32
+ export type UpdateStorageAssetSchema = z.infer<typeof updateStorageAssetSchema>;
40
33
 
41
34
  /**
42
- * Select node
35
+ * Select storageAsset
43
36
  */
44
- export const selectNodeSchema = createSelectSchema(nodes);
45
- export const selectNodeWithChildrenSchema = selectNodeSchema.extend({
46
- children: z.array(selectNodeSchema),
47
- });
37
+ export const selectStorageAssetSchema = createSelectSchema(storageAssets);
48
38
 
49
- export type SelectNodeSchema = z.infer<typeof selectNodeSchema>;
50
- export type SelectNodeWithChildrenSchema = z.infer<typeof selectNodeWithChildrenSchema>;
39
+ export type SelectStorageAssetSchema = z.infer<typeof selectStorageAssetSchema>;
51
40
 
52
- /**
53
- * Where input
54
- */
55
- export const nodesTableFiltersSchema = resolveFiltersSchema(nodesTableFilters)
56
- .partial()
57
- .extend({
58
- namespace: z.string(),
59
- parentId: z.string().nullable(),
60
- })
61
- .transform((input) => ({
62
- ...input,
63
- hidden: input?.hidden ?? false,
64
- isDeleted: input?.isDeleted ?? false,
65
- orphanedAt: input?.isOrphaned ?? false,
66
- }));
67
-
68
- export type NodesTableFilters = z.input<typeof nodesTableFiltersSchema>;
41
+ const assetMetadataSchema = z.record(z.string(), z.string()).optional();
69
42
 
70
43
  /**
71
- * Create folder node
44
+ * Upload schema
72
45
  */
73
- export const createFolderNodeSchema = createNodeSchema.omit({
74
- type: true,
75
- contentType: true,
76
- size: true,
77
- subtype: true,
46
+ export const uploadInputSchema = z.object({
47
+ name: z.string().min(1),
48
+ visibility: storageAssetVisibilitySchema.optional().default("private"),
49
+ size: z.number().int().nonnegative().nullable().optional(),
50
+ contentType: z.string().nullable().optional(),
51
+ metadata: assetMetadataSchema,
52
+ body: objectBodyInputSchema,
78
53
  });
79
54
 
80
- export type CreateFolderNodeSchema = z.infer<typeof createFolderNodeSchema>;
81
-
82
- /**
83
- * Upload file schema
84
- */
85
- export const uploadFileSchema = createNodeSchema.omit({ type: true });
86
-
87
- export type UploadFileSchema = z.infer<typeof uploadFileSchema>;
88
-
89
- /**
90
- * Presign file schema
91
- */
92
- export const presignFileSchema = uploadFileSchema.extend({ id: z.uuid() });
93
-
94
- export type PresignFileSchema = z.infer<typeof presignFileSchema>;
95
-
96
- /**
97
- * Get file url schema
98
- */
99
- export const getFileURLSchemaDefaults = { variant: "main", disposition: "inline" } as const;
100
-
101
- export const getFileURLSchema = z.object({
102
- variant: z.enum(imageVariants).optional().default(getFileURLSchemaDefaults.variant),
103
- disposition: z.enum(imageDispositions).optional().default(getFileURLSchemaDefaults.disposition),
55
+ export const presignUploadInputSchema = z.object({
56
+ uploadId: z.uuid().optional(),
57
+ name: z.string().min(1),
58
+ visibility: storageAssetVisibilitySchema.optional().default("private"),
59
+ size: z.number().int().nonnegative().nullable().optional(),
60
+ contentType: z.string().nullable().optional(),
61
+ metadata: assetMetadataSchema,
104
62
  });
105
63
 
106
- export type GetFileUrlInput = z.input<typeof getFileURLSchema>;
107
- export type GetFileURLSchema = z.infer<typeof getFileURLSchema>;
108
-
109
- /**
110
- * Get by parent id input
111
- */
112
- export const getNodesByParentIdSchema = tableQuerySchema
113
- .pick({ order: true, sort: true, search: true })
114
- .extend({ filters: nodesTableFiltersSchema });
115
-
116
- export type GetNodesByParentIdInput = z.input<typeof getNodesByParentIdSchema>;
117
-
118
- /**
119
- * Get object input
120
- */
121
- export const getObjectSchema = z.object({
122
- id: z.string(),
123
- variant: z.enum(imageVariants).optional().default(getFileURLSchemaDefaults.variant),
124
- disposition: z.string().optional().default(getFileURLSchemaDefaults.disposition),
64
+ export const presignUploadOutputSchema = selectStorageAssetSchema.extend({
65
+ presignedUrl: z.string(),
125
66
  });
126
67
 
127
- export type GetObjectInput = z.input<typeof getObjectSchema>;
128
- export type GetObjectSchema = z.infer<typeof getObjectSchema>;
68
+ export const confirmUploadInputSchema = z
69
+ .uuid()
70
+ .describe("The upload id of the pending upload to confirm, returned from the presign endpoint");
71
+
72
+ export type UploadInput = z.input<typeof uploadInputSchema>;
73
+ export type PresignUploadInput = z.input<typeof presignUploadInputSchema>;
74
+ export type PresignUploadOutput = z.infer<typeof presignUploadOutputSchema>;
75
+ export type ConfirmUploadInput = z.input<typeof confirmUploadInputSchema>;
129
76
 
130
77
  /**
131
- * Put object input
78
+ * Get file url schema
132
79
  */
133
- export const putObjectSchema = z.object({
134
- id: z.string(),
135
- name: z.string().optional().default(""),
136
- variant: z.enum(imageVariants).optional().default("main"),
137
- body: z.any().optional(),
138
- contentType: z.string().nullable().optional(),
139
- size: z.number().nullable().optional(),
80
+ export const getAssetURLSchema = z.object({
81
+ disposition: z.enum(imageDispositions).optional().default(getObjectOptionsDefaults.disposition),
140
82
  });
141
83
 
142
- export type PutObjectInput = z.input<typeof putObjectSchema> & {
143
- body?: PutObjectCommandInput["Body"];
144
- };
145
-
146
- export type PutObjectSchema = z.infer<typeof putObjectSchema>;
84
+ export type GetAssetURLInput = z.input<typeof getAssetURLSchema>;
85
+ export type GetAssetURLSchema = z.infer<typeof getAssetURLSchema>;
@@ -0,0 +1,281 @@
1
+ import { Readable } from "node:stream";
2
+ import type { ReadableStream } from "node:stream/web";
3
+ import {
4
+ DeleteObjectCommand,
5
+ DeleteObjectsCommand,
6
+ GetObjectCommand,
7
+ type GetObjectCommandOutput,
8
+ HeadObjectCommand,
9
+ PutObjectCommand,
10
+ S3Client,
11
+ type S3ClientConfig,
12
+ } from "@aws-sdk/client-s3";
13
+ import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
14
+ import z from "zod";
15
+ import type { StorageProvider } from "../lib/constants";
16
+ import { StorageAdapterError } from "../lib/errors";
17
+ import type { StorageAdapter } from "../lib/types";
18
+ import {
19
+ type GetObjectInput,
20
+ type GetObjectOptions,
21
+ type GetObjectOutput,
22
+ type GetObjectURLOptions,
23
+ getObjectInputSchema,
24
+ getObjectOptionsSchema,
25
+ getObjectOutputSchema,
26
+ getObjectURLOptionsSchema,
27
+ type HeadObjectInput,
28
+ type HeadObjectOutput,
29
+ headObjectInputSchema,
30
+ headObjectOutputSchema,
31
+ type PutObjectInput,
32
+ type PutObjectOutput,
33
+ type PutObjectURLInput,
34
+ type PutObjectURLOptions,
35
+ putObjectInputSchema,
36
+ putObjectOutputSchema,
37
+ putObjectURLInputSchema,
38
+ putObjectURLOptionsSchema,
39
+ } from "../lib/validators";
40
+
41
+ export type StorageS3AdapterConfig = S3ClientConfig & {
42
+ bucketName: string;
43
+ };
44
+
45
+ /**
46
+ * S3 Storage Adapter
47
+ * This adapter implements the storage service interface using AWS S3 as the backend.
48
+ * It provides methods for uploading, retrieving, and managing files in an S3 bucket.
49
+ */
50
+ class StorageS3Adapter implements StorageAdapter {
51
+ /**
52
+ * S3 Client
53
+ */
54
+ key: StorageProvider = "s3";
55
+ client: S3Client;
56
+ bucketName: string;
57
+
58
+ /**
59
+ * Constructor
60
+ */
61
+ constructor({ bucketName, ...config }: StorageS3AdapterConfig) {
62
+ this.client = new S3Client(config);
63
+ this.bucketName = bucketName;
64
+ }
65
+
66
+ /**
67
+ * Create get command
68
+ */
69
+ #createGetCommand(input: GetObjectInput, options: GetObjectOptions = {}) {
70
+ const key = getObjectInputSchema.parse(input);
71
+ const { disposition } = getObjectOptionsSchema.parse(options);
72
+
73
+ return new GetObjectCommand({
74
+ Bucket: this.bucketName,
75
+ Key: key,
76
+ ResponseContentDisposition: disposition,
77
+ });
78
+ }
79
+
80
+ /**
81
+ * Get object
82
+ */
83
+ async getObject(input: GetObjectInput, options: GetObjectOptions = {}): Promise<GetObjectOutput> {
84
+ const getCommand = this.#createGetCommand(input, options);
85
+
86
+ const result = await this.client.send(getCommand);
87
+
88
+ if (result.Body == null) {
89
+ throw new StorageAdapterError("OBJECT_NOT_READABLE", "Object body is missing", {
90
+ cause: new Error(
91
+ `ContentLength: ${result.ContentLength}, ContentType: ${result.ContentType}, Body: ${result.Body}`,
92
+ ),
93
+ });
94
+ }
95
+
96
+ return getObjectOutputSchema.parse({
97
+ contentType: result.ContentType,
98
+ size: result.ContentLength,
99
+ metadata: result.Metadata,
100
+ body: this.#toReadable(result.Body),
101
+ });
102
+ }
103
+
104
+ /**
105
+ * Get object URL
106
+ */
107
+ async getObjectURL(input: GetObjectInput, options: GetObjectURLOptions = {}) {
108
+ const { expiresIn } = getObjectURLOptionsSchema.parse(options);
109
+
110
+ // Validate input and create get command
111
+ const getCommand = this.#createGetCommand(input, options);
112
+
113
+ // Generate the presigned url
114
+ return await getSignedUrl(this.client, getCommand, { expiresIn });
115
+ }
116
+
117
+ /**
118
+ * Create head command
119
+ */
120
+ #createHeadCommand(input: HeadObjectInput) {
121
+ const { key } = headObjectInputSchema.parse(input);
122
+
123
+ return new HeadObjectCommand({
124
+ Bucket: this.bucketName,
125
+ Key: key,
126
+ });
127
+ }
128
+
129
+ /**
130
+ * Head object
131
+ */
132
+ async headObject(input: HeadObjectInput): Promise<HeadObjectOutput> {
133
+ const headCommand = this.#createHeadCommand(input);
134
+
135
+ const result = await this.client.send(headCommand);
136
+
137
+ if (result.ContentLength == null || result.ContentType == null) {
138
+ throw new StorageAdapterError("OBJECT_NOT_FOUND", "Object metadata could not be resolved", {
139
+ cause: new Error(
140
+ `ContentLength: ${result.ContentLength}, ContentType: ${result.ContentType}`,
141
+ ),
142
+ });
143
+ }
144
+
145
+ return headObjectOutputSchema.parse({
146
+ contentType: result.ContentType,
147
+ size: result.ContentLength,
148
+ metadata: result.Metadata,
149
+ });
150
+ }
151
+
152
+ /**
153
+ * Create put command
154
+ */
155
+ #createPutCommand(
156
+ data: z.infer<typeof putObjectInputSchema> | z.infer<typeof putObjectURLInputSchema>,
157
+ ) {
158
+ return new PutObjectCommand({
159
+ Bucket: this.bucketName,
160
+ Key: data.key,
161
+ Body: "body" in data ? data.body : undefined,
162
+ ContentType: data.contentType ?? undefined,
163
+ ContentLength: data.size ?? undefined,
164
+ Metadata: data.metadata ?? undefined,
165
+ });
166
+ }
167
+
168
+ /**
169
+ * Put object
170
+ */
171
+ async putObject(input: PutObjectInput): Promise<PutObjectOutput> {
172
+ const data = putObjectInputSchema.parse(input);
173
+ const putCommand = this.#createPutCommand(data);
174
+
175
+ const result = await this.client.send(putCommand);
176
+
177
+ return putObjectOutputSchema.parse({ size: result.Size });
178
+ }
179
+
180
+ /**
181
+ * Get signed URL
182
+ */
183
+ async putObjectURL(input: PutObjectURLInput, options: PutObjectURLOptions = {}) {
184
+ const { expiresIn } = putObjectURLOptionsSchema.parse(options);
185
+
186
+ // Validate input and create put command
187
+ const data = putObjectURLInputSchema.parse(input);
188
+ const putCommand = this.#createPutCommand(data);
189
+
190
+ // Generate the presigned url
191
+ return await getSignedUrl(this.client, putCommand, { expiresIn });
192
+ }
193
+
194
+ /**
195
+ * Delete object
196
+ */
197
+ async deleteObject(input: string): Promise<void> {
198
+ const key = z.string().parse(input);
199
+
200
+ const deleteCommand = new DeleteObjectCommand({
201
+ Bucket: this.bucketName,
202
+ Key: key,
203
+ });
204
+
205
+ const response = await this.client.send(deleteCommand);
206
+
207
+ if (response.DeleteMarker !== true && response.VersionId) {
208
+ throw new StorageAdapterError("OBJECT_DELETE_FAILED", "Failed to delete object", {
209
+ cause: new Error(
210
+ `DeleteMarker: ${response.DeleteMarker}, VersionId: ${response.VersionId}`,
211
+ ),
212
+ });
213
+ }
214
+ }
215
+
216
+ /**
217
+ * Delete multiple objects
218
+ */
219
+ async deleteObjects(input: string[]): Promise<void> {
220
+ const keys = z.array(z.string()).parse(input);
221
+
222
+ const deleteCommand = new DeleteObjectsCommand({
223
+ Bucket: this.bucketName,
224
+ Delete: { Objects: keys.map((Key) => ({ Key })) },
225
+ });
226
+
227
+ const response = await this.client.send(deleteCommand);
228
+
229
+ if (response.Errors && response.Errors.length > 0) {
230
+ throw new StorageAdapterError("OBJECT_DELETE_FAILED", "Failed to delete objects", {
231
+ cause: new Error(JSON.stringify(response.Errors)),
232
+ });
233
+ }
234
+ }
235
+
236
+ /**
237
+ * Transform the GetObjectCommandOutput Body into a normalized Readable stream
238
+ * S3 can return the Body in different formats depending on the environment and AWS SDK version:
239
+ * - In Node.js, it may return a Readable stream.
240
+ * - In newer AWS SDK versions in Node 18+, it may return a web ReadableStream with transformToWebStream method.
241
+ * - In older AWS SDK versions in Node 16, it may return a web ReadableStream without transformToWebStream.
242
+ * - It may also return a string, Buffer, or Uint8Array for small objects.
243
+ *
244
+ * This method normalizes all these cases into a Node.js Readable stream for consistent handling in the application.
245
+ */
246
+ #toReadable(body: GetObjectCommandOutput["Body"]): Readable {
247
+ if (!body) throw new StorageAdapterError("OBJECT_NOT_READABLE", "S3 object body is empty");
248
+
249
+ // If it's already a Node Readable, return as is
250
+ if (body instanceof Readable) return body;
251
+
252
+ if (typeof body.transformToWebStream === "function") {
253
+ // biome-ignore lint/suspicious/noExplicitAny: The AWS SDK v3 in Node 18+ returns a web ReadableStream with a transformToWebStream method, but the types don't reflect this correctly, so we need to use 'any' here.
254
+ return Readable.fromWeb((body as any).transformToWebStream());
255
+ }
256
+
257
+ // biome-ignore lint/suspicious/noExplicitAny: The AWS SDK v3 in Node 16 returns a web ReadableStream without a transformToWebStream method, but the types don't reflect this correctly, so we need to use 'any' here.
258
+ if (typeof (body as any).getReader === "function") {
259
+ return Readable.fromWeb(body as unknown as ReadableStream);
260
+ }
261
+
262
+ // If it's a string, Buffer, or Uint8Array, convert to Readable
263
+ if (typeof body === "string" || body instanceof Uint8Array || Buffer.isBuffer(body)) {
264
+ return Readable.from([body]);
265
+ }
266
+
267
+ throw new StorageAdapterError("UNSUPPORTED_BODY_TYPE", "Unsupported object body type");
268
+ }
269
+ }
270
+
271
+ /**
272
+ * S3 Storage Adapter
273
+ *
274
+ * This adapter implements the storage service interface using AWS S3 as the backend.
275
+ * It provides methods for uploading, retrieving, and managing files in an S3 bucket.
276
+ *
277
+ * @returns An instance of the S3StorageAdapter class.
278
+ */
279
+ export function storageS3Adapter(config: StorageS3AdapterConfig): StorageAdapter {
280
+ return new StorageS3Adapter(config);
281
+ }
@@ -0,0 +1,3 @@
1
+ // Storage providers
2
+ export const storageProviders = ["s3"] as const;
3
+ export type StorageProvider = (typeof storageProviders)[number];
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Storage adapter error codes and class
3
+ */
4
+ export type StorageAdapterErrorCode =
5
+ | "OBJECT_NOT_FOUND"
6
+ | "OBJECT_NOT_READABLE"
7
+ | "OBJECT_DELETE_FAILED"
8
+ | "OBJECT_HEAD_FAILED"
9
+ | "OBJECT_UPLOAD_FAILED"
10
+ | "OBJECT_URL_FAILED"
11
+ | "UNSUPPORTED_BODY_TYPE";
12
+
13
+ export class StorageAdapterError extends Error {
14
+ code: StorageAdapterErrorCode;
15
+
16
+ constructor(code: StorageAdapterErrorCode, message: string, options?: ErrorOptions) {
17
+ super(message, options);
18
+ this.name = "StorageError";
19
+ this.code = code;
20
+ }
21
+ }
@@ -0,0 +1,28 @@
1
+ import type { StorageProvider } from "./constants";
2
+ import type {
3
+ GetObjectInput,
4
+ GetObjectOptions,
5
+ GetObjectOutput,
6
+ GetObjectURLOptions,
7
+ HeadObjectInput,
8
+ HeadObjectOutput,
9
+ PutObjectInput,
10
+ PutObjectOutput,
11
+ PutObjectURLInput,
12
+ PutObjectURLOptions,
13
+ } from "./validators";
14
+
15
+ /**
16
+ * Storage adapter interface
17
+ */
18
+ export interface StorageAdapter {
19
+ key: StorageProvider;
20
+ bucketName: string;
21
+ getObject: (input: GetObjectInput, options?: GetObjectOptions) => Promise<GetObjectOutput>;
22
+ getObjectURL: (input: GetObjectInput, options?: GetObjectURLOptions) => Promise<string>;
23
+ headObject: (input: HeadObjectInput) => Promise<HeadObjectOutput>;
24
+ putObject: (props: PutObjectInput) => Promise<PutObjectOutput>;
25
+ putObjectURL: (props: PutObjectURLInput, options?: PutObjectURLOptions) => Promise<string>;
26
+ deleteObject: (key: string) => Promise<void>;
27
+ deleteObjects: (keys: string[]) => Promise<void>;
28
+ }