@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.
- package/dist/auth/server.d.mts +3 -3
- package/dist/auth/server.mjs +3 -3
- package/dist/components/editor/components/editor.client.d.mts +4 -3
- package/dist/components/editor/components/editor.client.d.mts.map +1 -1
- package/dist/components/editor/components/editor.client.mjs +5 -2
- package/dist/components/editor/components/editor.client.mjs.map +1 -1
- package/dist/components/editor/extensions/file-handler/extension.d.mts +4 -4
- package/dist/components/editor/extensions/file-handler/extension.d.mts.map +1 -1
- package/dist/components/editor/extensions/file-handler/extension.mjs.map +1 -1
- package/dist/components/editor/extensions/file-handler/strategy.d.mts +4 -6
- package/dist/components/editor/extensions/file-handler/strategy.d.mts.map +1 -1
- package/dist/components/editor/extensions/file-handler/strategy.mjs +11 -11
- package/dist/components/editor/extensions/file-handler/strategy.mjs.map +1 -1
- package/dist/components/editor/extensions/file-handler/utils.mjs +1 -1
- package/dist/components/editor/extensions/file-handler/utils.mjs.map +1 -1
- package/dist/components/editor/extensions/image/extension.mjs +9 -9
- package/dist/components/editor/extensions/image/extension.mjs.map +1 -1
- package/dist/components/editor/lib/constants.d.mts +1 -1
- package/dist/components/editor/lib/constants.mjs +1 -1
- package/dist/components/editor/lib/extensions.d.mts +1 -1
- package/dist/components/editor/lib/helpers.d.mts +11 -3
- package/dist/components/editor/lib/helpers.d.mts.map +1 -1
- package/dist/components/editor/lib/helpers.mjs +27 -13
- package/dist/components/editor/lib/helpers.mjs.map +1 -1
- package/dist/components/ui/combobox-dropdown.client.mjs +1 -0
- package/dist/components/ui/combobox-dropdown.client.mjs.map +1 -1
- package/dist/components/ui/combobox.client.mjs +1 -1
- package/dist/components/ui/combobox.client.mjs.map +1 -1
- package/dist/components.d.mts +2 -2
- package/dist/components.mjs +2 -2
- package/dist/config/server.d.mts +1 -3
- package/dist/config/server.mjs +1 -4
- package/dist/config.d.mts +2 -2
- package/dist/config.mjs +1 -1
- package/dist/data-tables/client.d.mts +2 -1
- package/dist/data-tables/client.mjs +2 -1
- package/dist/data-tables.d.mts +1 -1
- package/dist/database/client.d.mts +1 -0
- package/dist/database/client.mjs +1 -0
- package/dist/database/server.d.mts +2 -0
- package/dist/database/server.mjs +3 -0
- package/dist/database.d.mts +3 -0
- package/dist/database.mjs +3 -0
- package/dist/emails/client.d.mts +1 -0
- package/dist/emails/client.mjs +1 -0
- package/dist/emails/server.d.mts +2 -0
- package/dist/emails/server.mjs +3 -0
- package/dist/emails.d.mts +1 -0
- package/dist/emails.mjs +1 -0
- package/dist/lib/utils/markdown.d.mts +10 -0
- package/dist/lib/utils/markdown.d.mts.map +1 -0
- package/dist/lib/utils/markdown.mjs +15 -0
- package/dist/lib/utils/markdown.mjs.map +1 -0
- package/dist/lib/utils/url.mjs +2 -1
- package/dist/lib/utils/url.mjs.map +1 -1
- package/dist/lib/utils/user-agent.mjs +15 -0
- package/dist/lib/utils/user-agent.mjs.map +1 -1
- package/dist/lib.d.mts +2 -2
- package/dist/lib.mjs +2 -2
- package/dist/modules/auth/components/create-first-user-guard.server.d.mts +16 -0
- package/dist/modules/auth/components/create-first-user-guard.server.d.mts.map +1 -0
- package/dist/modules/auth/components/create-first-user-guard.server.mjs +16 -0
- package/dist/modules/auth/components/create-first-user-guard.server.mjs.map +1 -0
- package/dist/modules/auth/components/guard.server.d.mts +2 -2
- package/dist/modules/auth/components/guard.server.mjs +1 -1
- package/dist/modules/auth/components/guard.server.mjs.map +1 -1
- package/dist/modules/auth/db/schema.d.mts +1 -1
- package/dist/modules/auth/db/schema.mjs +2 -2
- package/dist/modules/auth/handler/create-client.client.d.mts +4838 -229
- package/dist/modules/auth/handler/create-client.client.d.mts.map +1 -1
- package/dist/modules/auth/handler/create-client.client.mjs.map +1 -1
- package/dist/modules/auth/handler/proxy.server.mjs +2 -2
- package/dist/modules/auth/handler/proxy.server.mjs.map +1 -1
- package/dist/modules/auth/handler/route.server.d.mts +2 -2
- package/dist/modules/auth/handler/route.server.d.mts.map +1 -1
- package/dist/modules/auth/handler/route.server.mjs.map +1 -1
- package/dist/modules/auth/handler/{init.d.mts → service.server.d.mts} +322 -90
- package/dist/modules/auth/handler/service.server.d.mts.map +1 -0
- package/dist/modules/auth/handler/{init.mjs → service.server.mjs} +19 -8
- package/dist/modules/auth/handler/service.server.mjs.map +1 -0
- package/dist/modules/auth/hooks/use-session.d.mts +9 -4
- package/dist/modules/auth/hooks/use-session.d.mts.map +1 -1
- package/dist/modules/auth/lib/helpers.server.d.mts +1 -1
- package/dist/modules/auth/lib/permissions.d.mts +1 -1
- package/dist/modules/auth/lib/validators.mjs +1 -1
- package/dist/modules/config/lib/context.d.mts +9 -10
- package/dist/modules/config/lib/context.d.mts.map +1 -1
- package/dist/modules/config/lib/context.mjs.map +1 -1
- package/dist/modules/data-tables/lib/converters/search.d.mts +1 -1
- package/dist/modules/data-tables/lib/converters/sorting.d.mts +1 -1
- package/dist/modules/data-tables/server/get-data.server.d.mts +3 -3
- package/dist/modules/data-tables/server/get-data.server.mjs +1 -1
- package/dist/modules/data-tables/server/get-data.server.mjs.map +1 -1
- package/dist/modules/data-tables/strategies/infinite/strategy.d.mts +1 -1
- package/dist/modules/data-tables/strategies/infinite/strategy.mjs +3 -0
- package/dist/modules/data-tables/strategies/infinite/strategy.mjs.map +1 -1
- package/dist/modules/data-tables/tables/data-table/components/row.mjs +5 -15
- package/dist/modules/data-tables/tables/data-table/components/row.mjs.map +1 -1
- package/dist/modules/data-tables/tables/inline-table/components/body.mjs +1 -1
- package/dist/modules/data-tables/tables/inline-table/components/body.mjs.map +1 -1
- package/dist/modules/data-tables/tables/inline-table/components/row.client.mjs +13 -23
- package/dist/modules/data-tables/tables/inline-table/components/row.client.mjs.map +1 -1
- package/dist/modules/data-tables/tables/inline-table/components/table.d.mts +1 -0
- package/dist/modules/data-tables/tables/inline-table/components/table.d.mts.map +1 -1
- package/dist/modules/data-tables/tables/inline-table/components/table.mjs +2 -1
- package/dist/modules/data-tables/tables/inline-table/components/table.mjs.map +1 -1
- package/dist/modules/data-tables/tables/inline-table/hooks/context.client.d.mts +5 -1
- package/dist/modules/data-tables/tables/inline-table/hooks/context.client.d.mts.map +1 -1
- package/dist/modules/data-tables/tables/inline-table/hooks/context.client.mjs +2 -1
- package/dist/modules/data-tables/tables/inline-table/hooks/context.client.mjs.map +1 -1
- package/dist/modules/data-tables/tables/inline-table/hooks/use-hotkeys.client.d.mts +30 -0
- package/dist/modules/data-tables/tables/inline-table/hooks/use-hotkeys.client.d.mts.map +1 -0
- package/dist/modules/data-tables/tables/inline-table/hooks/use-hotkeys.client.mjs +77 -9
- package/dist/modules/data-tables/tables/inline-table/hooks/use-hotkeys.client.mjs.map +1 -1
- package/dist/modules/{config/db → database/lib}/helpers.d.mts +2 -2
- package/dist/modules/database/lib/helpers.d.mts.map +1 -0
- package/dist/modules/{config/db → database/lib}/helpers.mjs +1 -1
- package/dist/modules/database/lib/helpers.mjs.map +1 -0
- package/dist/modules/database/lib/service.server.d.mts +34 -0
- package/dist/modules/database/lib/service.server.d.mts.map +1 -0
- package/dist/modules/database/lib/service.server.mjs +24 -0
- package/dist/modules/database/lib/service.server.mjs.map +1 -0
- package/dist/modules/{config/db → database/lib}/types.d.mts +1 -1
- package/dist/modules/database/lib/types.d.mts.map +1 -0
- package/dist/modules/emails/lib/service.server.d.mts +29 -0
- package/dist/modules/emails/lib/service.server.d.mts.map +1 -0
- package/dist/modules/emails/lib/service.server.mjs +21 -0
- package/dist/modules/emails/lib/service.server.mjs.map +1 -0
- package/dist/modules/inline-edit/components/date-input.client.mjs +1 -1
- package/dist/modules/inline-edit/components/date-input.client.mjs.map +1 -1
- package/dist/modules/inline-edit/components/date-picker.client.mjs +1 -0
- package/dist/modules/inline-edit/components/date-picker.client.mjs.map +1 -1
- package/dist/modules/inline-edit/components/date-time.client.mjs +1 -0
- package/dist/modules/inline-edit/components/date-time.client.mjs.map +1 -1
- package/dist/modules/inline-edit/components/editor.client.mjs +1 -0
- package/dist/modules/inline-edit/components/editor.client.mjs.map +1 -1
- package/dist/modules/inline-edit/components/input-recipient.client.mjs +1 -0
- package/dist/modules/inline-edit/components/input-recipient.client.mjs.map +1 -1
- package/dist/modules/inline-edit/components/input-toggle.client.mjs +1 -0
- package/dist/modules/inline-edit/components/input-toggle.client.mjs.map +1 -1
- package/dist/modules/inline-edit/components/input.client.d.mts.map +1 -1
- package/dist/modules/inline-edit/components/input.client.mjs +3 -0
- package/dist/modules/inline-edit/components/input.client.mjs.map +1 -1
- package/dist/modules/inline-edit/components/select.client.d.mts.map +1 -1
- package/dist/modules/inline-edit/components/select.client.mjs +1 -0
- package/dist/modules/inline-edit/components/select.client.mjs.map +1 -1
- package/dist/modules/inline-edit/components/switch.client.mjs +1 -0
- package/dist/modules/inline-edit/components/switch.client.mjs.map +1 -1
- package/dist/modules/inline-edit/components/toggle.client.mjs +1 -0
- package/dist/modules/inline-edit/components/toggle.client.mjs.map +1 -1
- package/dist/modules/router/handler/context.server.d.mts +12 -10
- package/dist/modules/router/handler/context.server.d.mts.map +1 -1
- package/dist/modules/router/handler/init.server.d.mts +13 -11
- package/dist/modules/router/handler/init.server.d.mts.map +1 -1
- package/dist/modules/router/handler/init.server.mjs +2 -2
- package/dist/modules/router/handler/init.server.mjs.map +1 -1
- package/dist/modules/router/handler/route.server.d.mts +1 -1
- package/dist/modules/storage/components/dropzone.client.d.mts +2 -2
- package/dist/modules/storage/components/dropzone.client.d.mts.map +1 -1
- package/dist/modules/storage/components/dropzone.client.mjs.map +1 -1
- package/dist/modules/storage/components/image-grid.client.d.mts +3 -3
- package/dist/modules/storage/components/image-grid.client.d.mts.map +1 -1
- package/dist/modules/storage/components/image-grid.client.mjs +20 -22
- package/dist/modules/storage/components/image-grid.client.mjs.map +1 -1
- package/dist/modules/storage/components/image.client.d.mts +8 -0
- package/dist/modules/storage/components/image.client.d.mts.map +1 -0
- package/dist/modules/storage/components/image.client.mjs +17 -0
- package/dist/modules/storage/components/image.client.mjs.map +1 -0
- package/dist/modules/storage/components/upload-button.client.d.mts +12 -0
- package/dist/modules/storage/components/upload-button.client.d.mts.map +1 -0
- package/dist/modules/storage/components/upload-button.client.mjs +34 -0
- package/dist/modules/storage/components/upload-button.client.mjs.map +1 -0
- package/dist/modules/storage/components/upload-zone-context.client.d.mts +5 -5
- package/dist/modules/storage/components/upload-zone-context.client.d.mts.map +1 -1
- package/dist/modules/storage/components/upload-zone-context.client.mjs +2 -2
- package/dist/modules/storage/components/upload-zone-context.client.mjs.map +1 -1
- package/dist/modules/storage/components/upload-zone.client.d.mts +4 -4
- package/dist/modules/storage/components/upload-zone.client.d.mts.map +1 -1
- package/dist/modules/storage/components/upload-zone.client.mjs +16 -9
- package/dist/modules/storage/components/upload-zone.client.mjs.map +1 -1
- package/dist/modules/storage/lib/constants.d.mts +1 -5
- package/dist/modules/storage/lib/constants.d.mts.map +1 -1
- package/dist/modules/storage/lib/constants.mjs +1 -13
- package/dist/modules/storage/lib/constants.mjs.map +1 -1
- package/dist/modules/storage/lib/helpers.d.mts +14 -28
- package/dist/modules/storage/lib/helpers.d.mts.map +1 -1
- package/dist/modules/storage/lib/helpers.mjs +17 -75
- package/dist/modules/storage/lib/helpers.mjs.map +1 -1
- package/dist/modules/storage/lib/procedures.server.d.mts +1991 -0
- package/dist/modules/{auth/handler/init.d.mts.map → storage/lib/procedures.server.d.mts.map} +1 -1
- package/dist/modules/storage/lib/procedures.server.mjs +22 -0
- package/dist/modules/storage/lib/procedures.server.mjs.map +1 -0
- package/dist/modules/storage/lib/router-handlers.server.d.mts +41 -0
- package/dist/modules/storage/lib/router-handlers.server.d.mts.map +1 -0
- package/dist/modules/storage/lib/router-handlers.server.mjs +124 -0
- package/dist/modules/storage/lib/router-handlers.server.mjs.map +1 -0
- package/dist/modules/storage/lib/schema.d.mts +68 -958
- package/dist/modules/storage/lib/schema.d.mts.map +1 -1
- package/dist/modules/storage/lib/schema.mjs +28 -65
- package/dist/modules/storage/lib/schema.mjs.map +1 -1
- package/dist/modules/storage/lib/service.server.d.mts +2155 -141
- package/dist/modules/storage/lib/service.server.d.mts.map +1 -1
- package/dist/modules/storage/lib/service.server.mjs +453 -242
- package/dist/modules/storage/lib/service.server.mjs.map +1 -1
- package/dist/modules/storage/lib/upload.client.d.mts +58 -0
- package/dist/modules/storage/lib/upload.client.d.mts.map +1 -0
- package/dist/modules/storage/lib/upload.client.mjs +87 -0
- package/dist/modules/storage/lib/upload.client.mjs.map +1 -0
- package/dist/modules/storage/lib/validators.d.mts +297 -835
- package/dist/modules/storage/lib/validators.d.mts.map +1 -1
- package/dist/modules/storage/lib/validators.mjs +32 -76
- package/dist/modules/storage/lib/validators.mjs.map +1 -1
- package/dist/modules/storage/providers/adapters/s3.server.d.mts +19 -0
- package/dist/modules/storage/providers/adapters/s3.server.d.mts.map +1 -0
- package/dist/modules/storage/providers/adapters/s3.server.mjs +173 -0
- package/dist/modules/storage/providers/adapters/s3.server.mjs.map +1 -0
- package/dist/modules/storage/providers/lib/constants.d.mts +6 -0
- package/dist/modules/storage/providers/lib/constants.d.mts.map +1 -0
- package/dist/modules/storage/providers/lib/constants.mjs +6 -0
- package/dist/modules/storage/providers/lib/constants.mjs.map +1 -0
- package/dist/modules/storage/providers/lib/errors.d.mts +12 -0
- package/dist/modules/storage/providers/lib/errors.d.mts.map +1 -0
- package/dist/modules/storage/providers/lib/errors.mjs +13 -0
- package/dist/modules/storage/providers/lib/errors.mjs.map +1 -0
- package/dist/modules/storage/providers/lib/types.d.mts +21 -0
- package/dist/modules/storage/providers/lib/types.d.mts.map +1 -0
- package/dist/modules/storage/providers/lib/validators.d.mts +112 -0
- package/dist/modules/storage/providers/lib/validators.d.mts.map +1 -0
- package/dist/modules/storage/providers/lib/validators.mjs +75 -0
- package/dist/modules/storage/providers/lib/validators.mjs.map +1 -0
- package/dist/router/server.d.mts +1 -1
- package/dist/storage/client.d.mts +4 -2
- package/dist/storage/client.mjs +4 -2
- package/dist/storage/server.d.mts +5 -4
- package/dist/storage/server.mjs +5 -4
- package/dist/storage.d.mts +9 -6
- package/dist/storage.mjs +8 -6
- package/package.json +18 -5
- package/src/components/editor/components/editor.client.tsx +9 -1
- package/src/components/editor/extensions/file-handler/extension.ts +4 -4
- package/src/components/editor/extensions/file-handler/strategy.ts +15 -40
- package/src/components/editor/extensions/file-handler/utils.ts +1 -1
- package/src/components/editor/extensions/image/extension.ts +10 -10
- package/src/components/editor/lib/helpers.ts +28 -11
- package/src/components/ui/combobox-dropdown.client.tsx +1 -0
- package/src/components/ui/combobox.client.tsx +1 -1
- package/src/entry.ts +12 -51
- package/src/lib/entry.ts +1 -5
- package/src/lib/utils/markdown.ts +10 -0
- package/src/lib/utils/url.ts +2 -1
- package/src/lib/utils/user-agent.ts +15 -0
- package/src/modules/auth/components/{guard-first-user.server.tsx → create-first-user-guard.server.tsx} +8 -8
- package/src/modules/auth/components/guard.server.tsx +1 -1
- package/src/modules/auth/entry.server.ts +4 -5
- package/src/modules/auth/handler/create-client.client.ts +2 -2
- package/src/modules/auth/handler/proxy.server.ts +1 -1
- package/src/modules/auth/handler/route.server.ts +2 -2
- package/src/modules/auth/handler/{init.ts → service.server.ts} +30 -9
- package/src/modules/config/entry.server.ts +0 -9
- package/src/modules/config/entry.ts +2 -2
- package/src/modules/config/lib/context.ts +9 -9
- package/src/modules/data-tables/entry.client.ts +1 -0
- package/src/modules/data-tables/server/get-data.server.ts +1 -1
- package/src/modules/data-tables/strategies/infinite/strategy.ts +4 -1
- package/src/modules/data-tables/tables/data-table/components/row.tsx +12 -21
- package/src/modules/data-tables/tables/inline-table/components/body.tsx +1 -1
- package/src/modules/data-tables/tables/inline-table/components/row.client.tsx +24 -30
- package/src/modules/data-tables/tables/inline-table/components/table.tsx +6 -1
- package/src/modules/data-tables/tables/inline-table/hooks/context.client.tsx +5 -0
- package/src/modules/data-tables/tables/inline-table/hooks/use-hotkeys.client.ts +119 -91
- package/src/modules/database/entry.client.ts +0 -0
- package/src/modules/database/entry.server.ts +4 -0
- package/src/modules/database/entry.ts +5 -0
- package/src/modules/database/lib/service.server.ts +33 -0
- package/src/modules/emails/entry.client.ts +0 -0
- package/src/modules/emails/entry.server.ts +4 -0
- package/src/modules/emails/entry.ts +0 -0
- package/src/modules/emails/lib/service.server.ts +29 -0
- package/src/modules/inline-edit/components/date-input.client.tsx +1 -1
- package/src/modules/inline-edit/components/date-picker.client.tsx +1 -0
- package/src/modules/inline-edit/components/date-time.client.tsx +1 -0
- package/src/modules/inline-edit/components/editor.client.tsx +3 -0
- package/src/modules/inline-edit/components/input-recipient.client.tsx +1 -0
- package/src/modules/inline-edit/components/input-toggle.client.tsx +1 -0
- package/src/modules/inline-edit/components/input.client.tsx +3 -0
- package/src/modules/inline-edit/components/select.client.tsx +5 -1
- package/src/modules/inline-edit/components/switch.client.tsx +1 -0
- package/src/modules/inline-edit/components/toggle.client.tsx +1 -0
- package/src/modules/router/handler/init.server.ts +2 -2
- package/src/modules/storage/components/dropzone.client.tsx +1 -1
- package/src/modules/storage/components/image-grid.client.tsx +23 -20
- package/src/modules/storage/components/image.client.tsx +8 -0
- package/src/modules/storage/components/upload-zone-context.client.tsx +11 -8
- package/src/modules/storage/components/upload-zone.client.tsx +22 -16
- package/src/modules/storage/entry.client.ts +3 -1
- package/src/modules/storage/entry.server.ts +9 -3
- package/src/modules/storage/entry.ts +13 -1
- package/src/modules/storage/lib/constants.ts +0 -11
- package/src/modules/storage/lib/helpers.ts +18 -65
- package/src/modules/storage/lib/procedures.server.ts +60 -0
- package/src/modules/storage/lib/router-handlers.server.ts +178 -0
- package/src/modules/storage/lib/schema.ts +26 -97
- package/src/modules/storage/lib/service.server.ts +636 -374
- package/src/modules/storage/lib/upload.client.ts +156 -0
- package/src/modules/storage/lib/validators.ts +50 -111
- package/src/modules/storage/providers/adapters/s3.server.ts +281 -0
- package/src/modules/storage/providers/lib/constants.ts +3 -0
- package/src/modules/storage/providers/lib/errors.ts +21 -0
- package/src/modules/storage/providers/lib/types.ts +28 -0
- package/src/modules/storage/providers/lib/validators.ts +122 -0
- package/dist/lib/config/constants.d.mts +0 -5
- package/dist/lib/config/constants.d.mts.map +0 -1
- package/dist/lib/config/constants.mjs +0 -6
- package/dist/lib/config/constants.mjs.map +0 -1
- package/dist/modules/auth/components/guard-first-user.server.d.mts +0 -18
- package/dist/modules/auth/components/guard-first-user.server.d.mts.map +0 -1
- package/dist/modules/auth/components/guard-first-user.server.mjs +0 -16
- package/dist/modules/auth/components/guard-first-user.server.mjs.map +0 -1
- package/dist/modules/auth/handler/init.mjs.map +0 -1
- package/dist/modules/config/db/helpers.d.mts.map +0 -1
- package/dist/modules/config/db/helpers.mjs.map +0 -1
- package/dist/modules/config/db/init.d.mts +0 -20
- package/dist/modules/config/db/init.d.mts.map +0 -1
- package/dist/modules/config/db/init.mjs +0 -15
- package/dist/modules/config/db/init.mjs.map +0 -1
- package/dist/modules/config/db/types.d.mts.map +0 -1
- package/dist/modules/config/providers/email.d.mts +0 -12
- package/dist/modules/config/providers/email.d.mts.map +0 -1
- package/dist/modules/config/providers/email.mjs +0 -11
- package/dist/modules/config/providers/email.mjs.map +0 -1
- package/dist/modules/storage/config/filters.d.mts +0 -17
- package/dist/modules/storage/config/filters.d.mts.map +0 -1
- package/dist/modules/storage/config/filters.mjs +0 -17
- package/dist/modules/storage/config/filters.mjs.map +0 -1
- package/dist/modules/storage/lib/create-client.server.d.mts +0 -11
- package/dist/modules/storage/lib/create-client.server.d.mts.map +0 -1
- package/dist/modules/storage/lib/create-client.server.mjs +0 -11
- package/dist/modules/storage/lib/create-client.server.mjs.map +0 -1
- package/dist/modules/storage/lib/create-upload.client.d.mts +0 -56
- package/dist/modules/storage/lib/create-upload.client.d.mts.map +0 -1
- package/dist/modules/storage/lib/create-upload.client.mjs +0 -98
- package/dist/modules/storage/lib/create-upload.client.mjs.map +0 -1
- package/dist/modules/storage/lib/proxy.server.d.mts +0 -21
- package/dist/modules/storage/lib/proxy.server.d.mts.map +0 -1
- package/dist/modules/storage/lib/proxy.server.mjs +0 -46
- package/dist/modules/storage/lib/proxy.server.mjs.map +0 -1
- package/dist/modules/storage/lib/router.server.d.mts +0 -31002
- package/dist/modules/storage/lib/router.server.d.mts.map +0 -1
- package/dist/modules/storage/lib/router.server.mjs +0 -86
- package/dist/modules/storage/lib/router.server.mjs.map +0 -1
- package/src/lib/config/constants.ts +0 -1
- package/src/lib/utils/time-picker.ts +0 -139
- package/src/modules/config/db/init.ts +0 -21
- package/src/modules/config/providers/email.ts +0 -13
- package/src/modules/storage/config/filters.ts +0 -12
- package/src/modules/storage/lib/create-client.server.ts +0 -14
- package/src/modules/storage/lib/create-upload.client.ts +0 -134
- package/src/modules/storage/lib/proxy.server.ts +0 -63
- package/src/modules/storage/lib/router.server.ts +0 -182
- /package/src/modules/{config/db → database/lib}/helpers.ts +0 -0
- /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 {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
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
|
-
*
|
|
8
|
+
* StorageAssets
|
|
12
9
|
*/
|
|
13
|
-
export type
|
|
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
|
-
*
|
|
13
|
+
* StorageAsset visibility enum
|
|
19
14
|
*/
|
|
20
|
-
export const
|
|
21
|
-
export type
|
|
15
|
+
export const storageAssetVisibilitySchema = z.enum(storageAssetVisibilityEnum.enumValues);
|
|
16
|
+
export type StorageAssetVisibility = z.infer<typeof storageAssetVisibilitySchema>;
|
|
22
17
|
|
|
23
18
|
/**
|
|
24
|
-
* Create
|
|
19
|
+
* Create storageAsset
|
|
25
20
|
*/
|
|
26
|
-
export const
|
|
27
|
-
namespace: z.string(),
|
|
28
|
-
});
|
|
21
|
+
export const createStorageAssetSchema = createInsertSchema(storageAssets);
|
|
29
22
|
|
|
30
|
-
export type
|
|
31
|
-
export type
|
|
23
|
+
export type CreateStorageAssetInput = z.input<typeof createStorageAssetSchema>;
|
|
24
|
+
export type CreateStorageAssetSchema = z.infer<typeof createStorageAssetSchema>;
|
|
32
25
|
|
|
33
26
|
/**
|
|
34
|
-
* Update
|
|
27
|
+
* Update storageAsset
|
|
35
28
|
*/
|
|
36
|
-
export const
|
|
29
|
+
export const updateStorageAssetSchema = createUpdateSchema(storageAssets);
|
|
37
30
|
|
|
38
|
-
export type
|
|
39
|
-
export type
|
|
31
|
+
export type UpdateStorageAssetInput = z.input<typeof updateStorageAssetSchema>;
|
|
32
|
+
export type UpdateStorageAssetSchema = z.infer<typeof updateStorageAssetSchema>;
|
|
40
33
|
|
|
41
34
|
/**
|
|
42
|
-
* Select
|
|
35
|
+
* Select storageAsset
|
|
43
36
|
*/
|
|
44
|
-
export const
|
|
45
|
-
export const selectNodeWithChildrenSchema = selectNodeSchema.extend({
|
|
46
|
-
children: z.array(selectNodeSchema),
|
|
47
|
-
});
|
|
37
|
+
export const selectStorageAssetSchema = createSelectSchema(storageAssets);
|
|
48
38
|
|
|
49
|
-
export type
|
|
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
|
-
*
|
|
44
|
+
* Upload schema
|
|
72
45
|
*/
|
|
73
|
-
export const
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
size:
|
|
77
|
-
|
|
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
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
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
|
|
107
|
-
|
|
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
|
|
128
|
-
|
|
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
|
-
*
|
|
78
|
+
* Get file url schema
|
|
132
79
|
*/
|
|
133
|
-
export const
|
|
134
|
-
|
|
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
|
|
143
|
-
|
|
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,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
|
+
}
|