@od-oneapp/storage 2026.1.1301

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 (69) hide show
  1. package/README.md +854 -0
  2. package/dist/client-next.d.mts +61 -0
  3. package/dist/client-next.d.mts.map +1 -0
  4. package/dist/client-next.mjs +111 -0
  5. package/dist/client-next.mjs.map +1 -0
  6. package/dist/client-utils-Dx6W25iz.d.mts +43 -0
  7. package/dist/client-utils-Dx6W25iz.d.mts.map +1 -0
  8. package/dist/client.d.mts +28 -0
  9. package/dist/client.d.mts.map +1 -0
  10. package/dist/client.mjs +183 -0
  11. package/dist/client.mjs.map +1 -0
  12. package/dist/env-BVHLmQdh.mjs +128 -0
  13. package/dist/env-BVHLmQdh.mjs.map +1 -0
  14. package/dist/env.mjs +3 -0
  15. package/dist/health-check-D7LnnDec.mjs +746 -0
  16. package/dist/health-check-D7LnnDec.mjs.map +1 -0
  17. package/dist/health-check-im_huJ59.d.mts +116 -0
  18. package/dist/health-check-im_huJ59.d.mts.map +1 -0
  19. package/dist/index.d.mts +60 -0
  20. package/dist/index.d.mts.map +1 -0
  21. package/dist/index.mjs +3 -0
  22. package/dist/keys.d.mts +37 -0
  23. package/dist/keys.d.mts.map +1 -0
  24. package/dist/keys.mjs +253 -0
  25. package/dist/keys.mjs.map +1 -0
  26. package/dist/server-edge.d.mts +28 -0
  27. package/dist/server-edge.d.mts.map +1 -0
  28. package/dist/server-edge.mjs +88 -0
  29. package/dist/server-edge.mjs.map +1 -0
  30. package/dist/server-next.d.mts +183 -0
  31. package/dist/server-next.d.mts.map +1 -0
  32. package/dist/server-next.mjs +1353 -0
  33. package/dist/server-next.mjs.map +1 -0
  34. package/dist/server.d.mts +70 -0
  35. package/dist/server.d.mts.map +1 -0
  36. package/dist/server.mjs +384 -0
  37. package/dist/server.mjs.map +1 -0
  38. package/dist/types.d.mts +321 -0
  39. package/dist/types.d.mts.map +1 -0
  40. package/dist/types.mjs +3 -0
  41. package/dist/validation.d.mts +101 -0
  42. package/dist/validation.d.mts.map +1 -0
  43. package/dist/validation.mjs +590 -0
  44. package/dist/validation.mjs.map +1 -0
  45. package/dist/vercel-blob-07Sx0Akn.d.mts +31 -0
  46. package/dist/vercel-blob-07Sx0Akn.d.mts.map +1 -0
  47. package/dist/vercel-blob-DA8HaYuw.mjs +158 -0
  48. package/dist/vercel-blob-DA8HaYuw.mjs.map +1 -0
  49. package/package.json +111 -0
  50. package/src/actions/blob-upload.ts +171 -0
  51. package/src/actions/index.ts +23 -0
  52. package/src/actions/mediaActions.ts +1071 -0
  53. package/src/actions/productMediaActions.ts +538 -0
  54. package/src/auth-helpers.ts +386 -0
  55. package/src/capabilities.ts +225 -0
  56. package/src/client-next.ts +184 -0
  57. package/src/client-utils.ts +292 -0
  58. package/src/client.ts +102 -0
  59. package/src/constants.ts +88 -0
  60. package/src/health-check.ts +81 -0
  61. package/src/multi-storage.ts +230 -0
  62. package/src/multipart.ts +497 -0
  63. package/src/retry-utils.test.ts +118 -0
  64. package/src/retry-utils.ts +59 -0
  65. package/src/server-edge.ts +129 -0
  66. package/src/server-next.ts +14 -0
  67. package/src/server.ts +666 -0
  68. package/src/validation.test.ts +312 -0
  69. package/src/validation.ts +827 -0
@@ -0,0 +1,61 @@
1
+ import { KeyGenerationOptions, KeyPattern, generateMultipleKeys, generateStorageKey, isKeyPattern, normalizeStorageKey, parseStorageKey, sanitizeStorageKey, validateStorageKey } from "./keys.mjs";
2
+ import { ValidationOptions, formatFileSize, parseFileSize, validateFileSize, validateMimeType } from "./validation.mjs";
3
+ import { BlobListResponse, ClientUploadOptions, CloudflareImagesBatchToken, CloudflareImagesListOptions, CloudflareImagesTransformOptions, CloudflareImagesVariant, DirectUploadResponse, ListOptions, PresignedUploadUrl, StorageObject, UploadOptions, UploadProgress, VercelBlobOptions } from "./types.mjs";
4
+ import { a as splitFileIntoChunks, i as downloadFromUrl, n as ClientPresignedUploadUrl, o as uploadDirectToUrl, r as ClientUploadProgress, s as uploadWithPresignedUrl, t as ClientMultipartUpload } from "./client-utils-Dx6W25iz.mjs";
5
+ import { generateClientTokenFromReadWriteToken, handleUpload, upload, uploadFile } from "./client.mjs";
6
+
7
+ //#region src/client-next.d.ts
8
+ declare function uploadFileWithProgress(pathname: string, file: File | Blob, options?: {
9
+ access?: 'public' | 'private';
10
+ addRandomSuffix?: boolean;
11
+ allowOverwrite?: boolean;
12
+ cacheControlMaxAge?: number;
13
+ clientPayload?: string;
14
+ contentType?: string;
15
+ multipart?: boolean;
16
+ onUploadProgress?: (event: {
17
+ loaded: number;
18
+ total?: number;
19
+ percentage?: number;
20
+ }) => void;
21
+ handleUploadUrl?: string;
22
+ }): Promise<{
23
+ url: string;
24
+ pathname: string;
25
+ }>;
26
+ declare function uploadMultipleFiles(files: File[], getPathname: (file: File, index: number) => string, options?: {
27
+ access?: 'public' | 'private';
28
+ addRandomSuffix?: boolean;
29
+ allowOverwrite?: boolean;
30
+ cacheControlMaxAge?: number;
31
+ clientPayload?: string;
32
+ contentType?: string;
33
+ multipart?: boolean;
34
+ onUploadProgress?: (event: {
35
+ loaded: number;
36
+ total?: number;
37
+ percentage?: number;
38
+ }) => void;
39
+ handleUploadUrl?: string;
40
+ onFileProgress?: (fileIndex: number, progress: {
41
+ loaded: number;
42
+ total?: number;
43
+ percentage?: number;
44
+ }) => void;
45
+ }): Promise<Array<{
46
+ url: string;
47
+ pathname: string;
48
+ success: boolean;
49
+ error?: string;
50
+ }>>;
51
+ declare function validateFileForUpload(file: File, options?: {
52
+ maxFileSize?: number;
53
+ allowedMimeTypes?: string[];
54
+ allowedExtensions?: string[];
55
+ }): Promise<{
56
+ valid: boolean;
57
+ errors: string[];
58
+ }>;
59
+ //#endregion
60
+ export { BlobListResponse, ClientMultipartUpload, ClientPresignedUploadUrl, ClientUploadOptions, ClientUploadProgress, CloudflareImagesBatchToken, CloudflareImagesListOptions, CloudflareImagesTransformOptions, CloudflareImagesVariant, DirectUploadResponse, KeyGenerationOptions, KeyPattern, ListOptions, PresignedUploadUrl, StorageObject, UploadOptions, UploadProgress, ValidationOptions, VercelBlobOptions, downloadFromUrl, formatFileSize, generateClientTokenFromReadWriteToken, generateMultipleKeys, generateStorageKey, handleUpload, isKeyPattern, normalizeStorageKey, parseFileSize, parseStorageKey, sanitizeStorageKey, splitFileIntoChunks, upload, uploadDirectToUrl, uploadFile, uploadFileWithProgress, uploadMultipleFiles, uploadWithPresignedUrl, validateFileForUpload, validateFileSize, validateMimeType, validateStorageKey };
61
+ //# sourceMappingURL=client-next.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client-next.d.mts","names":[],"sources":["../src/client-next.ts"],"mappings":";;;;;;;iBAwBsB,sBAAA,CACpB,QAAA,UACA,IAAA,EAAM,IAAA,GAAO,IAAA,EACb,OAAA;EACE,MAAA;EACA,eAAA;EACA,cAAA;EACA,kBAAA;EACA,aAAA;EACA,WAAA;EACA,SAAA;EACA,gBAAA,IAAoB,KAAA;IAAS,MAAA;IAAgB,KAAA;IAAgB,UAAA;EAAA;EAC7D,eAAA;AAAA,IAED,OAAA;EAAU,GAAA;EAAa,QAAA;AAAA;AAAA,iBA0BJ,mBAAA,CACpB,KAAA,EAAO,IAAA,IACP,WAAA,GAAc,IAAA,EAAM,IAAA,EAAM,KAAA,qBAC1B,OAAA;EACE,MAAA;EACA,eAAA;EACA,cAAA;EACA,kBAAA;EACA,aAAA;EACA,WAAA;EACA,SAAA;EACA,gBAAA,IAAoB,KAAA;IAAS,MAAA;IAAgB,KAAA;IAAgB,UAAA;EAAA;EAC7D,eAAA;EACA,cAAA,IACE,SAAA,UACA,QAAA;IAAY,MAAA;IAAgB,KAAA;IAAgB,UAAA;EAAA;AAAA,IAG/C,OAAA,CAAQ,KAAA;EAAQ,GAAA;EAAa,QAAA;EAAkB,OAAA;EAAkB,KAAA;AAAA;AAAA,iBAqD9C,qBAAA,CACpB,IAAA,EAAM,IAAA,EACN,OAAA;EACE,WAAA;EACA,gBAAA;EACA,iBAAA;AAAA,IAED,OAAA;EAAU,KAAA;EAAgB,MAAA;AAAA"}
@@ -0,0 +1,111 @@
1
+ 'use client';
2
+
3
+ import { generateMultipleKeys, generateStorageKey, isKeyPattern, normalizeStorageKey, parseStorageKey, sanitizeStorageKey, validateStorageKey } from "./keys.mjs";
4
+ import { formatFileSize, parseFileSize, validateFileSize, validateMimeType } from "./validation.mjs";
5
+ import { ClientMultipartUpload, downloadFromUrl, generateClientTokenFromReadWriteToken, handleUpload, splitFileIntoChunks, upload, uploadDirectToUrl, uploadFile, uploadWithPresignedUrl } from "./client.mjs";
6
+
7
+ //#region src/client-next.ts
8
+ /**
9
+ * @fileoverview Client-side storage exports for Next.js
10
+ *
11
+ * This file provides client-side storage functionality specifically for Next.js applications.
12
+ * NO REACT HOOKS - keep in consuming apps to avoid React peer dependency.
13
+ *
14
+ * Features:
15
+ * - File upload with progress tracking
16
+ * - Next.js-specific upload helpers
17
+ * - Client-side validation
18
+ *
19
+ * @module @od-oneapp/storage/client/next
20
+ */
21
+ async function uploadFileWithProgress(pathname, file, options) {
22
+ return await uploadFile(pathname, file, options);
23
+ }
24
+ /**
25
+ * Upload multiple files with progress tracking
26
+ *
27
+ * @param files - Array of files to upload
28
+ * @param getPathname - Function to generate pathname for each file
29
+ * @param options - Upload options
30
+ * @returns Array of upload results
31
+ *
32
+ * @example
33
+ * ```typescript
34
+ * const results = await uploadMultipleFiles(
35
+ * files,
36
+ * (file, index) => `uploads/${index}-${file.name}`,
37
+ * {
38
+ * onUploadProgress: (event) => {
39
+ * logInfo(`Uploaded ${event.percentage}%`);
40
+ * }
41
+ * }
42
+ * );
43
+ * ```
44
+ */
45
+ async function uploadMultipleFiles(files, getPathname, options) {
46
+ const results = [];
47
+ for (let i = 0; i < files.length; i++) {
48
+ const file = files[i];
49
+ if (!file) continue;
50
+ const pathname = getPathname(file, i);
51
+ try {
52
+ const result = await uploadFile(pathname, file, {
53
+ ...options,
54
+ onUploadProgress: options?.onFileProgress ? (event) => options.onFileProgress?.(i, event) : options?.onUploadProgress
55
+ });
56
+ results.push({
57
+ ...result,
58
+ success: true
59
+ });
60
+ } catch (error) {
61
+ results.push({
62
+ url: "",
63
+ pathname,
64
+ success: false,
65
+ error: error instanceof Error ? error.message : String(error)
66
+ });
67
+ }
68
+ }
69
+ return results;
70
+ }
71
+ /**
72
+ * Validate file before upload
73
+ *
74
+ * @param file - File to validate
75
+ * @param options - Validation options
76
+ * @returns Validation result
77
+ *
78
+ * @example
79
+ * ```typescript
80
+ * const validation = await validateFileForUpload(file, {
81
+ * maxFileSize: 10 * 1024 * 1024, // 10MB
82
+ * allowedMimeTypes: ['image/jpeg', 'image/png'],
83
+ * });
84
+ *
85
+ * if (!validation.valid) {
86
+ * logError('Validation failed:', validation.errors);
87
+ * }
88
+ * ```
89
+ */
90
+ async function validateFileForUpload(file, options = {}) {
91
+ const errors = [];
92
+ if (options.maxFileSize && file.size > options.maxFileSize) errors.push(`File size ${file.size} bytes exceeds maximum ${options.maxFileSize} bytes`);
93
+ if (options.allowedMimeTypes && options.allowedMimeTypes.length > 0) {
94
+ const mimeValidation = validateMimeType(file.type, options.allowedMimeTypes);
95
+ if (!mimeValidation.valid) {
96
+ if (mimeValidation.error) errors.push(mimeValidation.error);
97
+ }
98
+ }
99
+ if (options.allowedExtensions && options.allowedExtensions.length > 0) {
100
+ const extension = file.name.match(/\.[^/.]+$/)?.[0]?.toLowerCase();
101
+ if (extension && !options.allowedExtensions.includes(extension)) errors.push(`File extension ${extension} is not allowed. Allowed: ${options.allowedExtensions.join(", ")}`);
102
+ }
103
+ return {
104
+ valid: errors.length === 0,
105
+ errors
106
+ };
107
+ }
108
+
109
+ //#endregion
110
+ export { ClientMultipartUpload, downloadFromUrl, formatFileSize, generateClientTokenFromReadWriteToken, generateMultipleKeys, generateStorageKey, handleUpload, isKeyPattern, normalizeStorageKey, parseFileSize, parseStorageKey, sanitizeStorageKey, splitFileIntoChunks, upload, uploadDirectToUrl, uploadFile, uploadFileWithProgress, uploadMultipleFiles, uploadWithPresignedUrl, validateFileForUpload, validateFileSize, validateMimeType, validateStorageKey };
111
+ //# sourceMappingURL=client-next.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client-next.mjs","names":[],"sources":["../src/client-next.ts"],"sourcesContent":["/**\n * @fileoverview Client-side storage exports for Next.js\n *\n * This file provides client-side storage functionality specifically for Next.js applications.\n * NO REACT HOOKS - keep in consuming apps to avoid React peer dependency.\n *\n * Features:\n * - File upload with progress tracking\n * - Next.js-specific upload helpers\n * - Client-side validation\n *\n * @module @repo/storage/client/next\n */\n\n'use client';\n\n// Import for internal use\nimport { uploadFile } from './client';\nimport { validateMimeType } from './validation';\n\n// Re-export all client functionality\nexport * from './client';\n\n// Next.js-specific upload helpers (no hooks)\nexport async function uploadFileWithProgress(\n pathname: string,\n file: File | Blob,\n options?: {\n access?: 'public' | 'private';\n addRandomSuffix?: boolean;\n allowOverwrite?: boolean;\n cacheControlMaxAge?: number;\n clientPayload?: string;\n contentType?: string;\n multipart?: boolean;\n onUploadProgress?: (event: { loaded: number; total?: number; percentage?: number }) => void;\n handleUploadUrl?: string;\n },\n): Promise<{ url: string; pathname: string }> {\n // Use the base uploadFile function\n return await uploadFile(pathname, file, options);\n}\n\n/**\n * Upload multiple files with progress tracking\n *\n * @param files - Array of files to upload\n * @param getPathname - Function to generate pathname for each file\n * @param options - Upload options\n * @returns Array of upload results\n *\n * @example\n * ```typescript\n * const results = await uploadMultipleFiles(\n * files,\n * (file, index) => `uploads/${index}-${file.name}`,\n * {\n * onUploadProgress: (event) => {\n * logInfo(`Uploaded ${event.percentage}%`);\n * }\n * }\n * );\n * ```\n */\nexport async function uploadMultipleFiles(\n files: File[],\n getPathname: (file: File, index: number) => string,\n options?: {\n access?: 'public' | 'private';\n addRandomSuffix?: boolean;\n allowOverwrite?: boolean;\n cacheControlMaxAge?: number;\n clientPayload?: string;\n contentType?: string;\n multipart?: boolean;\n onUploadProgress?: (event: { loaded: number; total?: number; percentage?: number }) => void;\n handleUploadUrl?: string;\n onFileProgress?: (\n fileIndex: number,\n progress: { loaded: number; total?: number; percentage?: number },\n ) => void;\n },\n): Promise<Array<{ url: string; pathname: string; success: boolean; error?: string }>> {\n const results: Array<{ url: string; pathname: string; success: boolean; error?: string }> = [];\n\n for (let i = 0; i < files.length; i++) {\n const file = files[i];\n if (!file) continue;\n const pathname = getPathname(file, i);\n\n try {\n const result = await uploadFile(pathname, file, {\n ...options,\n onUploadProgress: options?.onFileProgress\n ? (event: { loaded: number; total?: number; percentage?: number }) =>\n options.onFileProgress?.(i, event)\n : options?.onUploadProgress,\n });\n\n results.push({\n ...result,\n success: true,\n });\n } catch (error) {\n results.push({\n url: '',\n pathname,\n success: false,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n return results;\n}\n\n/**\n * Validate file before upload\n *\n * @param file - File to validate\n * @param options - Validation options\n * @returns Validation result\n *\n * @example\n * ```typescript\n * const validation = await validateFileForUpload(file, {\n * maxFileSize: 10 * 1024 * 1024, // 10MB\n * allowedMimeTypes: ['image/jpeg', 'image/png'],\n * });\n *\n * if (!validation.valid) {\n * logError('Validation failed:', validation.errors);\n * }\n * ```\n */\nexport async function validateFileForUpload(\n file: File,\n options: {\n maxFileSize?: number;\n allowedMimeTypes?: string[];\n allowedExtensions?: string[];\n } = {},\n): Promise<{ valid: boolean; errors: string[] }> {\n const errors: string[] = [];\n\n // Validate file size\n if (options.maxFileSize && file.size > options.maxFileSize) {\n errors.push(`File size ${file.size} bytes exceeds maximum ${options.maxFileSize} bytes`);\n }\n\n // Validate MIME type\n if (options.allowedMimeTypes && options.allowedMimeTypes.length > 0) {\n const mimeValidation = validateMimeType(file.type, options.allowedMimeTypes);\n if (!mimeValidation.valid) {\n if (mimeValidation.error) {\n errors.push(mimeValidation.error);\n }\n }\n }\n\n // Validate file extension\n if (options.allowedExtensions && options.allowedExtensions.length > 0) {\n const extension = file.name.match(/\\.[^/.]+$/)?.[0]?.toLowerCase();\n if (extension && !options.allowedExtensions.includes(extension)) {\n errors.push(\n `File extension ${extension} is not allowed. Allowed: ${options.allowedExtensions.join(', ')}`,\n );\n }\n }\n\n return {\n valid: errors.length === 0,\n errors,\n };\n}\n\n// Re-export validation utilities for convenience\nexport {\n formatFileSize,\n parseFileSize,\n validateFileSize,\n validateMimeType,\n validateStorageKey,\n} from './validation';\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAwBA,eAAsB,uBACpB,UACA,MACA,SAW4C;AAE5C,QAAO,MAAM,WAAW,UAAU,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;;;AAwBlD,eAAsB,oBACpB,OACA,aACA,SAeqF;CACrF,MAAM,UAAsF,EAAE;AAE9F,MAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;EACrC,MAAM,OAAO,MAAM;AACnB,MAAI,CAAC,KAAM;EACX,MAAM,WAAW,YAAY,MAAM,EAAE;AAErC,MAAI;GACF,MAAM,SAAS,MAAM,WAAW,UAAU,MAAM;IAC9C,GAAG;IACH,kBAAkB,SAAS,kBACtB,UACC,QAAQ,iBAAiB,GAAG,MAAM,GACpC,SAAS;IACd,CAAC;AAEF,WAAQ,KAAK;IACX,GAAG;IACH,SAAS;IACV,CAAC;WACK,OAAO;AACd,WAAQ,KAAK;IACX,KAAK;IACL;IACA,SAAS;IACT,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;IAC9D,CAAC;;;AAIN,QAAO;;;;;;;;;;;;;;;;;;;;;AAsBT,eAAsB,sBACpB,MACA,UAII,EAAE,EACyC;CAC/C,MAAM,SAAmB,EAAE;AAG3B,KAAI,QAAQ,eAAe,KAAK,OAAO,QAAQ,YAC7C,QAAO,KAAK,aAAa,KAAK,KAAK,yBAAyB,QAAQ,YAAY,QAAQ;AAI1F,KAAI,QAAQ,oBAAoB,QAAQ,iBAAiB,SAAS,GAAG;EACnE,MAAM,iBAAiB,iBAAiB,KAAK,MAAM,QAAQ,iBAAiB;AAC5E,MAAI,CAAC,eAAe,OAClB;OAAI,eAAe,MACjB,QAAO,KAAK,eAAe,MAAM;;;AAMvC,KAAI,QAAQ,qBAAqB,QAAQ,kBAAkB,SAAS,GAAG;EACrE,MAAM,YAAY,KAAK,KAAK,MAAM,YAAY,GAAG,IAAI,aAAa;AAClE,MAAI,aAAa,CAAC,QAAQ,kBAAkB,SAAS,UAAU,CAC7D,QAAO,KACL,kBAAkB,UAAU,4BAA4B,QAAQ,kBAAkB,KAAK,KAAK,GAC7F;;AAIL,QAAO;EACL,OAAO,OAAO,WAAW;EACzB;EACD"}
@@ -0,0 +1,43 @@
1
+ import { PresignedUploadUrl } from "./types.mjs";
2
+
3
+ //#region src/client-utils.d.ts
4
+ interface ClientPresignedUploadUrl extends PresignedUploadUrl {
5
+ key: string;
6
+ }
7
+ interface ClientUploadProgress {
8
+ loaded: number;
9
+ total: number;
10
+ percentage: number;
11
+ }
12
+ declare function uploadWithPresignedUrl(presignedData: ClientPresignedUploadUrl, file: File | Blob, options?: {
13
+ onProgress?: (progress: ClientUploadProgress) => void;
14
+ }): Promise<void>;
15
+ declare function uploadDirectToUrl(url: string, file: File | Blob, options?: {
16
+ headers?: Record<string, string>;
17
+ onProgress?: (progress: ClientUploadProgress) => void;
18
+ }): Promise<void>;
19
+ declare class ClientMultipartUpload {
20
+ private uploadId;
21
+ private key;
22
+ private parts;
23
+ constructor(uploadId: string, key: string);
24
+ uploadPart(partNumber: number, presignedUrl: string, data: Blob, _onProgress?: (progress: ClientUploadProgress) => void): Promise<void>;
25
+ getParts(): {
26
+ PartNumber: number;
27
+ ETag: string;
28
+ }[];
29
+ getUploadId(): string;
30
+ getKey(): string;
31
+ }
32
+ declare function splitFileIntoChunks(file: File | Blob, chunkSize?: number): AsyncGenerator<{
33
+ chunk: Blob;
34
+ partNumber: number;
35
+ start: number;
36
+ end: number;
37
+ }>;
38
+ declare function downloadFromUrl(url: string, options?: {
39
+ onProgress?: (progress: ClientUploadProgress) => void;
40
+ }): Promise<Blob>;
41
+ //#endregion
42
+ export { splitFileIntoChunks as a, downloadFromUrl as i, ClientPresignedUploadUrl as n, uploadDirectToUrl as o, ClientUploadProgress as r, uploadWithPresignedUrl as s, ClientMultipartUpload as t };
43
+ //# sourceMappingURL=client-utils-Dx6W25iz.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client-utils-Dx6W25iz.d.mts","names":[],"sources":["../src/client-utils.ts"],"mappings":";;;UAoBiB,wBAAA,SAAiC,kBAAA;EAChD,GAAA;AAAA;AAAA,UAOe,oBAAA;EACf,MAAA;EACA,KAAA;EACA,UAAA;AAAA;AAAA,iBAMoB,sBAAA,CACpB,aAAA,EAAe,wBAAA,EACf,IAAA,EAAM,IAAA,GAAO,IAAA,EACb,OAAA;EACE,UAAA,IAAc,QAAA,EAAU,oBAAA;AAAA,IAEzB,OAAA;AAAA,iBA2DmB,iBAAA,CACpB,GAAA,UACA,IAAA,EAAM,IAAA,GAAO,IAAA,EACb,OAAA;EACE,OAAA,GAAU,MAAA;EACV,UAAA,IAAc,QAAA,EAAU,oBAAA;AAAA,IAEzB,OAAA;AAAA,cAyDU,qBAAA;EAAA,QACH,QAAA;EAAA,QACA,GAAA;EAAA,QACA,KAAA;cAEI,QAAA,UAAkB,GAAA;EAKxB,UAAA,CACJ,UAAA,UACA,YAAA,UACA,IAAA,EAAM,IAAA,EACN,WAAA,IAAe,QAAA,EAAU,oBAAA,YACxB,OAAA;EAgBH,QAAA,CAAA;;;;EAIA,WAAA,CAAA;EAIA,MAAA,CAAA;AAAA;AAAA,iBAQqB,mBAAA,CACrB,IAAA,EAAM,IAAA,GAAO,IAAA,EACb,SAAA,YACC,cAAA;EAAiB,KAAA,EAAO,IAAA;EAAM,UAAA;EAAoB,KAAA;EAAe,GAAA;AAAA;AAAA,iBAsB9C,eAAA,CACpB,GAAA,UACA,OAAA;EACE,UAAA,IAAc,QAAA,EAAU,oBAAA;AAAA,IAEzB,OAAA,CAAQ,IAAA"}
@@ -0,0 +1,28 @@
1
+ import { KeyGenerationOptions, KeyPattern, generateMultipleKeys, generateStorageKey, isKeyPattern, normalizeStorageKey, parseStorageKey, sanitizeStorageKey, validateStorageKey } from "./keys.mjs";
2
+ import { ValidationOptions, formatFileSize, parseFileSize, validateFileSize, validateMimeType } from "./validation.mjs";
3
+ import { BlobListResponse, ClientUploadOptions, CloudflareImagesBatchToken, CloudflareImagesListOptions, CloudflareImagesTransformOptions, CloudflareImagesVariant, DirectUploadResponse, ListOptions, PresignedUploadUrl, StorageObject, UploadOptions, UploadProgress, VercelBlobOptions } from "./types.mjs";
4
+ import { a as splitFileIntoChunks, i as downloadFromUrl, n as ClientPresignedUploadUrl, o as uploadDirectToUrl, r as ClientUploadProgress, s as uploadWithPresignedUrl, t as ClientMultipartUpload } from "./client-utils-Dx6W25iz.mjs";
5
+ import { generateClientTokenFromReadWriteToken, handleUpload, upload } from "@vercel/blob/client";
6
+
7
+ //#region src/client.d.ts
8
+ declare function uploadFile(pathname: string, file: File | Blob, options?: {
9
+ access?: 'public' | 'private';
10
+ addRandomSuffix?: boolean;
11
+ allowOverwrite?: boolean;
12
+ cacheControlMaxAge?: number;
13
+ clientPayload?: string;
14
+ contentType?: string;
15
+ multipart?: boolean;
16
+ onUploadProgress?: (event: {
17
+ loaded: number;
18
+ total?: number;
19
+ percentage?: number;
20
+ }) => void;
21
+ handleUploadUrl?: string;
22
+ }): Promise<{
23
+ url: string;
24
+ pathname: string;
25
+ }>;
26
+ //#endregion
27
+ export { type BlobListResponse, ClientMultipartUpload, ClientPresignedUploadUrl, type ClientUploadOptions, ClientUploadProgress, type CloudflareImagesBatchToken, type CloudflareImagesListOptions, type CloudflareImagesTransformOptions, type CloudflareImagesVariant, type DirectUploadResponse, type KeyGenerationOptions, type KeyPattern, type ListOptions, type PresignedUploadUrl, type StorageObject, type UploadOptions, type UploadProgress, type ValidationOptions, type VercelBlobOptions, downloadFromUrl, formatFileSize, generateClientTokenFromReadWriteToken, generateMultipleKeys, generateStorageKey, handleUpload, isKeyPattern, normalizeStorageKey, parseFileSize, parseStorageKey, sanitizeStorageKey, splitFileIntoChunks, upload, uploadDirectToUrl, uploadFile, uploadWithPresignedUrl, validateFileSize, validateMimeType, validateStorageKey };
28
+ //# sourceMappingURL=client.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.mts","names":[],"sources":["../src/client.ts"],"mappings":";;;;;;;iBAoDsB,UAAA,CACpB,QAAA,UACA,IAAA,EAAM,IAAA,GAAO,IAAA,EACb,OAAA;EACE,MAAA;EACA,eAAA;EACA,cAAA;EACA,kBAAA;EACA,aAAA;EACA,WAAA;EACA,SAAA;EACA,gBAAA,IAAoB,KAAA;IAAS,MAAA;IAAgB,KAAA;IAAgB,UAAA;EAAA;EAC7D,eAAA;AAAA,IAED,OAAA;EAAU,GAAA;EAAa,QAAA;AAAA"}
@@ -0,0 +1,183 @@
1
+ import { generateMultipleKeys, generateStorageKey, isKeyPattern, normalizeStorageKey, parseStorageKey, sanitizeStorageKey, validateStorageKey } from "./keys.mjs";
2
+ import { formatFileSize, parseFileSize, validateFileSize, validateMimeType } from "./validation.mjs";
3
+ import { generateClientTokenFromReadWriteToken, handleUpload, upload, upload as upload$1 } from "@vercel/blob/client";
4
+
5
+ //#region src/client-utils.ts
6
+ /**
7
+ * Upload a file using a presigned URL (works with R2, S3, etc.)
8
+ */
9
+ async function uploadWithPresignedUrl(presignedData, file, options) {
10
+ const formData = new FormData();
11
+ if (presignedData.fields) Object.entries(presignedData.fields).forEach(([key, value]) => {
12
+ formData.append(key, value);
13
+ });
14
+ formData.append("file", file);
15
+ if (options?.onProgress) return new Promise((resolve, reject) => {
16
+ const xhr = new XMLHttpRequest();
17
+ xhr.upload.addEventListener("progress", (event) => {
18
+ if (event.lengthComputable && options.onProgress) options.onProgress({
19
+ loaded: event.loaded,
20
+ total: event.total,
21
+ percentage: event.loaded / event.total * 100
22
+ });
23
+ });
24
+ xhr.addEventListener("load", () => {
25
+ if (xhr.status >= 200 && xhr.status < 300) resolve();
26
+ else reject(/* @__PURE__ */ new Error(`Upload failed with status ${xhr.status}`));
27
+ });
28
+ xhr.addEventListener("error", () => {
29
+ reject(/* @__PURE__ */ new Error("Upload failed"));
30
+ });
31
+ xhr.open("POST", presignedData.url);
32
+ xhr.send(formData);
33
+ });
34
+ const response = await fetch(presignedData.url, {
35
+ method: "POST",
36
+ body: formData
37
+ });
38
+ if (!response.ok) throw new Error(`Upload failed with status ${response.status}`);
39
+ }
40
+ /**
41
+ * Upload directly to a URL (PUT method, typically for presigned PUT URLs)
42
+ */
43
+ async function uploadDirectToUrl(url, file, options) {
44
+ if (options?.onProgress) return new Promise((resolve, reject) => {
45
+ const xhr = new XMLHttpRequest();
46
+ xhr.upload.addEventListener("progress", (event) => {
47
+ if (event.lengthComputable && options.onProgress) options.onProgress({
48
+ loaded: event.loaded,
49
+ total: event.total,
50
+ percentage: event.loaded / event.total * 100
51
+ });
52
+ });
53
+ xhr.addEventListener("load", () => {
54
+ if (xhr.status >= 200 && xhr.status < 300) resolve();
55
+ else reject(/* @__PURE__ */ new Error(`Upload failed with status ${xhr.status}`));
56
+ });
57
+ xhr.addEventListener("error", () => {
58
+ reject(/* @__PURE__ */ new Error("Upload failed"));
59
+ });
60
+ xhr.open("PUT", url);
61
+ if (options?.headers) Object.entries(options.headers).forEach(([key, value]) => {
62
+ xhr.setRequestHeader(key, value);
63
+ });
64
+ xhr.send(file);
65
+ });
66
+ const response = await fetch(url, {
67
+ method: "PUT",
68
+ body: file,
69
+ headers: options?.headers
70
+ });
71
+ if (!response.ok) throw new Error(`Upload failed with status ${response.status}`);
72
+ }
73
+ /**
74
+ * Client-side multipart upload coordinator
75
+ * Works with server-side APIs to manage multipart uploads
76
+ */
77
+ var ClientMultipartUpload = class {
78
+ uploadId;
79
+ key;
80
+ parts = [];
81
+ constructor(uploadId, key) {
82
+ this.uploadId = uploadId;
83
+ this.key = key;
84
+ }
85
+ async uploadPart(partNumber, presignedUrl, data, _onProgress) {
86
+ const response = await fetch(presignedUrl, {
87
+ method: "PUT",
88
+ body: data
89
+ });
90
+ if (!response.ok) throw new Error(`Part upload failed with status ${response.status}`);
91
+ const etag = response.headers.get("ETag") ?? "";
92
+ this.parts.push({
93
+ PartNumber: partNumber,
94
+ ETag: etag
95
+ });
96
+ }
97
+ getParts() {
98
+ return this.parts.sort((a, b) => a.PartNumber - b.PartNumber);
99
+ }
100
+ getUploadId() {
101
+ return this.uploadId;
102
+ }
103
+ getKey() {
104
+ return this.key;
105
+ }
106
+ };
107
+ /**
108
+ * Split a file into chunks for multipart upload
109
+ */
110
+ async function* splitFileIntoChunks(file, chunkSize = 5 * 1024 * 1024) {
111
+ const totalSize = file.size;
112
+ let partNumber = 1;
113
+ for (let start = 0; start < totalSize; start += chunkSize) {
114
+ const end = Math.min(start + chunkSize, totalSize);
115
+ yield {
116
+ chunk: file.slice(start, end),
117
+ partNumber,
118
+ start,
119
+ end
120
+ };
121
+ partNumber++;
122
+ }
123
+ }
124
+ /**
125
+ * Download a file from a URL with progress tracking
126
+ */
127
+ async function downloadFromUrl(url, options) {
128
+ const response = await fetch(url);
129
+ if (!response.ok) throw new Error(`Download failed with status ${response.status}`);
130
+ if (!options?.onProgress || !response.body) return response.blob();
131
+ const contentLength = response.headers.get("content-length");
132
+ const total = contentLength ? parseInt(contentLength, 10) : 0;
133
+ const reader = response.body.getReader();
134
+ const chunks = [];
135
+ let loaded = 0;
136
+ while (true) {
137
+ const { done, value } = await reader.read();
138
+ if (done) break;
139
+ chunks.push(value);
140
+ loaded += value.length;
141
+ if (total > 0) options.onProgress({
142
+ loaded,
143
+ total,
144
+ percentage: loaded / total * 100
145
+ });
146
+ }
147
+ return new Blob(chunks.map((chunk) => chunk.buffer.slice(chunk.byteOffset, chunk.byteOffset + chunk.byteLength)), { type: response.headers.get("content-type") ?? "application/octet-stream" });
148
+ }
149
+
150
+ //#endregion
151
+ //#region src/client.ts
152
+ /**
153
+ * @fileoverview Client-side storage exports (non-Next.js)
154
+ *
155
+ * This file provides client-side storage functionality for non-Next.js environments.
156
+ * For Next.js applications, use '@od-oneapp/storage/client/next' instead.
157
+ *
158
+ * CLEAN BREAK: Removed legacy wrappers, direct Vercel SDK re-exports only.
159
+ *
160
+ * Features:
161
+ * - File upload utilities
162
+ * - Client-side validation
163
+ * - Key generation utilities
164
+ *
165
+ * @module @od-oneapp/storage/client
166
+ */
167
+ async function uploadFile(pathname, file, options) {
168
+ const { handleUploadUrl, ...vercelOptions } = options ?? {};
169
+ if (handleUploadUrl) return await upload$1(pathname, file, {
170
+ ...vercelOptions,
171
+ access: "public",
172
+ handleUploadUrl
173
+ });
174
+ else return await upload$1(pathname, file, {
175
+ ...vercelOptions,
176
+ access: "public",
177
+ handleUploadUrl: "/api/upload"
178
+ });
179
+ }
180
+
181
+ //#endregion
182
+ export { ClientMultipartUpload, downloadFromUrl, formatFileSize, generateClientTokenFromReadWriteToken, generateMultipleKeys, generateStorageKey, handleUpload, isKeyPattern, normalizeStorageKey, parseFileSize, parseStorageKey, sanitizeStorageKey, splitFileIntoChunks, upload, uploadDirectToUrl, uploadFile, uploadWithPresignedUrl, validateFileSize, validateMimeType, validateStorageKey };
183
+ //# sourceMappingURL=client.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.mjs","names":["vercelUpload"],"sources":["../src/client-utils.ts","../src/client.ts"],"sourcesContent":["/**\n * @fileoverview Client-side utilities for storage operations\n *\n * These work with server-side APIs to enable client uploads without exposing credentials.\n * Provides presigned URL uploads and progress tracking.\n *\n * Features:\n * - Presigned URL uploads\n * - Upload progress tracking\n * - Client-side file handling\n *\n * @module @repo/storage/client-utils\n */\n\nimport type { PresignedUploadUrl as BasePresignedUploadUrl } from '../types';\n\n/**\n * Extended presigned upload URL configuration for client-side use\n * Includes the storage key for tracking uploads\n */\nexport interface ClientPresignedUploadUrl extends BasePresignedUploadUrl {\n key: string;\n}\n\n/**\n * Upload progress information for client-side tracking\n * Uses 'percentage' to align with types.ts UploadProgress\n */\nexport interface ClientUploadProgress {\n loaded: number;\n total: number;\n percentage: number;\n}\n\n/**\n * Upload a file using a presigned URL (works with R2, S3, etc.)\n */\nexport async function uploadWithPresignedUrl(\n presignedData: ClientPresignedUploadUrl,\n file: File | Blob,\n options?: {\n onProgress?: (progress: ClientUploadProgress) => void;\n },\n): Promise<void> {\n const formData = new FormData();\n\n // Add any required fields first (for POST uploads)\n if (presignedData.fields) {\n Object.entries(presignedData.fields).forEach(([key, value]) => {\n formData.append(key, value);\n });\n }\n\n // Add the file last\n formData.append('file', file);\n\n // For progress tracking, we need XMLHttpRequest\n if (options?.onProgress) {\n return new Promise((resolve, reject) => {\n const xhr = new XMLHttpRequest();\n\n xhr.upload.addEventListener('progress', event => {\n if (event.lengthComputable && options.onProgress) {\n options.onProgress({\n loaded: event.loaded,\n total: event.total,\n percentage: (event.loaded / event.total) * 100,\n });\n }\n });\n\n xhr.addEventListener('load', () => {\n if (xhr.status >= 200 && xhr.status < 300) {\n resolve();\n } else {\n reject(new Error(`Upload failed with status ${xhr.status}`));\n }\n });\n\n xhr.addEventListener('error', () => {\n reject(new Error('Upload failed'));\n });\n\n xhr.open('POST', presignedData.url);\n xhr.send(formData);\n });\n }\n\n // Simple fetch for no progress tracking\n const response = await fetch(presignedData.url, {\n method: 'POST',\n body: formData,\n });\n\n if (!response.ok) {\n throw new Error(`Upload failed with status ${response.status}`);\n }\n}\n\n/**\n * Upload directly to a URL (PUT method, typically for presigned PUT URLs)\n */\nexport async function uploadDirectToUrl(\n url: string,\n file: File | Blob,\n options?: {\n headers?: Record<string, string>;\n onProgress?: (progress: ClientUploadProgress) => void;\n },\n): Promise<void> {\n // For progress tracking, we need XMLHttpRequest\n if (options?.onProgress) {\n return new Promise((resolve, reject) => {\n const xhr = new XMLHttpRequest();\n\n xhr.upload.addEventListener('progress', event => {\n if (event.lengthComputable && options.onProgress) {\n options.onProgress({\n loaded: event.loaded,\n total: event.total,\n percentage: (event.loaded / event.total) * 100,\n });\n }\n });\n\n xhr.addEventListener('load', () => {\n if (xhr.status >= 200 && xhr.status < 300) {\n resolve();\n } else {\n reject(new Error(`Upload failed with status ${xhr.status}`));\n }\n });\n\n xhr.addEventListener('error', () => {\n reject(new Error('Upload failed'));\n });\n\n xhr.open('PUT', url);\n\n // Set headers\n if (options?.headers) {\n Object.entries(options.headers).forEach(([key, value]) => {\n xhr.setRequestHeader(key, value);\n });\n }\n\n xhr.send(file);\n });\n }\n\n // Simple fetch for no progress tracking\n const response = await fetch(url, {\n method: 'PUT',\n body: file,\n headers: options?.headers,\n });\n\n if (!response.ok) {\n throw new Error(`Upload failed with status ${response.status}`);\n }\n}\n\n/**\n * Client-side multipart upload coordinator\n * Works with server-side APIs to manage multipart uploads\n */\nexport class ClientMultipartUpload {\n private uploadId: string;\n private key: string;\n private parts: Array<{ PartNumber: number; ETag: string }> = [];\n\n constructor(uploadId: string, key: string) {\n this.uploadId = uploadId;\n this.key = key;\n }\n\n async uploadPart(\n partNumber: number,\n presignedUrl: string,\n data: Blob,\n _onProgress?: (progress: ClientUploadProgress) => void,\n ): Promise<void> {\n // Note: onProgress tracking for presigned URL uploads requires XMLHttpRequest\n // This is a simplified implementation using fetch\n const response = await fetch(presignedUrl, {\n method: 'PUT',\n body: data,\n });\n\n if (!response.ok) {\n throw new Error(`Part upload failed with status ${response.status}`);\n }\n\n const etag = response.headers.get('ETag') ?? '';\n this.parts.push({ PartNumber: partNumber, ETag: etag });\n }\n\n getParts() {\n return this.parts.sort((a, b) => a.PartNumber - b.PartNumber);\n }\n\n getUploadId() {\n return this.uploadId;\n }\n\n getKey() {\n return this.key;\n }\n}\n\n/**\n * Split a file into chunks for multipart upload\n */\nexport async function* splitFileIntoChunks(\n file: File | Blob,\n chunkSize: number = 5 * 1024 * 1024, // 5MB default\n): AsyncGenerator<{ chunk: Blob; partNumber: number; start: number; end: number }> {\n const totalSize = file.size;\n let partNumber = 1;\n\n for (let start = 0; start < totalSize; start += chunkSize) {\n const end = Math.min(start + chunkSize, totalSize);\n const chunk = file.slice(start, end);\n\n yield {\n chunk,\n partNumber,\n start,\n end,\n };\n\n partNumber++;\n }\n}\n\n/**\n * Download a file from a URL with progress tracking\n */\nexport async function downloadFromUrl(\n url: string,\n options?: {\n onProgress?: (progress: ClientUploadProgress) => void;\n },\n): Promise<Blob> {\n const response = await fetch(url);\n\n if (!response.ok) {\n throw new Error(`Download failed with status ${response.status}`);\n }\n\n // If no progress tracking needed, just return blob\n if (!options?.onProgress || !response.body) {\n return response.blob();\n }\n\n // Stream with progress tracking\n const contentLength = response.headers.get('content-length');\n const total = contentLength ? parseInt(contentLength, 10) : 0;\n\n const reader = response.body.getReader();\n const chunks: Uint8Array[] = [];\n let loaded = 0;\n\n while (true) {\n const { done, value } = await reader.read();\n\n if (done) break;\n\n chunks.push(value);\n loaded += value.length;\n\n if (total > 0) {\n options.onProgress({\n loaded,\n total,\n percentage: (loaded / total) * 100,\n });\n }\n }\n\n const blob = new Blob(\n chunks.map(\n chunk =>\n chunk.buffer.slice(chunk.byteOffset, chunk.byteOffset + chunk.byteLength) as ArrayBuffer,\n ),\n {\n type: response.headers.get('content-type') ?? 'application/octet-stream',\n },\n );\n\n return blob;\n}\n","/**\n * @fileoverview Client-side storage exports (non-Next.js)\n *\n * This file provides client-side storage functionality for non-Next.js environments.\n * For Next.js applications, use '@od-oneapp/storage/client/next' instead.\n *\n * CLEAN BREAK: Removed legacy wrappers, direct Vercel SDK re-exports only.\n *\n * Features:\n * - File upload utilities\n * - Client-side validation\n * - Key generation utilities\n *\n * @module @od-oneapp/storage/client\n */\n\n// Re-export core Vercel Blob client utilities\n// Import for internal use\nimport { upload as vercelUpload } from '@vercel/blob/client';\n\nexport {\n generateClientTokenFromReadWriteToken,\n handleUpload,\n upload,\n} from '@vercel/blob/client';\n\n// Export client-side validation utilities\nexport {\n formatFileSize,\n parseFileSize,\n validateFileSize,\n validateMimeType,\n validateStorageKey,\n type ValidationOptions,\n} from './validation';\n\n// Export key generation utilities (validateStorageKey is exported from './validation')\nexport {\n generateMultipleKeys,\n generateStorageKey,\n isKeyPattern,\n normalizeStorageKey,\n parseStorageKey,\n sanitizeStorageKey,\n type KeyGenerationOptions,\n type KeyPattern,\n} from '../keys';\n\n// Export client-side utilities for presigned URLs (R2, S3, etc.)\nexport * from './client-utils';\n\n// Type-safe wrapper for Vercel's upload function\nexport async function uploadFile(\n pathname: string,\n file: File | Blob,\n options?: {\n access?: 'public' | 'private';\n addRandomSuffix?: boolean;\n allowOverwrite?: boolean;\n cacheControlMaxAge?: number;\n clientPayload?: string;\n contentType?: string;\n multipart?: boolean;\n onUploadProgress?: (event: { loaded: number; total?: number; percentage?: number }) => void;\n handleUploadUrl?: string;\n },\n): Promise<{ url: string; pathname: string }> {\n const { handleUploadUrl, ...vercelOptions } = options ?? {};\n\n if (handleUploadUrl) {\n // Use handleUpload pattern for server-side processing\n return await vercelUpload(pathname, file, {\n ...vercelOptions,\n access: 'public' as const,\n handleUploadUrl,\n });\n } else {\n // Use direct upload with client token\n return await vercelUpload(pathname, file, {\n ...vercelOptions,\n access: 'public' as const,\n handleUploadUrl: '/api/upload', // Default upload URL\n });\n }\n}\n\n// Export types that are safe for client-side use\nexport type {\n BlobListResponse,\n ClientUploadOptions,\n CloudflareImagesBatchToken,\n CloudflareImagesListOptions,\n CloudflareImagesTransformOptions,\n CloudflareImagesVariant,\n DirectUploadResponse,\n ListOptions,\n PresignedUploadUrl,\n StorageObject,\n UploadOptions,\n UploadProgress,\n VercelBlobOptions,\n} from '../types';\n"],"mappings":";;;;;;;;AAqCA,eAAsB,uBACpB,eACA,MACA,SAGe;CACf,MAAM,WAAW,IAAI,UAAU;AAG/B,KAAI,cAAc,OAChB,QAAO,QAAQ,cAAc,OAAO,CAAC,SAAS,CAAC,KAAK,WAAW;AAC7D,WAAS,OAAO,KAAK,MAAM;GAC3B;AAIJ,UAAS,OAAO,QAAQ,KAAK;AAG7B,KAAI,SAAS,WACX,QAAO,IAAI,SAAS,SAAS,WAAW;EACtC,MAAM,MAAM,IAAI,gBAAgB;AAEhC,MAAI,OAAO,iBAAiB,aAAY,UAAS;AAC/C,OAAI,MAAM,oBAAoB,QAAQ,WACpC,SAAQ,WAAW;IACjB,QAAQ,MAAM;IACd,OAAO,MAAM;IACb,YAAa,MAAM,SAAS,MAAM,QAAS;IAC5C,CAAC;IAEJ;AAEF,MAAI,iBAAiB,cAAc;AACjC,OAAI,IAAI,UAAU,OAAO,IAAI,SAAS,IACpC,UAAS;OAET,wBAAO,IAAI,MAAM,6BAA6B,IAAI,SAAS,CAAC;IAE9D;AAEF,MAAI,iBAAiB,eAAe;AAClC,0BAAO,IAAI,MAAM,gBAAgB,CAAC;IAClC;AAEF,MAAI,KAAK,QAAQ,cAAc,IAAI;AACnC,MAAI,KAAK,SAAS;GAClB;CAIJ,MAAM,WAAW,MAAM,MAAM,cAAc,KAAK;EAC9C,QAAQ;EACR,MAAM;EACP,CAAC;AAEF,KAAI,CAAC,SAAS,GACZ,OAAM,IAAI,MAAM,6BAA6B,SAAS,SAAS;;;;;AAOnE,eAAsB,kBACpB,KACA,MACA,SAIe;AAEf,KAAI,SAAS,WACX,QAAO,IAAI,SAAS,SAAS,WAAW;EACtC,MAAM,MAAM,IAAI,gBAAgB;AAEhC,MAAI,OAAO,iBAAiB,aAAY,UAAS;AAC/C,OAAI,MAAM,oBAAoB,QAAQ,WACpC,SAAQ,WAAW;IACjB,QAAQ,MAAM;IACd,OAAO,MAAM;IACb,YAAa,MAAM,SAAS,MAAM,QAAS;IAC5C,CAAC;IAEJ;AAEF,MAAI,iBAAiB,cAAc;AACjC,OAAI,IAAI,UAAU,OAAO,IAAI,SAAS,IACpC,UAAS;OAET,wBAAO,IAAI,MAAM,6BAA6B,IAAI,SAAS,CAAC;IAE9D;AAEF,MAAI,iBAAiB,eAAe;AAClC,0BAAO,IAAI,MAAM,gBAAgB,CAAC;IAClC;AAEF,MAAI,KAAK,OAAO,IAAI;AAGpB,MAAI,SAAS,QACX,QAAO,QAAQ,QAAQ,QAAQ,CAAC,SAAS,CAAC,KAAK,WAAW;AACxD,OAAI,iBAAiB,KAAK,MAAM;IAChC;AAGJ,MAAI,KAAK,KAAK;GACd;CAIJ,MAAM,WAAW,MAAM,MAAM,KAAK;EAChC,QAAQ;EACR,MAAM;EACN,SAAS,SAAS;EACnB,CAAC;AAEF,KAAI,CAAC,SAAS,GACZ,OAAM,IAAI,MAAM,6BAA6B,SAAS,SAAS;;;;;;AAQnE,IAAa,wBAAb,MAAmC;CACjC,AAAQ;CACR,AAAQ;CACR,AAAQ,QAAqD,EAAE;CAE/D,YAAY,UAAkB,KAAa;AACzC,OAAK,WAAW;AAChB,OAAK,MAAM;;CAGb,MAAM,WACJ,YACA,cACA,MACA,aACe;EAGf,MAAM,WAAW,MAAM,MAAM,cAAc;GACzC,QAAQ;GACR,MAAM;GACP,CAAC;AAEF,MAAI,CAAC,SAAS,GACZ,OAAM,IAAI,MAAM,kCAAkC,SAAS,SAAS;EAGtE,MAAM,OAAO,SAAS,QAAQ,IAAI,OAAO,IAAI;AAC7C,OAAK,MAAM,KAAK;GAAE,YAAY;GAAY,MAAM;GAAM,CAAC;;CAGzD,WAAW;AACT,SAAO,KAAK,MAAM,MAAM,GAAG,MAAM,EAAE,aAAa,EAAE,WAAW;;CAG/D,cAAc;AACZ,SAAO,KAAK;;CAGd,SAAS;AACP,SAAO,KAAK;;;;;;AAOhB,gBAAuB,oBACrB,MACA,YAAoB,IAAI,OAAO,MACkD;CACjF,MAAM,YAAY,KAAK;CACvB,IAAI,aAAa;AAEjB,MAAK,IAAI,QAAQ,GAAG,QAAQ,WAAW,SAAS,WAAW;EACzD,MAAM,MAAM,KAAK,IAAI,QAAQ,WAAW,UAAU;AAGlD,QAAM;GACJ,OAHY,KAAK,MAAM,OAAO,IAAI;GAIlC;GACA;GACA;GACD;AAED;;;;;;AAOJ,eAAsB,gBACpB,KACA,SAGe;CACf,MAAM,WAAW,MAAM,MAAM,IAAI;AAEjC,KAAI,CAAC,SAAS,GACZ,OAAM,IAAI,MAAM,+BAA+B,SAAS,SAAS;AAInE,KAAI,CAAC,SAAS,cAAc,CAAC,SAAS,KACpC,QAAO,SAAS,MAAM;CAIxB,MAAM,gBAAgB,SAAS,QAAQ,IAAI,iBAAiB;CAC5D,MAAM,QAAQ,gBAAgB,SAAS,eAAe,GAAG,GAAG;CAE5D,MAAM,SAAS,SAAS,KAAK,WAAW;CACxC,MAAM,SAAuB,EAAE;CAC/B,IAAI,SAAS;AAEb,QAAO,MAAM;EACX,MAAM,EAAE,MAAM,UAAU,MAAM,OAAO,MAAM;AAE3C,MAAI,KAAM;AAEV,SAAO,KAAK,MAAM;AAClB,YAAU,MAAM;AAEhB,MAAI,QAAQ,EACV,SAAQ,WAAW;GACjB;GACA;GACA,YAAa,SAAS,QAAS;GAChC,CAAC;;AAcN,QAVa,IAAI,KACf,OAAO,KACL,UACE,MAAM,OAAO,MAAM,MAAM,YAAY,MAAM,aAAa,MAAM,WAAW,CAC5E,EACD,EACE,MAAM,SAAS,QAAQ,IAAI,eAAe,IAAI,4BAC/C,CACF;;;;;;;;;;;;;;;;;;;;AC5OH,eAAsB,WACpB,UACA,MACA,SAW4C;CAC5C,MAAM,EAAE,iBAAiB,GAAG,kBAAkB,WAAW,EAAE;AAE3D,KAAI,gBAEF,QAAO,MAAMA,SAAa,UAAU,MAAM;EACxC,GAAG;EACH,QAAQ;EACR;EACD,CAAC;KAGF,QAAO,MAAMA,SAAa,UAAU,MAAM;EACxC,GAAG;EACH,QAAQ;EACR,iBAAiB;EAClB,CAAC"}
@@ -0,0 +1,128 @@
1
+ import { logWarn } from "@od-oneapp/shared/logger";
2
+ import { createEnv } from "@t3-oss/env-core";
3
+ import { z } from "zod/v4";
4
+
5
+ //#region env.ts
6
+ /**
7
+ * @fileoverview env.ts
8
+ */
9
+ /**
10
+ * Helper to parse and validate integer environment variables
11
+ */
12
+ const parsePositiveInteger = (val, fieldName) => {
13
+ const parsed = Number.parseInt(val, 10);
14
+ if (!Number.isFinite(parsed) || !Number.isInteger(parsed) || parsed < 0) throw new Error(`${fieldName} must be a valid positive integer, got: ${val}`);
15
+ return parsed;
16
+ };
17
+ const env = createEnv({
18
+ server: {
19
+ VERCEL_BLOB_READ_WRITE_TOKEN: z.string().min(1).optional(),
20
+ CLOUDFLARE_IMAGES_ACCOUNT_ID: z.string().min(1).optional(),
21
+ CLOUDFLARE_IMAGES_API_TOKEN: z.string().min(1).optional(),
22
+ CLOUDFLARE_IMAGES_DELIVERY_URL: z.string().url().optional(),
23
+ CLOUDFLARE_IMAGES_SIGNING_KEY: z.string().min(1).optional(),
24
+ R2_ACCESS_KEY_ID: z.string().min(1).optional(),
25
+ R2_ACCOUNT_ID: z.string().min(1).optional(),
26
+ R2_BUCKET: z.string().min(1).optional(),
27
+ R2_SECRET_ACCESS_KEY: z.string().min(1).optional(),
28
+ R2_CREDENTIALS: z.string().transform((val) => {
29
+ if (!val) return void 0;
30
+ try {
31
+ return JSON.parse(val);
32
+ } catch {
33
+ return;
34
+ }
35
+ }).pipe(z.array(z.object({
36
+ name: z.string().optional(),
37
+ bucket: z.string(),
38
+ accountId: z.string(),
39
+ accessKeyId: z.string(),
40
+ secretAccessKey: z.string()
41
+ })).optional()).optional(),
42
+ STORAGE_CONFIG: z.string().transform((val) => {
43
+ if (!val) return void 0;
44
+ try {
45
+ return JSON.parse(val);
46
+ } catch {
47
+ return;
48
+ }
49
+ }).optional(),
50
+ STORAGE_LOG_LEVEL: z.enum([
51
+ "info",
52
+ "warn",
53
+ "error"
54
+ ]).default("error"),
55
+ STORAGE_LOG_PERFORMANCE: z.string().default("false").transform((val) => val === "true"),
56
+ STORAGE_LOG_PROVIDER: z.enum([
57
+ "console",
58
+ "sentry",
59
+ "pino"
60
+ ]).default("console"),
61
+ STORAGE_PROVIDER: z.enum([
62
+ "vercel-blob",
63
+ "cloudflare-r2",
64
+ "cloudflare-images",
65
+ "multi"
66
+ ]).optional(),
67
+ STORAGE_MAX_FILE_SIZE: z.string().default("104857600").transform((val) => parsePositiveInteger(val, "STORAGE_MAX_FILE_SIZE")),
68
+ STORAGE_MAX_FILES_PER_UPLOAD: z.string().default("10").transform((val) => parsePositiveInteger(val, "STORAGE_MAX_FILES_PER_UPLOAD")),
69
+ STORAGE_RATE_LIMIT_REQUESTS: z.string().default("100").transform((val) => parsePositiveInteger(val, "STORAGE_RATE_LIMIT_REQUESTS")),
70
+ STORAGE_RATE_LIMIT_WINDOW_MS: z.string().default("60000").transform((val) => parsePositiveInteger(val, "STORAGE_RATE_LIMIT_WINDOW_MS")),
71
+ STORAGE_ENFORCE_AUTH: z.string().default("true").transform((val) => val === "true"),
72
+ STORAGE_ENABLE_RATE_LIMIT: z.string().default("true").transform((val) => val === "true"),
73
+ STORAGE_ENFORCE_CSRF: z.string().default("true").transform((val) => val === "true")
74
+ },
75
+ runtimeEnv: process.env,
76
+ emptyStringAsUndefined: true,
77
+ onValidationError: (error) => {
78
+ logWarn("Storage environment validation failed:", { message: Array.isArray(error) ? error.map((e) => e.message).join(", ") : String(error) });
79
+ }
80
+ });
81
+ /**
82
+ * Provide a storage environment configuration with safe defaults.
83
+ *
84
+ * Returns the validated `env` from createEnv. The fallback code below exists
85
+ * for edge cases where env validation might fail silently, but in practice
86
+ * createEnv always returns a truthy object (even with undefined values).
87
+ *
88
+ * @returns The validated environment configuration
89
+ */
90
+ function safeEnv() {
91
+ return env;
92
+ }
93
+ /**
94
+ * Get environment with fallback defaults for resilience.
95
+ * Use this when you need guaranteed values even if env validation failed.
96
+ *
97
+ * @returns Environment configuration with fallback defaults applied
98
+ */
99
+ function getEnvWithDefaults() {
100
+ return {
101
+ VERCEL_BLOB_READ_WRITE_TOKEN: process.env.VERCEL_BLOB_READ_WRITE_TOKEN ?? "",
102
+ CLOUDFLARE_IMAGES_ACCOUNT_ID: process.env.CLOUDFLARE_IMAGES_ACCOUNT_ID ?? "",
103
+ CLOUDFLARE_IMAGES_API_TOKEN: process.env.CLOUDFLARE_IMAGES_API_TOKEN ?? "",
104
+ CLOUDFLARE_IMAGES_DELIVERY_URL: process.env.CLOUDFLARE_IMAGES_DELIVERY_URL ?? "",
105
+ CLOUDFLARE_IMAGES_SIGNING_KEY: process.env.CLOUDFLARE_IMAGES_SIGNING_KEY ?? "",
106
+ R2_ACCESS_KEY_ID: process.env.R2_ACCESS_KEY_ID ?? "",
107
+ R2_ACCOUNT_ID: process.env.R2_ACCOUNT_ID ?? "",
108
+ R2_BUCKET: process.env.R2_BUCKET ?? "",
109
+ R2_SECRET_ACCESS_KEY: process.env.R2_SECRET_ACCESS_KEY ?? "",
110
+ R2_CREDENTIALS: process.env.R2_CREDENTIALS ?? "",
111
+ STORAGE_CONFIG: process.env.STORAGE_CONFIG ?? "",
112
+ STORAGE_LOG_LEVEL: process.env.STORAGE_LOG_LEVEL ?? "error",
113
+ STORAGE_LOG_PERFORMANCE: process.env.STORAGE_LOG_PERFORMANCE === "true",
114
+ STORAGE_LOG_PROVIDER: process.env.STORAGE_LOG_PROVIDER ?? "console",
115
+ STORAGE_PROVIDER: process.env.STORAGE_PROVIDER ?? "",
116
+ STORAGE_MAX_FILE_SIZE: parsePositiveInteger(process.env.STORAGE_MAX_FILE_SIZE ?? "104857600", "STORAGE_MAX_FILE_SIZE"),
117
+ STORAGE_MAX_FILES_PER_UPLOAD: parsePositiveInteger(process.env.STORAGE_MAX_FILES_PER_UPLOAD ?? "10", "STORAGE_MAX_FILES_PER_UPLOAD"),
118
+ STORAGE_RATE_LIMIT_REQUESTS: parsePositiveInteger(process.env.STORAGE_RATE_LIMIT_REQUESTS ?? "100", "STORAGE_RATE_LIMIT_REQUESTS"),
119
+ STORAGE_RATE_LIMIT_WINDOW_MS: parsePositiveInteger(process.env.STORAGE_RATE_LIMIT_WINDOW_MS ?? "60000", "STORAGE_RATE_LIMIT_WINDOW_MS"),
120
+ STORAGE_ENFORCE_AUTH: process.env.STORAGE_ENFORCE_AUTH !== "false",
121
+ STORAGE_ENABLE_RATE_LIMIT: process.env.STORAGE_ENABLE_RATE_LIMIT !== "false",
122
+ STORAGE_ENFORCE_CSRF: process.env.STORAGE_ENFORCE_CSRF !== "false"
123
+ };
124
+ }
125
+
126
+ //#endregion
127
+ export { getEnvWithDefaults as n, safeEnv as r, env as t };
128
+ //# sourceMappingURL=env-BVHLmQdh.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env-BVHLmQdh.mjs","names":[],"sources":["../env.ts"],"sourcesContent":["/**\n * @fileoverview env.ts\n */\n\nimport { logWarn } from '@repo/shared/logger';\nimport { createEnv } from '@t3-oss/env-core';\nimport { z } from 'zod/v4';\n\n/**\n * Helper to parse and validate integer environment variables\n */\nconst parsePositiveInteger = (val: string, fieldName: string): number => {\n const parsed = Number.parseInt(val, 10);\n if (!Number.isFinite(parsed) || !Number.isInteger(parsed) || parsed < 0) {\n throw new Error(`${fieldName} must be a valid positive integer, got: ${val}`);\n }\n return parsed;\n};\n\nexport const env = createEnv({\n server: {\n // Vercel Blob\n VERCEL_BLOB_READ_WRITE_TOKEN: z.string().min(1).optional(),\n // Cloudflare Images\n CLOUDFLARE_IMAGES_ACCOUNT_ID: z.string().min(1).optional(),\n CLOUDFLARE_IMAGES_API_TOKEN: z.string().min(1).optional(),\n CLOUDFLARE_IMAGES_DELIVERY_URL: z.string().url().optional(),\n CLOUDFLARE_IMAGES_SIGNING_KEY: z.string().min(1).optional(),\n // Cloudflare R2 - Legacy single config\n R2_ACCESS_KEY_ID: z.string().min(1).optional(),\n R2_ACCOUNT_ID: z.string().min(1).optional(),\n R2_BUCKET: z.string().min(1).optional(),\n R2_SECRET_ACCESS_KEY: z.string().min(1).optional(),\n // Multi-R2 config as JSON\n R2_CREDENTIALS: z\n .string()\n .transform(val => {\n if (!val) return undefined;\n try {\n return JSON.parse(val);\n } catch {\n return undefined;\n }\n })\n .pipe(\n z\n .array(\n z.object({\n name: z.string().optional(),\n bucket: z.string(),\n accountId: z.string(),\n accessKeyId: z.string(),\n secretAccessKey: z.string(),\n }),\n )\n .optional(),\n )\n .optional(),\n // Full storage config as JSON\n STORAGE_CONFIG: z\n .string()\n .transform(val => {\n if (!val) return undefined;\n try {\n return JSON.parse(val);\n } catch {\n return undefined;\n }\n })\n .optional(),\n STORAGE_LOG_LEVEL: z.enum(['info', 'warn', 'error']).default('error'),\n STORAGE_LOG_PERFORMANCE: z\n .string()\n .default('false')\n .transform((val: string) => val === 'true'),\n STORAGE_LOG_PROVIDER: z.enum(['console', 'sentry', 'pino']).default('console'),\n STORAGE_PROVIDER: z\n .enum(['vercel-blob', 'cloudflare-r2', 'cloudflare-images', 'multi'])\n .optional(),\n // File size limits (bytes)\n STORAGE_MAX_FILE_SIZE: z\n .string()\n .default('104857600') // 100MB default\n .transform((val: string) => parsePositiveInteger(val, 'STORAGE_MAX_FILE_SIZE')),\n STORAGE_MAX_FILES_PER_UPLOAD: z\n .string()\n .default('10')\n .transform((val: string) => parsePositiveInteger(val, 'STORAGE_MAX_FILES_PER_UPLOAD')),\n // Rate limiting\n STORAGE_RATE_LIMIT_REQUESTS: z\n .string()\n .default('100')\n .transform((val: string) => parsePositiveInteger(val, 'STORAGE_RATE_LIMIT_REQUESTS')),\n STORAGE_RATE_LIMIT_WINDOW_MS: z\n .string()\n .default('60000') // 1 minute\n .transform((val: string) => parsePositiveInteger(val, 'STORAGE_RATE_LIMIT_WINDOW_MS')),\n // Security feature flags (secure-by-default for production)\n STORAGE_ENFORCE_AUTH: z\n .string()\n .default('true')\n .transform((val: string) => val === 'true'),\n STORAGE_ENABLE_RATE_LIMIT: z\n .string()\n .default('true')\n .transform((val: string) => val === 'true'),\n STORAGE_ENFORCE_CSRF: z\n .string()\n .default('true')\n .transform((val: string) => val === 'true'),\n },\n runtimeEnv: process.env,\n emptyStringAsUndefined: true,\n onValidationError: error => {\n const message = Array.isArray(error) ? error.map(e => e.message).join(', ') : String(error);\n logWarn('Storage environment validation failed:', { message });\n // Don't throw in packages - use fallbacks for resilience\n return undefined as never;\n },\n});\n\n/**\n * Provide a storage environment configuration with safe defaults.\n *\n * Returns the validated `env` from createEnv. The fallback code below exists\n * for edge cases where env validation might fail silently, but in practice\n * createEnv always returns a truthy object (even with undefined values).\n *\n * @returns The validated environment configuration\n */\nexport function safeEnv(): typeof env {\n // env from createEnv is always truthy, this is the primary return path\n return env;\n}\n\n/**\n * Get environment with fallback defaults for resilience.\n * Use this when you need guaranteed values even if env validation failed.\n *\n * @returns Environment configuration with fallback defaults applied\n */\nexport function getEnvWithDefaults() {\n return {\n VERCEL_BLOB_READ_WRITE_TOKEN: process.env.VERCEL_BLOB_READ_WRITE_TOKEN ?? '',\n CLOUDFLARE_IMAGES_ACCOUNT_ID: process.env.CLOUDFLARE_IMAGES_ACCOUNT_ID ?? '',\n CLOUDFLARE_IMAGES_API_TOKEN: process.env.CLOUDFLARE_IMAGES_API_TOKEN ?? '',\n CLOUDFLARE_IMAGES_DELIVERY_URL: process.env.CLOUDFLARE_IMAGES_DELIVERY_URL ?? '',\n CLOUDFLARE_IMAGES_SIGNING_KEY: process.env.CLOUDFLARE_IMAGES_SIGNING_KEY ?? '',\n R2_ACCESS_KEY_ID: process.env.R2_ACCESS_KEY_ID ?? '',\n R2_ACCOUNT_ID: process.env.R2_ACCOUNT_ID ?? '',\n R2_BUCKET: process.env.R2_BUCKET ?? '',\n R2_SECRET_ACCESS_KEY: process.env.R2_SECRET_ACCESS_KEY ?? '',\n R2_CREDENTIALS: process.env.R2_CREDENTIALS ?? '',\n STORAGE_CONFIG: process.env.STORAGE_CONFIG ?? '',\n STORAGE_LOG_LEVEL: process.env.STORAGE_LOG_LEVEL ?? 'error',\n STORAGE_LOG_PERFORMANCE: process.env.STORAGE_LOG_PERFORMANCE === 'true',\n STORAGE_LOG_PROVIDER: process.env.STORAGE_LOG_PROVIDER ?? 'console',\n STORAGE_PROVIDER: process.env.STORAGE_PROVIDER ?? '',\n STORAGE_MAX_FILE_SIZE: parsePositiveInteger(\n process.env.STORAGE_MAX_FILE_SIZE ?? '104857600',\n 'STORAGE_MAX_FILE_SIZE',\n ),\n STORAGE_MAX_FILES_PER_UPLOAD: parsePositiveInteger(\n process.env.STORAGE_MAX_FILES_PER_UPLOAD ?? '10',\n 'STORAGE_MAX_FILES_PER_UPLOAD',\n ),\n STORAGE_RATE_LIMIT_REQUESTS: parsePositiveInteger(\n process.env.STORAGE_RATE_LIMIT_REQUESTS ?? '100',\n 'STORAGE_RATE_LIMIT_REQUESTS',\n ),\n STORAGE_RATE_LIMIT_WINDOW_MS: parsePositiveInteger(\n process.env.STORAGE_RATE_LIMIT_WINDOW_MS ?? '60000',\n 'STORAGE_RATE_LIMIT_WINDOW_MS',\n ),\n STORAGE_ENFORCE_AUTH: process.env.STORAGE_ENFORCE_AUTH !== 'false',\n STORAGE_ENABLE_RATE_LIMIT: process.env.STORAGE_ENABLE_RATE_LIMIT !== 'false',\n STORAGE_ENFORCE_CSRF: process.env.STORAGE_ENFORCE_CSRF !== 'false',\n };\n}\n\n// Export type for better DX\nexport type Env = typeof env;\n"],"mappings":"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"}
package/dist/env.mjs ADDED
@@ -0,0 +1,3 @@
1
+ import { n as getEnvWithDefaults, r as safeEnv, t as env } from "./env-BVHLmQdh.mjs";
2
+
3
+ export { env, getEnvWithDefaults, safeEnv };