@od-oneapp/storage 2026.2.2001-canary.1 → 2026.2.2301-canary

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/client-next.d.mts CHANGED
@@ -1,7 +1,8 @@
1
1
  import { KeyGenerationOptions, KeyPattern, generateMultipleKeys, generateStorageKey, isKeyPattern, normalizeStorageKey, parseStorageKey, sanitizeStorageKey, validateStorageKey } from "./keys.mjs";
2
2
  import { ValidationOptions, formatFileSize, parseFileSize, validateFileSize, validateMimeType } from "./validation.mjs";
3
3
  import { BlobListResponse, ClientUploadOptions, CloudflareImagesBatchToken, CloudflareImagesListOptions, CloudflareImagesTransformOptions, CloudflareImagesVariant, DirectUploadResponse, ListOptions, PresignedUploadUrl, StorageObject, UploadOptions, UploadProgress, VercelBlobOptions } from "./types.mjs";
4
- import { ClientMultipartUpload, ClientPresignedUploadUrl, ClientUploadProgress, downloadFromUrl, generateClientTokenFromReadWriteToken, handleUpload, splitFileIntoChunks, upload, uploadDirectToUrl, uploadFile, uploadWithPresignedUrl } from "./client.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";
5
6
 
6
7
  //#region src/client-next.d.ts
7
8
  declare function uploadFileWithProgress(pathname: string, file: File | Blob, options?: {
@@ -1 +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"}
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,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"}
package/client.d.mts CHANGED
@@ -1,47 +1,9 @@
1
1
  import { KeyGenerationOptions, KeyPattern, generateMultipleKeys, generateStorageKey, isKeyPattern, normalizeStorageKey, parseStorageKey, sanitizeStorageKey, validateStorageKey } from "./keys.mjs";
2
2
  import { ValidationOptions, formatFileSize, parseFileSize, validateFileSize, validateMimeType } from "./validation.mjs";
3
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";
4
5
  import { generateClientTokenFromReadWriteToken, handleUpload, upload } from "@vercel/blob/client";
5
6
 
6
- //#region src/client-utils.d.ts
7
- interface ClientPresignedUploadUrl extends PresignedUploadUrl {
8
- key: string;
9
- }
10
- interface ClientUploadProgress {
11
- loaded: number;
12
- total: number;
13
- percentage: number;
14
- }
15
- declare function uploadWithPresignedUrl(presignedData: ClientPresignedUploadUrl, file: File | Blob, options?: {
16
- onProgress?: (progress: ClientUploadProgress) => void;
17
- }): Promise<void>;
18
- declare function uploadDirectToUrl(url: string, file: File | Blob, options?: {
19
- headers?: Record<string, string>;
20
- onProgress?: (progress: ClientUploadProgress) => void;
21
- }): Promise<void>;
22
- declare class ClientMultipartUpload {
23
- private uploadId;
24
- private key;
25
- private parts;
26
- constructor(uploadId: string, key: string);
27
- uploadPart(partNumber: number, presignedUrl: string, data: Blob, _onProgress?: (progress: ClientUploadProgress) => void): Promise<void>;
28
- getParts(): {
29
- PartNumber: number;
30
- ETag: string;
31
- }[];
32
- getUploadId(): string;
33
- getKey(): string;
34
- }
35
- declare function splitFileIntoChunks(file: File | Blob, chunkSize?: number): AsyncGenerator<{
36
- chunk: Blob;
37
- partNumber: number;
38
- start: number;
39
- end: number;
40
- }>;
41
- declare function downloadFromUrl(url: string, options?: {
42
- onProgress?: (progress: ClientUploadProgress) => void;
43
- }): Promise<Blob>;
44
- //#endregion
45
7
  //#region src/client.d.ts
46
8
  declare function uploadFile(pathname: string, file: File | Blob, options?: {
47
9
  access?: 'public' | 'private';
package/client.d.mts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.mts","names":[],"sources":["../src/client-utils.ts","../src/client.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;;;iBC/LW,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"}
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"}
@@ -35,14 +35,14 @@ const getRuntimeInfo = () => {
35
35
  type: "edge",
36
36
  variant: "cloudflare"
37
37
  };
38
- if (typeof process !== "undefined" && process.versions?.bun) return {
39
- type: "bun",
40
- version: process.versions.bun
41
- };
42
38
  if (typeof globalThis !== "undefined" && "window" in globalThis && typeof globalThis.window !== "undefined" && typeof globalThis.window.document !== "undefined" && typeof globalThis.window.navigator !== "undefined") return {
43
39
  type: "browser",
44
40
  isNextJs: Boolean(globalThis.window.__NEXT_DATA__)
45
41
  };
42
+ if (typeof process !== "undefined" && process.versions?.bun) return {
43
+ type: "bun",
44
+ version: process.versions.bun
45
+ };
46
46
  if (typeof process !== "undefined" && process.versions?.node) {
47
47
  const nodeVersion = parseInt(process.versions.node.split(".")[0] ?? "0");
48
48
  const nodeVersionMinor = parseInt(process.versions.node.split(".")[1] ?? "0");
@@ -216,5 +216,5 @@ function getEnvWithDefaults() {
216
216
  }
217
217
 
218
218
  //#endregion
219
- export { getEnvWithDefaults as n, safeEnv as r, env as t };
220
- //# sourceMappingURL=env-BRxsA_k1.mjs.map
219
+ export { logWarn as a, logError as i, getEnvWithDefaults as n, safeEnv as r, env as t };
220
+ //# sourceMappingURL=env-d2CieWaM.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env-d2CieWaM.mjs","names":[],"sources":["../../shared/src/logger/core.ts","../env.ts"],"sourcesContent":["/**\n * @fileoverview Canonical logger for the OneApp platform.\n *\n * This module provides isomorphic logging functions that work in any environment\n * (Browser, Node.js, Edge). Logs directly to console with runtime information.\n *\n * Preferred usage is to import from '@od-oneapp/shared/logger'.\n */\n\n/**\n * Get runtime environment information.\n *\n * Detects the current runtime environment (browser, Node.js, edge, Bun) and returns\n * detailed information about the environment type, version, and capabilities.\n *\n * @returns Runtime information object with type, version, and environment-specific details\n *\n * @example\n * ```typescript\n * const runtime = getRuntimeInfo();\n * // Returns: { type: 'node', version: '22.0.0', major: 22, minor: 0, isNode22Plus: true, isNextJs: true }\n * // or: { type: 'browser', isNextJs: true }\n * // or: { type: 'edge', variant: 'vercel' }\n * ```\n */\nexport const getRuntimeInfo = () => {\n // 1. Edge runtime detection (Vercel Edge, Cloudflare Workers)\n // Check these before browser because they might have a partial window mock\n if (typeof globalThis !== 'undefined' && (globalThis as any).EdgeRuntime) {\n return { type: 'edge', variant: 'vercel' };\n }\n if (\n typeof globalThis !== 'undefined' &&\n (globalThis as any).caches &&\n typeof (globalThis as any).caches !== 'undefined'\n ) {\n return { type: 'edge', variant: 'cloudflare' };\n }\n\n // 2. Browser detection\n if (\n typeof globalThis !== 'undefined' &&\n 'window' in globalThis &&\n typeof (globalThis as any).window !== 'undefined' &&\n typeof (globalThis as any).window.document !== 'undefined' &&\n typeof (globalThis as any).window.navigator !== 'undefined'\n ) {\n return { type: 'browser', isNextJs: Boolean((globalThis as any).window.__NEXT_DATA__) };\n }\n\n // 3. Bun detection\n if (typeof process !== 'undefined' && (process as any).versions?.bun) {\n return { type: 'bun', version: (process as any).versions.bun };\n }\n\n // 4. Node.js detection with version check\n if (typeof process !== 'undefined' && process.versions?.node) {\n const nodeVersion = parseInt(process.versions.node.split('.')[0] ?? '0');\n const nodeVersionMinor = parseInt(process.versions.node.split('.')[1] ?? '0');\n\n if (nodeVersion < 22) {\n // Note: Using console.warn here as observability system may not be initialized yet\n // eslint-disable-next-line no-console\n console.warn(\n `[Observability] Node ${process.versions.node} detected. Node 22+ is required for optimal performance and latest features.`,\n );\n }\n\n return {\n type: 'node',\n version: process.versions.node,\n major: nodeVersion,\n minor: nodeVersionMinor,\n isNode22Plus: nodeVersion >= 22,\n isNextJs:\n Boolean(process.env.NEXT_RUNTIME) ||\n Boolean(process.env.__NEXT_RUNTIME) ||\n Boolean(process.env.NEXT_PUBLIC_VERCEL_ENV),\n };\n }\n\n // Fallback\n return { type: 'unknown' };\n};\n\n// Cache the runtime info\nconst runtimeInfo = getRuntimeInfo();\n\n/**\n * Get cached runtime environment information.\n *\n * Returns the runtime information that was detected at module load time.\n * This is cached to avoid repeated detection checks.\n *\n * @returns Cached runtime information object\n */\nexport const getRuntimeEnvironment = () => runtimeInfo;\n\n/**\n * Detect if code is running in a browser environment\n * Extracted to shared utility to avoid duplication\n * @returns true if running in browser, false otherwise\n */\nexport function isBrowser(): boolean {\n return (\n typeof globalThis !== 'undefined' &&\n 'window' in globalThis &&\n typeof (globalThis as any).window !== 'undefined' &&\n typeof (globalThis as any).window.document !== 'undefined' &&\n typeof (globalThis as any).window.navigator !== 'undefined'\n );\n}\n\n/**\n * Determine if console logging should be enabled based on environment\n * Centralized logic to avoid duplication across entry points\n * @param envNodeEnv - The NEXT_PUBLIC_NODE_ENV value\n * @param consoleEnabled - The NEXT_PUBLIC_OBSERVABILITY_CONSOLE_ENABLED value (explicit control)\n * @param debugEnabled - The NEXT_PUBLIC_OBSERVABILITY_DEBUG value\n * @returns boolean indicating if console should be enabled\n */\nexport function shouldEnableConsole(\n envNodeEnv?: string,\n consoleEnabled?: boolean,\n debugEnabled?: boolean,\n): boolean {\n const isDevelopment = envNodeEnv === 'development' || process.env.NODE_ENV === 'development';\n\n // Priority: explicit control > development mode > debug mode\n if (consoleEnabled !== undefined) {\n return consoleEnabled;\n }\n if (isDevelopment) {\n return true;\n }\n return debugEnabled ?? false;\n}\n\n/**\n * Create a generic log function factory.\n *\n * Factory function that creates log functions for different levels (debug, info, warn, error).\n * Logs directly to console with runtime information.\n */\nconst createLogFunction = (level: 'debug' | 'info' | 'warn' | 'error') => {\n return (message: string | Error, context?: any): void => {\n if (message instanceof Error) {\n // For Error objects, log the error itself (console.error will show stack trace)\n // and include context as additional arguments\n if (context) {\n // eslint-disable-next-line no-console\n (console[level] as any)(`[${runtimeInfo.type}]`, message, context);\n } else {\n // eslint-disable-next-line no-console\n (console[level] as any)(`[${runtimeInfo.type}]`, message);\n }\n } else {\n // For string messages, format with context\n const contextStr = context ? JSON.stringify(context) : '';\n const logMessage = contextStr ? `${message} ${contextStr}` : message;\n // eslint-disable-next-line no-console\n (console[level] as any)(`[${runtimeInfo.type}]`, logMessage);\n }\n };\n};\n\n/**\n * Log a debug message (isomorphic - works in any environment).\n */\nexport const logDebug = createLogFunction('debug');\n\n/**\n * Log an info message (isomorphic - works in any environment).\n */\nexport const logInfo = createLogFunction('info');\n\n/**\n * Log a warning message (isomorphic - works in any environment).\n */\nexport const logWarn = createLogFunction('warn');\n\n/**\n * Log an error message (isomorphic - works in any environment).\n */\nexport const logError = createLogFunction('error');\n","/**\n * @fileoverview env.ts\n */\n\nimport { logWarn } from '@od-oneapp/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/env.mjs CHANGED
@@ -1,3 +1,3 @@
1
- import { n as getEnvWithDefaults, r as safeEnv, t as env } from "./env-BRxsA_k1.mjs";
1
+ import { n as getEnvWithDefaults, r as safeEnv, t as env } from "./env-d2CieWaM.mjs";
2
2
 
3
3
  export { env, getEnvWithDefaults, safeEnv };
@@ -1,117 +1,8 @@
1
+ import { a as logWarn } from "./env-d2CieWaM.mjs";
1
2
  import { t as VercelBlobProvider } from "./vercel-blob-DrfolJEu.mjs";
2
3
  import { CloudflareImagesProvider } from "@od-oneapp/integration-cloudflare/storage-provider/images";
3
4
  import { CloudflareR2Provider } from "@od-oneapp/integration-cloudflare/storage-provider/r2";
4
5
 
5
- //#region ../shared/src/logs.tsx
6
- /**
7
- * @fileoverview Canonical logger for the OneApp platform.
8
- *
9
- * This module provides isomorphic logging functions that work in any environment
10
- * (Browser, Node.js, Edge). Logs directly to console with runtime information.
11
- *
12
- * Preferred usage is to import from '@od-oneapp/shared/logs'.
13
- */
14
- /**
15
- * Get runtime environment information.
16
- *
17
- * Detects the current runtime environment (browser, Node.js, edge, Bun) and returns
18
- * detailed information about the environment type, version, and capabilities.
19
- *
20
- * @returns Runtime information object with type, version, and environment-specific details
21
- *
22
- * @example
23
- * ```typescript
24
- * const runtime = getRuntimeInfo();
25
- * // Returns: { type: 'node', version: '22.0.0', major: 22, minor: 0, isNode22Plus: true, isNextJs: true }
26
- * // or: { type: 'browser', isNextJs: true }
27
- * // or: { type: 'edge', variant: 'vercel' }
28
- * ```
29
- */
30
- const getRuntimeInfo = () => {
31
- if (typeof globalThis !== "undefined" && globalThis.EdgeRuntime) return {
32
- type: "edge",
33
- variant: "vercel"
34
- };
35
- if (typeof globalThis !== "undefined" && globalThis.caches && typeof globalThis.caches !== "undefined") return {
36
- type: "edge",
37
- variant: "cloudflare"
38
- };
39
- try {
40
- const versions = globalThis.process?.versions;
41
- if (versions?.bun) return {
42
- type: "bun",
43
- version: versions.bun
44
- };
45
- if (versions?.node) {
46
- const nodeVersion = parseInt(versions.node.split(".")[0] ?? "0");
47
- const nodeVersionMinor = parseInt(versions.node.split(".")[1] ?? "0");
48
- if (nodeVersion < 22) console.warn(`[Observability] Node ${versions.node} detected. Node 22+ is required for optimal performance and latest features.`);
49
- const env = globalThis.process?.env;
50
- return {
51
- type: "node",
52
- version: versions.node,
53
- major: nodeVersion,
54
- minor: nodeVersionMinor,
55
- isNode22Plus: nodeVersion >= 22,
56
- isNextJs: Boolean(env?.NEXT_RUNTIME) || Boolean(env?.__NEXT_RUNTIME) || Boolean(env?.NEXT_PUBLIC_VERCEL_ENV)
57
- };
58
- }
59
- } catch {}
60
- if (typeof globalThis !== "undefined" && "window" in globalThis && typeof globalThis.window !== "undefined" && typeof globalThis.window?.document !== "undefined" && typeof globalThis.window?.navigator !== "undefined") return {
61
- type: "browser",
62
- isNextJs: Boolean(globalThis.window?.__NEXT_DATA__)
63
- };
64
- return { type: "unknown" };
65
- };
66
- const runtimeInfo = getRuntimeInfo();
67
- /**
68
- * Create a generic log function factory.
69
- *
70
- * Factory function that creates log functions for different levels (debug, info, warn, error).
71
- * Logs directly to console with runtime information.
72
- */
73
- const createLogFunction = (level) => {
74
- return (message, context) => {
75
- let actualContext;
76
- let errorObj;
77
- if (context instanceof Error) errorObj = context;
78
- else actualContext = context;
79
- if (message instanceof Error) {
80
- const combinedContext = {
81
- ...actualContext,
82
- ...errorObj ? { secondaryError: errorObj.message } : {}
83
- };
84
- const consoleMethod = console[level];
85
- if (Object.keys(combinedContext).length > 0) consoleMethod(`[${runtimeInfo.type}]`, message, combinedContext);
86
- else consoleMethod(`[${runtimeInfo.type}]`, message);
87
- } else {
88
- const finalError = errorObj;
89
- const contextStr = actualContext ? JSON.stringify(actualContext) : "";
90
- const logMessage = contextStr ? `${message} ${contextStr}` : message;
91
- const consoleMethod = console[level];
92
- if (finalError) consoleMethod(`[${runtimeInfo.type}]`, logMessage, finalError);
93
- else consoleMethod(`[${runtimeInfo.type}]`, logMessage);
94
- }
95
- };
96
- };
97
- /**
98
- * Log a debug message (isomorphic - works in any environment).
99
- */
100
- const logDebug = createLogFunction("debug");
101
- /**
102
- * Log an info message (isomorphic - works in any environment).
103
- */
104
- const logInfo = createLogFunction("info");
105
- /**
106
- * Log a warning message (isomorphic - works in any environment).
107
- */
108
- const logWarn = createLogFunction("warn");
109
- /**
110
- * Log an error message (isomorphic - works in any environment).
111
- */
112
- const logError = createLogFunction("error");
113
-
114
- //#endregion
115
6
  //#region providers/cloudflare-images.ts
116
7
  /**
117
8
  * @fileoverview Cloudflare Images storage provider
@@ -828,5 +719,5 @@ async function storageHealthCheck(provider) {
828
719
  }
829
720
 
830
721
  //#endregion
831
- export { logWarn as S, DEFAULT_STORAGE_CAPABILITIES as _, getBestProvider as a, CloudflareImagesProvider$1 as b, hasAllCapabilities as c, validateProviderCapabilities as d, MultipartUploadManager as f, MultiStorageManager as g, hasMultipartSupport as h, describeProviderCapabilities as i, hasAnyCapability as l, getOptimalPartSize as m, storageHealthCheck as n, getCapabilityMatrix as o, createMultipartUploadManager as p, checkProviderSuitability as r, getProviderCapabilities as s, checkProviderHealth as t, hasCapability as u, STORAGE_CONSTANTS as v, logError as x, CloudflareR2Provider$1 as y };
832
- //# sourceMappingURL=health-check-ekerANJG.mjs.map
722
+ export { DEFAULT_STORAGE_CAPABILITIES as _, getBestProvider as a, CloudflareImagesProvider$1 as b, hasAllCapabilities as c, validateProviderCapabilities as d, MultipartUploadManager as f, MultiStorageManager as g, hasMultipartSupport as h, describeProviderCapabilities as i, hasAnyCapability as l, getOptimalPartSize as m, storageHealthCheck as n, getCapabilityMatrix as o, createMultipartUploadManager as p, checkProviderSuitability as r, getProviderCapabilities as s, checkProviderHealth as t, hasCapability as u, STORAGE_CONSTANTS as v, CloudflareR2Provider$1 as y };
723
+ //# sourceMappingURL=health-check-Dij2-CYd.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"health-check-Dij2-CYd.mjs","names":["CloudflareImagesProvider","CloudflareImagesProviderInternal","CloudflareR2Provider","CloudflareR2ProviderInternal","CloudflareR2Provider","CloudflareImagesProvider"],"sources":["../providers/cloudflare-images.ts","../providers/cloudflare-r2.ts","../src/constants.ts","../src/multi-storage.ts","../src/multipart.ts","../src/capabilities.ts","../src/health-check.ts"],"sourcesContent":["/**\n * @fileoverview Cloudflare Images storage provider\n *\n * Static import from the monorepo integration package.\n * The integration code is bundled into the published package by tsdown.\n */\n\nimport { CloudflareImagesProvider as CloudflareImagesProviderInternal } from '@od-oneapp/integration-cloudflare/storage-provider/images';\n\nimport type { StorageProvider } from '../types';\n\nexport const CloudflareImagesProvider: new (...args: unknown[]) => StorageProvider =\n CloudflareImagesProviderInternal as unknown as new (...args: unknown[]) => StorageProvider;\n","/**\n * @fileoverview Cloudflare R2 storage provider\n *\n * Static import from the monorepo integration package.\n * The integration code is bundled into the published package by tsdown.\n */\n\nimport { CloudflareR2Provider as CloudflareR2ProviderInternal } from '@od-oneapp/integration-cloudflare/storage-provider/r2';\n\nimport type { StorageProvider } from '../types';\n\nexport const CloudflareR2Provider: new (...args: unknown[]) => StorageProvider =\n CloudflareR2ProviderInternal as unknown as new (...args: unknown[]) => StorageProvider;\n","/**\n * @fileoverview Storage Package Constants\n *\n * Centralized constants for storage operations to avoid magic numbers\n * and improve maintainability.\n *\n * Includes:\n * - URL expiration times\n * - File size limits\n * - Multipart upload thresholds\n * - Retry configuration\n * - Rate limiting settings\n *\n * @module @repo/storage/constants\n */\n\nexport const STORAGE_CONSTANTS = {\n // URL Expiration Times (seconds)\n DEFAULT_URL_EXPIRY_SECONDS: 3600, // 1 hour\n PRODUCT_URL_EXPIRY_SECONDS: 3600, // 1 hour for product photos\n UPLOAD_URL_EXPIRY_SECONDS: 1800, // 30 minutes for uploads\n ADMIN_URL_EXPIRY_SECONDS: 7200, // 2 hours for admin operations\n\n // File Size Limits (bytes)\n MULTIPART_THRESHOLD_BYTES: 100 * 1024 * 1024, // 100MB - use multipart above this\n DEFAULT_PART_SIZE_BYTES: 5 * 1024 * 1024, // 5MB default part size\n DEFAULT_MAX_PART_SIZE_BYTES: 25 * 1024 * 1024, // 25MB max part size\n DEFAULT_QUEUE_SIZE: 4, // Concurrent upload parts\n\n // Batch Operations\n DEFAULT_BATCH_SIZE: 5, // Process 5 items concurrently\n MAX_BATCH_SIZE: 50, // Maximum batch size\n\n // Timeouts (milliseconds)\n DEFAULT_REQUEST_TIMEOUT_MS: 30000, // 30 seconds\n DEFAULT_UPLOAD_TIMEOUT_MS: 300000, // 5 minutes for uploads\n DEFAULT_DOWNLOAD_TIMEOUT_MS: 60000, // 1 minute for downloads\n\n // Retry Configuration\n DEFAULT_MAX_RETRIES: 3,\n RETRY_BASE_DELAY_MS: 1000, // 1 second base delay\n\n // Key Validation\n MAX_KEY_LENGTH: 1024,\n MAX_FILENAME_LENGTH: 255,\n\n // Rate Limiting (requests per window)\n DEFAULT_RATE_LIMIT_REQUESTS: 100,\n DEFAULT_RATE_LIMIT_WINDOW_MS: 60 * 1000, // 1 minute\n\n // Health Check\n HEALTH_CHECK_KEY: '__health_check__',\n} as const;\n\n/**\n * File size thresholds for multipart upload decisions\n */\nexport const MULTIPART_THRESHOLDS = {\n SMALL_FILE: 100 * 1024 * 1024, // < 100MB - use simple upload\n MEDIUM_FILE: 1024 * 1024 * 1024, // < 1GB - use 10MB parts\n LARGE_FILE: Infinity, // >= 1GB - use 25MB parts\n} as const;\n\n/**\n * Part sizes based on file size\n */\nexport const PART_SIZES = {\n SMALL: 5 * 1024 * 1024, // 5MB for files < 100MB\n MEDIUM: 10 * 1024 * 1024, // 10MB for files < 1GB\n LARGE: 25 * 1024 * 1024, // 25MB for files >= 1GB\n} as const;\n\n/**\n * Default storage capabilities for providers that don't implement getCapabilities()\n * Single source of truth for capability defaults\n */\nexport const DEFAULT_STORAGE_CAPABILITIES = {\n multipart: false,\n presignedUrls: false,\n progressTracking: false,\n abortSignal: false,\n metadata: false,\n customDomains: false,\n edgeCompatible: false,\n versioning: false,\n encryption: false,\n directoryListing: false,\n} as const;\n","/**\n * @fileoverview Multi-storage provider manager\n *\n * Manages multiple storage providers with routing and fallback capabilities.\n * Allows using different providers for different use cases or as backups.\n *\n * Features:\n * - Provider routing based on key patterns\n * - Fallback to default provider\n * - Unified API across multiple providers\n *\n * @module @repo/storage/multi-storage\n */\n\nimport { CloudflareImagesProvider } from '../providers/cloudflare-images';\nimport { CloudflareR2Provider } from '../providers/cloudflare-r2';\nimport { VercelBlobProvider } from '../providers/vercel-blob';\nimport {\n type ListOptions,\n type MultiStorageConfig,\n type StorageConfig,\n type StorageObject,\n type StorageProvider,\n type UploadOptions,\n} from '../types';\n\nexport class MultiStorageManager {\n private providers: Map<string, StorageProvider> = new Map();\n private defaultProvider: string;\n private routing: MultiStorageConfig['routing'];\n\n constructor(config: MultiStorageConfig) {\n // Initialize all providers\n for (const [name, providerConfig] of Object.entries(config.providers)) {\n this.providers.set(name, this.createProvider(providerConfig));\n }\n\n // Set default provider\n const firstProvider = Object.keys(config.providers)[0];\n this.defaultProvider = config.defaultProvider ?? firstProvider ?? '';\n if (!this.defaultProvider) {\n throw new Error('No storage providers configured');\n }\n\n this.routing = config.routing;\n }\n\n private createProvider(config: StorageConfig): StorageProvider {\n switch (config.provider) {\n case 'multi':\n throw new Error('Multi provider cannot be nested');\n\n case 'cloudflare-r2':\n if (!config.cloudflareR2) {\n throw new Error('Cloudflare R2 configuration is required');\n }\n // Handle array of R2 configs\n if (Array.isArray(config.cloudflareR2)) {\n if (config.cloudflareR2.length === 0) {\n throw new Error('No R2 configurations provided');\n }\n const firstR2Config = config.cloudflareR2[0];\n if (!firstR2Config) {\n throw new Error('First R2 configuration is undefined');\n }\n // Use first one for single provider (backward compatibility)\n return new CloudflareR2Provider(firstR2Config);\n }\n return new CloudflareR2Provider(config.cloudflareR2);\n\n case 'cloudflare-images':\n if (!config.cloudflareImages) {\n throw new Error('Cloudflare Images configuration is required');\n }\n return new CloudflareImagesProvider(config.cloudflareImages);\n\n case 'vercel-blob':\n if (!config.vercelBlob?.token) {\n throw new Error('Vercel Blob token is required');\n }\n return new VercelBlobProvider(config.vercelBlob.token);\n\n default:\n throw new Error(`Unknown storage provider: ${config.provider}`);\n }\n }\n\n private getProviderForKey(key: string): { provider: StorageProvider; providerName: string } {\n // Check routing rules\n if (this.routing) {\n // Check file type routing\n const extension = key.split('.').pop()?.toLowerCase();\n\n // Image routing\n if (this.routing.images && this.isImageFile(extension)) {\n const provider = this.providers.get(this.routing.images);\n if (provider) {\n return { provider, providerName: this.routing.images };\n }\n }\n\n // Document routing\n if (this.routing.documents && this.isDocumentFile(extension)) {\n const provider = this.providers.get(this.routing.documents);\n if (provider) {\n return { provider, providerName: this.routing.documents };\n }\n }\n\n // Custom routing rules\n for (const [pattern, providerName] of Object.entries(this.routing)) {\n if (pattern !== 'images' && pattern !== 'documents' && providerName) {\n // Simple pattern matching (could be enhanced with regex)\n if (key.includes(pattern)) {\n const provider = this.providers.get(providerName);\n if (provider) {\n return { provider, providerName };\n }\n }\n }\n }\n }\n\n // Fall back to default provider\n const provider = this.providers.get(this.defaultProvider);\n if (!provider) {\n throw new Error(`Default provider '${this.defaultProvider}' not found`);\n }\n\n return { provider, providerName: this.defaultProvider };\n }\n\n private isImageFile(extension?: string): boolean {\n const imageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'avif', 'svg', 'ico'];\n return extension ? imageExtensions.includes(extension) : false;\n }\n\n private isDocumentFile(extension?: string): boolean {\n const documentExtensions = ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt', 'csv'];\n return extension ? documentExtensions.includes(extension) : false;\n }\n\n // Get a specific provider by name\n getProvider(name: string): StorageProvider | undefined {\n return this.providers.get(name);\n }\n\n // Storage operations that route to appropriate provider\n async delete(key: string): Promise<void> {\n const { provider } = this.getProviderForKey(key);\n return provider.delete(key);\n }\n\n async download(key: string): Promise<Blob> {\n const { provider } = this.getProviderForKey(key);\n return provider.download(key);\n }\n\n async exists(key: string): Promise<boolean> {\n const { provider } = this.getProviderForKey(key);\n return provider.exists(key);\n }\n\n async getMetadata(key: string): Promise<StorageObject> {\n const { provider } = this.getProviderForKey(key);\n return provider.getMetadata(key);\n }\n\n async getUrl(key: string, options?: { expiresIn?: number }): Promise<string> {\n const { provider } = this.getProviderForKey(key);\n return provider.getUrl(key, options);\n }\n\n async list(options?: ListOptions & { provider?: string }): Promise<StorageObject[]> {\n // If specific provider requested, use it\n if (options?.provider) {\n const provider = this.providers.get(options.provider);\n if (!provider) {\n throw new Error(`Provider '${options.provider}' not found`);\n }\n return provider.list(options);\n }\n\n // Otherwise, list from all providers\n const allResults: StorageObject[] = [];\n for (const provider of this.providers.values()) {\n const results = await provider.list(options);\n allResults.push(...results);\n }\n return allResults;\n }\n\n async upload(\n key: string,\n data: ArrayBuffer | Blob | Buffer | File | ReadableStream,\n options?: UploadOptions & { provider?: string },\n ): Promise<StorageObject> {\n let provider: StorageProvider;\n\n // If specific provider requested, use it\n if (options?.provider) {\n const requestedProvider = this.providers.get(options.provider);\n if (!requestedProvider) {\n throw new Error(`Provider '${options.provider}' not found`);\n }\n provider = requestedProvider;\n } else {\n // Otherwise, use routing logic\n const { provider: routedProvider } = this.getProviderForKey(key);\n provider = routedProvider;\n }\n\n return provider.upload(key, data, options);\n }\n\n // Extended methods for Cloudflare Images\n async getCloudflareImagesProvider(): Promise<InstanceType<typeof CloudflareImagesProvider> | undefined> {\n for (const provider of this.providers.values()) {\n if (provider instanceof CloudflareImagesProvider) {\n return provider;\n }\n }\n return undefined;\n }\n\n // Get all provider names\n getProviderNames(): string[] {\n return Array.from(this.providers.keys());\n }\n}\n","/**\n * @fileoverview Unified Multipart Upload Manager\n *\n * Provides a consistent interface for multipart uploads across all storage providers.\n * Handles provider-specific differences and provides retry logic, progress tracking,\n * and error recovery.\n *\n * Features:\n * - Automatic part size calculation\n * - Concurrent part uploads\n * - Progress tracking\n * - Resume support\n * - Error recovery\n *\n * @module @repo/storage/multipart\n */\n\nimport { logWarn } from '@od-oneapp/shared/logs';\n\nimport {\n type MultipartUploadResult as BaseMultipartUploadResult,\n type MultipartUploadOptions,\n type StorageProvider,\n type UploadOptions,\n type UploadProgress,\n} from '../types';\n\nimport { MULTIPART_THRESHOLDS, PART_SIZES, STORAGE_CONSTANTS } from './constants';\n\nexport interface MultipartUploadState {\n uploadId: string;\n key: string;\n provider: string;\n parts: Array<{\n partNumber: number;\n etag?: string;\n size: number;\n uploaded: boolean;\n }>;\n totalSize: number;\n uploadedSize: number;\n completed: boolean;\n aborted: boolean;\n error?: string;\n}\n\n/**\n * Extended multipart upload result with detailed part information\n * Extends the base MultipartUploadResult from types.ts\n */\nexport interface MultipartUploadResult extends BaseMultipartUploadResult {\n parts: Array<{ partNumber: number; etag: string; size: number }>;\n totalParts: number;\n}\n\nexport class MultipartUploadManager {\n private provider: StorageProvider;\n private state: MultipartUploadState | null = null;\n private abortController: AbortController | null = null;\n\n constructor(provider: StorageProvider) {\n this.provider = provider;\n }\n\n /**\n * Check if provider supports multipart uploads\n */\n supportsMultipart(): boolean {\n const capabilities = this.provider.getCapabilities?.();\n return capabilities?.multipart ?? false;\n }\n\n /**\n * Create a new multipart upload\n *\n * @param key - Storage key\n * @param totalSize - Total file size in bytes\n * @param options - Upload options\n * @returns Upload state\n */\n async createUpload(\n key: string,\n totalSize: number,\n options: MultipartUploadOptions = {},\n ): Promise<MultipartUploadState> {\n if (!this.supportsMultipart()) {\n throw new Error('Provider does not support multipart uploads');\n }\n\n if (this.state && !this.state.completed && !this.state.aborted) {\n throw new Error('Upload already in progress. Abort current upload first.');\n }\n\n // Calculate optimal part size\n const partSize = this.calculatePartSize(totalSize, options.partSize);\n const totalParts = Math.ceil(totalSize / partSize);\n\n // Create multipart upload\n const uploadOptions: UploadOptions = {\n onProgress: options.onProgress\n ? (progress: UploadProgress) => {\n options.onProgress?.({\n key: progress.key,\n loaded: progress.loaded,\n total: progress.total,\n part: progress.part ?? 0,\n percentage: progress.percentage ?? 0,\n });\n }\n : undefined,\n };\n const result = await this.provider.createMultipartUpload?.(key, uploadOptions);\n\n if (!result) {\n throw new Error('Failed to create multipart upload');\n }\n\n // Initialize state\n this.state = {\n uploadId: result.uploadId,\n key: result.key,\n provider: this.getProviderName(),\n parts: Array.from({ length: totalParts }, (_, i) => ({\n partNumber: i + 1,\n size: i === totalParts - 1 ? totalSize - i * partSize : partSize,\n uploaded: false,\n })),\n totalSize,\n uploadedSize: 0,\n completed: false,\n aborted: false,\n };\n\n this.abortController = new AbortController();\n\n return this.state;\n }\n\n /**\n * Upload a part\n *\n * @param partNumber - Part number (1-based)\n * @param data - Part data\n * @param options - Upload options\n * @returns Upload result\n */\n async uploadPart(\n partNumber: number,\n data: ArrayBuffer | Blob | Buffer,\n options: UploadOptions = {},\n ): Promise<{ etag: string; partNumber: number; size: number }> {\n if (!this.state) {\n throw new Error('No active upload. Call createUpload first.');\n }\n\n if (this.state.completed || this.state.aborted) {\n throw new Error('Upload is completed or aborted');\n }\n\n const part = this.state.parts.find(p => p.partNumber === partNumber);\n if (!part) {\n throw new Error(`Part ${partNumber} not found`);\n }\n\n if (part.uploaded) {\n throw new Error(`Part ${partNumber} already uploaded`);\n }\n\n // Check abort signal\n if (this.abortController?.signal.aborted) {\n throw new Error('Upload aborted');\n }\n\n try {\n // Upload part with retry logic\n const result = await this.uploadPartWithRetry(partNumber, data, options);\n\n // Update state\n part.etag = result.etag;\n part.uploaded = true;\n this.state.uploadedSize += part.size;\n\n // Report progress\n if (options.onProgress) {\n options.onProgress({\n key: this.state.key,\n loaded: this.state.uploadedSize,\n total: this.state.totalSize,\n part: partNumber,\n percentage: (this.state.uploadedSize / this.state.totalSize) * 100,\n });\n }\n\n return result;\n } catch (error) {\n this.state.error = error instanceof Error ? error.message : String(error);\n throw error;\n }\n }\n\n /**\n * Complete the multipart upload\n *\n * @returns Final upload result\n */\n async completeUpload(): Promise<MultipartUploadResult> {\n if (!this.state) {\n throw new Error('No active upload. Call createUpload first.');\n }\n\n if (this.state.completed) {\n throw new Error('Upload already completed');\n }\n\n if (this.state.aborted) {\n throw new Error('Upload was aborted');\n }\n\n // Check if all parts are uploaded\n const unuploadedParts = this.state.parts.filter(p => !p.uploaded);\n if (unuploadedParts.length > 0) {\n throw new Error(`Upload incomplete: ${unuploadedParts.length} parts not uploaded`);\n }\n\n try {\n // Complete multipart upload\n const parts = this.state.parts\n .filter(p => p.etag)\n .map(p => ({ partNumber: p.partNumber, etag: p.etag ?? '' }))\n .filter(p => p.etag !== '');\n\n const result = await this.provider.completeMultipartUpload?.(this.state.uploadId, parts);\n\n if (!result) {\n throw new Error('Failed to complete multipart upload');\n }\n\n // Update state\n this.state.completed = true;\n\n return {\n ...result,\n key: result.key ?? this.state.key,\n uploadId: this.state.uploadId,\n parts: this.state.parts\n .filter(p => p.etag)\n .map(p => ({\n partNumber: p.partNumber,\n etag: p.etag ?? '',\n size: p.size,\n })),\n totalParts: this.state.parts.length,\n };\n } catch (error) {\n this.state.error = error instanceof Error ? error.message : String(error);\n throw error;\n }\n }\n\n /**\n * Abort the multipart upload\n */\n async abortUpload(): Promise<void> {\n if (!this.state) {\n return;\n }\n\n if (this.state.completed) {\n return;\n }\n\n // Signal abort\n this.abortController?.abort();\n this.state.aborted = true;\n\n try {\n // Abort on provider\n await this.provider.abortMultipartUpload?.(this.state.uploadId);\n } catch (error) {\n // Log error but don't throw - we want to clean up state\n\n // Use structured logging instead of console.warn\n logWarn('Failed to abort upload on provider', {\n error: error instanceof Error ? error.message : String(error),\n uploadId: this.state.uploadId,\n key: this.state.key,\n });\n }\n\n // Reset state\n this.state = null;\n this.abortController = null;\n }\n\n /**\n * Get current upload state\n */\n getState(): MultipartUploadState | null {\n return this.state;\n }\n\n /**\n * Resume upload from state (for recovery)\n *\n * @param state - Previous upload state\n */\n async resumeUpload(state: MultipartUploadState): Promise<void> {\n if (this.state && !this.state.completed && !this.state.aborted) {\n throw new Error('Upload already in progress');\n }\n\n this.state = { ...state };\n this.abortController = new AbortController();\n }\n\n /**\n * Upload file in chunks automatically\n *\n * @param key - Storage key\n * @param data - File data\n * @param options - Upload options\n * @returns Upload result\n */\n async uploadFile(\n key: string,\n data: ArrayBuffer | Blob | Buffer,\n options: MultipartUploadOptions = {},\n ): Promise<MultipartUploadResult> {\n const totalSize =\n data instanceof ArrayBuffer\n ? data.byteLength\n : data instanceof Buffer\n ? data.length\n : (data as Blob).size;\n\n // Create upload\n await this.createUpload(key, totalSize, options);\n\n const partSize = this.calculatePartSize(totalSize, options.partSize);\n const totalParts = Math.ceil(totalSize / partSize);\n\n // Upload parts\n for (let i = 0; i < totalParts; i++) {\n const start = i * partSize;\n const end = Math.min(start + partSize, totalSize);\n const partData = data.slice(start, end);\n\n await this.uploadPart(i + 1, partData, {\n onProgress: options.onProgress\n ? (progress: UploadProgress) => {\n options.onProgress?.({\n key: progress.key,\n loaded: progress.loaded,\n total: progress.total,\n part: progress.part ?? 0,\n percentage: progress.percentage ?? 0,\n });\n }\n : undefined,\n });\n }\n\n // Complete upload\n return await this.completeUpload();\n }\n\n private async uploadPartWithRetry(\n partNumber: number,\n data: ArrayBuffer | Blob | Buffer,\n options: UploadOptions,\n maxRetries: number = 3,\n ): Promise<{ etag: string; partNumber: number; size: number }> {\n let lastError: Error | null = null;\n\n for (let attempt = 1; attempt <= maxRetries; attempt++) {\n try {\n if (!this.state?.uploadId) {\n throw new Error('Upload ID not initialized');\n }\n\n const result = await this.provider.uploadPart?.(this.state.uploadId, partNumber, data, {\n ...options,\n abortSignal: this.abortController?.signal,\n });\n\n if (!result) {\n throw new Error('Failed to upload part');\n }\n\n return {\n etag: result.etag ?? '',\n partNumber: result.partNumber ?? partNumber,\n size:\n data instanceof ArrayBuffer\n ? data.byteLength\n : data instanceof Buffer\n ? data.length\n : (data as Blob).size,\n };\n } catch (error) {\n lastError = error instanceof Error ? error : new Error(String(error));\n\n // Don't retry on abort\n if (this.abortController?.signal.aborted) {\n throw lastError;\n }\n\n // Don't retry on validation errors\n if (lastError.message.includes('validation') || lastError.message.includes('invalid')) {\n throw lastError;\n }\n\n // Wait before retry (exponential backoff)\n if (attempt < maxRetries) {\n await new Promise(resolve =>\n setTimeout(resolve, Math.pow(2, attempt) * STORAGE_CONSTANTS.RETRY_BASE_DELAY_MS),\n );\n }\n }\n }\n\n throw lastError ?? new Error('Upload failed after retries');\n }\n\n private calculatePartSize(totalSize: number, userPartSize?: number): number {\n if (userPartSize) {\n return Math.min(userPartSize, totalSize);\n }\n\n // Use constants for part size thresholds\n if (totalSize < MULTIPART_THRESHOLDS.SMALL_FILE) {\n return PART_SIZES.SMALL;\n } else if (totalSize < MULTIPART_THRESHOLDS.MEDIUM_FILE) {\n return PART_SIZES.MEDIUM;\n } else {\n // Scale part size to ensure we never exceed 10,000 parts (S3/R2 limit)\n const maxParts = 9999; // Stay safely under 10,000 limit\n const minPartSize = Math.ceil(totalSize / maxParts);\n return Math.max(PART_SIZES.LARGE, minPartSize);\n }\n }\n\n private getProviderName(): string {\n return this.provider.constructor.name;\n }\n}\n\n/**\n * Create a multipart upload manager for a provider\n *\n * @param provider - Storage provider\n * @returns Multipart upload manager\n */\nexport function createMultipartUploadManager(provider: StorageProvider): MultipartUploadManager {\n if (!hasMultipartSupport(provider)) {\n throw new Error('The provided storage provider does not support multipart uploads');\n }\n return new MultipartUploadManager(provider);\n}\n\n/**\n * Determines whether the given storage provider supports multipart uploads.\n *\n * @param provider - The storage provider to check\n * @returns `true` if the provider supports multipart uploads, `false` otherwise.\n */\nexport function hasMultipartSupport(provider: StorageProvider): boolean {\n const capabilities = provider.getCapabilities?.();\n return capabilities?.multipart ?? false;\n}\n\n/**\n * Selects an appropriate multipart upload part size for a file.\n *\n * If `userPartSize` is provided, it will be capped at the file size; otherwise the part size\n * is chosen from configured thresholds for small, medium, or large files.\n *\n * @param fileSize - File size in bytes\n * @param userPartSize - Optional user-specified part size in bytes; capped to `fileSize` when provided\n * @returns The selected part size in bytes\n */\nexport function getOptimalPartSize(fileSize: number, userPartSize?: number): number {\n if (userPartSize) {\n return Math.min(userPartSize, fileSize);\n }\n\n if (fileSize < MULTIPART_THRESHOLDS.SMALL_FILE) {\n return PART_SIZES.SMALL;\n } else if (fileSize < MULTIPART_THRESHOLDS.MEDIUM_FILE) {\n return PART_SIZES.MEDIUM;\n } else {\n // Scale part size to ensure we never exceed 10,000 parts (S3/R2 limit)\n const maxParts = 9999; // Stay safely under 10,000 limit\n const minPartSize = Math.ceil(fileSize / maxParts);\n return Math.max(PART_SIZES.LARGE, minPartSize);\n }\n}\n","/**\n * @fileoverview Storage Provider Capabilities Utilities\n *\n * Provides utilities for checking storage provider capabilities and feature support.\n * Helps determine which features are available for each provider.\n *\n * @module @repo/storage/capabilities\n */\n\nimport { DEFAULT_STORAGE_CAPABILITIES, MULTIPART_THRESHOLDS } from './constants';\n\nimport type { StorageCapabilities, StorageProvider } from '../types';\n\n/**\n * Check if a storage provider has a specific capability\n * @param provider - The storage provider to check\n * @param capability - The capability to check for\n * @returns True if the provider supports the capability\n */\nexport function hasCapability(\n provider: StorageProvider,\n capability: keyof StorageCapabilities,\n): boolean {\n const capabilities = provider.getCapabilities?.();\n return capabilities?.[capability] ?? false;\n}\n\n/**\n * Check if a storage provider supports multiple capabilities\n * @param provider - The storage provider to check\n * @param capabilities - Array of capabilities to check for\n * @returns True if the provider supports all capabilities\n */\nexport function hasAllCapabilities(\n provider: StorageProvider,\n capabilities: Array<keyof StorageCapabilities>,\n): boolean {\n return capabilities.every(capability => hasCapability(provider, capability));\n}\n\n/**\n * Check if a storage provider supports any of the specified capabilities\n * @param provider - The storage provider to check\n * @param capabilities - Array of capabilities to check for\n * @returns True if the provider supports at least one capability\n */\nexport function hasAnyCapability(\n provider: StorageProvider,\n capabilities: Array<keyof StorageCapabilities>,\n): boolean {\n return capabilities.some(capability => hasCapability(provider, capability));\n}\n\n/**\n * Get all capabilities supported by a storage provider\n * @param provider - The storage provider to check\n * @returns Object with all capabilities and their support status\n */\nexport function getProviderCapabilities(provider: StorageProvider): StorageCapabilities {\n return provider.getCapabilities?.() ?? { ...DEFAULT_STORAGE_CAPABILITIES };\n}\n\n/**\n * Get a human-readable description of provider capabilities\n * @param provider - The storage provider to describe\n * @returns String describing the provider's capabilities\n */\nexport function describeProviderCapabilities(provider: StorageProvider): string {\n const capabilities = getProviderCapabilities(provider);\n const supportedFeatures: string[] = [];\n const unsupportedFeatures: string[] = [];\n\n if (capabilities.multipart) supportedFeatures.push('multipart uploads');\n else unsupportedFeatures.push('multipart uploads');\n\n if (capabilities.presignedUrls) supportedFeatures.push('presigned URLs');\n else unsupportedFeatures.push('presigned URLs');\n\n if (capabilities.progressTracking) supportedFeatures.push('progress tracking');\n else unsupportedFeatures.push('progress tracking');\n\n if (capabilities.abortSignal) supportedFeatures.push('abort signals');\n else unsupportedFeatures.push('abort signals');\n\n if (capabilities.metadata) supportedFeatures.push('metadata');\n else unsupportedFeatures.push('metadata');\n\n if (capabilities.customDomains) supportedFeatures.push('custom domains');\n else unsupportedFeatures.push('custom domains');\n\n if (capabilities.edgeCompatible) supportedFeatures.push('edge runtime');\n else unsupportedFeatures.push('edge runtime');\n\n let description = `Provider supports: ${supportedFeatures.join(', ')}`;\n\n if (unsupportedFeatures.length > 0) {\n description += `\\nProvider does not support: ${unsupportedFeatures.join(', ')}`;\n }\n\n return description;\n}\n\n/**\n * Validate that a provider supports the required capabilities for an operation\n * @param provider - The storage provider to validate\n * @param requiredCapabilities - Capabilities required for the operation\n * @throws Error if provider doesn't support required capabilities\n */\nexport function validateProviderCapabilities(\n provider: StorageProvider,\n requiredCapabilities: Array<keyof StorageCapabilities>,\n): void {\n const missingCapabilities = requiredCapabilities.filter(\n capability => !hasCapability(provider, capability),\n );\n\n if (missingCapabilities.length > 0) {\n const providerName = provider.constructor.name;\n throw new Error(\n `Provider ${providerName} does not support required capabilities: ${missingCapabilities.join(', ')}`,\n );\n }\n}\n\n/**\n * Get the best provider for a specific use case based on capabilities\n * @param providers - Array of storage providers to choose from\n * @param requiredCapabilities - Capabilities required for the use case\n * @returns The best provider or null if none meet the requirements\n */\nexport function getBestProvider(\n providers: StorageProvider[],\n requiredCapabilities: Array<keyof StorageCapabilities>,\n): StorageProvider | null {\n const suitableProviders = providers.filter(provider =>\n hasAllCapabilities(provider, requiredCapabilities),\n );\n\n if (suitableProviders.length === 0) {\n return null;\n }\n\n // If multiple providers are suitable, prefer edge-compatible ones\n const edgeCompatible = suitableProviders.filter(provider =>\n hasCapability(provider, 'edgeCompatible'),\n );\n\n return edgeCompatible.length > 0 ? (edgeCompatible[0] ?? null) : (suitableProviders[0] ?? null);\n}\n\n/**\n * Builds a map from provider names to their reported storage capabilities.\n *\n * @param providers - Array of entries each containing a `name` (used as the map key) and a `provider` instance\n * @returns A mapping from each provider name to its `StorageCapabilities`\n */\nexport function getCapabilityMatrix(\n providers: Array<{ name: string; provider: StorageProvider }>,\n): Record<string, StorageCapabilities> {\n const matrix: Record<string, StorageCapabilities> = {};\n\n for (const { name, provider } of providers) {\n matrix[name] = getProviderCapabilities(provider);\n }\n\n return matrix;\n}\n\n/**\n * Evaluate a storage provider's suitability for a specific file and produce actionable recommendations and warnings.\n *\n * @param provider - The storage provider to evaluate\n * @param fileSize - File size in bytes\n * @param fileType - MIME type of the file\n * @returns An object with `suitable` (`true` if there are no warnings, `false` otherwise), `recommendations` (suggested actions to improve handling), and `warnings` (issues that reduce suitability)\n */\nexport function checkProviderSuitability(\n provider: StorageProvider,\n fileSize: number,\n fileType: string,\n): {\n suitable: boolean;\n recommendations: string[];\n warnings: string[];\n} {\n const capabilities = getProviderCapabilities(provider);\n const recommendations: string[] = [];\n const warnings: string[] = [];\n\n // Check file size suitability\n if (fileSize > MULTIPART_THRESHOLDS.SMALL_FILE) {\n // > 100MB\n if (!capabilities.multipart) {\n warnings.push('Large file detected but provider does not support multipart uploads');\n } else {\n recommendations.push('Use multipart upload for this large file');\n }\n }\n\n // Check file type suitability\n if (fileType.startsWith('image/')) {\n if (capabilities.metadata) {\n recommendations.push('Consider storing image metadata for better organization');\n }\n }\n\n if (fileType.startsWith('video/')) {\n if (!capabilities.multipart) {\n warnings.push('Video files are typically large and benefit from multipart uploads');\n }\n }\n\n // Check edge compatibility\n if (fileType.startsWith('text/') && !capabilities.edgeCompatible) {\n recommendations.push('Text files could be processed in edge runtime for better performance');\n }\n\n const suitable = warnings.length === 0;\n\n return {\n suitable,\n recommendations,\n warnings,\n };\n}\n","/**\n * @fileoverview Health check utilities for storage providers\n *\n * Provides health check functionality to verify storage provider availability\n * and performance. Useful for monitoring and alerting.\n *\n * @module @repo/storage/health-check\n */\n\nimport type { StorageProvider } from '../types';\n\n/**\n * Health check result with status and metrics\n */\nexport interface HealthCheckResult {\n status: 'healthy' | 'degraded' | 'unhealthy';\n latencyMs: number;\n error?: string;\n details?: Record<string, unknown>;\n}\n\n/**\n * Check the health of a storage provider\n *\n * @param provider - The storage provider to check\n * @returns Health check result with status and latency\n */\nexport async function checkProviderHealth(provider: StorageProvider): Promise<HealthCheckResult> {\n const startTime = Date.now();\n\n try {\n // Perform a lightweight operation to check provider health\n // Using list with limit 1 as a health check probe\n await provider.list({ limit: 1 });\n\n const latencyMs = Date.now() - startTime;\n\n // Define health thresholds\n const HEALTHY_THRESHOLD_MS = 1000; // < 1s is healthy\n const DEGRADED_THRESHOLD_MS = 3000; // 1-3s is degraded\n\n let status: 'healthy' | 'degraded' | 'unhealthy';\n if (latencyMs < HEALTHY_THRESHOLD_MS) {\n status = 'healthy';\n } else if (latencyMs < DEGRADED_THRESHOLD_MS) {\n status = 'degraded';\n } else {\n status = 'unhealthy';\n }\n\n return {\n status,\n latencyMs,\n details: {\n provider: provider.constructor.name,\n threshold_healthy_ms: HEALTHY_THRESHOLD_MS,\n threshold_degraded_ms: DEGRADED_THRESHOLD_MS,\n },\n };\n } catch (error) {\n const latencyMs = Date.now() - startTime;\n return {\n status: 'unhealthy',\n latencyMs,\n error: error instanceof Error ? error.message : String(error),\n details: {\n provider: provider.constructor.name,\n },\n };\n }\n}\n\n/**\n * Perform a comprehensive health check on storage system\n *\n * @param provider - The storage provider to check\n * @returns Detailed health check result\n */\nexport async function storageHealthCheck(provider: StorageProvider): Promise<HealthCheckResult> {\n return checkProviderHealth(provider);\n}\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { ListOptions, MultiStorageConfig, MultipartUploadOptions, MultipartUploadResult as MultipartUploadResult$1, PresignedUploadUrl, StorageCapabilities, StorageObject, StorageProvider, UploadOptions } from "./types.mjs";
1
+ import { ListOptions, MultiStorageConfig, MultipartUploadOptions, MultipartUploadResult as MultipartUploadResult$1, StorageCapabilities, StorageObject, StorageProvider, UploadOptions } from "./types.mjs";
2
2
 
3
3
  //#region providers/cloudflare-images.d.ts
4
4
  declare const CloudflareImagesProvider: new (...args: unknown[]) => StorageProvider;
@@ -34,33 +34,6 @@ declare class MultiStorageManager {
34
34
  //#region providers/cloudflare-r2.d.ts
35
35
  declare const CloudflareR2Provider: new (...args: unknown[]) => StorageProvider;
36
36
  //#endregion
37
- //#region providers/vercel-blob.d.ts
38
- declare class VercelBlobProvider implements StorageProvider {
39
- private token;
40
- constructor(token: string);
41
- delete(key: string): Promise<void>;
42
- download(key: string): Promise<Blob>;
43
- exists(key: string): Promise<boolean>;
44
- getMetadata(key: string): Promise<StorageObject>;
45
- getUrl(key: string, _options?: {
46
- expiresIn?: number;
47
- }): Promise<string>;
48
- list(options?: ListOptions): Promise<StorageObject[]>;
49
- upload(key: string, data: ArrayBuffer | Blob | Buffer | File | ReadableStream, options?: UploadOptions): Promise<StorageObject>;
50
- createMultipartUpload(key: string, _options?: UploadOptions): Promise<{
51
- uploadId: string;
52
- key: string;
53
- }>;
54
- uploadPart(): Promise<{
55
- etag: string;
56
- partNumber: number;
57
- }>;
58
- completeMultipartUpload(): Promise<StorageObject>;
59
- abortMultipartUpload(): Promise<void>;
60
- getPresignedUploadUrl(): Promise<PresignedUploadUrl>;
61
- getCapabilities(): StorageCapabilities;
62
- }
63
- //#endregion
64
37
  //#region src/multipart.d.ts
65
38
  interface MultipartUploadState {
66
39
  uploadId: string;
@@ -139,5 +112,5 @@ interface HealthCheckResult {
139
112
  declare function checkProviderHealth(provider: StorageProvider): Promise<HealthCheckResult>;
140
113
  declare function storageHealthCheck(provider: StorageProvider): Promise<HealthCheckResult>;
141
114
  //#endregion
142
- export { CloudflareImagesProvider as S, getOptimalPartSize as _, describeProviderCapabilities as a, CloudflareR2Provider as b, getProviderCapabilities as c, hasCapability as d, validateProviderCapabilities as f, createMultipartUploadManager as g, MultipartUploadState as h, checkProviderSuitability as i, hasAllCapabilities as l, MultipartUploadResult as m, checkProviderHealth as n, getBestProvider as o, MultipartUploadManager as p, storageHealthCheck as r, getCapabilityMatrix as s, HealthCheckResult as t, hasAnyCapability as u, hasMultipartSupport as v, MultiStorageManager as x, VercelBlobProvider as y };
143
- //# sourceMappingURL=health-check-Cxg9x7Cb.d.mts.map
115
+ export { getOptimalPartSize as _, describeProviderCapabilities as a, MultiStorageManager as b, getProviderCapabilities as c, hasCapability as d, validateProviderCapabilities as f, createMultipartUploadManager as g, MultipartUploadState as h, checkProviderSuitability as i, hasAllCapabilities as l, MultipartUploadResult as m, checkProviderHealth as n, getBestProvider as o, MultipartUploadManager as p, storageHealthCheck as r, getCapabilityMatrix as s, HealthCheckResult as t, hasAnyCapability as u, hasMultipartSupport as v, CloudflareImagesProvider as x, CloudflareR2Provider as y };
116
+ //# sourceMappingURL=health-check-im_huJ59.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"health-check-im_huJ59.d.mts","names":[],"sources":["../providers/cloudflare-images.ts","../src/multi-storage.ts","../providers/cloudflare-r2.ts","../src/multipart.ts","../src/capabilities.ts","../src/health-check.ts"],"mappings":"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"}
package/index.mjs CHANGED
@@ -1,3 +1,3 @@
1
- import { n as getEnvWithDefaults, r as safeEnv, t as env } from "./env-BRxsA_k1.mjs";
1
+ import { n as getEnvWithDefaults, r as safeEnv, t as env } from "./env-d2CieWaM.mjs";
2
2
 
3
3
  export { env, getEnvWithDefaults, safeEnv };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@od-oneapp/storage",
3
- "version": "2026.2.2001-canary.1",
3
+ "version": "2026.2.2301-canary",
4
4
  "description": "File storage package",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -56,8 +56,6 @@
56
56
  "default": "./validation.mjs"
57
57
  }
58
58
  },
59
- "peerDependencies": {},
60
- "peerDependenciesMeta": {},
61
59
  "repository": {
62
60
  "type": "git",
63
61
  "url": "https://github.com/OneDigital-Product/monorepo.git",
@@ -119,5 +117,16 @@
119
117
  }
120
118
  },
121
119
  "registry": "https://registry.npmjs.org/"
120
+ },
121
+ "main": "./env.mjs",
122
+ "types": "./env.d.mts",
123
+ "dependencies": {
124
+ "@od-oneapp/integration-cloudflare": "canary",
125
+ "@od-oneapp/shared": "canary",
126
+ "@t3-oss/env-core": "^0.13.10",
127
+ "@vercel/blob": "^2.2.0",
128
+ "nanoid": "^5.1.6",
129
+ "tsdown": "^0.20.3",
130
+ "zod": "4.3.6"
122
131
  }
123
132
  }
package/server-edge.d.mts CHANGED
@@ -1,7 +1,8 @@
1
1
  import { safeEnv } from "./index.mjs";
2
2
  import { KeyGenerationOptions, KeyPattern, generateMultipleKeys, generateStorageKey, isKeyPattern, normalizeStorageKey, parseStorageKey, sanitizeStorageKey, validateStorageKey } from "./keys.mjs";
3
3
  import { ListOptions, StorageObject, StorageProvider, StorageProviderType, UploadOptions } from "./types.mjs";
4
- import { y as VercelBlobProvider } from "./health-check-Cxg9x7Cb.mjs";
4
+ import "./client.mjs";
5
+ import { t as VercelBlobProvider } from "./vercel-blob-07Sx0Akn.mjs";
5
6
 
6
7
  //#region src/server-edge.d.ts
7
8
  declare function createEdgeStorageProvider(token: string): VercelBlobProvider;
@@ -1 +1 @@
1
- {"version":3,"file":"server-edge.d.mts","names":[],"sources":["../src/server-edge.ts"],"mappings":";;;;;;iBAuDgB,yBAAA,CAA0B,KAAA,WAAgB,kBAAA;AAAA,iBAqB1C,cAAA,CAAA,GAAkB,kBAAA;AAAA,cAgBrB,WAAA;2BACS,OAAA;6BACE,OAAA,CAAA,IAAA;2BACF,OAAA;gCACK,OAAA,CADL,aAAA;wBAEA,OAAA;IAAc,SAAA;EAAA,MAAoB,OAAA;mBACrC,WAAA,KAAW,OAAA,CAAA,aAAA;wBAEf,IAAA,EACL,WAAA,GAAc,IAAA,GAAO,MAAA,GAAS,IAAA,GAAO,cAAA,EAAc,OAAA,GAC/C,aAAA,KAAa,OAAA,CAAA,aAAA;AAAA;AAAA,cAgBd,gBAAA;EAAA"}
1
+ {"version":3,"file":"server-edge.d.mts","names":[],"sources":["../src/server-edge.ts"],"mappings":";;;;;;;iBAuDgB,yBAAA,CAA0B,KAAA,WAAgB,kBAAA;AAAA,iBAqB1C,cAAA,CAAA,GAAkB,kBAAA;AAAA,cAgBrB,WAAA;2BACS,OAAA;6BACE,OAAA,CAAA,IAAA;2BACF,OAAA;gCACK,OAAA,CADL,aAAA;wBAEA,OAAA;IAAc,SAAA;EAAA,MAAoB,OAAA;mBACrC,WAAA,KAAW,OAAA,CAAA,aAAA;wBAEf,IAAA,EACL,WAAA,GAAc,IAAA,GAAO,MAAA,GAAS,IAAA,GAAO,cAAA,EAAc,OAAA,GAC/C,aAAA,KAAa,OAAA,CAAA,aAAA;AAAA;AAAA,cAgBd,gBAAA;EAAA"}
package/server-edge.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { r as safeEnv } from "./env-BRxsA_k1.mjs";
1
+ import { r as safeEnv } from "./env-d2CieWaM.mjs";
2
2
  import { generateMultipleKeys, generateStorageKey, isKeyPattern, normalizeStorageKey, parseStorageKey, sanitizeStorageKey, validateStorageKey } from "./keys.mjs";
3
3
  import { t as VercelBlobProvider } from "./vercel-blob-DrfolJEu.mjs";
4
4
 
package/server-next.d.mts CHANGED
@@ -2,7 +2,8 @@ import { env, safeEnv } from "./index.mjs";
2
2
  import { validateStorageKey } from "./keys.mjs";
3
3
  import { ConfigError, DownloadError, NetworkError, ProviderError, QuotaInfo, StorageError, StorageErrorCode, UploadError, ValidationError, ValidationOptions, createStorageError, formatFileSize, getErrorCode, getQuotaInfo, isQuotaExceeded, isRetryableError, parseFileSize, validateFileSize, validateMimeType, validateUploadOptions } from "./validation.mjs";
4
4
  import { BlobListResponse, BulkDeleteResponse, BulkMoveResponse, ClientUploadOptions, CloudflareImagesBatchToken, CloudflareImagesListOptions, CloudflareImagesSigningKey, CloudflareImagesStats, CloudflareImagesTransformOptions, CloudflareImagesVariant, DirectUploadResponse, EnhancedR2Credentials, HandleUploadConfig, ListOptions, MediaActionResponse, MultiStorageConfig, MultipartUploadOptions, OnBeforeGenerateTokenResult, PresignedUploadUrl, R2Credentials, StorageCapabilities, StorageConfig, StorageObject, StorageProvider, StorageProviderType, StreamUploadOptions, UploadOptions, UploadProgress, VercelBlobOptions } from "./types.mjs";
5
- import { S as CloudflareImagesProvider, _ as getOptimalPartSize, a as describeProviderCapabilities, b as CloudflareR2Provider, c as getProviderCapabilities, d as hasCapability, f as validateProviderCapabilities, g as createMultipartUploadManager, h as MultipartUploadState, i as checkProviderSuitability, l as hasAllCapabilities, m as MultipartUploadResult, n as checkProviderHealth, o as getBestProvider, p as MultipartUploadManager, r as storageHealthCheck, s as getCapabilityMatrix, t as HealthCheckResult, u as hasAnyCapability, v as hasMultipartSupport, x as MultiStorageManager, y as VercelBlobProvider } from "./health-check-Cxg9x7Cb.mjs";
5
+ import { t as VercelBlobProvider } from "./vercel-blob-07Sx0Akn.mjs";
6
+ import { _ as getOptimalPartSize, a as describeProviderCapabilities, b as MultiStorageManager, c as getProviderCapabilities, d as hasCapability, f as validateProviderCapabilities, g as createMultipartUploadManager, h as MultipartUploadState, i as checkProviderSuitability, l as hasAllCapabilities, m as MultipartUploadResult, n as checkProviderHealth, o as getBestProvider, p as MultipartUploadManager, r as storageHealthCheck, s as getCapabilityMatrix, t as HealthCheckResult, u as hasAnyCapability, v as hasMultipartSupport, x as CloudflareImagesProvider, y as CloudflareR2Provider } from "./health-check-im_huJ59.mjs";
6
7
  import { createStorageProvider, getMultiStorage, getProviderCapabilitiesFromConfig, getStorage, initializeMultiStorage, initializeStorage, multiStorage, resetStorageState, storage, validateStorageConfig } from "./server.mjs";
7
8
 
8
9
  //#region src/actions/mediaActions.d.ts
@@ -1 +1 @@
1
- {"version":3,"file":"server-next.d.mts","names":[],"sources":["../src/actions/mediaActions.ts","../src/actions/productMediaActions.ts","../src/actions/blob-upload.ts"],"mappings":"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"}
1
+ {"version":3,"file":"server-next.d.mts","names":[],"sources":["../src/actions/mediaActions.ts","../src/actions/productMediaActions.ts","../src/actions/blob-upload.ts"],"mappings":"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"}
package/server-next.mjs CHANGED
@@ -1,7 +1,7 @@
1
- import { r as safeEnv, t as env } from "./env-BRxsA_k1.mjs";
1
+ import { i as logError, r as safeEnv, t as env } from "./env-d2CieWaM.mjs";
2
2
  import { sanitizeStorageKey, validateStorageKey } from "./keys.mjs";
3
3
  import { ConfigError, DownloadError, NetworkError, ProviderError, StorageError, StorageErrorCode, UploadError, ValidationError, createStorageError, formatFileSize, getErrorCode, getQuotaInfo, isQuotaExceeded, isRetryableError, parseFileSize, validateFileSize, validateMimeType, validateUploadOptions, validateUrlForSSRF } from "./validation.mjs";
4
- import { a as getBestProvider, b as CloudflareImagesProvider, c as hasAllCapabilities, d as validateProviderCapabilities, f as MultipartUploadManager, g as MultiStorageManager, h as hasMultipartSupport, i as describeProviderCapabilities, l as hasAnyCapability, m as getOptimalPartSize, n as storageHealthCheck, o as getCapabilityMatrix, p as createMultipartUploadManager, r as checkProviderSuitability, s as getProviderCapabilities, t as checkProviderHealth, u as hasCapability, v as STORAGE_CONSTANTS, x as logError, y as CloudflareR2Provider } from "./health-check-ekerANJG.mjs";
4
+ import { a as getBestProvider, b as CloudflareImagesProvider, c as hasAllCapabilities, d as validateProviderCapabilities, f as MultipartUploadManager, g as MultiStorageManager, h as hasMultipartSupport, i as describeProviderCapabilities, l as hasAnyCapability, m as getOptimalPartSize, n as storageHealthCheck, o as getCapabilityMatrix, p as createMultipartUploadManager, r as checkProviderSuitability, s as getProviderCapabilities, t as checkProviderHealth, u as hasCapability, v as STORAGE_CONSTANTS, y as CloudflareR2Provider } from "./health-check-Dij2-CYd.mjs";
5
5
  import { t as VercelBlobProvider } from "./vercel-blob-DrfolJEu.mjs";
6
6
  import { createStorageProvider, getMultiStorage, getProviderCapabilitiesFromConfig, getStorage, initializeMultiStorage, initializeStorage, multiStorage, resetStorageState, storage, validateStorageConfig } from "./server.mjs";
7
7
  import { handleUpload } from "@vercel/blob/client";
package/server.d.mts CHANGED
@@ -2,7 +2,9 @@ import { env, safeEnv } from "./index.mjs";
2
2
  import { validateStorageKey } from "./keys.mjs";
3
3
  import { ConfigError, DownloadError, NetworkError, ProviderError, QuotaInfo, StorageError, StorageErrorCode, UploadError, ValidationError, ValidationOptions, createStorageError, formatFileSize, getErrorCode, getQuotaInfo, isQuotaExceeded, isRetryableError, parseFileSize, validateFileSize, validateMimeType, validateUploadOptions } from "./validation.mjs";
4
4
  import { BlobListResponse, BulkDeleteResponse, BulkMoveResponse, ClientUploadOptions, CloudflareImagesBatchToken, CloudflareImagesListOptions, CloudflareImagesSigningKey, CloudflareImagesStats, CloudflareImagesTransformOptions, CloudflareImagesVariant, DirectUploadResponse, EnhancedR2Credentials, HandleUploadConfig, ListOptions, MediaActionResponse, MultiStorageConfig, MultipartUploadOptions, OnBeforeGenerateTokenResult, PresignedUploadUrl, R2Credentials, StorageCapabilities, StorageConfig, StorageObject, StorageProvider, StorageProviderType, StreamUploadOptions, UploadOptions, UploadProgress, VercelBlobOptions } from "./types.mjs";
5
- import { S as CloudflareImagesProvider, _ as getOptimalPartSize, a as describeProviderCapabilities, b as CloudflareR2Provider, c as getProviderCapabilities, d as hasCapability, f as validateProviderCapabilities, g as createMultipartUploadManager, h as MultipartUploadState, i as checkProviderSuitability, l as hasAllCapabilities, m as MultipartUploadResult, n as checkProviderHealth, o as getBestProvider, p as MultipartUploadManager, r as storageHealthCheck, s as getCapabilityMatrix, t as HealthCheckResult, u as hasAnyCapability, v as hasMultipartSupport, x as MultiStorageManager, y as VercelBlobProvider } from "./health-check-Cxg9x7Cb.mjs";
5
+ import "./client.mjs";
6
+ import { t as VercelBlobProvider } from "./vercel-blob-07Sx0Akn.mjs";
7
+ import { _ as getOptimalPartSize, a as describeProviderCapabilities, b as MultiStorageManager, c as getProviderCapabilities, d as hasCapability, f as validateProviderCapabilities, g as createMultipartUploadManager, h as MultipartUploadState, i as checkProviderSuitability, l as hasAllCapabilities, m as MultipartUploadResult, n as checkProviderHealth, o as getBestProvider, p as MultipartUploadManager, r as storageHealthCheck, s as getCapabilityMatrix, t as HealthCheckResult, u as hasAnyCapability, v as hasMultipartSupport, x as CloudflareImagesProvider, y as CloudflareR2Provider } from "./health-check-im_huJ59.mjs";
6
8
 
7
9
  //#region src/server.d.ts
8
10
  declare function validateStorageConfig(config: StorageConfig): {
package/server.d.mts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.mts","names":[],"sources":["../src/server.ts"],"mappings":";;;;;;;iBAyGgB,qBAAA,CAAsB,MAAA,EAAQ,aAAA;EAC5C,KAAA;EACA,MAAA;EACA,QAAA;AAAA;AAAA,iBAmFc,iCAAA,CAAkC,MAAA,EAAQ,aAAA,GAAgB,mBAAA;AAAA,iBAsE1D,qBAAA,CAAsB,MAAA,EAAQ,aAAA,GAAgB,eAAA;AAAA,iBAiD9C,iBAAA,CAAA;AAAA,iBA+DA,UAAA,CAAA,GAAc,eAAA;AAAA,iBAgBd,iBAAA,CAAA,GAAqB,eAAA;AAAA,iBAgFrB,sBAAA,CAAA,GAA0B,mBAAA;AAAA,iBAiG1B,eAAA,CAAA,GAAmB,mBAAA;AAAA,cAWtB,OAAA;2BACS,OAAA;6BACE,OAAA,CAAA,IAAA;2BACF,OAAA;gCACK,OAAA,CAAA,aAAA;wBACL,OAAA;IAAc,SAAA;EAAA,MAAoB,OAAA;mBACrC,WAAA,KAAW,OAAA,CAAA,aAAA;wBAEf,IAAA,EACL,WAAA,GAAc,IAAA,GAAO,MAAA,GAAS,IAAA,GAAO,cAAA,EAAc,OAAA,GAC/C,aAAA,KAAa,OAAA,CAAA,aAAA;uCAIU,OAAA,GAAY,aAAA,KAAa,OAAA;;;;iCAS1C,UAAA,UACE,IAAA,EACZ,WAAA,GAAc,IAAA,GAAO,MAAA,EAAM,OAAA,GACvB,aAAA,KAAa,OAAA;;;;8CAUP,KAAA,EACT,KAAA;IAAQ,IAAA;IAAc,UAAA;EAAA,OAAqB,OAAA,CAAA,aAAA;8CASb,OAAA;uCASJ,OAAA;IAAc,SAAA;IAAoB,WAAA;EAAA,MAAsB,OAAA,CATpD,kBAAA;;;cA4B5B,YAAA;2BACS,OAAA;6BACE,OAAA,CAAA,IAAA;2BACF,OAAA;gCACK,OAAA,CAAA,aAAA;iCACC,eAAA;;wBAEN,OAAA;IAAc,SAAA;EAAA,MAAoB,OAAA;mBACrC,WAAA;IAAgB,QAAA;EAAA,MAAmB,OAAA,CAAA,aAAA;wBAEvC,IAAA,EACL,WAAA,GAAc,IAAA,GAAO,MAAA,GAAS,IAAA,GAAO,cAAA,EAAc,OAAA,GAC/C,aAAA;IAAkB,QAAA;EAAA,MAAmB,OAAA,CAAA,aAAA;AAAA"}
1
+ {"version":3,"file":"server.d.mts","names":[],"sources":["../src/server.ts"],"mappings":";;;;;;;;;iBAyGgB,qBAAA,CAAsB,MAAA,EAAQ,aAAA;EAC5C,KAAA;EACA,MAAA;EACA,QAAA;AAAA;AAAA,iBAmFc,iCAAA,CAAkC,MAAA,EAAQ,aAAA,GAAgB,mBAAA;AAAA,iBAsE1D,qBAAA,CAAsB,MAAA,EAAQ,aAAA,GAAgB,eAAA;AAAA,iBAiD9C,iBAAA,CAAA;AAAA,iBA+DA,UAAA,CAAA,GAAc,eAAA;AAAA,iBAgBd,iBAAA,CAAA,GAAqB,eAAA;AAAA,iBAgFrB,sBAAA,CAAA,GAA0B,mBAAA;AAAA,iBAiG1B,eAAA,CAAA,GAAmB,mBAAA;AAAA,cAWtB,OAAA;2BACS,OAAA;6BACE,OAAA,CAAA,IAAA;2BACF,OAAA;gCACK,OAAA,CAAA,aAAA;wBACL,OAAA;IAAc,SAAA;EAAA,MAAoB,OAAA;mBACrC,WAAA,KAAW,OAAA,CAAA,aAAA;wBAEf,IAAA,EACL,WAAA,GAAc,IAAA,GAAO,MAAA,GAAS,IAAA,GAAO,cAAA,EAAc,OAAA,GAC/C,aAAA,KAAa,OAAA,CAAA,aAAA;uCAIU,OAAA,GAAY,aAAA,KAAa,OAAA;;;;iCAS1C,UAAA,UACE,IAAA,EACZ,WAAA,GAAc,IAAA,GAAO,MAAA,EAAM,OAAA,GACvB,aAAA,KAAa,OAAA;;;;8CAUP,KAAA,EACT,KAAA;IAAQ,IAAA;IAAc,UAAA;EAAA,OAAqB,OAAA,CAAA,aAAA;8CASb,OAAA;uCASJ,OAAA;IAAc,SAAA;IAAoB,WAAA;EAAA,MAAsB,OAAA,CATpD,kBAAA;;;cA4B5B,YAAA;2BACS,OAAA;6BACE,OAAA,CAAA,IAAA;2BACF,OAAA;gCACK,OAAA,CAAA,aAAA;iCACC,eAAA;;wBAEN,OAAA;IAAc,SAAA;EAAA,MAAoB,OAAA;mBACrC,WAAA;IAAgB,QAAA;EAAA,MAAmB,OAAA,CAAA,aAAA;wBAEvC,IAAA,EACL,WAAA,GAAc,IAAA,GAAO,MAAA,GAAS,IAAA,GAAO,cAAA,EAAc,OAAA,GAC/C,aAAA;IAAkB,QAAA;EAAA,MAAmB,OAAA,CAAA,aAAA;AAAA"}
package/server.mjs CHANGED
@@ -1,7 +1,7 @@
1
- import { r as safeEnv, t as env } from "./env-BRxsA_k1.mjs";
1
+ import { a as logWarn, r as safeEnv, t as env } from "./env-d2CieWaM.mjs";
2
2
  import { validateStorageKey } from "./keys.mjs";
3
3
  import { ConfigError, DownloadError, NetworkError, ProviderError, StorageError, StorageErrorCode, UploadError, ValidationError, createStorageError, formatFileSize, getErrorCode, getQuotaInfo, isQuotaExceeded, isRetryableError, parseFileSize, validateFileSize, validateMimeType, validateUploadOptions } from "./validation.mjs";
4
- import { S as logWarn, _ as DEFAULT_STORAGE_CAPABILITIES, a as getBestProvider, b as CloudflareImagesProvider, c as hasAllCapabilities, d as validateProviderCapabilities, f as MultipartUploadManager, g as MultiStorageManager, h as hasMultipartSupport, i as describeProviderCapabilities, l as hasAnyCapability, m as getOptimalPartSize, n as storageHealthCheck, o as getCapabilityMatrix, p as createMultipartUploadManager, r as checkProviderSuitability, s as getProviderCapabilities, t as checkProviderHealth, u as hasCapability, y as CloudflareR2Provider } from "./health-check-ekerANJG.mjs";
4
+ import { _ as DEFAULT_STORAGE_CAPABILITIES, a as getBestProvider, b as CloudflareImagesProvider, c as hasAllCapabilities, d as validateProviderCapabilities, f as MultipartUploadManager, g as MultiStorageManager, h as hasMultipartSupport, i as describeProviderCapabilities, l as hasAnyCapability, m as getOptimalPartSize, n as storageHealthCheck, o as getCapabilityMatrix, p as createMultipartUploadManager, r as checkProviderSuitability, s as getProviderCapabilities, t as checkProviderHealth, u as hasCapability, y as CloudflareR2Provider } from "./health-check-Dij2-CYd.mjs";
5
5
  import { t as VercelBlobProvider } from "./vercel-blob-DrfolJEu.mjs";
6
6
 
7
7
  //#region src/server.ts
@@ -0,0 +1,31 @@
1
+ import { ListOptions, PresignedUploadUrl, StorageCapabilities, StorageObject, StorageProvider, UploadOptions } from "./types.mjs";
2
+
3
+ //#region providers/vercel-blob.d.ts
4
+ declare class VercelBlobProvider implements StorageProvider {
5
+ private token;
6
+ constructor(token: string);
7
+ delete(key: string): Promise<void>;
8
+ download(key: string): Promise<Blob>;
9
+ exists(key: string): Promise<boolean>;
10
+ getMetadata(key: string): Promise<StorageObject>;
11
+ getUrl(key: string, _options?: {
12
+ expiresIn?: number;
13
+ }): Promise<string>;
14
+ list(options?: ListOptions): Promise<StorageObject[]>;
15
+ upload(key: string, data: ArrayBuffer | Blob | Buffer | File | ReadableStream, options?: UploadOptions): Promise<StorageObject>;
16
+ createMultipartUpload(key: string, _options?: UploadOptions): Promise<{
17
+ uploadId: string;
18
+ key: string;
19
+ }>;
20
+ uploadPart(): Promise<{
21
+ etag: string;
22
+ partNumber: number;
23
+ }>;
24
+ completeMultipartUpload(): Promise<StorageObject>;
25
+ abortMultipartUpload(): Promise<void>;
26
+ getPresignedUploadUrl(): Promise<PresignedUploadUrl>;
27
+ getCapabilities(): StorageCapabilities;
28
+ }
29
+ //#endregion
30
+ export { VercelBlobProvider as t };
31
+ //# sourceMappingURL=vercel-blob-07Sx0Akn.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vercel-blob-07Sx0Akn.d.mts","names":[],"sources":["../providers/vercel-blob.ts"],"mappings":";;;cAsBa,kBAAA,YAA8B,eAAA;EAAA,QACjC,KAAA;cAEI,KAAA;EAON,MAAA,CAAO,GAAA,WAAc,OAAA;EAQrB,QAAA,CAAS,GAAA,WAAc,OAAA,CAAQ,IAAA;EAgC/B,MAAA,CAAO,GAAA,WAAc,OAAA;EAmBrB,WAAA,CAAY,GAAA,WAAc,OAAA,CAAQ,aAAA;EAmBlC,MAAA,CAAO,GAAA,UAAa,QAAA;IAAa,SAAA;EAAA,IAAuB,OAAA;EAWxD,IAAA,CAAK,OAAA,GAAU,WAAA,GAAc,OAAA,CAAQ,aAAA;EA6BrC,MAAA,CACJ,GAAA,UACA,IAAA,EAAM,WAAA,GAAc,IAAA,GAAO,MAAA,GAAS,IAAA,GAAO,cAAA,EAC3C,OAAA,GAAU,aAAA,GACT,OAAA,CAAQ,aAAA;EAgDL,qBAAA,CACJ,GAAA,UACA,QAAA,GAAW,aAAA,GACV,OAAA;IAAU,QAAA;IAAkB,GAAA;EAAA;EAKzB,UAAA,CAAA,GAAc,OAAA;IAAU,IAAA;IAAc,UAAA;EAAA;EAMtC,uBAAA,CAAA,GAA2B,OAAA,CAAQ,aAAA;EAMnC,oBAAA,CAAA,GAAwB,OAAA;EAMxB,qBAAA,CAAA,GAAyB,OAAA,CAAQ,kBAAA;EAMvC,eAAA,CAAA,GAAmB,mBAAA;AAAA"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"env-BRxsA_k1.mjs","names":[],"sources":["../../shared/src/logger/core.ts","../env.ts"],"sourcesContent":["/**\n * @fileoverview Canonical logger for the OneApp platform.\n *\n * This module provides isomorphic logging functions that work in any environment\n * (Browser, Node.js, Edge). Logs directly to console with runtime information.\n *\n * Preferred usage is to import from '@od-oneapp/shared/logger'.\n */\n\n/**\n * Get runtime environment information.\n *\n * Detects the current runtime environment (browser, Node.js, edge, Bun) and returns\n * detailed information about the environment type, version, and capabilities.\n *\n * @returns Runtime information object with type, version, and environment-specific details\n *\n * @example\n * ```typescript\n * const runtime = getRuntimeInfo();\n * // Returns: { type: 'node', version: '22.0.0', major: 22, minor: 0, isNode22Plus: true, isNextJs: true }\n * // or: { type: 'browser', isNextJs: true }\n * // or: { type: 'edge', variant: 'vercel' }\n * ```\n */\nexport const getRuntimeInfo = () => {\n // Edge runtime detection (Vercel Edge, Cloudflare Workers)\n if (typeof globalThis !== 'undefined' && (globalThis as any).EdgeRuntime) {\n return { type: 'edge', variant: 'vercel' };\n }\n if (\n typeof globalThis !== 'undefined' &&\n (globalThis as any).caches &&\n typeof (globalThis as any).caches !== 'undefined'\n ) {\n return { type: 'edge', variant: 'cloudflare' };\n }\n\n // Bun detection\n if (typeof process !== 'undefined' && process.versions?.bun) {\n return { type: 'bun', version: process.versions.bun };\n }\n\n // Browser detection (more robust)\n if (\n typeof globalThis !== 'undefined' &&\n 'window' in globalThis &&\n typeof (globalThis as any).window !== 'undefined' &&\n typeof (globalThis as any).window.document !== 'undefined' &&\n typeof (globalThis as any).window.navigator !== 'undefined'\n ) {\n return { type: 'browser', isNextJs: Boolean((globalThis as any).window.__NEXT_DATA__) };\n }\n\n // Node.js detection with version check\n if (typeof process !== 'undefined' && process.versions?.node) {\n const nodeVersion = parseInt(process.versions.node.split('.')[0] ?? '0');\n const nodeVersionMinor = parseInt(process.versions.node.split('.')[1] ?? '0');\n\n if (nodeVersion < 22) {\n // Note: Using console.warn here as observability system may not be initialized yet\n // eslint-disable-next-line no-console\n console.warn(\n `[Observability] Node ${process.versions.node} detected. Node 22+ is required for optimal performance and latest features.`,\n );\n }\n\n return {\n type: 'node',\n version: process.versions.node,\n major: nodeVersion,\n minor: nodeVersionMinor,\n isNode22Plus: nodeVersion >= 22,\n isNextJs:\n Boolean(process.env.NEXT_RUNTIME) ||\n Boolean(process.env.__NEXT_RUNTIME) ||\n Boolean(process.env.NEXT_PUBLIC_VERCEL_ENV),\n };\n }\n\n // Fallback\n return { type: 'unknown' };\n};\n\n// Cache the runtime info\nconst runtimeInfo = getRuntimeInfo();\n\n/**\n * Get cached runtime environment information.\n *\n * Returns the runtime information that was detected at module load time.\n * This is cached to avoid repeated detection checks.\n *\n * @returns Cached runtime information object\n */\nexport const getRuntimeEnvironment = () => runtimeInfo;\n\n/**\n * Detect if code is running in a browser environment\n * Extracted to shared utility to avoid duplication\n * @returns true if running in browser, false otherwise\n */\nexport function isBrowser(): boolean {\n return (\n typeof globalThis !== 'undefined' &&\n 'window' in globalThis &&\n typeof (globalThis as any).window !== 'undefined' &&\n typeof (globalThis as any).window.document !== 'undefined' &&\n typeof (globalThis as any).window.navigator !== 'undefined'\n );\n}\n\n/**\n * Determine if console logging should be enabled based on environment\n * Centralized logic to avoid duplication across entry points\n * @param envNodeEnv - The NEXT_PUBLIC_NODE_ENV value\n * @param consoleEnabled - The NEXT_PUBLIC_OBSERVABILITY_CONSOLE_ENABLED value (explicit control)\n * @param debugEnabled - The NEXT_PUBLIC_OBSERVABILITY_DEBUG value\n * @returns boolean indicating if console should be enabled\n */\nexport function shouldEnableConsole(\n envNodeEnv?: string,\n consoleEnabled?: boolean,\n debugEnabled?: boolean,\n): boolean {\n const isDevelopment = envNodeEnv === 'development' || process.env.NODE_ENV === 'development';\n\n // Priority: explicit control > development mode > debug mode\n if (consoleEnabled !== undefined) {\n return consoleEnabled;\n }\n if (isDevelopment) {\n return true;\n }\n return debugEnabled ?? false;\n}\n\n/**\n * Create a generic log function factory.\n *\n * Factory function that creates log functions for different levels (debug, info, warn, error).\n * Logs directly to console with runtime information.\n */\nconst createLogFunction = (level: 'debug' | 'info' | 'warn' | 'error') => {\n return (message: string | Error, context?: any): void => {\n if (message instanceof Error) {\n // For Error objects, log the error itself (console.error will show stack trace)\n // and include context as additional arguments\n if (context) {\n // eslint-disable-next-line no-console\n (console[level] as any)(`[${runtimeInfo.type}]`, message, context);\n } else {\n // eslint-disable-next-line no-console\n (console[level] as any)(`[${runtimeInfo.type}]`, message);\n }\n } else {\n // For string messages, format with context\n const contextStr = context ? JSON.stringify(context) : '';\n const logMessage = contextStr ? `${message} ${contextStr}` : message;\n // eslint-disable-next-line no-console\n (console[level] as any)(`[${runtimeInfo.type}]`, logMessage);\n }\n };\n};\n\n/**\n * Log a debug message (isomorphic - works in any environment).\n */\nexport const logDebug = createLogFunction('debug');\n\n/**\n * Log an info message (isomorphic - works in any environment).\n */\nexport const logInfo = createLogFunction('info');\n\n/**\n * Log a warning message (isomorphic - works in any environment).\n */\nexport const logWarn = createLogFunction('warn');\n\n/**\n * Log an error message (isomorphic - works in any environment).\n */\nexport const logError = createLogFunction('error');\n","/**\n * @fileoverview env.ts\n */\n\nimport { logWarn } from '@od-oneapp/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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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"health-check-Cxg9x7Cb.d.mts","names":[],"sources":["../providers/cloudflare-images.ts","../src/multi-storage.ts","../providers/cloudflare-r2.ts","../providers/vercel-blob.ts","../src/multipart.ts","../src/capabilities.ts","../src/health-check.ts"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"health-check-ekerANJG.mjs","names":["CloudflareImagesProvider","CloudflareImagesProviderInternal","CloudflareR2Provider","CloudflareR2ProviderInternal","CloudflareR2Provider","CloudflareImagesProvider"],"sources":["../../shared/src/logs.tsx","../providers/cloudflare-images.ts","../providers/cloudflare-r2.ts","../src/constants.ts","../src/multi-storage.ts","../src/multipart.ts","../src/capabilities.ts","../src/health-check.ts"],"sourcesContent":["/**\n * @fileoverview Canonical logger for the OneApp platform.\n *\n * This module provides isomorphic logging functions that work in any environment\n * (Browser, Node.js, Edge). Logs directly to console with runtime information.\n *\n * Preferred usage is to import from '@od-oneapp/shared/logs'.\n */\n\n/**\n * Get runtime environment information.\n *\n * Detects the current runtime environment (browser, Node.js, edge, Bun) and returns\n * detailed information about the environment type, version, and capabilities.\n *\n * @returns Runtime information object with type, version, and environment-specific details\n *\n * @example\n * ```typescript\n * const runtime = getRuntimeInfo();\n * // Returns: { type: 'node', version: '22.0.0', major: 22, minor: 0, isNode22Plus: true, isNextJs: true }\n * // or: { type: 'browser', isNextJs: true }\n * // or: { type: 'edge', variant: 'vercel' }\n * ```\n */\nexport const getRuntimeInfo = () => {\n // Edge runtime detection (Vercel Edge, Cloudflare Workers)\n // Note: Casting globalThis to check for runtime-specific properties not in standard TypeScript types\n if (\n typeof globalThis !== 'undefined' &&\n (globalThis as unknown as { EdgeRuntime?: unknown }).EdgeRuntime\n ) {\n return { type: 'edge', variant: 'vercel' };\n }\n if (\n typeof globalThis !== 'undefined' &&\n (globalThis as unknown as { caches?: unknown }).caches &&\n typeof (globalThis as unknown as { caches?: unknown }).caches !== 'undefined'\n ) {\n return { type: 'edge', variant: 'cloudflare' };\n }\n\n // Bun/Node detection - access via globalThis to avoid Edge Runtime static analysis of process.versions\n try {\n const proc = (globalThis as unknown as { process?: { versions?: Record<string, string> } })\n .process;\n const versions = proc?.versions;\n if (versions?.bun) {\n return { type: 'bun', version: versions.bun };\n }\n\n // Node.js detection with version check\n if (versions?.node) {\n const nodeVersion = parseInt(versions.node.split('.')[0] ?? '0');\n const nodeVersionMinor = parseInt(versions.node.split('.')[1] ?? '0');\n\n if (nodeVersion < 22) {\n // eslint-disable-next-line no-console\n console.warn(\n `[Observability] Node ${versions.node} detected. Node 22+ is required for optimal performance and latest features.`,\n );\n }\n\n const env = (globalThis as unknown as { process?: { env?: Record<string, string | undefined> } })\n .process?.env;\n return {\n type: 'node',\n version: versions.node,\n major: nodeVersion,\n minor: nodeVersionMinor,\n isNode22Plus: nodeVersion >= 22,\n isNextJs:\n Boolean(env?.NEXT_RUNTIME) ||\n Boolean(env?.__NEXT_RUNTIME) ||\n Boolean(env?.NEXT_PUBLIC_VERCEL_ENV),\n };\n }\n } catch {\n // process.versions not available (e.g. Edge Runtime) - fall through to fallback\n }\n\n // Browser detection (more robust)\n // Note: Casting globalThis to check for browser-specific properties not in standard Node.js types\n if (\n typeof globalThis !== 'undefined' &&\n 'window' in globalThis &&\n typeof (globalThis as unknown as { window?: unknown }).window !== 'undefined' &&\n typeof (globalThis as unknown as { window?: { document?: unknown } }).window?.document !==\n 'undefined' &&\n typeof (globalThis as unknown as { window?: { navigator?: unknown } }).window?.navigator !==\n 'undefined'\n ) {\n return {\n type: 'browser',\n isNextJs: Boolean(\n (globalThis as unknown as { window?: { __NEXT_DATA__?: unknown } }).window?.__NEXT_DATA__,\n ),\n };\n }\n\n // Fallback\n return { type: 'unknown' };\n};\n\n// Cache the runtime info\nconst runtimeInfo = getRuntimeInfo();\n\n/**\n * Get cached runtime environment information.\n *\n * Returns the runtime information that was detected at module load time.\n * This is cached to avoid repeated detection checks.\n *\n * @returns Cached runtime information object\n */\nexport const getRuntimeEnvironment = () => runtimeInfo;\n\n/**\n * Detect if code is running in a browser environment\n * Extracted to shared utility to avoid duplication\n * @returns true if running in browser, false otherwise\n */\nexport function isBrowser(): boolean {\n // Note: Casting globalThis to check for browser-specific properties not in standard Node.js types\n return (\n typeof globalThis !== 'undefined' &&\n 'window' in globalThis &&\n typeof (globalThis as unknown as { window?: unknown }).window !== 'undefined' &&\n typeof (globalThis as unknown as { window?: { document?: unknown } }).window?.document !==\n 'undefined' &&\n typeof (globalThis as unknown as { window?: { navigator?: unknown } }).window?.navigator !==\n 'undefined'\n );\n}\n\n/**\n * Determine if console logging should be enabled based on environment\n * Centralized logic to avoid duplication across entry points\n * @param envNodeEnv - The NEXT_PUBLIC_NODE_ENV value\n * @param consoleEnabled - The NEXT_PUBLIC_OBSERVABILITY_CONSOLE_ENABLED value (explicit control)\n * @param debugEnabled - The NEXT_PUBLIC_OBSERVABILITY_DEBUG value\n * @returns boolean indicating if console should be enabled\n */\nexport function shouldEnableConsole(\n envNodeEnv?: string,\n consoleEnabled?: boolean,\n debugEnabled?: boolean,\n): boolean {\n const nodeEnv = (\n globalThis as unknown as { process?: { env?: { NODE_ENV?: string } } }\n ).process?.env?.NODE_ENV;\n const isDevelopment = envNodeEnv === 'development' || nodeEnv === 'development';\n\n // Priority: explicit control > development mode > debug mode\n if (consoleEnabled !== undefined) {\n return consoleEnabled;\n }\n if (isDevelopment) {\n return true;\n }\n return debugEnabled ?? false;\n}\n\n/**\n * Create a generic log function factory.\n *\n * Factory function that creates log functions for different levels (debug, info, warn, error).\n * Logs directly to console with runtime information.\n */\nconst createLogFunction = (level: 'debug' | 'info' | 'warn' | 'error') => {\n return (message: string | Error, context?: Record<string, unknown> | Error): void => {\n // Determine the actual context object and error object\n let actualContext: Record<string, unknown> | undefined;\n let errorObj: Error | undefined;\n\n if (context instanceof Error) {\n errorObj = context;\n } else {\n actualContext = context;\n }\n\n if (message instanceof Error) {\n // If message is an Error, use it as the primary error\n const combinedContext = {\n ...actualContext,\n ...(errorObj ? { secondaryError: errorObj.message } : {}),\n };\n\n // eslint-disable-next-line no-console -- Logger implementation requires console access\n const consoleMethod = console[level];\n if (Object.keys(combinedContext).length > 0) {\n consoleMethod(`[${runtimeInfo.type}]`, message, combinedContext);\n } else {\n consoleMethod(`[${runtimeInfo.type}]`, message);\n }\n } else {\n // For string messages\n const finalError = errorObj;\n const contextStr = actualContext ? JSON.stringify(actualContext) : '';\n const logMessage = contextStr ? `${message} ${contextStr}` : message;\n\n // eslint-disable-next-line no-console -- Logger implementation requires console access\n const consoleMethod = console[level];\n if (finalError) {\n consoleMethod(`[${runtimeInfo.type}]`, logMessage, finalError);\n } else {\n consoleMethod(`[${runtimeInfo.type}]`, logMessage);\n }\n }\n };\n};\n\n/**\n * Log a debug message (isomorphic - works in any environment).\n */\nexport const logDebug = createLogFunction('debug');\n\n/**\n * Log an info message (isomorphic - works in any environment).\n */\nexport const logInfo = createLogFunction('info');\n\n/**\n * Log a message (alias for logInfo).\n */\nexport const log = logInfo;\n\n/**\n * Log a warning message (isomorphic - works in any environment).\n */\nexport const logWarn = createLogFunction('warn');\n\n/**\n * Log an error message (isomorphic - works in any environment).\n */\nexport const logError = createLogFunction('error');\n\n/**\n * Compatibility Logger class for components that use `new Logger('name')` pattern.\n * @deprecated Use logDebug, logInfo, logWarn, logError directly from @od-oneapp/shared/logs\n */\nexport class Logger {\n private prefix: string;\n\n constructor(name: string) {\n this.prefix = name;\n }\n\n debug(message: string, context?: Record<string, unknown>): void {\n logDebug(`[${this.prefix}] ${message}`, context);\n }\n\n info(message: string, context?: Record<string, unknown>): void {\n logInfo(`[${this.prefix}] ${message}`, context);\n }\n\n log(message: string, context?: Record<string, unknown>): void {\n this.info(message, context);\n }\n\n warn(message: string, context?: Record<string, unknown>): void {\n logWarn(`[${this.prefix}] ${message}`, context);\n }\n\n error(message: string | Error, context?: Record<string, unknown>): void {\n if (message instanceof Error) {\n logError(message, { prefix: this.prefix, ...context });\n } else {\n logError(new Error(message), { prefix: this.prefix, ...context });\n }\n }\n}\n","/**\n * @fileoverview Cloudflare Images storage provider\n *\n * Static import from the monorepo integration package.\n * The integration code is bundled into the published package by tsdown.\n */\n\nimport { CloudflareImagesProvider as CloudflareImagesProviderInternal } from '@od-oneapp/integration-cloudflare/storage-provider/images';\n\nimport type { StorageProvider } from '../types';\n\nexport const CloudflareImagesProvider: new (...args: unknown[]) => StorageProvider =\n CloudflareImagesProviderInternal as unknown as new (...args: unknown[]) => StorageProvider;\n","/**\n * @fileoverview Cloudflare R2 storage provider\n *\n * Static import from the monorepo integration package.\n * The integration code is bundled into the published package by tsdown.\n */\n\nimport { CloudflareR2Provider as CloudflareR2ProviderInternal } from '@od-oneapp/integration-cloudflare/storage-provider/r2';\n\nimport type { StorageProvider } from '../types';\n\nexport const CloudflareR2Provider: new (...args: unknown[]) => StorageProvider =\n CloudflareR2ProviderInternal as unknown as new (...args: unknown[]) => StorageProvider;\n","/**\n * @fileoverview Storage Package Constants\n *\n * Centralized constants for storage operations to avoid magic numbers\n * and improve maintainability.\n *\n * Includes:\n * - URL expiration times\n * - File size limits\n * - Multipart upload thresholds\n * - Retry configuration\n * - Rate limiting settings\n *\n * @module @repo/storage/constants\n */\n\nexport const STORAGE_CONSTANTS = {\n // URL Expiration Times (seconds)\n DEFAULT_URL_EXPIRY_SECONDS: 3600, // 1 hour\n PRODUCT_URL_EXPIRY_SECONDS: 3600, // 1 hour for product photos\n UPLOAD_URL_EXPIRY_SECONDS: 1800, // 30 minutes for uploads\n ADMIN_URL_EXPIRY_SECONDS: 7200, // 2 hours for admin operations\n\n // File Size Limits (bytes)\n MULTIPART_THRESHOLD_BYTES: 100 * 1024 * 1024, // 100MB - use multipart above this\n DEFAULT_PART_SIZE_BYTES: 5 * 1024 * 1024, // 5MB default part size\n DEFAULT_MAX_PART_SIZE_BYTES: 25 * 1024 * 1024, // 25MB max part size\n DEFAULT_QUEUE_SIZE: 4, // Concurrent upload parts\n\n // Batch Operations\n DEFAULT_BATCH_SIZE: 5, // Process 5 items concurrently\n MAX_BATCH_SIZE: 50, // Maximum batch size\n\n // Timeouts (milliseconds)\n DEFAULT_REQUEST_TIMEOUT_MS: 30000, // 30 seconds\n DEFAULT_UPLOAD_TIMEOUT_MS: 300000, // 5 minutes for uploads\n DEFAULT_DOWNLOAD_TIMEOUT_MS: 60000, // 1 minute for downloads\n\n // Retry Configuration\n DEFAULT_MAX_RETRIES: 3,\n RETRY_BASE_DELAY_MS: 1000, // 1 second base delay\n\n // Key Validation\n MAX_KEY_LENGTH: 1024,\n MAX_FILENAME_LENGTH: 255,\n\n // Rate Limiting (requests per window)\n DEFAULT_RATE_LIMIT_REQUESTS: 100,\n DEFAULT_RATE_LIMIT_WINDOW_MS: 60 * 1000, // 1 minute\n\n // Health Check\n HEALTH_CHECK_KEY: '__health_check__',\n} as const;\n\n/**\n * File size thresholds for multipart upload decisions\n */\nexport const MULTIPART_THRESHOLDS = {\n SMALL_FILE: 100 * 1024 * 1024, // < 100MB - use simple upload\n MEDIUM_FILE: 1024 * 1024 * 1024, // < 1GB - use 10MB parts\n LARGE_FILE: Infinity, // >= 1GB - use 25MB parts\n} as const;\n\n/**\n * Part sizes based on file size\n */\nexport const PART_SIZES = {\n SMALL: 5 * 1024 * 1024, // 5MB for files < 100MB\n MEDIUM: 10 * 1024 * 1024, // 10MB for files < 1GB\n LARGE: 25 * 1024 * 1024, // 25MB for files >= 1GB\n} as const;\n\n/**\n * Default storage capabilities for providers that don't implement getCapabilities()\n * Single source of truth for capability defaults\n */\nexport const DEFAULT_STORAGE_CAPABILITIES = {\n multipart: false,\n presignedUrls: false,\n progressTracking: false,\n abortSignal: false,\n metadata: false,\n customDomains: false,\n edgeCompatible: false,\n versioning: false,\n encryption: false,\n directoryListing: false,\n} as const;\n","/**\n * @fileoverview Multi-storage provider manager\n *\n * Manages multiple storage providers with routing and fallback capabilities.\n * Allows using different providers for different use cases or as backups.\n *\n * Features:\n * - Provider routing based on key patterns\n * - Fallback to default provider\n * - Unified API across multiple providers\n *\n * @module @repo/storage/multi-storage\n */\n\nimport { CloudflareImagesProvider } from '../providers/cloudflare-images';\nimport { CloudflareR2Provider } from '../providers/cloudflare-r2';\nimport { VercelBlobProvider } from '../providers/vercel-blob';\nimport {\n type ListOptions,\n type MultiStorageConfig,\n type StorageConfig,\n type StorageObject,\n type StorageProvider,\n type UploadOptions,\n} from '../types';\n\nexport class MultiStorageManager {\n private providers: Map<string, StorageProvider> = new Map();\n private defaultProvider: string;\n private routing: MultiStorageConfig['routing'];\n\n constructor(config: MultiStorageConfig) {\n // Initialize all providers\n for (const [name, providerConfig] of Object.entries(config.providers)) {\n this.providers.set(name, this.createProvider(providerConfig));\n }\n\n // Set default provider\n const firstProvider = Object.keys(config.providers)[0];\n this.defaultProvider = config.defaultProvider ?? firstProvider ?? '';\n if (!this.defaultProvider) {\n throw new Error('No storage providers configured');\n }\n\n this.routing = config.routing;\n }\n\n private createProvider(config: StorageConfig): StorageProvider {\n switch (config.provider) {\n case 'multi':\n throw new Error('Multi provider cannot be nested');\n\n case 'cloudflare-r2':\n if (!config.cloudflareR2) {\n throw new Error('Cloudflare R2 configuration is required');\n }\n // Handle array of R2 configs\n if (Array.isArray(config.cloudflareR2)) {\n if (config.cloudflareR2.length === 0) {\n throw new Error('No R2 configurations provided');\n }\n const firstR2Config = config.cloudflareR2[0];\n if (!firstR2Config) {\n throw new Error('First R2 configuration is undefined');\n }\n // Use first one for single provider (backward compatibility)\n return new CloudflareR2Provider(firstR2Config);\n }\n return new CloudflareR2Provider(config.cloudflareR2);\n\n case 'cloudflare-images':\n if (!config.cloudflareImages) {\n throw new Error('Cloudflare Images configuration is required');\n }\n return new CloudflareImagesProvider(config.cloudflareImages);\n\n case 'vercel-blob':\n if (!config.vercelBlob?.token) {\n throw new Error('Vercel Blob token is required');\n }\n return new VercelBlobProvider(config.vercelBlob.token);\n\n default:\n throw new Error(`Unknown storage provider: ${config.provider}`);\n }\n }\n\n private getProviderForKey(key: string): { provider: StorageProvider; providerName: string } {\n // Check routing rules\n if (this.routing) {\n // Check file type routing\n const extension = key.split('.').pop()?.toLowerCase();\n\n // Image routing\n if (this.routing.images && this.isImageFile(extension)) {\n const provider = this.providers.get(this.routing.images);\n if (provider) {\n return { provider, providerName: this.routing.images };\n }\n }\n\n // Document routing\n if (this.routing.documents && this.isDocumentFile(extension)) {\n const provider = this.providers.get(this.routing.documents);\n if (provider) {\n return { provider, providerName: this.routing.documents };\n }\n }\n\n // Custom routing rules\n for (const [pattern, providerName] of Object.entries(this.routing)) {\n if (pattern !== 'images' && pattern !== 'documents' && providerName) {\n // Simple pattern matching (could be enhanced with regex)\n if (key.includes(pattern)) {\n const provider = this.providers.get(providerName);\n if (provider) {\n return { provider, providerName };\n }\n }\n }\n }\n }\n\n // Fall back to default provider\n const provider = this.providers.get(this.defaultProvider);\n if (!provider) {\n throw new Error(`Default provider '${this.defaultProvider}' not found`);\n }\n\n return { provider, providerName: this.defaultProvider };\n }\n\n private isImageFile(extension?: string): boolean {\n const imageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'avif', 'svg', 'ico'];\n return extension ? imageExtensions.includes(extension) : false;\n }\n\n private isDocumentFile(extension?: string): boolean {\n const documentExtensions = ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt', 'csv'];\n return extension ? documentExtensions.includes(extension) : false;\n }\n\n // Get a specific provider by name\n getProvider(name: string): StorageProvider | undefined {\n return this.providers.get(name);\n }\n\n // Storage operations that route to appropriate provider\n async delete(key: string): Promise<void> {\n const { provider } = this.getProviderForKey(key);\n return provider.delete(key);\n }\n\n async download(key: string): Promise<Blob> {\n const { provider } = this.getProviderForKey(key);\n return provider.download(key);\n }\n\n async exists(key: string): Promise<boolean> {\n const { provider } = this.getProviderForKey(key);\n return provider.exists(key);\n }\n\n async getMetadata(key: string): Promise<StorageObject> {\n const { provider } = this.getProviderForKey(key);\n return provider.getMetadata(key);\n }\n\n async getUrl(key: string, options?: { expiresIn?: number }): Promise<string> {\n const { provider } = this.getProviderForKey(key);\n return provider.getUrl(key, options);\n }\n\n async list(options?: ListOptions & { provider?: string }): Promise<StorageObject[]> {\n // If specific provider requested, use it\n if (options?.provider) {\n const provider = this.providers.get(options.provider);\n if (!provider) {\n throw new Error(`Provider '${options.provider}' not found`);\n }\n return provider.list(options);\n }\n\n // Otherwise, list from all providers\n const allResults: StorageObject[] = [];\n for (const provider of this.providers.values()) {\n const results = await provider.list(options);\n allResults.push(...results);\n }\n return allResults;\n }\n\n async upload(\n key: string,\n data: ArrayBuffer | Blob | Buffer | File | ReadableStream,\n options?: UploadOptions & { provider?: string },\n ): Promise<StorageObject> {\n let provider: StorageProvider;\n\n // If specific provider requested, use it\n if (options?.provider) {\n const requestedProvider = this.providers.get(options.provider);\n if (!requestedProvider) {\n throw new Error(`Provider '${options.provider}' not found`);\n }\n provider = requestedProvider;\n } else {\n // Otherwise, use routing logic\n const { provider: routedProvider } = this.getProviderForKey(key);\n provider = routedProvider;\n }\n\n return provider.upload(key, data, options);\n }\n\n // Extended methods for Cloudflare Images\n async getCloudflareImagesProvider(): Promise<InstanceType<typeof CloudflareImagesProvider> | undefined> {\n for (const provider of this.providers.values()) {\n if (provider instanceof CloudflareImagesProvider) {\n return provider;\n }\n }\n return undefined;\n }\n\n // Get all provider names\n getProviderNames(): string[] {\n return Array.from(this.providers.keys());\n }\n}\n","/**\n * @fileoverview Unified Multipart Upload Manager\n *\n * Provides a consistent interface for multipart uploads across all storage providers.\n * Handles provider-specific differences and provides retry logic, progress tracking,\n * and error recovery.\n *\n * Features:\n * - Automatic part size calculation\n * - Concurrent part uploads\n * - Progress tracking\n * - Resume support\n * - Error recovery\n *\n * @module @repo/storage/multipart\n */\n\nimport { logWarn } from '@od-oneapp/shared/logs';\n\nimport {\n type MultipartUploadResult as BaseMultipartUploadResult,\n type MultipartUploadOptions,\n type StorageProvider,\n type UploadOptions,\n type UploadProgress,\n} from '../types';\n\nimport { MULTIPART_THRESHOLDS, PART_SIZES, STORAGE_CONSTANTS } from './constants';\n\nexport interface MultipartUploadState {\n uploadId: string;\n key: string;\n provider: string;\n parts: Array<{\n partNumber: number;\n etag?: string;\n size: number;\n uploaded: boolean;\n }>;\n totalSize: number;\n uploadedSize: number;\n completed: boolean;\n aborted: boolean;\n error?: string;\n}\n\n/**\n * Extended multipart upload result with detailed part information\n * Extends the base MultipartUploadResult from types.ts\n */\nexport interface MultipartUploadResult extends BaseMultipartUploadResult {\n parts: Array<{ partNumber: number; etag: string; size: number }>;\n totalParts: number;\n}\n\nexport class MultipartUploadManager {\n private provider: StorageProvider;\n private state: MultipartUploadState | null = null;\n private abortController: AbortController | null = null;\n\n constructor(provider: StorageProvider) {\n this.provider = provider;\n }\n\n /**\n * Check if provider supports multipart uploads\n */\n supportsMultipart(): boolean {\n const capabilities = this.provider.getCapabilities?.();\n return capabilities?.multipart ?? false;\n }\n\n /**\n * Create a new multipart upload\n *\n * @param key - Storage key\n * @param totalSize - Total file size in bytes\n * @param options - Upload options\n * @returns Upload state\n */\n async createUpload(\n key: string,\n totalSize: number,\n options: MultipartUploadOptions = {},\n ): Promise<MultipartUploadState> {\n if (!this.supportsMultipart()) {\n throw new Error('Provider does not support multipart uploads');\n }\n\n if (this.state && !this.state.completed && !this.state.aborted) {\n throw new Error('Upload already in progress. Abort current upload first.');\n }\n\n // Calculate optimal part size\n const partSize = this.calculatePartSize(totalSize, options.partSize);\n const totalParts = Math.ceil(totalSize / partSize);\n\n // Create multipart upload\n const uploadOptions: UploadOptions = {\n onProgress: options.onProgress\n ? (progress: UploadProgress) => {\n options.onProgress?.({\n key: progress.key,\n loaded: progress.loaded,\n total: progress.total,\n part: progress.part ?? 0,\n percentage: progress.percentage ?? 0,\n });\n }\n : undefined,\n };\n const result = await this.provider.createMultipartUpload?.(key, uploadOptions);\n\n if (!result) {\n throw new Error('Failed to create multipart upload');\n }\n\n // Initialize state\n this.state = {\n uploadId: result.uploadId,\n key: result.key,\n provider: this.getProviderName(),\n parts: Array.from({ length: totalParts }, (_, i) => ({\n partNumber: i + 1,\n size: i === totalParts - 1 ? totalSize - i * partSize : partSize,\n uploaded: false,\n })),\n totalSize,\n uploadedSize: 0,\n completed: false,\n aborted: false,\n };\n\n this.abortController = new AbortController();\n\n return this.state;\n }\n\n /**\n * Upload a part\n *\n * @param partNumber - Part number (1-based)\n * @param data - Part data\n * @param options - Upload options\n * @returns Upload result\n */\n async uploadPart(\n partNumber: number,\n data: ArrayBuffer | Blob | Buffer,\n options: UploadOptions = {},\n ): Promise<{ etag: string; partNumber: number; size: number }> {\n if (!this.state) {\n throw new Error('No active upload. Call createUpload first.');\n }\n\n if (this.state.completed || this.state.aborted) {\n throw new Error('Upload is completed or aborted');\n }\n\n const part = this.state.parts.find(p => p.partNumber === partNumber);\n if (!part) {\n throw new Error(`Part ${partNumber} not found`);\n }\n\n if (part.uploaded) {\n throw new Error(`Part ${partNumber} already uploaded`);\n }\n\n // Check abort signal\n if (this.abortController?.signal.aborted) {\n throw new Error('Upload aborted');\n }\n\n try {\n // Upload part with retry logic\n const result = await this.uploadPartWithRetry(partNumber, data, options);\n\n // Update state\n part.etag = result.etag;\n part.uploaded = true;\n this.state.uploadedSize += part.size;\n\n // Report progress\n if (options.onProgress) {\n options.onProgress({\n key: this.state.key,\n loaded: this.state.uploadedSize,\n total: this.state.totalSize,\n part: partNumber,\n percentage: (this.state.uploadedSize / this.state.totalSize) * 100,\n });\n }\n\n return result;\n } catch (error) {\n this.state.error = error instanceof Error ? error.message : String(error);\n throw error;\n }\n }\n\n /**\n * Complete the multipart upload\n *\n * @returns Final upload result\n */\n async completeUpload(): Promise<MultipartUploadResult> {\n if (!this.state) {\n throw new Error('No active upload. Call createUpload first.');\n }\n\n if (this.state.completed) {\n throw new Error('Upload already completed');\n }\n\n if (this.state.aborted) {\n throw new Error('Upload was aborted');\n }\n\n // Check if all parts are uploaded\n const unuploadedParts = this.state.parts.filter(p => !p.uploaded);\n if (unuploadedParts.length > 0) {\n throw new Error(`Upload incomplete: ${unuploadedParts.length} parts not uploaded`);\n }\n\n try {\n // Complete multipart upload\n const parts = this.state.parts\n .filter(p => p.etag)\n .map(p => ({ partNumber: p.partNumber, etag: p.etag ?? '' }))\n .filter(p => p.etag !== '');\n\n const result = await this.provider.completeMultipartUpload?.(this.state.uploadId, parts);\n\n if (!result) {\n throw new Error('Failed to complete multipart upload');\n }\n\n // Update state\n this.state.completed = true;\n\n return {\n ...result,\n key: result.key ?? this.state.key,\n uploadId: this.state.uploadId,\n parts: this.state.parts\n .filter(p => p.etag)\n .map(p => ({\n partNumber: p.partNumber,\n etag: p.etag ?? '',\n size: p.size,\n })),\n totalParts: this.state.parts.length,\n };\n } catch (error) {\n this.state.error = error instanceof Error ? error.message : String(error);\n throw error;\n }\n }\n\n /**\n * Abort the multipart upload\n */\n async abortUpload(): Promise<void> {\n if (!this.state) {\n return;\n }\n\n if (this.state.completed) {\n return;\n }\n\n // Signal abort\n this.abortController?.abort();\n this.state.aborted = true;\n\n try {\n // Abort on provider\n await this.provider.abortMultipartUpload?.(this.state.uploadId);\n } catch (error) {\n // Log error but don't throw - we want to clean up state\n\n // Use structured logging instead of console.warn\n logWarn('Failed to abort upload on provider', {\n error: error instanceof Error ? error.message : String(error),\n uploadId: this.state.uploadId,\n key: this.state.key,\n });\n }\n\n // Reset state\n this.state = null;\n this.abortController = null;\n }\n\n /**\n * Get current upload state\n */\n getState(): MultipartUploadState | null {\n return this.state;\n }\n\n /**\n * Resume upload from state (for recovery)\n *\n * @param state - Previous upload state\n */\n async resumeUpload(state: MultipartUploadState): Promise<void> {\n if (this.state && !this.state.completed && !this.state.aborted) {\n throw new Error('Upload already in progress');\n }\n\n this.state = { ...state };\n this.abortController = new AbortController();\n }\n\n /**\n * Upload file in chunks automatically\n *\n * @param key - Storage key\n * @param data - File data\n * @param options - Upload options\n * @returns Upload result\n */\n async uploadFile(\n key: string,\n data: ArrayBuffer | Blob | Buffer,\n options: MultipartUploadOptions = {},\n ): Promise<MultipartUploadResult> {\n const totalSize =\n data instanceof ArrayBuffer\n ? data.byteLength\n : data instanceof Buffer\n ? data.length\n : (data as Blob).size;\n\n // Create upload\n await this.createUpload(key, totalSize, options);\n\n const partSize = this.calculatePartSize(totalSize, options.partSize);\n const totalParts = Math.ceil(totalSize / partSize);\n\n // Upload parts\n for (let i = 0; i < totalParts; i++) {\n const start = i * partSize;\n const end = Math.min(start + partSize, totalSize);\n const partData = data.slice(start, end);\n\n await this.uploadPart(i + 1, partData, {\n onProgress: options.onProgress\n ? (progress: UploadProgress) => {\n options.onProgress?.({\n key: progress.key,\n loaded: progress.loaded,\n total: progress.total,\n part: progress.part ?? 0,\n percentage: progress.percentage ?? 0,\n });\n }\n : undefined,\n });\n }\n\n // Complete upload\n return await this.completeUpload();\n }\n\n private async uploadPartWithRetry(\n partNumber: number,\n data: ArrayBuffer | Blob | Buffer,\n options: UploadOptions,\n maxRetries: number = 3,\n ): Promise<{ etag: string; partNumber: number; size: number }> {\n let lastError: Error | null = null;\n\n for (let attempt = 1; attempt <= maxRetries; attempt++) {\n try {\n if (!this.state?.uploadId) {\n throw new Error('Upload ID not initialized');\n }\n\n const result = await this.provider.uploadPart?.(this.state.uploadId, partNumber, data, {\n ...options,\n abortSignal: this.abortController?.signal,\n });\n\n if (!result) {\n throw new Error('Failed to upload part');\n }\n\n return {\n etag: result.etag ?? '',\n partNumber: result.partNumber ?? partNumber,\n size:\n data instanceof ArrayBuffer\n ? data.byteLength\n : data instanceof Buffer\n ? data.length\n : (data as Blob).size,\n };\n } catch (error) {\n lastError = error instanceof Error ? error : new Error(String(error));\n\n // Don't retry on abort\n if (this.abortController?.signal.aborted) {\n throw lastError;\n }\n\n // Don't retry on validation errors\n if (lastError.message.includes('validation') || lastError.message.includes('invalid')) {\n throw lastError;\n }\n\n // Wait before retry (exponential backoff)\n if (attempt < maxRetries) {\n await new Promise(resolve =>\n setTimeout(resolve, Math.pow(2, attempt) * STORAGE_CONSTANTS.RETRY_BASE_DELAY_MS),\n );\n }\n }\n }\n\n throw lastError ?? new Error('Upload failed after retries');\n }\n\n private calculatePartSize(totalSize: number, userPartSize?: number): number {\n if (userPartSize) {\n return Math.min(userPartSize, totalSize);\n }\n\n // Use constants for part size thresholds\n if (totalSize < MULTIPART_THRESHOLDS.SMALL_FILE) {\n return PART_SIZES.SMALL;\n } else if (totalSize < MULTIPART_THRESHOLDS.MEDIUM_FILE) {\n return PART_SIZES.MEDIUM;\n } else {\n // Scale part size to ensure we never exceed 10,000 parts (S3/R2 limit)\n const maxParts = 9999; // Stay safely under 10,000 limit\n const minPartSize = Math.ceil(totalSize / maxParts);\n return Math.max(PART_SIZES.LARGE, minPartSize);\n }\n }\n\n private getProviderName(): string {\n return this.provider.constructor.name;\n }\n}\n\n/**\n * Create a multipart upload manager for a provider\n *\n * @param provider - Storage provider\n * @returns Multipart upload manager\n */\nexport function createMultipartUploadManager(provider: StorageProvider): MultipartUploadManager {\n if (!hasMultipartSupport(provider)) {\n throw new Error('The provided storage provider does not support multipart uploads');\n }\n return new MultipartUploadManager(provider);\n}\n\n/**\n * Determines whether the given storage provider supports multipart uploads.\n *\n * @param provider - The storage provider to check\n * @returns `true` if the provider supports multipart uploads, `false` otherwise.\n */\nexport function hasMultipartSupport(provider: StorageProvider): boolean {\n const capabilities = provider.getCapabilities?.();\n return capabilities?.multipart ?? false;\n}\n\n/**\n * Selects an appropriate multipart upload part size for a file.\n *\n * If `userPartSize` is provided, it will be capped at the file size; otherwise the part size\n * is chosen from configured thresholds for small, medium, or large files.\n *\n * @param fileSize - File size in bytes\n * @param userPartSize - Optional user-specified part size in bytes; capped to `fileSize` when provided\n * @returns The selected part size in bytes\n */\nexport function getOptimalPartSize(fileSize: number, userPartSize?: number): number {\n if (userPartSize) {\n return Math.min(userPartSize, fileSize);\n }\n\n if (fileSize < MULTIPART_THRESHOLDS.SMALL_FILE) {\n return PART_SIZES.SMALL;\n } else if (fileSize < MULTIPART_THRESHOLDS.MEDIUM_FILE) {\n return PART_SIZES.MEDIUM;\n } else {\n // Scale part size to ensure we never exceed 10,000 parts (S3/R2 limit)\n const maxParts = 9999; // Stay safely under 10,000 limit\n const minPartSize = Math.ceil(fileSize / maxParts);\n return Math.max(PART_SIZES.LARGE, minPartSize);\n }\n}\n","/**\n * @fileoverview Storage Provider Capabilities Utilities\n *\n * Provides utilities for checking storage provider capabilities and feature support.\n * Helps determine which features are available for each provider.\n *\n * @module @repo/storage/capabilities\n */\n\nimport { DEFAULT_STORAGE_CAPABILITIES, MULTIPART_THRESHOLDS } from './constants';\n\nimport type { StorageCapabilities, StorageProvider } from '../types';\n\n/**\n * Check if a storage provider has a specific capability\n * @param provider - The storage provider to check\n * @param capability - The capability to check for\n * @returns True if the provider supports the capability\n */\nexport function hasCapability(\n provider: StorageProvider,\n capability: keyof StorageCapabilities,\n): boolean {\n const capabilities = provider.getCapabilities?.();\n return capabilities?.[capability] ?? false;\n}\n\n/**\n * Check if a storage provider supports multiple capabilities\n * @param provider - The storage provider to check\n * @param capabilities - Array of capabilities to check for\n * @returns True if the provider supports all capabilities\n */\nexport function hasAllCapabilities(\n provider: StorageProvider,\n capabilities: Array<keyof StorageCapabilities>,\n): boolean {\n return capabilities.every(capability => hasCapability(provider, capability));\n}\n\n/**\n * Check if a storage provider supports any of the specified capabilities\n * @param provider - The storage provider to check\n * @param capabilities - Array of capabilities to check for\n * @returns True if the provider supports at least one capability\n */\nexport function hasAnyCapability(\n provider: StorageProvider,\n capabilities: Array<keyof StorageCapabilities>,\n): boolean {\n return capabilities.some(capability => hasCapability(provider, capability));\n}\n\n/**\n * Get all capabilities supported by a storage provider\n * @param provider - The storage provider to check\n * @returns Object with all capabilities and their support status\n */\nexport function getProviderCapabilities(provider: StorageProvider): StorageCapabilities {\n return provider.getCapabilities?.() ?? { ...DEFAULT_STORAGE_CAPABILITIES };\n}\n\n/**\n * Get a human-readable description of provider capabilities\n * @param provider - The storage provider to describe\n * @returns String describing the provider's capabilities\n */\nexport function describeProviderCapabilities(provider: StorageProvider): string {\n const capabilities = getProviderCapabilities(provider);\n const supportedFeatures: string[] = [];\n const unsupportedFeatures: string[] = [];\n\n if (capabilities.multipart) supportedFeatures.push('multipart uploads');\n else unsupportedFeatures.push('multipart uploads');\n\n if (capabilities.presignedUrls) supportedFeatures.push('presigned URLs');\n else unsupportedFeatures.push('presigned URLs');\n\n if (capabilities.progressTracking) supportedFeatures.push('progress tracking');\n else unsupportedFeatures.push('progress tracking');\n\n if (capabilities.abortSignal) supportedFeatures.push('abort signals');\n else unsupportedFeatures.push('abort signals');\n\n if (capabilities.metadata) supportedFeatures.push('metadata');\n else unsupportedFeatures.push('metadata');\n\n if (capabilities.customDomains) supportedFeatures.push('custom domains');\n else unsupportedFeatures.push('custom domains');\n\n if (capabilities.edgeCompatible) supportedFeatures.push('edge runtime');\n else unsupportedFeatures.push('edge runtime');\n\n let description = `Provider supports: ${supportedFeatures.join(', ')}`;\n\n if (unsupportedFeatures.length > 0) {\n description += `\\nProvider does not support: ${unsupportedFeatures.join(', ')}`;\n }\n\n return description;\n}\n\n/**\n * Validate that a provider supports the required capabilities for an operation\n * @param provider - The storage provider to validate\n * @param requiredCapabilities - Capabilities required for the operation\n * @throws Error if provider doesn't support required capabilities\n */\nexport function validateProviderCapabilities(\n provider: StorageProvider,\n requiredCapabilities: Array<keyof StorageCapabilities>,\n): void {\n const missingCapabilities = requiredCapabilities.filter(\n capability => !hasCapability(provider, capability),\n );\n\n if (missingCapabilities.length > 0) {\n const providerName = provider.constructor.name;\n throw new Error(\n `Provider ${providerName} does not support required capabilities: ${missingCapabilities.join(', ')}`,\n );\n }\n}\n\n/**\n * Get the best provider for a specific use case based on capabilities\n * @param providers - Array of storage providers to choose from\n * @param requiredCapabilities - Capabilities required for the use case\n * @returns The best provider or null if none meet the requirements\n */\nexport function getBestProvider(\n providers: StorageProvider[],\n requiredCapabilities: Array<keyof StorageCapabilities>,\n): StorageProvider | null {\n const suitableProviders = providers.filter(provider =>\n hasAllCapabilities(provider, requiredCapabilities),\n );\n\n if (suitableProviders.length === 0) {\n return null;\n }\n\n // If multiple providers are suitable, prefer edge-compatible ones\n const edgeCompatible = suitableProviders.filter(provider =>\n hasCapability(provider, 'edgeCompatible'),\n );\n\n return edgeCompatible.length > 0 ? (edgeCompatible[0] ?? null) : (suitableProviders[0] ?? null);\n}\n\n/**\n * Builds a map from provider names to their reported storage capabilities.\n *\n * @param providers - Array of entries each containing a `name` (used as the map key) and a `provider` instance\n * @returns A mapping from each provider name to its `StorageCapabilities`\n */\nexport function getCapabilityMatrix(\n providers: Array<{ name: string; provider: StorageProvider }>,\n): Record<string, StorageCapabilities> {\n const matrix: Record<string, StorageCapabilities> = {};\n\n for (const { name, provider } of providers) {\n matrix[name] = getProviderCapabilities(provider);\n }\n\n return matrix;\n}\n\n/**\n * Evaluate a storage provider's suitability for a specific file and produce actionable recommendations and warnings.\n *\n * @param provider - The storage provider to evaluate\n * @param fileSize - File size in bytes\n * @param fileType - MIME type of the file\n * @returns An object with `suitable` (`true` if there are no warnings, `false` otherwise), `recommendations` (suggested actions to improve handling), and `warnings` (issues that reduce suitability)\n */\nexport function checkProviderSuitability(\n provider: StorageProvider,\n fileSize: number,\n fileType: string,\n): {\n suitable: boolean;\n recommendations: string[];\n warnings: string[];\n} {\n const capabilities = getProviderCapabilities(provider);\n const recommendations: string[] = [];\n const warnings: string[] = [];\n\n // Check file size suitability\n if (fileSize > MULTIPART_THRESHOLDS.SMALL_FILE) {\n // > 100MB\n if (!capabilities.multipart) {\n warnings.push('Large file detected but provider does not support multipart uploads');\n } else {\n recommendations.push('Use multipart upload for this large file');\n }\n }\n\n // Check file type suitability\n if (fileType.startsWith('image/')) {\n if (capabilities.metadata) {\n recommendations.push('Consider storing image metadata for better organization');\n }\n }\n\n if (fileType.startsWith('video/')) {\n if (!capabilities.multipart) {\n warnings.push('Video files are typically large and benefit from multipart uploads');\n }\n }\n\n // Check edge compatibility\n if (fileType.startsWith('text/') && !capabilities.edgeCompatible) {\n recommendations.push('Text files could be processed in edge runtime for better performance');\n }\n\n const suitable = warnings.length === 0;\n\n return {\n suitable,\n recommendations,\n warnings,\n };\n}\n","/**\n * @fileoverview Health check utilities for storage providers\n *\n * Provides health check functionality to verify storage provider availability\n * and performance. Useful for monitoring and alerting.\n *\n * @module @repo/storage/health-check\n */\n\nimport type { StorageProvider } from '../types';\n\n/**\n * Health check result with status and metrics\n */\nexport interface HealthCheckResult {\n status: 'healthy' | 'degraded' | 'unhealthy';\n latencyMs: number;\n error?: string;\n details?: Record<string, unknown>;\n}\n\n/**\n * Check the health of a storage provider\n *\n * @param provider - The storage provider to check\n * @returns Health check result with status and latency\n */\nexport async function checkProviderHealth(provider: StorageProvider): Promise<HealthCheckResult> {\n const startTime = Date.now();\n\n try {\n // Perform a lightweight operation to check provider health\n // Using list with limit 1 as a health check probe\n await provider.list({ limit: 1 });\n\n const latencyMs = Date.now() - startTime;\n\n // Define health thresholds\n const HEALTHY_THRESHOLD_MS = 1000; // < 1s is healthy\n const DEGRADED_THRESHOLD_MS = 3000; // 1-3s is degraded\n\n let status: 'healthy' | 'degraded' | 'unhealthy';\n if (latencyMs < HEALTHY_THRESHOLD_MS) {\n status = 'healthy';\n } else if (latencyMs < DEGRADED_THRESHOLD_MS) {\n status = 'degraded';\n } else {\n status = 'unhealthy';\n }\n\n return {\n status,\n latencyMs,\n details: {\n provider: provider.constructor.name,\n threshold_healthy_ms: HEALTHY_THRESHOLD_MS,\n threshold_degraded_ms: DEGRADED_THRESHOLD_MS,\n },\n };\n } catch (error) {\n const latencyMs = Date.now() - startTime;\n return {\n status: 'unhealthy',\n latencyMs,\n error: error instanceof Error ? error.message : String(error),\n details: {\n provider: provider.constructor.name,\n },\n };\n }\n}\n\n/**\n * Perform a comprehensive health check on storage system\n *\n * @param provider - The storage provider to check\n * @returns Detailed health check result\n */\nexport async function storageHealthCheck(provider: StorageProvider): Promise<HealthCheckResult> {\n return checkProviderHealth(provider);\n}\n"],"mappings":"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"}