@rovela-ai/sdk 0.1.25 → 0.1.27

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 (115) hide show
  1. package/dist/admin/components/CategoryForm.d.ts.map +1 -1
  2. package/dist/admin/components/CategoryForm.js +2 -2
  3. package/dist/admin/components/CategoryForm.js.map +1 -1
  4. package/dist/admin/components/ProductForm.d.ts.map +1 -1
  5. package/dist/admin/components/ProductForm.js +3 -35
  6. package/dist/admin/components/ProductForm.js.map +1 -1
  7. package/dist/admin/components/ProductTable.d.ts.map +1 -1
  8. package/dist/admin/components/ProductTable.js +6 -1
  9. package/dist/admin/components/ProductTable.js.map +1 -1
  10. package/dist/admin/server/admin-service.d.ts +3 -3
  11. package/dist/admin/server/admin-service.d.ts.map +1 -1
  12. package/dist/admin/server/admin-service.js +12 -22
  13. package/dist/admin/server/admin-service.js.map +1 -1
  14. package/dist/auth/server/customer-service.d.ts +2 -2
  15. package/dist/auth/server/customer-service.d.ts.map +1 -1
  16. package/dist/auth/server/customer-service.js +11 -20
  17. package/dist/auth/server/customer-service.js.map +1 -1
  18. package/dist/auth/server/password-reset-service.d.ts +1 -0
  19. package/dist/auth/server/password-reset-service.d.ts.map +1 -1
  20. package/dist/auth/server/password-reset-service.js +5 -7
  21. package/dist/auth/server/password-reset-service.js.map +1 -1
  22. package/dist/auth/server/verification-service.d.ts +1 -0
  23. package/dist/auth/server/verification-service.d.ts.map +1 -1
  24. package/dist/auth/server/verification-service.js +6 -9
  25. package/dist/auth/server/verification-service.js.map +1 -1
  26. package/dist/core/db/client.d.ts +2 -44
  27. package/dist/core/db/client.d.ts.map +1 -1
  28. package/dist/core/db/client.js +2 -106
  29. package/dist/core/db/client.js.map +1 -1
  30. package/dist/core/db/index.d.ts +1 -1
  31. package/dist/core/db/index.d.ts.map +1 -1
  32. package/dist/core/db/index.js +2 -2
  33. package/dist/core/db/index.js.map +1 -1
  34. package/dist/core/db/queries.d.ts +18 -35
  35. package/dist/core/db/queries.d.ts.map +1 -1
  36. package/dist/core/db/queries.js +69 -110
  37. package/dist/core/db/queries.js.map +1 -1
  38. package/dist/core/db/schema.d.ts +1 -137
  39. package/dist/core/db/schema.d.ts.map +1 -1
  40. package/dist/core/db/schema.js +6 -23
  41. package/dist/core/db/schema.js.map +1 -1
  42. package/dist/core/server/index.d.ts +1 -1
  43. package/dist/core/server/index.d.ts.map +1 -1
  44. package/dist/core/server/index.js +1 -3
  45. package/dist/core/server/index.js.map +1 -1
  46. package/dist/core/types.d.ts +0 -5
  47. package/dist/core/types.d.ts.map +1 -1
  48. package/dist/emails/config.d.ts.map +1 -1
  49. package/dist/emails/config.js +11 -17
  50. package/dist/emails/config.js.map +1 -1
  51. package/dist/media/api/delete.d.ts +44 -0
  52. package/dist/media/api/delete.d.ts.map +1 -0
  53. package/dist/media/api/delete.js +134 -0
  54. package/dist/media/api/delete.js.map +1 -0
  55. package/dist/media/api/index.d.ts +17 -0
  56. package/dist/media/api/index.d.ts.map +1 -0
  57. package/dist/media/api/index.js +17 -0
  58. package/dist/media/api/index.js.map +1 -0
  59. package/dist/media/api/presign.d.ts +39 -0
  60. package/dist/media/api/presign.d.ts.map +1 -0
  61. package/dist/media/api/presign.js +138 -0
  62. package/dist/media/api/presign.js.map +1 -0
  63. package/dist/media/components/DropZone.d.ts +18 -0
  64. package/dist/media/components/DropZone.d.ts.map +1 -0
  65. package/dist/media/components/DropZone.js +112 -0
  66. package/dist/media/components/DropZone.js.map +1 -0
  67. package/dist/media/components/ImageGalleryUpload.d.ts +18 -0
  68. package/dist/media/components/ImageGalleryUpload.d.ts.map +1 -0
  69. package/dist/media/components/ImageGalleryUpload.js +156 -0
  70. package/dist/media/components/ImageGalleryUpload.js.map +1 -0
  71. package/dist/media/components/ImageUpload.d.ts +17 -0
  72. package/dist/media/components/ImageUpload.d.ts.map +1 -0
  73. package/dist/media/components/ImageUpload.js +95 -0
  74. package/dist/media/components/ImageUpload.js.map +1 -0
  75. package/dist/media/components/index.d.ts +10 -0
  76. package/dist/media/components/index.d.ts.map +1 -0
  77. package/dist/media/components/index.js +9 -0
  78. package/dist/media/components/index.js.map +1 -0
  79. package/dist/media/config.d.ts +57 -0
  80. package/dist/media/config.d.ts.map +1 -0
  81. package/dist/media/config.js +142 -0
  82. package/dist/media/config.js.map +1 -0
  83. package/dist/media/hooks/index.d.ts +8 -0
  84. package/dist/media/hooks/index.d.ts.map +1 -0
  85. package/dist/media/hooks/index.js +7 -0
  86. package/dist/media/hooks/index.js.map +1 -0
  87. package/dist/media/hooks/useUpload.d.ts +32 -0
  88. package/dist/media/hooks/useUpload.d.ts.map +1 -0
  89. package/dist/media/hooks/useUpload.js +258 -0
  90. package/dist/media/hooks/useUpload.js.map +1 -0
  91. package/dist/media/index.d.ts +57 -0
  92. package/dist/media/index.d.ts.map +1 -0
  93. package/dist/media/index.js +68 -0
  94. package/dist/media/index.js.map +1 -0
  95. package/dist/media/server/delete.d.ts +59 -0
  96. package/dist/media/server/delete.d.ts.map +1 -0
  97. package/dist/media/server/delete.js +176 -0
  98. package/dist/media/server/delete.js.map +1 -0
  99. package/dist/media/server/index.d.ts +10 -0
  100. package/dist/media/server/index.d.ts.map +1 -0
  101. package/dist/media/server/index.js +13 -0
  102. package/dist/media/server/index.js.map +1 -0
  103. package/dist/media/server/presign.d.ts +57 -0
  104. package/dist/media/server/presign.d.ts.map +1 -0
  105. package/dist/media/server/presign.js +112 -0
  106. package/dist/media/server/presign.js.map +1 -0
  107. package/dist/media/server/r2-client.d.ts +30 -0
  108. package/dist/media/server/r2-client.d.ts.map +1 -0
  109. package/dist/media/server/r2-client.js +76 -0
  110. package/dist/media/server/r2-client.js.map +1 -0
  111. package/dist/media/types.d.ts +271 -0
  112. package/dist/media/types.d.ts.map +1 -0
  113. package/dist/media/types.js +52 -0
  114. package/dist/media/types.js.map +1 -0
  115. package/package.json +15 -1
@@ -0,0 +1,142 @@
1
+ /**
2
+ * @rovela-ai/sdk/media/config
3
+ *
4
+ * Media storage configuration.
5
+ * Loads R2/S3 credentials from environment variables.
6
+ */
7
+ // =============================================================================
8
+ // Environment Variable Loading
9
+ // =============================================================================
10
+ /**
11
+ * Get media storage configuration from environment variables.
12
+ * Returns null if required variables are missing.
13
+ */
14
+ export function getMediaConfig() {
15
+ const accountId = process.env.R2_ACCOUNT_ID;
16
+ const accessKeyId = process.env.R2_ACCESS_KEY_ID;
17
+ const secretAccessKey = process.env.R2_SECRET_ACCESS_KEY;
18
+ const bucketName = process.env.R2_BUCKET_NAME;
19
+ const publicUrl = process.env.R2_PUBLIC_URL;
20
+ const storeId = process.env.STORE_ID;
21
+ // All are required
22
+ if (!accountId || !accessKeyId || !secretAccessKey || !bucketName || !publicUrl || !storeId) {
23
+ return null;
24
+ }
25
+ return {
26
+ accountId,
27
+ accessKeyId,
28
+ secretAccessKey,
29
+ bucketName,
30
+ publicUrl,
31
+ storeId,
32
+ };
33
+ }
34
+ /**
35
+ * Check if media storage is configured
36
+ */
37
+ export function isMediaConfigured() {
38
+ return getMediaConfig() !== null;
39
+ }
40
+ /**
41
+ * Get media configuration or throw an error if not configured.
42
+ * Use this in API routes where configuration is required.
43
+ */
44
+ export function requireMediaConfig() {
45
+ const config = getMediaConfig();
46
+ if (!config) {
47
+ throw new Error('Media storage not configured. Required environment variables: ' +
48
+ 'R2_ACCOUNT_ID, R2_ACCESS_KEY_ID, R2_SECRET_ACCESS_KEY, R2_BUCKET_NAME, R2_PUBLIC_URL, STORE_ID');
49
+ }
50
+ return config;
51
+ }
52
+ // =============================================================================
53
+ // Upload Configuration
54
+ // =============================================================================
55
+ /**
56
+ * Default upload configuration
57
+ */
58
+ export const defaultUploadConfig = {
59
+ maxSizeBytes: 10 * 1024 * 1024, // 10MB
60
+ allowedTypes: ['image/jpeg', 'image/png', 'image/webp', 'image/gif'],
61
+ maxFiles: 10,
62
+ };
63
+ /**
64
+ * Get upload configuration with optional overrides
65
+ */
66
+ export function getUploadConfig(overrides) {
67
+ return {
68
+ ...defaultUploadConfig,
69
+ ...overrides,
70
+ };
71
+ }
72
+ // =============================================================================
73
+ // Path Helpers
74
+ // =============================================================================
75
+ /**
76
+ * Build the storage key (path) for a file.
77
+ *
78
+ * Structure: stores/{storeId}/{folder}/{entityId?}/{filename}
79
+ *
80
+ * Examples:
81
+ * - stores/abc123/products/prod456/1699999999_abc123.jpg
82
+ * - stores/abc123/categories/cat789/cover.jpg
83
+ * - stores/abc123/general/1699999999_abc123.jpg
84
+ */
85
+ export function buildStorageKey(storeId, folder, filename, entityId) {
86
+ const parts = ['stores', storeId, folder];
87
+ if (entityId) {
88
+ parts.push(entityId);
89
+ }
90
+ parts.push(filename);
91
+ return parts.join('/');
92
+ }
93
+ /**
94
+ * Build the public URL for a stored file
95
+ */
96
+ export function buildPublicUrl(publicBaseUrl, key) {
97
+ // Remove trailing slash from base URL if present
98
+ const baseUrl = publicBaseUrl.endsWith('/') ? publicBaseUrl.slice(0, -1) : publicBaseUrl;
99
+ return `${baseUrl}/${key}`;
100
+ }
101
+ /**
102
+ * Extract the storage key from a public URL
103
+ */
104
+ export function extractKeyFromUrl(publicBaseUrl, url) {
105
+ const baseUrl = publicBaseUrl.endsWith('/') ? publicBaseUrl.slice(0, -1) : publicBaseUrl;
106
+ if (!url.startsWith(baseUrl)) {
107
+ return null;
108
+ }
109
+ return url.slice(baseUrl.length + 1);
110
+ }
111
+ // =============================================================================
112
+ // Content Type Mapping
113
+ // =============================================================================
114
+ /**
115
+ * Map of file extensions to MIME types
116
+ */
117
+ const EXTENSION_TO_MIME = {
118
+ jpg: 'image/jpeg',
119
+ jpeg: 'image/jpeg',
120
+ png: 'image/png',
121
+ gif: 'image/gif',
122
+ webp: 'image/webp',
123
+ svg: 'image/svg+xml',
124
+ ico: 'image/x-icon',
125
+ bmp: 'image/bmp',
126
+ tiff: 'image/tiff',
127
+ tif: 'image/tiff',
128
+ };
129
+ /**
130
+ * Get MIME type from filename extension
131
+ */
132
+ export function getMimeType(filename) {
133
+ const ext = filename.split('.').pop()?.toLowerCase() || '';
134
+ return EXTENSION_TO_MIME[ext] || 'application/octet-stream';
135
+ }
136
+ /**
137
+ * Check if a MIME type is an allowed image type
138
+ */
139
+ export function isAllowedImageType(mimeType, config = defaultUploadConfig) {
140
+ return config.allowedTypes.includes(mimeType);
141
+ }
142
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/media/config.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,gFAAgF;AAChF,+BAA+B;AAC/B,gFAAgF;AAEhF;;;GAGG;AACH,MAAM,UAAU,cAAc;IAC5B,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,aAAa,CAAA;IAC3C,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAA;IAChD,MAAM,eAAe,GAAG,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAA;IACxD,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,CAAA;IAC7C,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,aAAa,CAAA;IAC3C,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAA;IAEpC,mBAAmB;IACnB,IAAI,CAAC,SAAS,IAAI,CAAC,WAAW,IAAI,CAAC,eAAe,IAAI,CAAC,UAAU,IAAI,CAAC,SAAS,IAAI,CAAC,OAAO,EAAE,CAAC;QAC5F,OAAO,IAAI,CAAA;IACb,CAAC;IAED,OAAO;QACL,SAAS;QACT,WAAW;QACX,eAAe;QACf,UAAU;QACV,SAAS;QACT,OAAO;KACR,CAAA;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,iBAAiB;IAC/B,OAAO,cAAc,EAAE,KAAK,IAAI,CAAA;AAClC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,kBAAkB;IAChC,MAAM,MAAM,GAAG,cAAc,EAAE,CAAA;IAC/B,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CACb,gEAAgE;YAC9D,gGAAgG,CACnG,CAAA;IACH,CAAC;IACD,OAAO,MAAM,CAAA;AACf,CAAC;AAED,gFAAgF;AAChF,uBAAuB;AACvB,gFAAgF;AAEhF;;GAEG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAiB;IAC/C,YAAY,EAAE,EAAE,GAAG,IAAI,GAAG,IAAI,EAAE,OAAO;IACvC,YAAY,EAAE,CAAC,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,WAAW,CAAC;IACpE,QAAQ,EAAE,EAAE;CACb,CAAA;AAED;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,SAAiC;IAC/D,OAAO;QACL,GAAG,mBAAmB;QACtB,GAAG,SAAS;KACb,CAAA;AACH,CAAC;AAED,gFAAgF;AAChF,eAAe;AACf,gFAAgF;AAEhF;;;;;;;;;GASG;AACH,MAAM,UAAU,eAAe,CAC7B,OAAe,EACf,MAAc,EACd,QAAgB,EAChB,QAAiB;IAEjB,MAAM,KAAK,GAAG,CAAC,QAAQ,EAAE,OAAO,EAAE,MAAM,CAAC,CAAA;IAEzC,IAAI,QAAQ,EAAE,CAAC;QACb,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;IACtB,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;IAEpB,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;AACxB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,aAAqB,EAAE,GAAW;IAC/D,iDAAiD;IACjD,MAAM,OAAO,GAAG,aAAa,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,CAAA;IACxF,OAAO,GAAG,OAAO,IAAI,GAAG,EAAE,CAAA;AAC5B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAAC,aAAqB,EAAE,GAAW;IAClE,MAAM,OAAO,GAAG,aAAa,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,CAAA;IAExF,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QAC7B,OAAO,IAAI,CAAA;IACb,CAAC;IAED,OAAO,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAA;AACtC,CAAC;AAED,gFAAgF;AAChF,uBAAuB;AACvB,gFAAgF;AAEhF;;GAEG;AACH,MAAM,iBAAiB,GAA2B;IAChD,GAAG,EAAE,YAAY;IACjB,IAAI,EAAE,YAAY;IAClB,GAAG,EAAE,WAAW;IAChB,GAAG,EAAE,WAAW;IAChB,IAAI,EAAE,YAAY;IAClB,GAAG,EAAE,eAAe;IACpB,GAAG,EAAE,cAAc;IACnB,GAAG,EAAE,WAAW;IAChB,IAAI,EAAE,YAAY;IAClB,GAAG,EAAE,YAAY;CAClB,CAAA;AAED;;GAEG;AACH,MAAM,UAAU,WAAW,CAAC,QAAgB;IAC1C,MAAM,GAAG,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,CAAA;IAC1D,OAAO,iBAAiB,CAAC,GAAG,CAAC,IAAI,0BAA0B,CAAA;AAC7D,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,kBAAkB,CAChC,QAAgB,EAChB,SAAuB,mBAAmB;IAE1C,OAAO,MAAM,CAAC,YAAY,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAA;AAC/C,CAAC"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * @rovela-ai/sdk/media/hooks
3
+ *
4
+ * React hooks for media uploads.
5
+ */
6
+ export { useUpload } from './useUpload';
7
+ export type { UseUploadOptions, UseUploadReturn } from '../types';
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/media/hooks/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AACvC,YAAY,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * @rovela-ai/sdk/media/hooks
3
+ *
4
+ * React hooks for media uploads.
5
+ */
6
+ export { useUpload } from './useUpload';
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/media/hooks/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA"}
@@ -0,0 +1,32 @@
1
+ import type { UseUploadOptions, UseUploadReturn } from '../types';
2
+ /**
3
+ * React hook for uploading files to R2 storage.
4
+ *
5
+ * @param options - Upload configuration options
6
+ * @returns Upload functions and state
7
+ *
8
+ * @example
9
+ * ```tsx
10
+ * function ImageUploader() {
11
+ * const { upload, isUploading, progress, error } = useUpload({
12
+ * folder: 'products',
13
+ * entityId: 'prod_123',
14
+ * onSuccess: (result) => console.log('Uploaded:', result.url),
15
+ * });
16
+ *
17
+ * const handleFile = async (file: File) => {
18
+ * const result = await upload(file);
19
+ * if (result.success) {
20
+ * // Use result.url
21
+ * }
22
+ * };
23
+ *
24
+ * return (
25
+ * <input type="file" onChange={(e) => handleFile(e.target.files[0])} />
26
+ * );
27
+ * }
28
+ * ```
29
+ */
30
+ export declare function useUpload(options: UseUploadOptions): UseUploadReturn;
31
+ export default useUpload;
32
+ //# sourceMappingURL=useUpload.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useUpload.d.ts","sourceRoot":"","sources":["../../../src/media/hooks/useUpload.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EACV,gBAAgB,EAChB,eAAe,EAMhB,MAAM,UAAU,CAAA;AAOjB;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,gBAAgB,GAAG,eAAe,CAqMpE;AAmED,eAAe,SAAS,CAAA"}
@@ -0,0 +1,258 @@
1
+ 'use client';
2
+ /**
3
+ * @rovela-ai/sdk/media/hooks/useUpload
4
+ *
5
+ * React hook for uploading files to R2 storage via presigned URLs.
6
+ */
7
+ import { useState, useCallback, useRef } from 'react';
8
+ import { validateFile, DEFAULT_UPLOAD_CONFIG } from '../types';
9
+ // =============================================================================
10
+ // Hook Implementation
11
+ // =============================================================================
12
+ /**
13
+ * React hook for uploading files to R2 storage.
14
+ *
15
+ * @param options - Upload configuration options
16
+ * @returns Upload functions and state
17
+ *
18
+ * @example
19
+ * ```tsx
20
+ * function ImageUploader() {
21
+ * const { upload, isUploading, progress, error } = useUpload({
22
+ * folder: 'products',
23
+ * entityId: 'prod_123',
24
+ * onSuccess: (result) => console.log('Uploaded:', result.url),
25
+ * });
26
+ *
27
+ * const handleFile = async (file: File) => {
28
+ * const result = await upload(file);
29
+ * if (result.success) {
30
+ * // Use result.url
31
+ * }
32
+ * };
33
+ *
34
+ * return (
35
+ * <input type="file" onChange={(e) => handleFile(e.target.files[0])} />
36
+ * );
37
+ * }
38
+ * ```
39
+ */
40
+ export function useUpload(options) {
41
+ const { folder, entityId, config, onSuccess, onError, onProgress } = options;
42
+ // Merge config with defaults
43
+ const uploadConfig = {
44
+ ...DEFAULT_UPLOAD_CONFIG,
45
+ ...config,
46
+ };
47
+ // State
48
+ const [status, setStatus] = useState('idle');
49
+ const [progress, setProgress] = useState(null);
50
+ const [error, setError] = useState(null);
51
+ // Abort controller ref for cancellation
52
+ const abortControllerRef = useRef(null);
53
+ /**
54
+ * Upload a single file
55
+ */
56
+ const upload = useCallback(async (file) => {
57
+ // Validate file
58
+ const validation = validateFile(file, uploadConfig);
59
+ if (!validation.valid) {
60
+ const errorMsg = validation.error || 'File validation failed';
61
+ setError(errorMsg);
62
+ setStatus('error');
63
+ onError?.(errorMsg);
64
+ return {
65
+ success: false,
66
+ filename: file.name,
67
+ size: file.size,
68
+ contentType: file.type,
69
+ error: errorMsg,
70
+ };
71
+ }
72
+ // Reset state
73
+ setError(null);
74
+ setStatus('preparing');
75
+ setProgress(null);
76
+ // Create abort controller
77
+ abortControllerRef.current = new AbortController();
78
+ const signal = abortControllerRef.current.signal;
79
+ try {
80
+ // Step 1: Get presigned URL from API
81
+ const presignResponse = await fetch('/api/media/presign', {
82
+ method: 'POST',
83
+ headers: { 'Content-Type': 'application/json' },
84
+ body: JSON.stringify({
85
+ filename: file.name,
86
+ contentType: file.type,
87
+ folder,
88
+ entityId,
89
+ }),
90
+ signal,
91
+ });
92
+ if (!presignResponse.ok) {
93
+ const errorData = await presignResponse.json().catch(() => ({}));
94
+ throw new Error(errorData.error || 'Failed to get upload URL');
95
+ }
96
+ const presignData = await presignResponse.json();
97
+ if (!presignData.success || !presignData.data) {
98
+ throw new Error(presignData.error || 'Failed to get upload URL');
99
+ }
100
+ // Step 2: Upload file directly to R2
101
+ setStatus('uploading');
102
+ // Use XMLHttpRequest for progress tracking
103
+ const uploadResult = await uploadWithProgress(presignData.data.uploadUrl, file, (prog) => {
104
+ setProgress(prog);
105
+ onProgress?.(prog);
106
+ }, signal);
107
+ if (!uploadResult.success) {
108
+ throw new Error(uploadResult.error || 'Upload failed');
109
+ }
110
+ // Success
111
+ setStatus('success');
112
+ setProgress({ loaded: file.size, total: file.size, percentage: 100 });
113
+ const result = {
114
+ success: true,
115
+ url: presignData.data.publicUrl,
116
+ filename: file.name,
117
+ size: file.size,
118
+ contentType: file.type,
119
+ };
120
+ onSuccess?.(result);
121
+ return result;
122
+ }
123
+ catch (err) {
124
+ // Handle abort
125
+ if (err instanceof Error && err.name === 'AbortError') {
126
+ setStatus('idle');
127
+ setError(null);
128
+ return {
129
+ success: false,
130
+ filename: file.name,
131
+ size: file.size,
132
+ contentType: file.type,
133
+ error: 'Upload cancelled',
134
+ };
135
+ }
136
+ // Handle error
137
+ const errorMsg = err instanceof Error ? err.message : 'Upload failed';
138
+ setError(errorMsg);
139
+ setStatus('error');
140
+ onError?.(errorMsg);
141
+ return {
142
+ success: false,
143
+ filename: file.name,
144
+ size: file.size,
145
+ contentType: file.type,
146
+ error: errorMsg,
147
+ };
148
+ }
149
+ finally {
150
+ abortControllerRef.current = null;
151
+ }
152
+ }, [folder, entityId, uploadConfig, onSuccess, onError, onProgress]);
153
+ /**
154
+ * Upload multiple files
155
+ */
156
+ const uploadMultiple = useCallback(async (files) => {
157
+ // Validate max files
158
+ if (files.length > uploadConfig.maxFiles) {
159
+ const errorMsg = `Maximum ${uploadConfig.maxFiles} files allowed`;
160
+ setError(errorMsg);
161
+ onError?.(errorMsg);
162
+ return files.map((f) => ({
163
+ success: false,
164
+ filename: f.name,
165
+ size: f.size,
166
+ contentType: f.type,
167
+ error: errorMsg,
168
+ }));
169
+ }
170
+ // Upload sequentially to avoid overwhelming the server
171
+ const results = [];
172
+ for (const file of files) {
173
+ const result = await upload(file);
174
+ results.push(result);
175
+ // Stop if there's an error (optional - could continue)
176
+ if (!result.success) {
177
+ break;
178
+ }
179
+ }
180
+ return results;
181
+ }, [upload, uploadConfig.maxFiles, onError]);
182
+ /**
183
+ * Reset state to idle
184
+ */
185
+ const reset = useCallback(() => {
186
+ // Cancel any in-progress upload
187
+ if (abortControllerRef.current) {
188
+ abortControllerRef.current.abort();
189
+ abortControllerRef.current = null;
190
+ }
191
+ setStatus('idle');
192
+ setProgress(null);
193
+ setError(null);
194
+ }, []);
195
+ return {
196
+ upload,
197
+ uploadMultiple,
198
+ status,
199
+ progress,
200
+ isUploading: status === 'preparing' || status === 'uploading',
201
+ error,
202
+ reset,
203
+ };
204
+ }
205
+ // =============================================================================
206
+ // Helper Functions
207
+ // =============================================================================
208
+ /**
209
+ * Upload file with progress tracking using XMLHttpRequest
210
+ */
211
+ function uploadWithProgress(url, file, onProgress, signal) {
212
+ return new Promise((resolve) => {
213
+ const xhr = new XMLHttpRequest();
214
+ // Handle abort
215
+ if (signal) {
216
+ signal.addEventListener('abort', () => {
217
+ xhr.abort();
218
+ resolve({ success: false, error: 'Upload cancelled' });
219
+ });
220
+ }
221
+ // Track progress
222
+ xhr.upload.addEventListener('progress', (event) => {
223
+ if (event.lengthComputable) {
224
+ onProgress({
225
+ loaded: event.loaded,
226
+ total: event.total,
227
+ percentage: Math.round((event.loaded / event.total) * 100),
228
+ });
229
+ }
230
+ });
231
+ // Handle completion
232
+ xhr.addEventListener('load', () => {
233
+ if (xhr.status >= 200 && xhr.status < 300) {
234
+ resolve({ success: true });
235
+ }
236
+ else {
237
+ resolve({ success: false, error: `Upload failed with status ${xhr.status}` });
238
+ }
239
+ });
240
+ // Handle error
241
+ xhr.addEventListener('error', () => {
242
+ resolve({ success: false, error: 'Network error during upload' });
243
+ });
244
+ // Handle abort
245
+ xhr.addEventListener('abort', () => {
246
+ resolve({ success: false, error: 'Upload cancelled' });
247
+ });
248
+ // Send request
249
+ xhr.open('PUT', url);
250
+ xhr.setRequestHeader('Content-Type', file.type);
251
+ xhr.send(file);
252
+ });
253
+ }
254
+ // =============================================================================
255
+ // Exports
256
+ // =============================================================================
257
+ export default useUpload;
258
+ //# sourceMappingURL=useUpload.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useUpload.js","sourceRoot":"","sources":["../../../src/media/hooks/useUpload.ts"],"names":[],"mappings":"AAAA,YAAY,CAAA;AAEZ;;;;GAIG;AAEH,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,OAAO,CAAA;AAUrD,OAAO,EAAE,YAAY,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAA;AAE9D,gFAAgF;AAChF,sBAAsB;AACtB,gFAAgF;AAEhF;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,MAAM,UAAU,SAAS,CAAC,OAAyB;IACjD,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,UAAU,EAAE,GAAG,OAAO,CAAA;IAE5E,6BAA6B;IAC7B,MAAM,YAAY,GAAiB;QACjC,GAAG,qBAAqB;QACxB,GAAG,MAAM;KACV,CAAA;IAED,QAAQ;IACR,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAe,MAAM,CAAC,CAAA;IAC1D,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,QAAQ,CAAwB,IAAI,CAAC,CAAA;IACrE,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAgB,IAAI,CAAC,CAAA;IAEvD,wCAAwC;IACxC,MAAM,kBAAkB,GAAG,MAAM,CAAyB,IAAI,CAAC,CAAA;IAE/D;;OAEG;IACH,MAAM,MAAM,GAAG,WAAW,CACxB,KAAK,EAAE,IAAU,EAAyB,EAAE;QAC1C,gBAAgB;QAChB,MAAM,UAAU,GAAG,YAAY,CAAC,IAAI,EAAE,YAAY,CAAC,CAAA;QACnD,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC;YACtB,MAAM,QAAQ,GAAG,UAAU,CAAC,KAAK,IAAI,wBAAwB,CAAA;YAC7D,QAAQ,CAAC,QAAQ,CAAC,CAAA;YAClB,SAAS,CAAC,OAAO,CAAC,CAAA;YAClB,OAAO,EAAE,CAAC,QAAQ,CAAC,CAAA;YACnB,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,QAAQ,EAAE,IAAI,CAAC,IAAI;gBACnB,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,WAAW,EAAE,IAAI,CAAC,IAAI;gBACtB,KAAK,EAAE,QAAQ;aAChB,CAAA;QACH,CAAC;QAED,cAAc;QACd,QAAQ,CAAC,IAAI,CAAC,CAAA;QACd,SAAS,CAAC,WAAW,CAAC,CAAA;QACtB,WAAW,CAAC,IAAI,CAAC,CAAA;QAEjB,0BAA0B;QAC1B,kBAAkB,CAAC,OAAO,GAAG,IAAI,eAAe,EAAE,CAAA;QAClD,MAAM,MAAM,GAAG,kBAAkB,CAAC,OAAO,CAAC,MAAM,CAAA;QAEhD,IAAI,CAAC;YACH,qCAAqC;YACrC,MAAM,eAAe,GAAG,MAAM,KAAK,CAAC,oBAAoB,EAAE;gBACxD,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;gBAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;oBACnB,QAAQ,EAAE,IAAI,CAAC,IAAI;oBACnB,WAAW,EAAE,IAAI,CAAC,IAAI;oBACtB,MAAM;oBACN,QAAQ;iBACT,CAAC;gBACF,MAAM;aACP,CAAC,CAAA;YAEF,IAAI,CAAC,eAAe,CAAC,EAAE,EAAE,CAAC;gBACxB,MAAM,SAAS,GAAG,MAAM,eAAe,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;gBAChE,MAAM,IAAI,KAAK,CAAC,SAAS,CAAC,KAAK,IAAI,0BAA0B,CAAC,CAAA;YAChE,CAAC;YAED,MAAM,WAAW,GAAuB,MAAM,eAAe,CAAC,IAAI,EAAE,CAAA;YACpE,IAAI,CAAC,WAAW,CAAC,OAAO,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC;gBAC9C,MAAM,IAAI,KAAK,CAAC,WAAW,CAAC,KAAK,IAAI,0BAA0B,CAAC,CAAA;YAClE,CAAC;YAED,qCAAqC;YACrC,SAAS,CAAC,WAAW,CAAC,CAAA;YAEtB,2CAA2C;YAC3C,MAAM,YAAY,GAAG,MAAM,kBAAkB,CAC3C,WAAW,CAAC,IAAI,CAAC,SAAS,EAC1B,IAAI,EACJ,CAAC,IAAI,EAAE,EAAE;gBACP,WAAW,CAAC,IAAI,CAAC,CAAA;gBACjB,UAAU,EAAE,CAAC,IAAI,CAAC,CAAA;YACpB,CAAC,EACD,MAAM,CACP,CAAA;YAED,IAAI,CAAC,YAAY,CAAC,OAAO,EAAE,CAAC;gBAC1B,MAAM,IAAI,KAAK,CAAC,YAAY,CAAC,KAAK,IAAI,eAAe,CAAC,CAAA;YACxD,CAAC;YAED,UAAU;YACV,SAAS,CAAC,SAAS,CAAC,CAAA;YACpB,WAAW,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,IAAI,EAAE,UAAU,EAAE,GAAG,EAAE,CAAC,CAAA;YAErE,MAAM,MAAM,GAAiB;gBAC3B,OAAO,EAAE,IAAI;gBACb,GAAG,EAAE,WAAW,CAAC,IAAI,CAAC,SAAS;gBAC/B,QAAQ,EAAE,IAAI,CAAC,IAAI;gBACnB,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,WAAW,EAAE,IAAI,CAAC,IAAI;aACvB,CAAA;YAED,SAAS,EAAE,CAAC,MAAM,CAAC,CAAA;YACnB,OAAO,MAAM,CAAA;QACf,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,eAAe;YACf,IAAI,GAAG,YAAY,KAAK,IAAI,GAAG,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;gBACtD,SAAS,CAAC,MAAM,CAAC,CAAA;gBACjB,QAAQ,CAAC,IAAI,CAAC,CAAA;gBACd,OAAO;oBACL,OAAO,EAAE,KAAK;oBACd,QAAQ,EAAE,IAAI,CAAC,IAAI;oBACnB,IAAI,EAAE,IAAI,CAAC,IAAI;oBACf,WAAW,EAAE,IAAI,CAAC,IAAI;oBACtB,KAAK,EAAE,kBAAkB;iBAC1B,CAAA;YACH,CAAC;YAED,eAAe;YACf,MAAM,QAAQ,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAA;YACrE,QAAQ,CAAC,QAAQ,CAAC,CAAA;YAClB,SAAS,CAAC,OAAO,CAAC,CAAA;YAClB,OAAO,EAAE,CAAC,QAAQ,CAAC,CAAA;YAEnB,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,QAAQ,EAAE,IAAI,CAAC,IAAI;gBACnB,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,WAAW,EAAE,IAAI,CAAC,IAAI;gBACtB,KAAK,EAAE,QAAQ;aAChB,CAAA;QACH,CAAC;gBAAS,CAAC;YACT,kBAAkB,CAAC,OAAO,GAAG,IAAI,CAAA;QACnC,CAAC;IACH,CAAC,EACD,CAAC,MAAM,EAAE,QAAQ,EAAE,YAAY,EAAE,SAAS,EAAE,OAAO,EAAE,UAAU,CAAC,CACjE,CAAA;IAED;;OAEG;IACH,MAAM,cAAc,GAAG,WAAW,CAChC,KAAK,EAAE,KAAa,EAA2B,EAAE;QAC/C,qBAAqB;QACrB,IAAI,KAAK,CAAC,MAAM,GAAG,YAAY,CAAC,QAAQ,EAAE,CAAC;YACzC,MAAM,QAAQ,GAAG,WAAW,YAAY,CAAC,QAAQ,gBAAgB,CAAA;YACjE,QAAQ,CAAC,QAAQ,CAAC,CAAA;YAClB,OAAO,EAAE,CAAC,QAAQ,CAAC,CAAA;YACnB,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;gBACvB,OAAO,EAAE,KAAK;gBACd,QAAQ,EAAE,CAAC,CAAC,IAAI;gBAChB,IAAI,EAAE,CAAC,CAAC,IAAI;gBACZ,WAAW,EAAE,CAAC,CAAC,IAAI;gBACnB,KAAK,EAAE,QAAQ;aAChB,CAAC,CAAC,CAAA;QACL,CAAC;QAED,uDAAuD;QACvD,MAAM,OAAO,GAAmB,EAAE,CAAA;QAClC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,CAAA;YACjC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;YAEpB,uDAAuD;YACvD,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;gBACpB,MAAK;YACP,CAAC;QACH,CAAC;QAED,OAAO,OAAO,CAAA;IAChB,CAAC,EACD,CAAC,MAAM,EAAE,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CACzC,CAAA;IAED;;OAEG;IACH,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE;QAC7B,gCAAgC;QAChC,IAAI,kBAAkB,CAAC,OAAO,EAAE,CAAC;YAC/B,kBAAkB,CAAC,OAAO,CAAC,KAAK,EAAE,CAAA;YAClC,kBAAkB,CAAC,OAAO,GAAG,IAAI,CAAA;QACnC,CAAC;QAED,SAAS,CAAC,MAAM,CAAC,CAAA;QACjB,WAAW,CAAC,IAAI,CAAC,CAAA;QACjB,QAAQ,CAAC,IAAI,CAAC,CAAA;IAChB,CAAC,EAAE,EAAE,CAAC,CAAA;IAEN,OAAO;QACL,MAAM;QACN,cAAc;QACd,MAAM;QACN,QAAQ;QACR,WAAW,EAAE,MAAM,KAAK,WAAW,IAAI,MAAM,KAAK,WAAW;QAC7D,KAAK;QACL,KAAK;KACN,CAAA;AACH,CAAC;AAED,gFAAgF;AAChF,mBAAmB;AACnB,gFAAgF;AAEhF;;GAEG;AACH,SAAS,kBAAkB,CACzB,GAAW,EACX,IAAU,EACV,UAA8C,EAC9C,MAAoB;IAEpB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,MAAM,GAAG,GAAG,IAAI,cAAc,EAAE,CAAA;QAEhC,eAAe;QACf,IAAI,MAAM,EAAE,CAAC;YACX,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE;gBACpC,GAAG,CAAC,KAAK,EAAE,CAAA;gBACX,OAAO,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,kBAAkB,EAAE,CAAC,CAAA;YACxD,CAAC,CAAC,CAAA;QACJ,CAAC;QAED,iBAAiB;QACjB,GAAG,CAAC,MAAM,CAAC,gBAAgB,CAAC,UAAU,EAAE,CAAC,KAAK,EAAE,EAAE;YAChD,IAAI,KAAK,CAAC,gBAAgB,EAAE,CAAC;gBAC3B,UAAU,CAAC;oBACT,MAAM,EAAE,KAAK,CAAC,MAAM;oBACpB,KAAK,EAAE,KAAK,CAAC,KAAK;oBAClB,UAAU,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC;iBAC3D,CAAC,CAAA;YACJ,CAAC;QACH,CAAC,CAAC,CAAA;QAEF,oBAAoB;QACpB,GAAG,CAAC,gBAAgB,CAAC,MAAM,EAAE,GAAG,EAAE;YAChC,IAAI,GAAG,CAAC,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,MAAM,GAAG,GAAG,EAAE,CAAC;gBAC1C,OAAO,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAA;YAC5B,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,6BAA6B,GAAG,CAAC,MAAM,EAAE,EAAE,CAAC,CAAA;YAC/E,CAAC;QACH,CAAC,CAAC,CAAA;QAEF,eAAe;QACf,GAAG,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE;YACjC,OAAO,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,6BAA6B,EAAE,CAAC,CAAA;QACnE,CAAC,CAAC,CAAA;QAEF,eAAe;QACf,GAAG,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE;YACjC,OAAO,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,kBAAkB,EAAE,CAAC,CAAA;QACxD,CAAC,CAAC,CAAA;QAEF,eAAe;QACf,GAAG,CAAC,IAAI,CAAC,KAAK,EAAE,GAAG,CAAC,CAAA;QACpB,GAAG,CAAC,gBAAgB,CAAC,cAAc,EAAE,IAAI,CAAC,IAAI,CAAC,CAAA;QAC/C,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IAChB,CAAC,CAAC,CAAA;AACJ,CAAC;AAED,gFAAgF;AAChF,UAAU;AACV,gFAAgF;AAEhF,eAAe,SAAS,CAAA"}
@@ -0,0 +1,57 @@
1
+ /**
2
+ * @rovela-ai/sdk/media
3
+ *
4
+ * Media upload module for R2 storage.
5
+ *
6
+ * This module provides:
7
+ * - Server-side presigned URL generation
8
+ * - Client-side upload hooks and components
9
+ * - API route handlers for Next.js
10
+ *
11
+ * ## Quick Start
12
+ *
13
+ * 1. Add environment variables:
14
+ * ```env
15
+ * R2_ACCOUNT_ID=xxx
16
+ * R2_ACCESS_KEY_ID=xxx
17
+ * R2_SECRET_ACCESS_KEY=xxx
18
+ * R2_BUCKET_NAME=xxx
19
+ * R2_PUBLIC_URL=https://pub-xxx.r2.dev
20
+ * STORE_ID=xxx
21
+ * ```
22
+ *
23
+ * 2. Create API routes:
24
+ * ```typescript
25
+ * // app/api/media/presign/route.ts
26
+ * export { POST } from '@rovela-ai/sdk/media/api'
27
+ *
28
+ * // app/api/media/route.ts
29
+ * export { DELETE } from '@rovela-ai/sdk/media/api'
30
+ * ```
31
+ *
32
+ * 3. Use components:
33
+ * ```tsx
34
+ * import { ImageGalleryUpload } from '@rovela-ai/sdk/media'
35
+ *
36
+ * <ImageGalleryUpload
37
+ * value={images}
38
+ * onChange={setImages}
39
+ * folder="products"
40
+ * entityId={productId}
41
+ * />
42
+ * ```
43
+ *
44
+ * ## Module Structure
45
+ *
46
+ * - `@rovela-ai/sdk/media` - Types, config, components, hooks
47
+ * - `@rovela-ai/sdk/media/server` - Server-side utilities (presign, delete)
48
+ * - `@rovela-ai/sdk/media/api` - Next.js API route handlers
49
+ *
50
+ * @module media
51
+ */
52
+ export type { MediaStorageConfig, UploadConfig, MediaFolder, PresignedUrlRequest, PresignedUrlResponse, PresignApiRequest, PresignApiResponse, DeleteApiRequest, DeleteApiResponse, MediaApiError, UploadProgress, UploadStatus, UploadResult, UploadState, UseUploadOptions, UseUploadReturn, DropZoneProps, ImageUploadProps, ImageGalleryUploadProps, FileValidation, } from './types';
53
+ export { DEFAULT_UPLOAD_CONFIG, validateFile, generateUniqueFilename, getFileExtension } from './types';
54
+ export { getMediaConfig, isMediaConfigured, requireMediaConfig, defaultUploadConfig, getUploadConfig, buildStorageKey, buildPublicUrl, extractKeyFromUrl, getMimeType, isAllowedImageType, } from './config';
55
+ export { useUpload } from './hooks';
56
+ export { DropZone, ImageUpload, ImageGalleryUpload } from './components';
57
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/media/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkDG;AAMH,YAAY,EAEV,kBAAkB,EAClB,YAAY,EACZ,WAAW,EAEX,mBAAmB,EACnB,oBAAoB,EACpB,iBAAiB,EACjB,kBAAkB,EAClB,gBAAgB,EAChB,iBAAiB,EACjB,aAAa,EAEb,cAAc,EACd,YAAY,EACZ,YAAY,EACZ,WAAW,EAEX,gBAAgB,EAChB,eAAe,EAEf,aAAa,EACb,gBAAgB,EAChB,uBAAuB,EAEvB,cAAc,GACf,MAAM,SAAS,CAAA;AAMhB,OAAO,EAAE,qBAAqB,EAAE,YAAY,EAAE,sBAAsB,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAA;AAMvG,OAAO,EACL,cAAc,EACd,iBAAiB,EACjB,kBAAkB,EAClB,mBAAmB,EACnB,eAAe,EACf,eAAe,EACf,cAAc,EACd,iBAAiB,EACjB,WAAW,EACX,kBAAkB,GACnB,MAAM,UAAU,CAAA;AAMjB,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA;AAMnC,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAA"}
@@ -0,0 +1,68 @@
1
+ /**
2
+ * @rovela-ai/sdk/media
3
+ *
4
+ * Media upload module for R2 storage.
5
+ *
6
+ * This module provides:
7
+ * - Server-side presigned URL generation
8
+ * - Client-side upload hooks and components
9
+ * - API route handlers for Next.js
10
+ *
11
+ * ## Quick Start
12
+ *
13
+ * 1. Add environment variables:
14
+ * ```env
15
+ * R2_ACCOUNT_ID=xxx
16
+ * R2_ACCESS_KEY_ID=xxx
17
+ * R2_SECRET_ACCESS_KEY=xxx
18
+ * R2_BUCKET_NAME=xxx
19
+ * R2_PUBLIC_URL=https://pub-xxx.r2.dev
20
+ * STORE_ID=xxx
21
+ * ```
22
+ *
23
+ * 2. Create API routes:
24
+ * ```typescript
25
+ * // app/api/media/presign/route.ts
26
+ * export { POST } from '@rovela-ai/sdk/media/api'
27
+ *
28
+ * // app/api/media/route.ts
29
+ * export { DELETE } from '@rovela-ai/sdk/media/api'
30
+ * ```
31
+ *
32
+ * 3. Use components:
33
+ * ```tsx
34
+ * import { ImageGalleryUpload } from '@rovela-ai/sdk/media'
35
+ *
36
+ * <ImageGalleryUpload
37
+ * value={images}
38
+ * onChange={setImages}
39
+ * folder="products"
40
+ * entityId={productId}
41
+ * />
42
+ * ```
43
+ *
44
+ * ## Module Structure
45
+ *
46
+ * - `@rovela-ai/sdk/media` - Types, config, components, hooks
47
+ * - `@rovela-ai/sdk/media/server` - Server-side utilities (presign, delete)
48
+ * - `@rovela-ai/sdk/media/api` - Next.js API route handlers
49
+ *
50
+ * @module media
51
+ */
52
+ // =============================================================================
53
+ // Constants & Utilities
54
+ // =============================================================================
55
+ export { DEFAULT_UPLOAD_CONFIG, validateFile, generateUniqueFilename, getFileExtension } from './types';
56
+ // =============================================================================
57
+ // Configuration
58
+ // =============================================================================
59
+ export { getMediaConfig, isMediaConfigured, requireMediaConfig, defaultUploadConfig, getUploadConfig, buildStorageKey, buildPublicUrl, extractKeyFromUrl, getMimeType, isAllowedImageType, } from './config';
60
+ // =============================================================================
61
+ // Hooks
62
+ // =============================================================================
63
+ export { useUpload } from './hooks';
64
+ // =============================================================================
65
+ // Components
66
+ // =============================================================================
67
+ export { DropZone, ImageUpload, ImageGalleryUpload } from './components';
68
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/media/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkDG;AAmCH,gFAAgF;AAChF,wBAAwB;AACxB,gFAAgF;AAEhF,OAAO,EAAE,qBAAqB,EAAE,YAAY,EAAE,sBAAsB,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAA;AAEvG,gFAAgF;AAChF,gBAAgB;AAChB,gFAAgF;AAEhF,OAAO,EACL,cAAc,EACd,iBAAiB,EACjB,kBAAkB,EAClB,mBAAmB,EACnB,eAAe,EACf,eAAe,EACf,cAAc,EACd,iBAAiB,EACjB,WAAW,EACX,kBAAkB,GACnB,MAAM,UAAU,CAAA;AAEjB,gFAAgF;AAChF,QAAQ;AACR,gFAAgF;AAEhF,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA;AAEnC,gFAAgF;AAChF,aAAa;AACb,gFAAgF;AAEhF,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAA"}
@@ -0,0 +1,59 @@
1
+ /**
2
+ * @rovela-ai/sdk/media/server/delete
3
+ *
4
+ * File deletion from R2 storage.
5
+ * Server-side only - do not import in client components.
6
+ */
7
+ import type { MediaStorageConfig } from '../types';
8
+ /**
9
+ * Delete a file from R2 storage.
10
+ *
11
+ * @param url - Public URL of the file to delete
12
+ * @param config - Optional storage configuration override
13
+ * @returns True if deletion was successful
14
+ * @throws Error if URL is invalid or doesn't belong to this store
15
+ *
16
+ * @example
17
+ * ```typescript
18
+ * await deleteFile('https://pub-xxx.r2.dev/stores/abc123/products/img.jpg');
19
+ * ```
20
+ */
21
+ export declare function deleteFile(url: string, config?: MediaStorageConfig): Promise<boolean>;
22
+ /**
23
+ * Delete a file by its storage key.
24
+ * Use this when you have the key directly instead of the URL.
25
+ *
26
+ * @param key - Storage key of the file
27
+ * @param config - Optional storage configuration override
28
+ * @returns True if deletion was successful
29
+ */
30
+ export declare function deleteFileByKey(key: string, config?: MediaStorageConfig): Promise<boolean>;
31
+ /**
32
+ * Delete multiple files from R2 storage.
33
+ *
34
+ * @param urls - Array of public URLs to delete
35
+ * @param config - Optional storage configuration override
36
+ * @returns Object with results for each URL
37
+ *
38
+ * @example
39
+ * ```typescript
40
+ * const results = await deleteFiles([
41
+ * 'https://pub-xxx.r2.dev/stores/abc123/products/img1.jpg',
42
+ * 'https://pub-xxx.r2.dev/stores/abc123/products/img2.jpg',
43
+ * ]);
44
+ * // { succeeded: ['url1', 'url2'], failed: [] }
45
+ * ```
46
+ */
47
+ export declare function deleteFiles(urls: string[], config?: MediaStorageConfig): Promise<{
48
+ succeeded: string[];
49
+ failed: string[];
50
+ }>;
51
+ /**
52
+ * Safely delete a file - returns false instead of throwing if file doesn't exist.
53
+ *
54
+ * @param url - Public URL of the file to delete
55
+ * @param config - Optional storage configuration override
56
+ * @returns True if deleted, false if not found or invalid
57
+ */
58
+ export declare function safeDeleteFile(url: string, config?: MediaStorageConfig): Promise<boolean>;
59
+ //# sourceMappingURL=delete.d.ts.map