@arke-institute/sdk 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/dist/{index.d.mts → client-dAk3E64p.d.cts} +1 -7
  2. package/dist/client-dAk3E64p.d.ts +183 -0
  3. package/dist/{index.mjs → collections/index.cjs} +34 -5
  4. package/dist/collections/index.cjs.map +1 -0
  5. package/dist/collections/index.d.cts +9 -0
  6. package/dist/collections/index.d.ts +9 -1
  7. package/dist/collections/index.js +5 -32
  8. package/dist/collections/index.js.map +1 -1
  9. package/dist/content/index.cjs +506 -0
  10. package/dist/content/index.cjs.map +1 -0
  11. package/dist/content/index.d.cts +403 -0
  12. package/dist/content/index.d.ts +403 -0
  13. package/dist/content/index.js +473 -0
  14. package/dist/content/index.js.map +1 -0
  15. package/dist/edit/index.cjs +1029 -0
  16. package/dist/edit/index.cjs.map +1 -0
  17. package/dist/edit/index.d.cts +78 -0
  18. package/dist/edit/index.d.ts +78 -0
  19. package/dist/edit/index.js +983 -0
  20. package/dist/edit/index.js.map +1 -0
  21. package/dist/errors-3L7IiHcr.d.cts +480 -0
  22. package/dist/errors-B82BMmRP.d.cts +343 -0
  23. package/dist/errors-B82BMmRP.d.ts +343 -0
  24. package/dist/errors-BTe8GKRQ.d.ts +480 -0
  25. package/dist/graph/index.cjs +433 -0
  26. package/dist/graph/index.cjs.map +1 -0
  27. package/dist/graph/index.d.cts +456 -0
  28. package/dist/graph/index.d.ts +456 -0
  29. package/dist/graph/index.js +402 -0
  30. package/dist/graph/index.js.map +1 -0
  31. package/dist/index.cjs +3761 -0
  32. package/dist/index.cjs.map +1 -0
  33. package/dist/index.d.cts +7 -0
  34. package/dist/index.d.ts +7 -189
  35. package/dist/index.js +3502 -30
  36. package/dist/index.js.map +1 -1
  37. package/dist/query/index.cjs +289 -0
  38. package/dist/query/index.cjs.map +1 -0
  39. package/dist/query/index.d.cts +541 -0
  40. package/dist/query/index.d.ts +541 -0
  41. package/dist/query/index.js +261 -0
  42. package/dist/query/index.js.map +1 -0
  43. package/dist/upload/index.cjs +1634 -0
  44. package/dist/upload/index.cjs.map +1 -0
  45. package/dist/upload/index.d.cts +150 -0
  46. package/dist/upload/index.d.ts +150 -0
  47. package/dist/upload/index.js +1597 -0
  48. package/dist/upload/index.js.map +1 -0
  49. package/package.json +43 -8
  50. package/dist/collections/index.d.mts +0 -1
  51. package/dist/collections/index.mjs +0 -204
  52. package/dist/collections/index.mjs.map +0 -1
  53. package/dist/index.mjs.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/upload/utils/errors.ts","../../src/upload/platforms/common.ts","../../src/upload/lib/validation.ts","../../src/upload/utils/hash.ts","../../src/upload/types/processing.ts","../../src/upload/platforms/node.ts","../../src/upload/platforms/browser.ts","../../src/upload/lib/worker-client-fetch.ts","../../src/upload/utils/retry.ts","../../src/upload/uploader.ts","../../src/upload/lib/simple-fetch.ts","../../src/upload/lib/multipart-fetch.ts","../../src/collections/errors.ts","../../src/collections/client.ts","../../src/upload/client.ts","../../src/upload/index.ts"],"sourcesContent":["/**\n * Custom error classes for better error handling\n */\n\nexport class WorkerAPIError extends Error {\n constructor(\n message: string,\n public statusCode?: number,\n public details?: any\n ) {\n super(message);\n this.name = 'WorkerAPIError';\n Error.captureStackTrace(this, this.constructor);\n }\n}\n\nexport class UploadError extends Error {\n constructor(\n message: string,\n public fileName?: string,\n public statusCode?: number,\n public cause?: Error\n ) {\n super(message);\n this.name = 'UploadError';\n Error.captureStackTrace(this, this.constructor);\n }\n}\n\nexport class ValidationError extends Error {\n constructor(message: string, public field?: string) {\n super(message);\n this.name = 'ValidationError';\n Error.captureStackTrace(this, this.constructor);\n }\n}\n\nexport class NetworkError extends Error {\n constructor(message: string, public cause?: Error) {\n super(message);\n this.name = 'NetworkError';\n Error.captureStackTrace(this, this.constructor);\n }\n}\n\nexport class ScanError extends Error {\n constructor(message: string, public path?: string) {\n super(message);\n this.name = 'ScanError';\n Error.captureStackTrace(this, this.constructor);\n }\n}\n\n/**\n * Determine if an error is retryable\n */\nexport function isRetryableError(error: any): boolean {\n // Network errors are retryable\n if (error instanceof NetworkError) {\n return true;\n }\n\n // Worker API 5xx errors are retryable\n if (error instanceof WorkerAPIError) {\n return error.statusCode ? error.statusCode >= 500 : false;\n }\n\n // Upload errors with 5xx or 429 status codes are retryable\n if (error instanceof UploadError) {\n if (error.statusCode) {\n return error.statusCode >= 500 || error.statusCode === 429;\n }\n return false;\n }\n\n // Network-level errors (Node.js)\n if (error.code === 'ECONNRESET' ||\n error.code === 'ETIMEDOUT' ||\n error.code === 'ENOTFOUND' ||\n error.code === 'ECONNREFUSED') {\n return true;\n }\n\n return false;\n}\n","/**\n * Common platform types and utilities\n */\n\nimport type { FileInfo } from '../types/file.js';\nimport type { ProcessingConfig } from '../types/processing.js';\n\n/**\n * Platform-specific file source\n * Can be a path string (Node.js) or File object (Browser)\n */\nexport type FileSource = string | File;\n\n/**\n * Platform-specific scanner interface\n */\nexport interface PlatformScanner {\n /**\n * Scan files from the provided source\n * @param source - File source (path for Node.js, File[] for browser)\n * @param options - Scan options\n */\n scanFiles(\n source: FileSource | FileSource[],\n options: PlatformScanOptions\n ): Promise<FileInfo[]>;\n\n /**\n * Read file contents as ArrayBuffer\n * @param file - FileInfo with platform-specific localPath\n */\n readFile(file: FileInfo): Promise<ArrayBuffer>;\n}\n\n/**\n * Options for platform scanning\n */\nexport interface PlatformScanOptions {\n /**\n * Logical root path for the batch\n */\n rootPath: string;\n\n /**\n * Follow symbolic links (Node.js only)\n */\n followSymlinks?: boolean;\n\n /**\n * Default processing configuration\n */\n defaultProcessingConfig?: ProcessingConfig;\n}\n\n/**\n * Detect current runtime platform\n */\nexport function detectPlatform(): 'node' | 'browser' | 'unknown' {\n // Check for Node.js\n if (\n typeof process !== 'undefined' &&\n process.versions != null &&\n process.versions.node != null\n ) {\n return 'node';\n }\n\n // Check for browser\n if (typeof window !== 'undefined' && typeof document !== 'undefined') {\n return 'browser';\n }\n\n return 'unknown';\n}\n\n/**\n * Normalize path separators to forward slashes\n */\nexport function normalizePath(p: string): string {\n return p.replace(/\\\\/g, '/');\n}\n\n/**\n * Get file extension from filename\n */\nexport function getExtension(filename: string): string {\n const lastDot = filename.lastIndexOf('.');\n return lastDot === -1 ? '' : filename.slice(lastDot + 1).toLowerCase();\n}\n\n/**\n * Get MIME type from filename\n */\nexport function getMimeType(filename: string): string {\n const ext = getExtension(filename);\n\n // Basic MIME type mapping\n const mimeTypes: Record<string, string> = {\n // Images\n 'jpg': 'image/jpeg',\n 'jpeg': 'image/jpeg',\n 'png': 'image/png',\n 'gif': 'image/gif',\n 'webp': 'image/webp',\n 'tif': 'image/tiff',\n 'tiff': 'image/tiff',\n 'bmp': 'image/bmp',\n 'svg': 'image/svg+xml',\n\n // Documents\n 'pdf': 'application/pdf',\n 'txt': 'text/plain',\n 'json': 'application/json',\n 'xml': 'application/xml',\n 'html': 'text/html',\n 'htm': 'text/html',\n 'css': 'text/css',\n 'js': 'application/javascript',\n\n // Archives\n 'zip': 'application/zip',\n 'tar': 'application/x-tar',\n 'gz': 'application/gzip',\n\n // Audio\n 'mp3': 'audio/mpeg',\n 'wav': 'audio/wav',\n 'ogg': 'audio/ogg',\n\n // Video\n 'mp4': 'video/mp4',\n 'webm': 'video/webm',\n 'mov': 'video/quicktime',\n };\n\n return mimeTypes[ext] || 'application/octet-stream';\n}\n","/**\n * Validation utilities for paths, files, and configuration\n */\n\nimport { ValidationError } from '../utils/errors.js';\nimport type { CustomPrompts } from '../types/config.js';\n\n// Size limits per API spec\nconst MAX_FILE_SIZE = 5 * 1024 * 1024 * 1024; // 5 GB\nconst MAX_BATCH_SIZE = 100 * 1024 * 1024 * 1024; // 100 GB\n\n// Invalid path characters\nconst INVALID_PATH_CHARS = /[<>:\"|?*\\x00-\\x1f]/;\n\n// Image MIME types that will be processed by OCR\nconst OCR_PROCESSABLE_TYPES = [\n 'image/jpeg',\n 'image/png',\n 'image/webp',\n];\n\n/**\n * Get file extension (including the dot)\n */\nexport function getFileExtension(fileName: string): string {\n const match = fileName.match(/\\.[^.]+$/);\n return match ? match[0] : '';\n}\n\n/**\n * Validate file size\n */\nexport function validateFileSize(size: number): void {\n if (size <= 0) {\n throw new ValidationError('File size must be greater than 0');\n }\n if (size > MAX_FILE_SIZE) {\n throw new ValidationError(\n `File size (${formatBytes(size)}) exceeds maximum allowed size (${formatBytes(MAX_FILE_SIZE)})`\n );\n }\n}\n\n/**\n * Validate batch size\n */\nexport function validateBatchSize(totalSize: number): void {\n if (totalSize > MAX_BATCH_SIZE) {\n throw new ValidationError(\n `Total batch size (${formatBytes(totalSize)}) exceeds maximum allowed size (${formatBytes(MAX_BATCH_SIZE)})`\n );\n }\n}\n\n/**\n * Validate logical path format\n */\nexport function validateLogicalPath(path: string): void {\n // Must start with /\n if (!path.startsWith('/')) {\n throw new ValidationError('Logical path must start with /', 'path');\n }\n\n // No invalid characters\n if (INVALID_PATH_CHARS.test(path)) {\n throw new ValidationError(\n 'Logical path contains invalid characters',\n 'path'\n );\n }\n\n // Allow \"/\" as root path, otherwise require at least one segment\n const segments = path.split('/').filter((s) => s.length > 0);\n if (segments.length === 0 && path !== '/') {\n throw new ValidationError('Logical path cannot be empty', 'path');\n }\n\n // No . or .. segments (directory traversal)\n for (const segment of segments) {\n if (segment === '.' || segment === '..') {\n throw new ValidationError(\n 'Logical path cannot contain . or .. segments',\n 'path'\n );\n }\n }\n}\n\n/**\n * Validate worker URL\n */\nexport function validateWorkerUrl(url: string): void {\n try {\n const parsed = new URL(url);\n if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {\n throw new Error('Protocol must be http or https');\n }\n } catch (error: any) {\n throw new ValidationError(`Invalid worker URL: ${error.message}`, 'workerUrl');\n }\n}\n\n/**\n * Validate uploader name\n */\nexport function validateUploader(uploader: string): void {\n if (!uploader || uploader.trim().length === 0) {\n throw new ValidationError('Uploader name cannot be empty', 'uploader');\n }\n}\n\n/**\n * Validate parent PI format\n * Note: Existence validation happens at worker level\n */\nexport function validateParentPi(pi: string): void {\n // PI must be exactly 26 characters (ULID format)\n if (pi.length !== 26) {\n throw new ValidationError(\n 'parent_pi must be exactly 26 characters',\n 'parent_pi'\n );\n }\n\n // PI must be alphanumeric (case-insensitive)\n if (!/^[0-9A-Z]{26}$/i.test(pi)) {\n throw new ValidationError(\n 'parent_pi must contain only alphanumeric characters (0-9, A-Z)',\n 'parent_pi'\n );\n }\n}\n\n/**\n * Validate metadata JSON\n */\nexport function validateMetadata(metadata: string): Record<string, any> {\n try {\n const parsed = JSON.parse(metadata);\n if (typeof parsed !== 'object' || Array.isArray(parsed)) {\n throw new Error('Metadata must be a JSON object');\n }\n return parsed;\n } catch (error: any) {\n throw new ValidationError(`Invalid metadata JSON: ${error.message}`, 'metadata');\n }\n}\n\n/**\n * Validate .ref.json file content\n *\n * Required fields:\n * - url: Publicly accessible HTTP(S) URL to the referenced resource\n *\n * Optional fields:\n * - type: MIME type (e.g., 'image/jpeg', 'application/pdf')\n * - size: File size in bytes\n * - filename: Original filename for display\n * - ocr: Pre-existing OCR text (if already processed)\n *\n * Note: All other fields are allowed and will be passed through to the worker.\n */\nexport function validateRefJson(content: string, fileName: string, logger?: any): void {\n let parsed: any;\n\n // Parse JSON\n try {\n parsed = JSON.parse(content);\n } catch (error: any) {\n throw new ValidationError(\n `Invalid JSON in ${fileName}: ${error.message}`,\n 'ref'\n );\n }\n\n // Must be an object\n if (typeof parsed !== 'object' || Array.isArray(parsed) || parsed === null) {\n throw new ValidationError(\n `${fileName} must contain a JSON object`,\n 'ref'\n );\n }\n\n // Required field: url\n if (!parsed.url || typeof parsed.url !== 'string') {\n throw new ValidationError(\n `${fileName} must contain a 'url' field with a string value`,\n 'ref'\n );\n }\n\n // Validate URL format\n try {\n const url = new URL(parsed.url);\n if (url.protocol !== 'http:' && url.protocol !== 'https:') {\n throw new Error('URL must use HTTP or HTTPS protocol');\n }\n } catch (error: any) {\n throw new ValidationError(\n `Invalid URL in ${fileName}: ${error.message}`,\n 'ref'\n );\n }\n\n // Warn if type field is missing\n if (!parsed.type) {\n if (logger) {\n logger.warn(`${fileName}: Missing 'type' field (optional but recommended)`);\n }\n }\n\n // Warn if type is OCR-processable but extension not in filename\n if (parsed.type && OCR_PROCESSABLE_TYPES.includes(parsed.type)) {\n const typeToExt: { [key: string]: string } = {\n 'image/jpeg': '.jpg',\n 'image/png': '.png',\n 'image/webp': '.webp',\n };\n\n const expectedExt = typeToExt[parsed.type];\n if (expectedExt && !fileName.includes(`${expectedExt}.ref.json`)) {\n if (logger) {\n logger.warn(\n `${fileName}: Type is '${parsed.type}' but filename doesn't include '${expectedExt}.ref.json' pattern. ` +\n `This file may not be processed by OCR. Consider renaming to include the extension (e.g., 'photo${expectedExt}.ref.json').`\n );\n }\n }\n }\n}\n\n/**\n * Format bytes to human-readable string\n */\nexport function formatBytes(bytes: number): string {\n if (bytes === 0) return '0 B';\n\n const k = 1024;\n const sizes = ['B', 'KB', 'MB', 'GB', 'TB'];\n const i = Math.floor(Math.log(bytes) / Math.log(k));\n\n return `${(bytes / Math.pow(k, i)).toFixed(2)} ${sizes[i]}`;\n}\n\n/**\n * Normalize path to POSIX format (forward slashes)\n */\nexport function normalizePath(path: string): string {\n return path.replace(/\\\\/g, '/');\n}\n\n/**\n * Validate TIFF quality (for future preprocessor configuration)\n */\nexport function validateTiffQuality(quality: number): void {\n if (isNaN(quality) || quality < 1 || quality > 100) {\n throw new ValidationError(\n 'TIFF quality must be a number between 1 and 100',\n 'tiffQuality'\n );\n }\n}\n\n/**\n * Validate custom prompts\n */\nexport function validateCustomPrompts(prompts?: CustomPrompts): void {\n if (!prompts) return;\n\n const MAX_LENGTH = 50000; // 50KB per field - supports metadata file uploads\n const MAX_TOTAL_LENGTH = 75000; // 75KB total - stays under 128KB queue message limit\n const fields: Array<keyof CustomPrompts> = [\n 'general',\n 'reorganization',\n 'pinax',\n 'description',\n 'cheimarros',\n ];\n\n let totalLength = 0;\n\n for (const field of fields) {\n const value = prompts[field];\n if (value) {\n if (value.length > MAX_LENGTH) {\n throw new ValidationError(\n `Custom prompt '${field}' exceeds maximum length of ${MAX_LENGTH} characters (current: ${value.length})`,\n 'customPrompts'\n );\n }\n totalLength += value.length;\n }\n }\n\n if (totalLength > MAX_TOTAL_LENGTH) {\n throw new ValidationError(\n `Total custom prompts length (${totalLength}) exceeds maximum of ${MAX_TOTAL_LENGTH} characters`,\n 'customPrompts'\n );\n }\n}\n\n/**\n * Validate that customPrompts is not incorrectly placed in processing config\n */\nexport function validateCustomPromptsLocation(processingConfig?: any): void {\n if (!processingConfig) return;\n\n // Check if customPrompts was incorrectly placed inside processing config\n if ('customPrompts' in processingConfig) {\n throw new ValidationError(\n 'customPrompts must be a top-level field in UploaderConfig, not inside the processing config. ' +\n 'Use: new ArkeUploader({ customPrompts: {...}, processing: {...} }) ' +\n 'NOT: new ArkeUploader({ processing: { customPrompts: {...} } })',\n 'processing'\n );\n }\n}\n","/**\n * Hash and CID computation utilities\n */\n\nimport { CID } from 'multiformats/cid';\nimport * as raw from 'multiformats/codecs/raw';\nimport { sha256 } from 'multiformats/hashes/sha2';\n\n/**\n * Compute IPFS CID v1 for a file (Node.js only)\n * Uses raw codec and SHA-256 hash\n * Returns base32-encoded CID string\n */\nexport async function computeFileCID(filePath: string): Promise<string> {\n // Dynamic import to avoid bundling fs in browser builds\n const fs = await import('fs/promises');\n\n try {\n // Read file contents\n const fileBuffer = await fs.readFile(filePath);\n\n // Compute SHA-256 hash\n const hash = await sha256.digest(fileBuffer);\n\n // Create CID v1 with raw codec\n const cid = CID.create(1, raw.code, hash);\n\n // Return base32-encoded string (default for v1)\n return cid.toString();\n } catch (error: any) {\n throw new Error(`CID computation failed: ${error.message}`);\n }\n}\n\n/**\n * Compute CID for a buffer (works in all environments)\n */\nexport async function computeBufferCID(buffer: Buffer): Promise<string> {\n const hash = await sha256.digest(buffer);\n const cid = CID.create(1, raw.code, hash);\n return cid.toString();\n}\n\n/**\n * Compute CID from Uint8Array (browser-compatible)\n */\nexport async function computeCIDFromBuffer(data: Uint8Array): Promise<string> {\n const hash = await sha256.digest(data);\n const cid = CID.create(1, raw.code, hash);\n return cid.toString();\n}\n","/**\n * Processing configuration types for per-directory control\n */\n\n/**\n * Configuration for processing stages applied to files\n */\nexport interface ProcessingConfig {\n /** Enable OCR on eligible files */\n ocr: boolean;\n\n /** Enable description/summary generation */\n describe: boolean;\n\n /** Enable pinax metadata generation */\n pinax: boolean;\n}\n\n/**\n * Default processing configuration\n */\nexport const DEFAULT_PROCESSING_CONFIG: ProcessingConfig = {\n ocr: true,\n describe: true,\n pinax: true,\n};\n","/**\n * Node.js platform adapter for file scanning\n */\n\nimport fs from 'fs/promises';\nimport path from 'path';\nimport type { FileInfo } from '../types/file.js';\nimport { ScanError } from '../utils/errors.js';\nimport { validateFileSize, validateLogicalPath, validateRefJson } from '../lib/validation.js';\nimport { computeFileCID } from '../utils/hash.js';\nimport { DEFAULT_PROCESSING_CONFIG, type ProcessingConfig } from '../types/processing.js';\nimport type { PlatformScanner, PlatformScanOptions } from './common.js';\nimport { normalizePath, getMimeType } from './common.js';\n\n/**\n * Node.js file scanner implementation\n */\nexport class NodeScanner implements PlatformScanner {\n /**\n * Scan directory recursively and collect file metadata\n */\n async scanFiles(\n source: string | string[],\n options: PlatformScanOptions\n ): Promise<FileInfo[]> {\n const dirPath = Array.isArray(source) ? source[0] : source;\n\n if (!dirPath || typeof dirPath !== 'string') {\n throw new ScanError('Node.js scanner requires a directory path', '');\n }\n\n const files: FileInfo[] = [];\n\n // Validate directory exists\n try {\n const stats = await fs.stat(dirPath);\n if (!stats.isDirectory()) {\n throw new ScanError(`Path is not a directory: ${dirPath}`, dirPath);\n }\n } catch (error: any) {\n if (error.code === 'ENOENT') {\n throw new ScanError(`Directory not found: ${dirPath}`, dirPath);\n }\n throw new ScanError(`Cannot access directory: ${error.message}`, dirPath);\n }\n\n // Validate logical path\n validateLogicalPath(options.rootPath);\n\n const globalProcessingConfig = options.defaultProcessingConfig || DEFAULT_PROCESSING_CONFIG;\n\n /**\n * Load processing config from directory\n */\n async function loadDirectoryProcessingConfig(\n dirPath: string\n ): Promise<ProcessingConfig | null> {\n const configPath = path.join(dirPath, '.arke-process.json');\n try {\n const content = await fs.readFile(configPath, 'utf-8');\n return JSON.parse(content);\n } catch (error: any) {\n if (error.code !== 'ENOENT') {\n console.warn(`Error reading processing config ${configPath}: ${error.message}`);\n }\n return null;\n }\n }\n\n /**\n * Merge configs\n */\n function mergeProcessingConfig(\n defaults: ProcessingConfig,\n override: Partial<ProcessingConfig> | null\n ): ProcessingConfig {\n if (!override) return defaults;\n return {\n ocr: override.ocr ?? defaults.ocr,\n describe: override.describe ?? defaults.describe,\n pinax: override.pinax ?? defaults.pinax,\n };\n }\n\n /**\n * Recursive walker\n */\n async function walk(currentPath: string, relativePath: string = ''): Promise<void> {\n const dirConfigOverride = await loadDirectoryProcessingConfig(currentPath);\n const currentProcessingConfig = mergeProcessingConfig(\n globalProcessingConfig,\n dirConfigOverride\n );\n\n let entries;\n try {\n entries = await fs.readdir(currentPath, { withFileTypes: true });\n } catch (error: any) {\n console.warn(`Cannot read directory: ${currentPath}`, error.message);\n return;\n }\n\n for (const entry of entries) {\n const fullPath = path.join(currentPath, entry.name);\n const relPath = path.join(relativePath, entry.name);\n\n try {\n // Handle symlinks\n if (entry.isSymbolicLink()) {\n if (!options.followSymlinks) {\n continue;\n }\n\n const stats = await fs.stat(fullPath);\n if (stats.isDirectory()) {\n await walk(fullPath, relPath);\n } else if (stats.isFile()) {\n await processFile(fullPath, relPath, stats.size, currentProcessingConfig);\n }\n continue;\n }\n\n // Handle directories\n if (entry.isDirectory()) {\n await walk(fullPath, relPath);\n continue;\n }\n\n // Handle regular files\n if (entry.isFile()) {\n const stats = await fs.stat(fullPath);\n await processFile(fullPath, relPath, stats.size, currentProcessingConfig);\n }\n } catch (error: any) {\n if (error instanceof ScanError && error.message.includes('.ref.json')) {\n throw error;\n }\n console.warn(`Error processing ${fullPath}: ${error.message}`);\n continue;\n }\n }\n }\n\n /**\n * Process single file\n */\n async function processFile(\n fullPath: string,\n relativePath: string,\n size: number,\n processingConfig: ProcessingConfig\n ): Promise<void> {\n const fileName = path.basename(fullPath);\n\n // Skip processing config files\n if (fileName === '.arke-process.json') {\n return;\n }\n\n // Validate .ref.json files\n if (fileName.endsWith('.ref.json')) {\n try {\n const content = await fs.readFile(fullPath, 'utf-8');\n validateRefJson(content, fileName, console);\n } catch (error: any) {\n throw new ScanError(\n `Invalid .ref.json file: ${fileName} - ${error.message}`,\n fullPath\n );\n }\n }\n\n // Validate file size\n try {\n validateFileSize(size);\n } catch (error: any) {\n console.warn(`Skipping file that exceeds size limit: ${fileName}`, error.message);\n return;\n }\n\n // Construct logical path\n const normalizedRelPath = normalizePath(relativePath);\n const logicalPath = path.posix.join(options.rootPath, normalizedRelPath);\n\n // Validate logical path\n try {\n validateLogicalPath(logicalPath);\n } catch (error: any) {\n console.warn(`Skipping file with invalid logical path: ${logicalPath}`, error.message);\n return;\n }\n\n // Determine content type\n const contentType = getMimeType(fileName);\n\n // Check if file is readable\n try {\n await fs.access(fullPath, fs.constants.R_OK);\n } catch (error) {\n console.warn(`Skipping unreadable file: ${fullPath}`);\n return;\n }\n\n // Compute CID (optional - continue without if computation fails)\n let cid: string | undefined;\n try {\n cid = await computeFileCID(fullPath);\n } catch (error: any) {\n console.warn(`Warning: CID computation failed for ${fullPath}, continuing without CID:`, error.message);\n cid = undefined;\n }\n\n // Add to results\n files.push({\n localPath: fullPath,\n logicalPath,\n fileName,\n size,\n contentType,\n cid,\n processingConfig,\n });\n }\n\n // Start scan\n await walk(dirPath);\n\n // Sort by size (smallest first)\n files.sort((a, b) => a.size - b.size);\n\n return files;\n }\n\n /**\n * Read file contents as ArrayBuffer\n */\n async readFile(file: FileInfo): Promise<ArrayBuffer> {\n const buffer = await fs.readFile(file.localPath);\n return buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength);\n }\n}\n","/**\n * Browser platform adapter for file handling\n */\n\nimport type { FileInfo } from '../types/file.js';\nimport { ScanError } from '../utils/errors.js';\nimport { validateFileSize, validateLogicalPath } from '../lib/validation.js';\nimport { computeCIDFromBuffer } from '../utils/hash.js';\nimport { DEFAULT_PROCESSING_CONFIG } from '../types/processing.js';\nimport type { PlatformScanner, PlatformScanOptions } from './common.js';\nimport { normalizePath, getMimeType } from './common.js';\n\n/**\n * Browser file scanner implementation\n */\nexport class BrowserScanner implements PlatformScanner {\n /**\n * Scan files from File or FileList\n */\n async scanFiles(\n source: File | File[],\n options: PlatformScanOptions\n ): Promise<FileInfo[]> {\n const fileList = Array.isArray(source) ? source : [source];\n\n if (fileList.length === 0) {\n throw new ScanError('No files provided', '');\n }\n\n // Validate logical path\n validateLogicalPath(options.rootPath);\n\n const globalProcessingConfig = options.defaultProcessingConfig || DEFAULT_PROCESSING_CONFIG;\n const files: FileInfo[] = [];\n\n for (const file of fileList) {\n try {\n const fileInfo = await this.processFile(file, options.rootPath, globalProcessingConfig);\n if (fileInfo) {\n files.push(fileInfo);\n }\n } catch (error: any) {\n console.warn(`Error processing ${file.name}: ${error.message}`);\n continue;\n }\n }\n\n // Sort by size (smallest first)\n files.sort((a, b) => a.size - b.size);\n\n return files;\n }\n\n /**\n * Process a single File object\n */\n private async processFile(\n file: File,\n rootPath: string,\n processingConfig: any\n ): Promise<FileInfo | null> {\n const fileName = file.name;\n const size = file.size;\n\n // Skip hidden files (starting with .) - includes .DS_Store, .gitignore, etc.\n // These often have permission issues or are constantly modified by the OS\n if (fileName.startsWith('.')) {\n return null;\n }\n\n // Skip common system/temp files that shouldn't be uploaded\n const skipFiles = ['Thumbs.db', 'desktop.ini', '__MACOSX'];\n if (skipFiles.includes(fileName)) {\n return null;\n }\n\n // Skip processing config files\n if (fileName === '.arke-process.json') {\n return null;\n }\n\n // Validate file size\n try {\n validateFileSize(size);\n } catch (error: any) {\n console.warn(`Skipping file that exceeds size limit: ${fileName}`, error.message);\n return null;\n }\n\n // Extract relative path from file.webkitRelativePath or use just the filename\n let relativePath = '';\n if ('webkitRelativePath' in file && file.webkitRelativePath) {\n // For directory uploads, extract relative path\n const parts = file.webkitRelativePath.split('/');\n // Remove the first part (directory name) and join the rest\n if (parts.length > 1) {\n relativePath = parts.slice(1).join('/');\n } else {\n relativePath = fileName;\n }\n } else {\n relativePath = fileName;\n }\n\n // Construct logical path\n const normalizedRelPath = normalizePath(relativePath);\n const logicalPath = `${rootPath}/${normalizedRelPath}`.replace(/\\/+/g, '/');\n\n // Validate logical path\n try {\n validateLogicalPath(logicalPath);\n } catch (error: any) {\n console.warn(`Skipping file with invalid logical path: ${logicalPath}`, error.message);\n return null;\n }\n\n // Determine content type\n const contentType = file.type || getMimeType(fileName);\n\n // Compute CID (optional - continue without if computation fails)\n let cid: string | undefined;\n try {\n const buffer = await file.arrayBuffer();\n cid = await computeCIDFromBuffer(new Uint8Array(buffer));\n } catch (error: any) {\n console.warn(`Warning: CID computation failed for ${fileName}, continuing without CID:`, error.message);\n cid = undefined;\n }\n\n // For browser files, we store the File object itself as a special marker\n // The actual File object will be passed separately during upload\n return {\n localPath: `__browser_file__${fileName}`, // Special marker for browser files\n logicalPath,\n fileName,\n size,\n contentType,\n cid,\n processingConfig,\n };\n }\n\n /**\n * Read file contents as ArrayBuffer\n * Note: In browser context, the File object should be passed directly\n */\n async readFile(file: FileInfo): Promise<ArrayBuffer> {\n throw new Error('Browser scanner requires File objects to be provided directly during upload');\n }\n}\n","/**\n * API client for communicating with the Arke Ingest Worker (fetch-based)\n */\n\nimport type {\n InitBatchRequest,\n InitBatchResponse,\n StartFileUploadRequest,\n StartFileUploadResponse,\n CompleteFileUploadRequest,\n CompleteFileUploadResponse,\n FinalizeBatchResponse,\n BatchStatusResponse,\n ErrorResponse,\n} from '../types/api.js';\nimport { WorkerAPIError, NetworkError } from '../utils/errors.js';\nimport { retryWithBackoff } from '../utils/retry.js';\n\nexport interface WorkerClientConfig {\n baseUrl: string;\n authToken?: string;\n timeout?: number;\n maxRetries?: number;\n retryInitialDelay?: number;\n retryMaxDelay?: number;\n retryJitter?: boolean;\n debug?: boolean;\n}\n\nexport class WorkerClient {\n private baseUrl: string;\n private authToken?: string;\n private timeout: number;\n private maxRetries: number;\n private retryInitialDelay: number;\n private retryMaxDelay: number;\n private retryJitter: boolean;\n private debug: boolean;\n\n constructor(config: WorkerClientConfig) {\n this.baseUrl = config.baseUrl.replace(/\\/$/, '');\n this.authToken = config.authToken;\n this.timeout = config.timeout ?? 30000; // 30 seconds\n this.maxRetries = config.maxRetries ?? 3;\n this.retryInitialDelay = config.retryInitialDelay ?? 1000; // 1 second\n this.retryMaxDelay = config.retryMaxDelay ?? 30000; // 30 seconds\n this.retryJitter = config.retryJitter ?? true;\n this.debug = config.debug ?? false;\n }\n\n setAuthToken(token?: string) {\n this.authToken = token;\n }\n\n /**\n * Make HTTP request with fetch\n */\n private async request<T>(\n method: string,\n path: string,\n body?: unknown\n ): Promise<T> {\n const url = `${this.baseUrl}${path}`;\n\n if (this.debug) {\n console.log(`HTTP Request: ${method} ${url}`, body);\n }\n\n try {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\n\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n };\n if (this.authToken) {\n headers['Authorization'] = `Bearer ${this.authToken}`;\n }\n\n const response = await fetch(url, {\n method,\n headers,\n body: body ? JSON.stringify(body) : undefined,\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n const data = await response.json();\n\n if (this.debug) {\n console.log(`HTTP Response: ${response.status}`, data);\n }\n\n if (!response.ok) {\n const errorData = data as ErrorResponse;\n throw new WorkerAPIError(\n errorData.error || 'Request failed',\n response.status,\n errorData.details\n );\n }\n\n return data as T;\n } catch (error: any) {\n if (error instanceof WorkerAPIError) {\n throw error;\n }\n\n if (error.name === 'AbortError') {\n throw new NetworkError(`Request timeout after ${this.timeout}ms`);\n }\n\n throw new NetworkError(`Network request failed: ${error.message}`);\n }\n }\n\n /**\n * Initialize a new batch upload\n */\n async initBatch(params: InitBatchRequest): Promise<InitBatchResponse> {\n return retryWithBackoff(\n () => this.request<InitBatchResponse>('POST', '/ingest/batches/init', params),\n {\n maxRetries: this.maxRetries,\n initialDelay: this.retryInitialDelay,\n maxDelay: this.retryMaxDelay,\n jitter: this.retryJitter,\n }\n );\n }\n\n /**\n * Request presigned URLs for a file upload\n */\n async startFileUpload(\n batchId: string,\n params: StartFileUploadRequest\n ): Promise<StartFileUploadResponse> {\n return retryWithBackoff(\n () =>\n this.request<StartFileUploadResponse>(\n 'POST',\n `/ingest/batches/${batchId}/files/start`,\n params\n ),\n {\n maxRetries: this.maxRetries,\n initialDelay: this.retryInitialDelay,\n maxDelay: this.retryMaxDelay,\n jitter: this.retryJitter,\n }\n );\n }\n\n /**\n * Mark a file upload as complete\n */\n async completeFileUpload(\n batchId: string,\n params: CompleteFileUploadRequest\n ): Promise<CompleteFileUploadResponse> {\n return retryWithBackoff(\n () =>\n this.request<CompleteFileUploadResponse>(\n 'POST',\n `/ingest/batches/${batchId}/files/complete`,\n params\n ),\n {\n maxRetries: this.maxRetries,\n initialDelay: this.retryInitialDelay,\n maxDelay: this.retryMaxDelay,\n jitter: this.retryJitter,\n }\n );\n }\n\n /**\n * Finalize the batch after all files are uploaded\n * Returns root_pi immediately for small batches, or status='discovery' for large batches\n */\n async finalizeBatch(batchId: string): Promise<FinalizeBatchResponse> {\n return retryWithBackoff(\n () =>\n this.request<FinalizeBatchResponse>(\n 'POST',\n `/ingest/batches/${batchId}/finalize`,\n {}\n ),\n {\n maxRetries: this.maxRetries,\n initialDelay: this.retryInitialDelay,\n maxDelay: this.retryMaxDelay,\n jitter: this.retryJitter,\n }\n );\n }\n\n /**\n * Get current batch status (used for polling during async discovery)\n */\n async getBatchStatus(batchId: string): Promise<BatchStatusResponse> {\n return retryWithBackoff(\n () =>\n this.request<BatchStatusResponse>(\n 'GET',\n `/ingest/batches/${batchId}/status`\n ),\n {\n maxRetries: this.maxRetries,\n initialDelay: this.retryInitialDelay,\n maxDelay: this.retryMaxDelay,\n jitter: this.retryJitter,\n }\n );\n }\n}\n","/**\n * Retry logic with exponential backoff\n */\n\nimport { isRetryableError } from './errors.js';\n\nexport interface RetryOptions {\n maxRetries: number;\n initialDelay: number;\n maxDelay: number;\n shouldRetry?: (error: any) => boolean;\n jitter?: boolean; // Add randomization to prevent thundering herd\n}\n\nconst DEFAULT_OPTIONS: RetryOptions = {\n maxRetries: 3,\n initialDelay: 1000, // 1 second\n maxDelay: 30000, // 30 seconds\n shouldRetry: isRetryableError,\n jitter: true,\n};\n\n/**\n * Retry a function with exponential backoff\n */\nexport async function retryWithBackoff<T>(\n fn: () => Promise<T>,\n options: Partial<RetryOptions> = {}\n): Promise<T> {\n const opts = { ...DEFAULT_OPTIONS, ...options };\n\n let lastError: any;\n\n for (let attempt = 0; attempt <= opts.maxRetries; attempt++) {\n try {\n return await fn();\n } catch (error: any) {\n lastError = error;\n\n // Don't retry if we've exhausted attempts\n if (attempt >= opts.maxRetries) {\n throw error;\n }\n\n // Check if error is retryable\n if (opts.shouldRetry && !opts.shouldRetry(error)) {\n throw error;\n }\n\n // Handle 429 Rate Limit with Retry-After header\n let delay: number;\n if (error.statusCode === 429 && error.retryAfter) {\n // Use Retry-After header if present (in seconds)\n delay = Math.min(error.retryAfter * 1000, opts.maxDelay);\n } else {\n // Calculate delay with exponential backoff\n delay = Math.min(\n opts.initialDelay * Math.pow(2, attempt),\n opts.maxDelay\n );\n }\n\n // Add jitter to prevent thundering herd (±25% randomization)\n if (opts.jitter) {\n const jitterAmount = delay * 0.25;\n delay = delay + (Math.random() * jitterAmount * 2 - jitterAmount);\n }\n\n await sleep(Math.floor(delay));\n }\n }\n\n throw lastError;\n}\n\n/**\n * Sleep for a given number of milliseconds\n */\nexport function sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n","/**\n * Main ArkeUploader SDK class\n */\n\nimport type {\n UploaderConfig,\n UploadOptions,\n UploadProgress,\n BatchResult,\n} from './types/config.js';\nimport type { FileInfo } from './types/file.js';\nimport { WorkerClient } from './lib/worker-client-fetch.js';\nimport { detectPlatform, type PlatformScanner, type FileSource } from './platforms/common.js';\nimport { uploadSimple } from './lib/simple-fetch.js';\nimport { uploadMultipart } from './lib/multipart-fetch.js';\nimport { ValidationError } from './utils/errors.js';\nimport { validateBatchSize, validateCustomPrompts, validateCustomPromptsLocation } from './lib/validation.js';\n\nconst MULTIPART_THRESHOLD = 5 * 1024 * 1024; // 5 MB\n\n/**\n * Upload client for Arke Institute's ingest service\n * Works in Node.js, browsers, and other JavaScript runtimes\n */\nexport class ArkeUploader {\n private config: UploaderConfig;\n private workerClient: WorkerClient;\n private scanner: PlatformScanner | null = null;\n private platform: 'node' | 'browser' | 'unknown';\n\n constructor(config: UploaderConfig) {\n // Validate that customPrompts is not incorrectly placed in processing config\n validateCustomPromptsLocation(config.processing);\n\n this.config = {\n rootPath: '/uploads', // Must have at least one segment (not just '/')\n parallelUploads: 5,\n parallelParts: 3,\n ...config,\n };\n\n this.workerClient = new WorkerClient({\n baseUrl: config.gatewayUrl,\n authToken: config.authToken,\n timeout: config.timeout,\n maxRetries: config.maxRetries,\n retryInitialDelay: config.retryInitialDelay,\n retryMaxDelay: config.retryMaxDelay,\n retryJitter: config.retryJitter,\n debug: false,\n });\n\n this.platform = detectPlatform();\n }\n\n /**\n * Get platform-specific scanner\n */\n private async getScanner(): Promise<PlatformScanner> {\n if (this.scanner) {\n return this.scanner;\n }\n\n if (this.platform === 'node') {\n const { NodeScanner } = await import('./platforms/node.js');\n this.scanner = new NodeScanner();\n } else if (this.platform === 'browser') {\n const { BrowserScanner } = await import('./platforms/browser.js');\n this.scanner = new BrowserScanner();\n } else {\n throw new ValidationError('Unsupported platform');\n }\n\n return this.scanner;\n }\n\n /**\n * Upload a batch of files\n * @param source - Directory path (Node.js) or File[]/FileList (browser)\n * @param options - Upload options\n */\n async uploadBatch(\n source: FileSource | FileSource[],\n options: UploadOptions = {}\n ): Promise<BatchResult> {\n const startTime = Date.now();\n const { onProgress, dryRun = false } = options;\n\n // Phase 1: Scanning\n this.reportProgress(onProgress, {\n phase: 'scanning',\n filesTotal: 0,\n filesUploaded: 0,\n bytesTotal: 0,\n bytesUploaded: 0,\n percentComplete: 0,\n });\n\n const scanner = await this.getScanner();\n const files = await scanner.scanFiles(source, {\n rootPath: this.config.rootPath || '/',\n followSymlinks: true,\n defaultProcessingConfig: this.config.processing,\n });\n\n if (files.length === 0) {\n throw new ValidationError('No files found to upload');\n }\n\n const totalSize = files.reduce((sum, f) => sum + f.size, 0);\n validateBatchSize(totalSize);\n\n // Validate custom prompts if provided\n if (this.config.customPrompts) {\n validateCustomPrompts(this.config.customPrompts);\n\n // Log which custom prompts are being used\n const promptFields = Object.keys(this.config.customPrompts).filter(\n key => this.config.customPrompts![key as keyof typeof this.config.customPrompts]\n );\n console.log(`[Arke Upload SDK] Custom prompts configured: ${promptFields.join(', ')}`);\n }\n\n if (dryRun) {\n return {\n batchId: 'dry-run',\n rootPi: 'dry-run',\n filesUploaded: files.length,\n bytesUploaded: totalSize,\n durationMs: Date.now() - startTime,\n };\n }\n\n // Phase 2: Initialize batch\n const { batch_id } = await this.workerClient.initBatch({\n uploader: this.config.uploader,\n root_path: this.config.rootPath || '/',\n parent_pi: this.config.parentPi || '',\n metadata: this.config.metadata,\n file_count: files.length,\n total_size: totalSize,\n custom_prompts: this.config.customPrompts,\n });\n\n // Confirm custom prompts were sent\n if (this.config.customPrompts) {\n console.log(`[Arke Upload SDK] Custom prompts sent to worker for batch ${batch_id}`);\n }\n\n // Phase 3: Upload files\n this.reportProgress(onProgress, {\n phase: 'uploading',\n filesTotal: files.length,\n filesUploaded: 0,\n bytesTotal: totalSize,\n bytesUploaded: 0,\n percentComplete: 0,\n });\n\n let filesUploaded = 0;\n let bytesUploaded = 0;\n\n // Upload files with concurrency control\n const { failedFiles } = await this.uploadFilesWithConcurrency(\n batch_id,\n files,\n source,\n this.config.parallelUploads || 5,\n (file, bytes) => {\n filesUploaded++;\n bytesUploaded += bytes;\n\n this.reportProgress(onProgress, {\n phase: 'uploading',\n filesTotal: files.length,\n filesUploaded,\n bytesTotal: totalSize,\n bytesUploaded,\n currentFile: file.fileName,\n percentComplete: Math.round((bytesUploaded / totalSize) * 100),\n });\n }\n );\n\n // Check if all files failed\n if (failedFiles.length === files.length) {\n throw new ValidationError(\n `All ${files.length} files failed to upload. First error: ${failedFiles[0]?.error || 'Unknown'}`\n );\n }\n\n // Log warning if some files failed but continue with finalization\n if (failedFiles.length > 0) {\n console.warn(\n `Warning: ${failedFiles.length} of ${files.length} files failed to upload:`,\n failedFiles.map(f => `${f.file.fileName}: ${f.error}`).join(', ')\n );\n }\n\n // Phase 4: Finalize and get root_pi\n this.reportProgress(onProgress, {\n phase: 'finalizing',\n filesTotal: files.length,\n filesUploaded,\n bytesTotal: totalSize,\n bytesUploaded,\n percentComplete: 95,\n });\n\n const finalizeResult = await this.workerClient.finalizeBatch(batch_id);\n\n // Get root_pi - either immediately (sync discovery) or via polling (async discovery)\n let rootPi: string;\n\n if (finalizeResult.root_pi) {\n // Sync path - root_pi available immediately\n rootPi = finalizeResult.root_pi;\n } else if (finalizeResult.status === 'discovery') {\n // Async path - poll until discovery completes\n this.reportProgress(onProgress, {\n phase: 'discovery',\n filesTotal: files.length,\n filesUploaded,\n bytesTotal: totalSize,\n bytesUploaded,\n percentComplete: 97,\n });\n\n rootPi = await this.pollForRootPi(batch_id, onProgress, files.length, totalSize, bytesUploaded);\n } else {\n // Unexpected state - this shouldn't happen but handle gracefully\n throw new ValidationError(\n `Finalization returned unexpected status: ${finalizeResult.status} without root_pi`\n );\n }\n\n // Complete\n this.reportProgress(onProgress, {\n phase: 'complete',\n filesTotal: files.length,\n filesUploaded,\n bytesTotal: totalSize,\n bytesUploaded,\n percentComplete: 100,\n });\n\n return {\n batchId: batch_id,\n rootPi,\n filesUploaded,\n bytesUploaded,\n durationMs: Date.now() - startTime,\n };\n }\n\n /**\n * Poll for root_pi during async discovery\n */\n private async pollForRootPi(\n batchId: string,\n onProgress: ((progress: UploadProgress) => void) | undefined,\n filesTotal: number,\n bytesTotal: number,\n bytesUploaded: number\n ): Promise<string> {\n const POLL_INTERVAL_MS = 2000;\n const MAX_POLL_TIME_MS = 30 * 60 * 1000; // 30 minutes\n const startTime = Date.now();\n\n while (Date.now() - startTime < MAX_POLL_TIME_MS) {\n const status = await this.workerClient.getBatchStatus(batchId);\n\n if (status.root_pi) {\n return status.root_pi;\n }\n\n if (status.status === 'failed') {\n throw new ValidationError(`Batch discovery failed`);\n }\n\n // Report discovery progress if available\n if (status.discovery_progress && onProgress) {\n const { total, published } = status.discovery_progress;\n const discoveryPercent = total > 0 ? Math.round((published / total) * 100) : 0;\n this.reportProgress(onProgress, {\n phase: 'discovery',\n filesTotal,\n filesUploaded: filesTotal,\n bytesTotal,\n bytesUploaded,\n percentComplete: 95 + Math.round(discoveryPercent * 0.04), // 95-99%\n });\n }\n\n // Wait before polling again\n await new Promise(resolve => setTimeout(resolve, POLL_INTERVAL_MS));\n }\n\n throw new ValidationError(`Discovery timed out after ${MAX_POLL_TIME_MS / 1000} seconds`);\n }\n\n /**\n * Upload files with controlled concurrency\n */\n private async uploadFilesWithConcurrency(\n batchId: string,\n files: FileInfo[],\n source: FileSource | FileSource[],\n concurrency: number,\n onFileComplete: (file: FileInfo, bytes: number) => void\n ): Promise<{ failedFiles: Array<{ file: FileInfo; error: string }> }> {\n const queue = [...files];\n const workers: Promise<void>[] = [];\n const failedFiles: Array<{ file: FileInfo; error: string }> = [];\n\n const processNext = async () => {\n while (queue.length > 0) {\n const file = queue.shift()!;\n try {\n await this.uploadSingleFile(batchId, file, source);\n onFileComplete(file, file.size);\n } catch (error: any) {\n // Log the error but continue with other files\n const errorMessage = error.message || 'Unknown error';\n console.error(`Failed to upload ${file.fileName}: ${errorMessage}`);\n failedFiles.push({ file, error: errorMessage });\n // Don't re-throw - continue processing other files\n }\n }\n };\n\n // Start concurrent workers\n for (let i = 0; i < Math.min(concurrency, files.length); i++) {\n workers.push(processNext());\n }\n\n await Promise.all(workers);\n return { failedFiles };\n }\n\n /**\n * Upload a single file\n */\n private async uploadSingleFile(\n batchId: string,\n file: FileInfo,\n source: FileSource | FileSource[]\n ): Promise<void> {\n // Request presigned URL(s)\n const uploadInfo = await this.workerClient.startFileUpload(batchId, {\n file_name: file.fileName,\n file_size: file.size,\n logical_path: file.logicalPath,\n content_type: file.contentType,\n cid: file.cid,\n processing_config: file.processingConfig,\n });\n\n // Get file data\n const fileData = await this.getFileData(file, source);\n\n // Prepare retry options\n const retryOptions = {\n maxRetries: this.config.maxRetries,\n retryInitialDelay: this.config.retryInitialDelay,\n retryMaxDelay: this.config.retryMaxDelay,\n retryJitter: this.config.retryJitter,\n };\n\n // Upload to R2\n if (uploadInfo.upload_type === 'simple') {\n await uploadSimple(fileData, uploadInfo.presigned_url!, file.contentType, retryOptions);\n } else {\n // Multipart upload - map presigned URLs to array of URL strings\n const partUrls = uploadInfo.presigned_urls!.map((p) => p.url);\n const parts = await uploadMultipart(\n fileData,\n partUrls,\n this.config.parallelParts || 3,\n retryOptions\n );\n\n // Complete multipart upload\n await this.workerClient.completeFileUpload(batchId, {\n r2_key: uploadInfo.r2_key,\n upload_id: uploadInfo.upload_id!,\n parts,\n });\n\n return;\n }\n\n // Complete simple upload\n await this.workerClient.completeFileUpload(batchId, {\n r2_key: uploadInfo.r2_key,\n });\n }\n\n /**\n * Get file data based on platform\n */\n private async getFileData(\n file: FileInfo,\n source: FileSource | FileSource[]\n ): Promise<ArrayBuffer> {\n if (this.platform === 'node') {\n // Read from filesystem\n const fs = await import('fs/promises');\n const buffer = await fs.readFile(file.localPath);\n return buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength);\n } else if (this.platform === 'browser') {\n // Find the File object from source\n const files = Array.isArray(source) ? source : [source];\n const browserFile = files.find(\n (f) => f instanceof File && f.name === file.fileName\n ) as File | undefined;\n\n if (!browserFile) {\n throw new Error(`Could not find browser File object for ${file.fileName}`);\n }\n\n return browserFile.arrayBuffer();\n }\n\n throw new Error('Unsupported platform for file reading');\n }\n\n /**\n * Report progress to callback\n */\n private reportProgress(\n callback: ((progress: UploadProgress) => void) | undefined,\n progress: UploadProgress\n ): void {\n if (callback) {\n callback(progress);\n }\n }\n}\n","/**\n * Simple upload logic for files < 5 MB (fetch-based)\n */\n\nimport { UploadError } from '../utils/errors.js';\nimport { retryWithBackoff } from '../utils/retry.js';\n\nexport interface SimpleUploadOptions {\n maxRetries?: number;\n retryInitialDelay?: number;\n retryMaxDelay?: number;\n retryJitter?: boolean;\n}\n\n/**\n * Upload file data using simple PUT to presigned URL\n */\nexport async function uploadSimple(\n fileData: ArrayBuffer,\n presignedUrl: string,\n contentType?: string,\n options: SimpleUploadOptions = {}\n): Promise<void> {\n const { maxRetries = 3, retryInitialDelay, retryMaxDelay, retryJitter } = options;\n\n await retryWithBackoff(\n async () => {\n let response: Response;\n try {\n response = await fetch(presignedUrl, {\n method: 'PUT',\n body: fileData,\n headers: {\n ...(contentType ? { 'Content-Type': contentType } : {}),\n },\n });\n } catch (error: any) {\n // Network-level errors (connection refused, timeout, etc.)\n throw new UploadError(`Upload failed: ${error.message}`, undefined, undefined, error);\n }\n\n if (!response.ok) {\n // Extract Retry-After header for 429 responses\n const retryAfter = response.headers.get('retry-after');\n const error = new UploadError(\n `Upload failed with status ${response.status}: ${response.statusText}`,\n undefined,\n response.status\n );\n\n // Attach retry-after if present (convert to seconds)\n if (retryAfter && response.status === 429) {\n (error as any).retryAfter = parseInt(retryAfter, 10);\n }\n\n throw error;\n }\n },\n {\n maxRetries,\n initialDelay: retryInitialDelay,\n maxDelay: retryMaxDelay,\n jitter: retryJitter,\n }\n );\n}\n","/**\n * Multipart upload logic for files ≥ 5 MB (fetch-based)\n */\n\nimport type { PartInfo } from '../types/api.js';\nimport { UploadError } from '../utils/errors.js';\nimport { retryWithBackoff } from '../utils/retry.js';\n\nconst DEFAULT_PART_SIZE = 10 * 1024 * 1024; // 10 MB\n\nexport interface MultipartUploadOptions {\n maxRetries?: number;\n retryInitialDelay?: number;\n retryMaxDelay?: number;\n retryJitter?: boolean;\n}\n\n/**\n * Upload file data using multipart upload with presigned URLs\n * @param fileData - File data as ArrayBuffer\n * @param presignedUrls - Array of presigned URLs for each part\n * @param concurrency - Number of parts to upload in parallel\n * @param options - Upload retry options\n * @returns Array of PartInfo with ETags\n */\nexport async function uploadMultipart(\n fileData: ArrayBuffer,\n presignedUrls: string[],\n concurrency: number = 3,\n options: MultipartUploadOptions = {}\n): Promise<PartInfo[]> {\n const totalSize = fileData.byteLength;\n const partSize = Math.ceil(totalSize / presignedUrls.length);\n\n // Create upload tasks for each part\n const parts: PartInfo[] = [];\n const queue: Array<() => Promise<void>> = [];\n\n const { maxRetries = 3, retryInitialDelay, retryMaxDelay, retryJitter } = options;\n\n for (let i = 0; i < presignedUrls.length; i++) {\n const partNumber = i + 1;\n const start = i * partSize;\n const end = Math.min(start + partSize, totalSize);\n const partData = fileData.slice(start, end);\n const url = presignedUrls[i];\n\n queue.push(async () => {\n const etag = await uploadPart(partData, url, partNumber, maxRetries, {\n initialDelay: retryInitialDelay,\n maxDelay: retryMaxDelay,\n jitter: retryJitter,\n });\n parts.push({ part_number: partNumber, etag });\n });\n }\n\n // Execute uploads with concurrency control\n await executeWithConcurrency(queue, concurrency);\n\n // Sort parts by part number\n parts.sort((a, b) => a.part_number - b.part_number);\n\n return parts;\n}\n\n/**\n * Upload a single part\n */\nasync function uploadPart(\n partData: ArrayBuffer,\n presignedUrl: string,\n partNumber: number,\n maxRetries: number = 3,\n retryOptions: { initialDelay?: number; maxDelay?: number; jitter?: boolean } = {}\n): Promise<string> {\n return retryWithBackoff(\n async () => {\n let response: Response;\n try {\n response = await fetch(presignedUrl, {\n method: 'PUT',\n body: partData,\n });\n } catch (error: any) {\n // Network-level errors (connection refused, timeout, etc.)\n throw new UploadError(\n `Part ${partNumber} upload failed: ${error.message}`,\n undefined,\n undefined,\n error\n );\n }\n\n if (!response.ok) {\n // Extract Retry-After header for 429 responses\n const retryAfter = response.headers.get('retry-after');\n const error = new UploadError(\n `Part ${partNumber} upload failed with status ${response.status}: ${response.statusText}`,\n undefined,\n response.status\n );\n\n // Attach retry-after if present (convert to seconds)\n if (retryAfter && response.status === 429) {\n (error as any).retryAfter = parseInt(retryAfter, 10);\n }\n\n throw error;\n }\n\n // Get ETag from response headers\n const etag = response.headers.get('etag');\n if (!etag) {\n throw new UploadError(\n `Part ${partNumber} upload succeeded but no ETag returned`,\n undefined,\n response.status\n );\n }\n\n // Clean ETag (remove quotes if present)\n return etag.replace(/\"/g, '');\n },\n {\n maxRetries,\n initialDelay: retryOptions.initialDelay,\n maxDelay: retryOptions.maxDelay,\n jitter: retryOptions.jitter,\n }\n );\n}\n\n/**\n * Execute tasks with controlled concurrency\n */\nasync function executeWithConcurrency(\n tasks: Array<() => Promise<void>>,\n concurrency: number\n): Promise<void> {\n const queue = [...tasks];\n const workers: Promise<void>[] = [];\n\n const processNext = async () => {\n while (queue.length > 0) {\n const task = queue.shift()!;\n await task();\n }\n };\n\n // Start concurrent workers\n for (let i = 0; i < Math.min(concurrency, tasks.length); i++) {\n workers.push(processNext());\n }\n\n await Promise.all(workers);\n}\n","export class CollectionsError extends Error {\n constructor(\n message: string,\n public code: string = 'UNKNOWN_ERROR',\n public details?: unknown\n ) {\n super(message);\n this.name = 'CollectionsError';\n }\n}\n","import { CollectionsError } from './errors';\nimport type {\n ChangeRootPayload,\n ChangeRootResponse,\n Collection,\n CollectionDetails,\n CollectionRole,\n CreateCollectionPayload,\n Invitation,\n InvitationsResponse,\n Member,\n MembersResponse,\n MyAccessResponse,\n MyCollectionsResponse,\n PaginatedCollections,\n PiPermissions,\n RegisterRootPayload,\n RootResponse,\n SuccessResponse,\n UpdateCollectionPayload,\n} from './types';\n\nexport interface CollectionsClientConfig {\n /**\n * Gateway base URL (e.g., https://api.arke.institute).\n * Must already point at the Arke gateway that proxies /collections/*.\n */\n gatewayUrl: string;\n /**\n * Optional bearer token for authenticated routes.\n * Public routes will still include it if provided.\n */\n authToken?: string;\n /**\n * Optional custom fetch (useful for testing).\n */\n fetchImpl?: typeof fetch;\n}\n\ntype JsonBody = Record<string, unknown>;\n\nexport class CollectionsClient {\n private baseUrl: string;\n private authToken?: string;\n private fetchImpl: typeof fetch;\n\n constructor(config: CollectionsClientConfig) {\n this.baseUrl = config.gatewayUrl.replace(/\\/$/, '');\n this.authToken = config.authToken;\n this.fetchImpl = config.fetchImpl ?? fetch;\n }\n\n setAuthToken(token?: string) {\n this.authToken = token;\n }\n\n // ---------------------------------------------------------------------------\n // Request helpers\n // ---------------------------------------------------------------------------\n\n private buildUrl(path: string, query?: Record<string, string | number | undefined>) {\n const url = new URL(`${this.baseUrl}${path}`);\n if (query) {\n Object.entries(query).forEach(([key, value]) => {\n if (value !== undefined && value !== null) {\n url.searchParams.set(key, String(value));\n }\n });\n }\n return url.toString();\n }\n\n private getHeaders(authRequired: boolean): HeadersInit {\n const headers: HeadersInit = { 'Content-Type': 'application/json' };\n if (authRequired || this.authToken) {\n if (!this.authToken && authRequired) {\n throw new CollectionsError('Authentication required for this operation', 'AUTH_REQUIRED');\n }\n if (this.authToken) {\n headers['Authorization'] = `Bearer ${this.authToken}`;\n }\n }\n return headers;\n }\n\n private async request<T>(\n path: string,\n options: RequestInit & {\n authRequired?: boolean;\n query?: Record<string, string | number | undefined>;\n } = {}\n ): Promise<T> {\n const authRequired = options.authRequired ?? false;\n const url = this.buildUrl(path, options.query);\n const headers = new Headers(this.getHeaders(authRequired));\n if (options.headers) {\n Object.entries(options.headers).forEach(([k, v]) => {\n if (v !== undefined) headers.set(k, v as string);\n });\n }\n\n const response = await this.fetchImpl(url, { ...options, headers });\n\n if (response.ok) {\n if (response.status === 204) {\n return undefined as T;\n }\n const contentType = response.headers.get('content-type') || '';\n if (contentType.includes('application/json')) {\n return (await response.json()) as T;\n }\n return (await response.text()) as unknown as T;\n }\n\n let body: unknown;\n const text = await response.text();\n try {\n body = JSON.parse(text);\n } catch {\n body = text;\n }\n\n const message =\n (body as JsonBody)?.error && typeof (body as JsonBody).error === 'string'\n ? ((body as JsonBody).error as string)\n : `Request failed with status ${response.status}`;\n\n throw new CollectionsError(message, 'HTTP_ERROR', {\n status: response.status,\n body,\n });\n }\n\n // ---------------------------------------------------------------------------\n // Collections\n // ---------------------------------------------------------------------------\n\n async listCollections(params?: { limit?: number; offset?: number }): Promise<PaginatedCollections> {\n return this.request('/collections', {\n method: 'GET',\n query: { limit: params?.limit, offset: params?.offset },\n });\n }\n\n async getCollection(id: string): Promise<CollectionDetails> {\n return this.request(`/collections/${id}`, { method: 'GET' });\n }\n\n async getCollectionRoot(id: string): Promise<RootResponse> {\n return this.request(`/collections/${id}/root`, { method: 'GET' });\n }\n\n async getMyAccess(id: string): Promise<MyAccessResponse> {\n return this.request(`/collections/${id}/my-access`, { method: 'GET', authRequired: true });\n }\n\n async createCollection(payload: CreateCollectionPayload): Promise<Collection> {\n return this.request('/collections', {\n method: 'POST',\n authRequired: true,\n body: JSON.stringify(payload),\n });\n }\n\n async registerRoot(payload: RegisterRootPayload): Promise<Collection & { rootPi: string }> {\n return this.request('/collections/register-root', {\n method: 'POST',\n authRequired: true,\n body: JSON.stringify(payload),\n });\n }\n\n async updateCollection(id: string, payload: UpdateCollectionPayload): Promise<Collection> {\n return this.request(`/collections/${id}`, {\n method: 'PATCH',\n authRequired: true,\n body: JSON.stringify(payload),\n });\n }\n\n async changeRoot(id: string, payload: ChangeRootPayload): Promise<ChangeRootResponse> {\n return this.request(`/collections/${id}/change-root`, {\n method: 'PATCH',\n authRequired: true,\n body: JSON.stringify(payload),\n });\n }\n\n async deleteCollection(id: string): Promise<SuccessResponse> {\n return this.request(`/collections/${id}`, {\n method: 'DELETE',\n authRequired: true,\n });\n }\n\n // ---------------------------------------------------------------------------\n // Members\n // ---------------------------------------------------------------------------\n\n async listMembers(collectionId: string): Promise<MembersResponse> {\n return this.request(`/collections/${collectionId}/members`, { method: 'GET' });\n }\n\n async updateMemberRole(\n collectionId: string,\n userId: string,\n role: CollectionRole\n ): Promise<{ success: true; role: CollectionRole }> {\n return this.request(`/collections/${collectionId}/members/${userId}`, {\n method: 'PATCH',\n authRequired: true,\n body: JSON.stringify({ role }),\n });\n }\n\n async removeMember(collectionId: string, userId: string): Promise<SuccessResponse> {\n return this.request(`/collections/${collectionId}/members/${userId}`, {\n method: 'DELETE',\n authRequired: true,\n });\n }\n\n // ---------------------------------------------------------------------------\n // Invitations\n // ---------------------------------------------------------------------------\n\n async createInvitation(collectionId: string, email: string, role: CollectionRole): Promise<Invitation> {\n return this.request(`/collections/${collectionId}/invitations`, {\n method: 'POST',\n authRequired: true,\n body: JSON.stringify({ email, role }),\n });\n }\n\n async listInvitations(collectionId: string): Promise<InvitationsResponse> {\n return this.request(`/collections/${collectionId}/invitations`, {\n method: 'GET',\n authRequired: true,\n });\n }\n\n async acceptInvitation(invitationId: string): Promise<{ success: true; role: CollectionRole }> {\n return this.request(`/invitations/${invitationId}/accept`, {\n method: 'POST',\n authRequired: true,\n });\n }\n\n async declineInvitation(invitationId: string): Promise<SuccessResponse> {\n return this.request(`/invitations/${invitationId}/decline`, {\n method: 'POST',\n authRequired: true,\n });\n }\n\n async revokeInvitation(invitationId: string): Promise<SuccessResponse> {\n return this.request(`/invitations/${invitationId}`, {\n method: 'DELETE',\n authRequired: true,\n });\n }\n\n // ---------------------------------------------------------------------------\n // Current user\n // ---------------------------------------------------------------------------\n\n async getMyCollections(): Promise<MyCollectionsResponse> {\n return this.request('/me/collections', { method: 'GET', authRequired: true });\n }\n\n async getMyInvitations(): Promise<InvitationsResponse> {\n return this.request('/me/invitations', { method: 'GET', authRequired: true });\n }\n\n // ---------------------------------------------------------------------------\n // PI permissions\n // ---------------------------------------------------------------------------\n\n async getPiPermissions(pi: string): Promise<PiPermissions> {\n return this.request(`/pi/${pi}/permissions`, { method: 'GET' });\n }\n}\n","/**\n * Upload Client with Collections Integration\n * Provides high-level upload operations with permission checks\n */\n\nimport type {\n UploaderConfig,\n UploadOptions,\n UploadProgress,\n BatchResult,\n CustomPrompts,\n} from './types/config';\nimport type { ProcessingConfig } from './types/processing';\nimport { ArkeUploader } from './uploader';\nimport { CollectionsClient, type CollectionsClientConfig } from '../collections/client';\nimport type { CreateCollectionPayload, Collection, PiPermissions } from '../collections/types';\n\nexport interface UploadClientConfig {\n /**\n * Gateway base URL (e.g., https://api.arke.institute)\n */\n gatewayUrl: string;\n /**\n * Bearer token for authentication\n */\n authToken: string;\n /**\n * Name of person/service uploading files (defaults to user ID from JWT)\n */\n uploader?: string;\n /**\n * Custom fetch implementation (optional, for testing)\n */\n fetchImpl?: typeof fetch;\n}\n\n/**\n * Extract user ID from JWT token (without verification)\n */\nfunction getUserIdFromToken(token: string): string | null {\n try {\n const parts = token.split('.');\n if (parts.length !== 3) return null;\n\n // Decode base64url payload\n const payload = parts[1]\n .replace(/-/g, '+')\n .replace(/_/g, '/');\n\n // Handle browser vs Node.js\n let decoded: string;\n if (typeof atob === 'function') {\n decoded = atob(payload);\n } else {\n decoded = Buffer.from(payload, 'base64').toString('utf-8');\n }\n\n const data = JSON.parse(decoded);\n return data.sub || null;\n } catch {\n return null;\n }\n}\n\nexport interface CreateCollectionUploadOptions {\n /**\n * Files to upload - directory path (Node.js) or File[]/FileList (browser)\n */\n files: string | File[] | FileList;\n /**\n * Collection metadata\n */\n collectionMetadata: CreateCollectionPayload;\n /**\n * Custom prompts for AI processing\n */\n customPrompts?: CustomPrompts;\n /**\n * Processing options (OCR, IIIF, etc.)\n */\n processing?: ProcessingConfig;\n /**\n * Progress callback\n */\n onProgress?: (progress: UploadProgress) => void;\n /**\n * Dry run mode\n */\n dryRun?: boolean;\n}\n\nexport interface AddToCollectionOptions {\n /**\n * Files to upload - directory path (Node.js) or File[]/FileList (browser)\n */\n files: string | File[] | FileList;\n /**\n * Parent PI to add files under (must be within a collection you can edit)\n */\n parentPi: string;\n /**\n * Custom prompts for AI processing\n */\n customPrompts?: CustomPrompts;\n /**\n * Processing options (OCR, IIIF, etc.)\n */\n processing?: ProcessingConfig;\n /**\n * Progress callback\n */\n onProgress?: (progress: UploadProgress) => void;\n /**\n * Dry run mode\n */\n dryRun?: boolean;\n}\n\nexport interface CreateCollectionUploadResult extends BatchResult {\n /**\n * The created collection\n */\n collection: Collection & { rootPi: string };\n}\n\n/**\n * High-level upload client with collections integration\n *\n * @example\n * ```typescript\n * import { UploadClient } from '@arke-institute/sdk';\n *\n * const client = new UploadClient({\n * gatewayUrl: 'https://api.arke.institute',\n * authToken: 'your-jwt-token',\n * uploader: 'my-app',\n * });\n *\n * // Create a new collection from files\n * const result = await client.createCollection({\n * files: './photos',\n * collectionMetadata: { title: 'My Archive', slug: 'my-archive' },\n * });\n *\n * // Add files to an existing collection\n * await client.addToCollection({\n * files: './more-photos',\n * parentPi: result.collection.rootPi,\n * });\n * ```\n */\nexport class UploadClient {\n private config: UploadClientConfig & { uploader: string };\n private collectionsClient: CollectionsClient;\n\n constructor(config: UploadClientConfig) {\n // Default uploader to user ID from JWT if not provided\n const uploader = config.uploader || getUserIdFromToken(config.authToken) || 'unknown';\n\n this.config = { ...config, uploader };\n this.collectionsClient = new CollectionsClient({\n gatewayUrl: config.gatewayUrl,\n authToken: config.authToken,\n fetchImpl: config.fetchImpl,\n });\n }\n\n /**\n * Update the auth token (e.g., after token refresh)\n */\n setAuthToken(token: string) {\n this.config = { ...this.config, authToken: token };\n this.collectionsClient.setAuthToken(token);\n }\n\n /**\n * Create a new collection and upload files to it\n *\n * Anyone authenticated can create a new collection.\n * The root PI of the uploaded files becomes the collection's root.\n */\n async createCollection(\n options: CreateCollectionUploadOptions\n ): Promise<CreateCollectionUploadResult> {\n const { files, collectionMetadata, customPrompts, processing, onProgress, dryRun } = options;\n\n // Default visibility to 'public' if not specified\n const metadata = {\n ...collectionMetadata,\n visibility: collectionMetadata.visibility || 'public',\n };\n\n // Create uploader for the batch\n const uploader = new ArkeUploader({\n gatewayUrl: this.config.gatewayUrl,\n authToken: this.config.authToken,\n uploader: this.config.uploader,\n customPrompts,\n processing,\n });\n\n // Upload the files first\n const batchResult = await uploader.uploadBatch(files as any, {\n onProgress,\n dryRun,\n });\n\n if (dryRun) {\n return {\n ...batchResult,\n collection: {\n id: 'dry-run',\n title: metadata.title,\n slug: metadata.slug,\n description: metadata.description,\n visibility: metadata.visibility,\n rootPi: 'dry-run',\n },\n };\n }\n\n // Register the root PI as a collection\n // The uploader returns the real rootPi after discovery completes\n const collection = await this.collectionsClient.registerRoot({\n ...metadata,\n rootPi: batchResult.rootPi,\n });\n\n return {\n ...batchResult,\n collection,\n };\n }\n\n /**\n * Add files to an existing collection\n *\n * Requires owner or editor role on the collection containing the parent PI.\n * Use this to add a folder or files to an existing collection hierarchy.\n *\n * Note: Permission checks are enforced server-side by the ingest worker.\n * The server will return 403 if the user lacks edit access to the parent PI.\n */\n async addToCollection(options: AddToCollectionOptions): Promise<BatchResult> {\n const { files, parentPi, customPrompts, processing, onProgress, dryRun } = options;\n\n // Create uploader with the parent PI\n const uploader = new ArkeUploader({\n gatewayUrl: this.config.gatewayUrl,\n authToken: this.config.authToken,\n uploader: this.config.uploader,\n parentPi,\n customPrompts,\n processing,\n });\n\n // Upload the files\n return uploader.uploadBatch(files as any, {\n onProgress,\n dryRun,\n });\n }\n\n /**\n * Check if you can edit a specific PI (i.e., add files to its collection)\n */\n async canEdit(pi: string): Promise<PiPermissions> {\n return this.collectionsClient.getPiPermissions(pi);\n }\n\n /**\n * Get access to the underlying collections client for other operations\n */\n get collections(): CollectionsClient {\n return this.collectionsClient;\n }\n}\n","/**\n * Arke Upload SDK\n * Upload client with collections integration for Arke Institute's ingest service\n */\n\n// Main client class (recommended)\nexport {\n UploadClient,\n type UploadClientConfig,\n type CreateCollectionUploadOptions,\n type AddToCollectionOptions,\n type CreateCollectionUploadResult,\n} from './client';\n\n// Low-level uploader (for advanced use)\nexport { ArkeUploader } from './uploader';\n\n// Type exports\nexport type {\n // Config types\n UploaderConfig,\n UploadOptions,\n UploadProgress,\n BatchResult,\n CustomPrompts,\n\n // Worker API types\n InitBatchRequest,\n InitBatchResponse,\n StartFileUploadRequest,\n StartFileUploadResponse,\n PresignedUrlInfo,\n PartInfo,\n CompleteFileUploadRequest,\n CompleteFileUploadResponse,\n FinalizeBatchResponse,\n\n // Batch types\n BatchContext,\n UploadConfig,\n CheckpointData,\n\n // File types\n FileInfo,\n ScanResult,\n UploadTask,\n\n // Processing types\n ProcessingConfig,\n} from './types/index';\n\n// Error classes\nexport {\n ValidationError,\n ScanError,\n WorkerAPIError,\n NetworkError,\n UploadError,\n} from './utils/errors';\n"],"mappings":"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","names":["path","path","fs","dirPath","path","NodeScanner","BrowserScanner","fs","code","path"]}
package/package.json CHANGED
@@ -1,20 +1,46 @@
1
1
  {
2
2
  "name": "@arke-institute/sdk",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
+ "type": "module",
4
5
  "description": "TypeScript SDK for building applications on the Arke platform",
5
- "main": "dist/index.js",
6
- "module": "dist/index.mjs",
6
+ "main": "dist/index.cjs",
7
+ "module": "dist/index.js",
7
8
  "types": "dist/index.d.ts",
8
9
  "exports": {
9
10
  ".": {
10
11
  "types": "./dist/index.d.ts",
11
- "import": "./dist/index.mjs",
12
- "require": "./dist/index.js"
12
+ "import": "./dist/index.js",
13
+ "require": "./dist/index.cjs"
13
14
  },
14
15
  "./collections": {
15
16
  "types": "./dist/collections/index.d.ts",
16
- "import": "./dist/collections/index.mjs",
17
- "require": "./dist/collections/index.js"
17
+ "import": "./dist/collections/index.js",
18
+ "require": "./dist/collections/index.cjs"
19
+ },
20
+ "./upload": {
21
+ "types": "./dist/upload/index.d.ts",
22
+ "import": "./dist/upload/index.js",
23
+ "require": "./dist/upload/index.cjs"
24
+ },
25
+ "./query": {
26
+ "types": "./dist/query/index.d.ts",
27
+ "import": "./dist/query/index.js",
28
+ "require": "./dist/query/index.cjs"
29
+ },
30
+ "./edit": {
31
+ "types": "./dist/edit/index.d.ts",
32
+ "import": "./dist/edit/index.js",
33
+ "require": "./dist/edit/index.cjs"
34
+ },
35
+ "./content": {
36
+ "types": "./dist/content/index.d.ts",
37
+ "import": "./dist/content/index.js",
38
+ "require": "./dist/content/index.cjs"
39
+ },
40
+ "./graph": {
41
+ "types": "./dist/graph/index.d.ts",
42
+ "import": "./dist/graph/index.js",
43
+ "require": "./dist/graph/index.cjs"
18
44
  }
19
45
  },
20
46
  "files": [
@@ -28,8 +54,13 @@
28
54
  "clean": "rm -rf dist",
29
55
  "prepublishOnly": "npm run build"
30
56
  },
31
- "dependencies": {},
57
+ "dependencies": {
58
+ "diff": "^7.0.0",
59
+ "multiformats": "^13.4.1"
60
+ },
32
61
  "devDependencies": {
62
+ "@types/diff": "^7.0.0",
63
+ "@types/node": "^20.10.0",
33
64
  "tsup": "^8.0.0",
34
65
  "typescript": "^5.3.0",
35
66
  "vitest": "^1.0.0"
@@ -38,6 +69,10 @@
38
69
  "arke",
39
70
  "sdk",
40
71
  "collections",
72
+ "upload",
73
+ "query",
74
+ "edit",
75
+ "knowledge-graph",
41
76
  "content",
42
77
  "typescript"
43
78
  ],
@@ -1 +0,0 @@
1
- export { ChangeRootPayload, ChangeRootResponse, Collection, CollectionDetails, CollectionRole, CollectionVisibility, CollectionsClient, CollectionsClientConfig, CollectionsError, CreateCollectionPayload, Invitation, InvitationsResponse, Member, MembersResponse, MyAccessResponse, MyCollectionsResponse, PaginatedCollections, PiPermissions, RegisterRootPayload, RootResponse, SuccessResponse, UpdateCollectionPayload } from '../index.mjs';
@@ -1,204 +0,0 @@
1
- // src/collections/errors.ts
2
- var CollectionsError = class extends Error {
3
- constructor(message, code = "UNKNOWN_ERROR", details) {
4
- super(message);
5
- this.code = code;
6
- this.details = details;
7
- this.name = "CollectionsError";
8
- }
9
- };
10
-
11
- // src/collections/client.ts
12
- var CollectionsClient = class {
13
- constructor(config) {
14
- this.baseUrl = config.gatewayUrl.replace(/\/$/, "");
15
- this.authToken = config.authToken;
16
- this.fetchImpl = config.fetchImpl ?? fetch;
17
- }
18
- setAuthToken(token) {
19
- this.authToken = token;
20
- }
21
- // ---------------------------------------------------------------------------
22
- // Request helpers
23
- // ---------------------------------------------------------------------------
24
- buildUrl(path, query) {
25
- const url = new URL(`${this.baseUrl}${path}`);
26
- if (query) {
27
- Object.entries(query).forEach(([key, value]) => {
28
- if (value !== void 0 && value !== null) {
29
- url.searchParams.set(key, String(value));
30
- }
31
- });
32
- }
33
- return url.toString();
34
- }
35
- getHeaders(authRequired) {
36
- const headers = { "Content-Type": "application/json" };
37
- if (authRequired || this.authToken) {
38
- if (!this.authToken && authRequired) {
39
- throw new CollectionsError("Authentication required for this operation", "AUTH_REQUIRED");
40
- }
41
- if (this.authToken) {
42
- headers["Authorization"] = `Bearer ${this.authToken}`;
43
- }
44
- }
45
- return headers;
46
- }
47
- async request(path, options = {}) {
48
- const authRequired = options.authRequired ?? false;
49
- const url = this.buildUrl(path, options.query);
50
- const headers = new Headers(this.getHeaders(authRequired));
51
- if (options.headers) {
52
- Object.entries(options.headers).forEach(([k, v]) => {
53
- if (v !== void 0) headers.set(k, v);
54
- });
55
- }
56
- const response = await this.fetchImpl(url, { ...options, headers });
57
- if (response.ok) {
58
- if (response.status === 204) {
59
- return void 0;
60
- }
61
- const contentType = response.headers.get("content-type") || "";
62
- if (contentType.includes("application/json")) {
63
- return await response.json();
64
- }
65
- return await response.text();
66
- }
67
- let body;
68
- try {
69
- body = await response.json();
70
- } catch {
71
- body = await response.text();
72
- }
73
- const message = body?.error && typeof body.error === "string" ? body.error : `Request failed with status ${response.status}`;
74
- throw new CollectionsError(message, "HTTP_ERROR", {
75
- status: response.status,
76
- body
77
- });
78
- }
79
- // ---------------------------------------------------------------------------
80
- // Collections
81
- // ---------------------------------------------------------------------------
82
- async listCollections(params) {
83
- return this.request("/collections", {
84
- method: "GET",
85
- query: { limit: params?.limit, offset: params?.offset }
86
- });
87
- }
88
- async getCollection(id) {
89
- return this.request(`/collections/${id}`, { method: "GET" });
90
- }
91
- async getCollectionRoot(id) {
92
- return this.request(`/collections/${id}/root`, { method: "GET" });
93
- }
94
- async getMyAccess(id) {
95
- return this.request(`/collections/${id}/my-access`, { method: "GET", authRequired: true });
96
- }
97
- async createCollection(payload) {
98
- return this.request("/collections", {
99
- method: "POST",
100
- authRequired: true,
101
- body: JSON.stringify(payload)
102
- });
103
- }
104
- async registerRoot(payload) {
105
- return this.request("/collections/register-root", {
106
- method: "POST",
107
- authRequired: true,
108
- body: JSON.stringify(payload)
109
- });
110
- }
111
- async updateCollection(id, payload) {
112
- return this.request(`/collections/${id}`, {
113
- method: "PATCH",
114
- authRequired: true,
115
- body: JSON.stringify(payload)
116
- });
117
- }
118
- async changeRoot(id, payload) {
119
- return this.request(`/collections/${id}/change-root`, {
120
- method: "PATCH",
121
- authRequired: true,
122
- body: JSON.stringify(payload)
123
- });
124
- }
125
- async deleteCollection(id) {
126
- return this.request(`/collections/${id}`, {
127
- method: "DELETE",
128
- authRequired: true
129
- });
130
- }
131
- // ---------------------------------------------------------------------------
132
- // Members
133
- // ---------------------------------------------------------------------------
134
- async listMembers(collectionId) {
135
- return this.request(`/collections/${collectionId}/members`, { method: "GET" });
136
- }
137
- async updateMemberRole(collectionId, userId, role) {
138
- return this.request(`/collections/${collectionId}/members/${userId}`, {
139
- method: "PATCH",
140
- authRequired: true,
141
- body: JSON.stringify({ role })
142
- });
143
- }
144
- async removeMember(collectionId, userId) {
145
- return this.request(`/collections/${collectionId}/members/${userId}`, {
146
- method: "DELETE",
147
- authRequired: true
148
- });
149
- }
150
- // ---------------------------------------------------------------------------
151
- // Invitations
152
- // ---------------------------------------------------------------------------
153
- async createInvitation(collectionId, email, role) {
154
- return this.request(`/collections/${collectionId}/invitations`, {
155
- method: "POST",
156
- authRequired: true,
157
- body: JSON.stringify({ email, role })
158
- });
159
- }
160
- async listInvitations(collectionId) {
161
- return this.request(`/collections/${collectionId}/invitations`, {
162
- method: "GET",
163
- authRequired: true
164
- });
165
- }
166
- async acceptInvitation(invitationId) {
167
- return this.request(`/invitations/${invitationId}/accept`, {
168
- method: "POST",
169
- authRequired: true
170
- });
171
- }
172
- async declineInvitation(invitationId) {
173
- return this.request(`/invitations/${invitationId}/decline`, {
174
- method: "POST",
175
- authRequired: true
176
- });
177
- }
178
- async revokeInvitation(invitationId) {
179
- return this.request(`/invitations/${invitationId}`, {
180
- method: "DELETE",
181
- authRequired: true
182
- });
183
- }
184
- // ---------------------------------------------------------------------------
185
- // Current user
186
- // ---------------------------------------------------------------------------
187
- async getMyCollections() {
188
- return this.request("/me/collections", { method: "GET", authRequired: true });
189
- }
190
- async getMyInvitations() {
191
- return this.request("/me/invitations", { method: "GET", authRequired: true });
192
- }
193
- // ---------------------------------------------------------------------------
194
- // PI permissions
195
- // ---------------------------------------------------------------------------
196
- async getPiPermissions(pi) {
197
- return this.request(`/pi/${pi}/permissions`, { method: "GET" });
198
- }
199
- };
200
- export {
201
- CollectionsClient,
202
- CollectionsError
203
- };
204
- //# sourceMappingURL=index.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../src/collections/errors.ts","../../src/collections/client.ts"],"sourcesContent":["export class CollectionsError extends Error {\n constructor(\n message: string,\n public code: string = 'UNKNOWN_ERROR',\n public details?: unknown\n ) {\n super(message);\n this.name = 'CollectionsError';\n }\n}\n","import { CollectionsError } from './errors';\nimport type {\n ChangeRootPayload,\n ChangeRootResponse,\n Collection,\n CollectionDetails,\n CollectionRole,\n CreateCollectionPayload,\n Invitation,\n InvitationsResponse,\n Member,\n MembersResponse,\n MyAccessResponse,\n MyCollectionsResponse,\n PaginatedCollections,\n PiPermissions,\n RegisterRootPayload,\n RootResponse,\n SuccessResponse,\n UpdateCollectionPayload,\n} from './types';\n\nexport interface CollectionsClientConfig {\n /**\n * Gateway base URL (e.g., https://api.arke.institute).\n * Must already point at the Arke gateway that proxies /collections/*.\n */\n gatewayUrl: string;\n /**\n * Optional bearer token for authenticated routes.\n * Public routes will still include it if provided.\n */\n authToken?: string;\n /**\n * Optional custom fetch (useful for testing).\n */\n fetchImpl?: typeof fetch;\n}\n\ntype JsonBody = Record<string, unknown>;\n\nexport class CollectionsClient {\n private baseUrl: string;\n private authToken?: string;\n private fetchImpl: typeof fetch;\n\n constructor(config: CollectionsClientConfig) {\n this.baseUrl = config.gatewayUrl.replace(/\\/$/, '');\n this.authToken = config.authToken;\n this.fetchImpl = config.fetchImpl ?? fetch;\n }\n\n setAuthToken(token?: string) {\n this.authToken = token;\n }\n\n // ---------------------------------------------------------------------------\n // Request helpers\n // ---------------------------------------------------------------------------\n\n private buildUrl(path: string, query?: Record<string, string | number | undefined>) {\n const url = new URL(`${this.baseUrl}${path}`);\n if (query) {\n Object.entries(query).forEach(([key, value]) => {\n if (value !== undefined && value !== null) {\n url.searchParams.set(key, String(value));\n }\n });\n }\n return url.toString();\n }\n\n private getHeaders(authRequired: boolean): HeadersInit {\n const headers: HeadersInit = { 'Content-Type': 'application/json' };\n if (authRequired || this.authToken) {\n if (!this.authToken && authRequired) {\n throw new CollectionsError('Authentication required for this operation', 'AUTH_REQUIRED');\n }\n if (this.authToken) {\n headers['Authorization'] = `Bearer ${this.authToken}`;\n }\n }\n return headers;\n }\n\n private async request<T>(\n path: string,\n options: RequestInit & {\n authRequired?: boolean;\n query?: Record<string, string | number | undefined>;\n } = {}\n ): Promise<T> {\n const authRequired = options.authRequired ?? false;\n const url = this.buildUrl(path, options.query);\n const headers = new Headers(this.getHeaders(authRequired));\n if (options.headers) {\n Object.entries(options.headers).forEach(([k, v]) => {\n if (v !== undefined) headers.set(k, v as string);\n });\n }\n\n const response = await this.fetchImpl(url, { ...options, headers });\n\n if (response.ok) {\n if (response.status === 204) {\n return undefined as T;\n }\n const contentType = response.headers.get('content-type') || '';\n if (contentType.includes('application/json')) {\n return (await response.json()) as T;\n }\n return (await response.text()) as unknown as T;\n }\n\n let body: unknown;\n try {\n body = await response.json();\n } catch {\n body = await response.text();\n }\n\n const message =\n (body as JsonBody)?.error && typeof (body as JsonBody).error === 'string'\n ? ((body as JsonBody).error as string)\n : `Request failed with status ${response.status}`;\n\n throw new CollectionsError(message, 'HTTP_ERROR', {\n status: response.status,\n body,\n });\n }\n\n // ---------------------------------------------------------------------------\n // Collections\n // ---------------------------------------------------------------------------\n\n async listCollections(params?: { limit?: number; offset?: number }): Promise<PaginatedCollections> {\n return this.request('/collections', {\n method: 'GET',\n query: { limit: params?.limit, offset: params?.offset },\n });\n }\n\n async getCollection(id: string): Promise<CollectionDetails> {\n return this.request(`/collections/${id}`, { method: 'GET' });\n }\n\n async getCollectionRoot(id: string): Promise<RootResponse> {\n return this.request(`/collections/${id}/root`, { method: 'GET' });\n }\n\n async getMyAccess(id: string): Promise<MyAccessResponse> {\n return this.request(`/collections/${id}/my-access`, { method: 'GET', authRequired: true });\n }\n\n async createCollection(payload: CreateCollectionPayload): Promise<Collection> {\n return this.request('/collections', {\n method: 'POST',\n authRequired: true,\n body: JSON.stringify(payload),\n });\n }\n\n async registerRoot(payload: RegisterRootPayload): Promise<Collection & { rootPi: string }> {\n return this.request('/collections/register-root', {\n method: 'POST',\n authRequired: true,\n body: JSON.stringify(payload),\n });\n }\n\n async updateCollection(id: string, payload: UpdateCollectionPayload): Promise<Collection> {\n return this.request(`/collections/${id}`, {\n method: 'PATCH',\n authRequired: true,\n body: JSON.stringify(payload),\n });\n }\n\n async changeRoot(id: string, payload: ChangeRootPayload): Promise<ChangeRootResponse> {\n return this.request(`/collections/${id}/change-root`, {\n method: 'PATCH',\n authRequired: true,\n body: JSON.stringify(payload),\n });\n }\n\n async deleteCollection(id: string): Promise<SuccessResponse> {\n return this.request(`/collections/${id}`, {\n method: 'DELETE',\n authRequired: true,\n });\n }\n\n // ---------------------------------------------------------------------------\n // Members\n // ---------------------------------------------------------------------------\n\n async listMembers(collectionId: string): Promise<MembersResponse> {\n return this.request(`/collections/${collectionId}/members`, { method: 'GET' });\n }\n\n async updateMemberRole(\n collectionId: string,\n userId: string,\n role: CollectionRole\n ): Promise<{ success: true; role: CollectionRole }> {\n return this.request(`/collections/${collectionId}/members/${userId}`, {\n method: 'PATCH',\n authRequired: true,\n body: JSON.stringify({ role }),\n });\n }\n\n async removeMember(collectionId: string, userId: string): Promise<SuccessResponse> {\n return this.request(`/collections/${collectionId}/members/${userId}`, {\n method: 'DELETE',\n authRequired: true,\n });\n }\n\n // ---------------------------------------------------------------------------\n // Invitations\n // ---------------------------------------------------------------------------\n\n async createInvitation(collectionId: string, email: string, role: CollectionRole): Promise<Invitation> {\n return this.request(`/collections/${collectionId}/invitations`, {\n method: 'POST',\n authRequired: true,\n body: JSON.stringify({ email, role }),\n });\n }\n\n async listInvitations(collectionId: string): Promise<InvitationsResponse> {\n return this.request(`/collections/${collectionId}/invitations`, {\n method: 'GET',\n authRequired: true,\n });\n }\n\n async acceptInvitation(invitationId: string): Promise<{ success: true; role: CollectionRole }> {\n return this.request(`/invitations/${invitationId}/accept`, {\n method: 'POST',\n authRequired: true,\n });\n }\n\n async declineInvitation(invitationId: string): Promise<SuccessResponse> {\n return this.request(`/invitations/${invitationId}/decline`, {\n method: 'POST',\n authRequired: true,\n });\n }\n\n async revokeInvitation(invitationId: string): Promise<SuccessResponse> {\n return this.request(`/invitations/${invitationId}`, {\n method: 'DELETE',\n authRequired: true,\n });\n }\n\n // ---------------------------------------------------------------------------\n // Current user\n // ---------------------------------------------------------------------------\n\n async getMyCollections(): Promise<MyCollectionsResponse> {\n return this.request('/me/collections', { method: 'GET', authRequired: true });\n }\n\n async getMyInvitations(): Promise<InvitationsResponse> {\n return this.request('/me/invitations', { method: 'GET', authRequired: true });\n }\n\n // ---------------------------------------------------------------------------\n // PI permissions\n // ---------------------------------------------------------------------------\n\n async getPiPermissions(pi: string): Promise<PiPermissions> {\n return this.request(`/pi/${pi}/permissions`, { method: 'GET' });\n }\n}\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/collections/errors.ts","../src/collections/client.ts"],"sourcesContent":["export class CollectionsError extends Error {\n constructor(\n message: string,\n public code: string = 'UNKNOWN_ERROR',\n public details?: unknown\n ) {\n super(message);\n this.name = 'CollectionsError';\n }\n}\n","import { CollectionsError } from './errors';\nimport type {\n ChangeRootPayload,\n ChangeRootResponse,\n Collection,\n CollectionDetails,\n CollectionRole,\n CreateCollectionPayload,\n Invitation,\n InvitationsResponse,\n Member,\n MembersResponse,\n MyAccessResponse,\n MyCollectionsResponse,\n PaginatedCollections,\n PiPermissions,\n RegisterRootPayload,\n RootResponse,\n SuccessResponse,\n UpdateCollectionPayload,\n} from './types';\n\nexport interface CollectionsClientConfig {\n /**\n * Gateway base URL (e.g., https://api.arke.institute).\n * Must already point at the Arke gateway that proxies /collections/*.\n */\n gatewayUrl: string;\n /**\n * Optional bearer token for authenticated routes.\n * Public routes will still include it if provided.\n */\n authToken?: string;\n /**\n * Optional custom fetch (useful for testing).\n */\n fetchImpl?: typeof fetch;\n}\n\ntype JsonBody = Record<string, unknown>;\n\nexport class CollectionsClient {\n private baseUrl: string;\n private authToken?: string;\n private fetchImpl: typeof fetch;\n\n constructor(config: CollectionsClientConfig) {\n this.baseUrl = config.gatewayUrl.replace(/\\/$/, '');\n this.authToken = config.authToken;\n this.fetchImpl = config.fetchImpl ?? fetch;\n }\n\n setAuthToken(token?: string) {\n this.authToken = token;\n }\n\n // ---------------------------------------------------------------------------\n // Request helpers\n // ---------------------------------------------------------------------------\n\n private buildUrl(path: string, query?: Record<string, string | number | undefined>) {\n const url = new URL(`${this.baseUrl}${path}`);\n if (query) {\n Object.entries(query).forEach(([key, value]) => {\n if (value !== undefined && value !== null) {\n url.searchParams.set(key, String(value));\n }\n });\n }\n return url.toString();\n }\n\n private getHeaders(authRequired: boolean): HeadersInit {\n const headers: HeadersInit = { 'Content-Type': 'application/json' };\n if (authRequired || this.authToken) {\n if (!this.authToken && authRequired) {\n throw new CollectionsError('Authentication required for this operation', 'AUTH_REQUIRED');\n }\n if (this.authToken) {\n headers['Authorization'] = `Bearer ${this.authToken}`;\n }\n }\n return headers;\n }\n\n private async request<T>(\n path: string,\n options: RequestInit & {\n authRequired?: boolean;\n query?: Record<string, string | number | undefined>;\n } = {}\n ): Promise<T> {\n const authRequired = options.authRequired ?? false;\n const url = this.buildUrl(path, options.query);\n const headers = new Headers(this.getHeaders(authRequired));\n if (options.headers) {\n Object.entries(options.headers).forEach(([k, v]) => {\n if (v !== undefined) headers.set(k, v as string);\n });\n }\n\n const response = await this.fetchImpl(url, { ...options, headers });\n\n if (response.ok) {\n if (response.status === 204) {\n return undefined as T;\n }\n const contentType = response.headers.get('content-type') || '';\n if (contentType.includes('application/json')) {\n return (await response.json()) as T;\n }\n return (await response.text()) as unknown as T;\n }\n\n let body: unknown;\n try {\n body = await response.json();\n } catch {\n body = await response.text();\n }\n\n const message =\n (body as JsonBody)?.error && typeof (body as JsonBody).error === 'string'\n ? ((body as JsonBody).error as string)\n : `Request failed with status ${response.status}`;\n\n throw new CollectionsError(message, 'HTTP_ERROR', {\n status: response.status,\n body,\n });\n }\n\n // ---------------------------------------------------------------------------\n // Collections\n // ---------------------------------------------------------------------------\n\n async listCollections(params?: { limit?: number; offset?: number }): Promise<PaginatedCollections> {\n return this.request('/collections', {\n method: 'GET',\n query: { limit: params?.limit, offset: params?.offset },\n });\n }\n\n async getCollection(id: string): Promise<CollectionDetails> {\n return this.request(`/collections/${id}`, { method: 'GET' });\n }\n\n async getCollectionRoot(id: string): Promise<RootResponse> {\n return this.request(`/collections/${id}/root`, { method: 'GET' });\n }\n\n async getMyAccess(id: string): Promise<MyAccessResponse> {\n return this.request(`/collections/${id}/my-access`, { method: 'GET', authRequired: true });\n }\n\n async createCollection(payload: CreateCollectionPayload): Promise<Collection> {\n return this.request('/collections', {\n method: 'POST',\n authRequired: true,\n body: JSON.stringify(payload),\n });\n }\n\n async registerRoot(payload: RegisterRootPayload): Promise<Collection & { rootPi: string }> {\n return this.request('/collections/register-root', {\n method: 'POST',\n authRequired: true,\n body: JSON.stringify(payload),\n });\n }\n\n async updateCollection(id: string, payload: UpdateCollectionPayload): Promise<Collection> {\n return this.request(`/collections/${id}`, {\n method: 'PATCH',\n authRequired: true,\n body: JSON.stringify(payload),\n });\n }\n\n async changeRoot(id: string, payload: ChangeRootPayload): Promise<ChangeRootResponse> {\n return this.request(`/collections/${id}/change-root`, {\n method: 'PATCH',\n authRequired: true,\n body: JSON.stringify(payload),\n });\n }\n\n async deleteCollection(id: string): Promise<SuccessResponse> {\n return this.request(`/collections/${id}`, {\n method: 'DELETE',\n authRequired: true,\n });\n }\n\n // ---------------------------------------------------------------------------\n // Members\n // ---------------------------------------------------------------------------\n\n async listMembers(collectionId: string): Promise<MembersResponse> {\n return this.request(`/collections/${collectionId}/members`, { method: 'GET' });\n }\n\n async updateMemberRole(\n collectionId: string,\n userId: string,\n role: CollectionRole\n ): Promise<{ success: true; role: CollectionRole }> {\n return this.request(`/collections/${collectionId}/members/${userId}`, {\n method: 'PATCH',\n authRequired: true,\n body: JSON.stringify({ role }),\n });\n }\n\n async removeMember(collectionId: string, userId: string): Promise<SuccessResponse> {\n return this.request(`/collections/${collectionId}/members/${userId}`, {\n method: 'DELETE',\n authRequired: true,\n });\n }\n\n // ---------------------------------------------------------------------------\n // Invitations\n // ---------------------------------------------------------------------------\n\n async createInvitation(collectionId: string, email: string, role: CollectionRole): Promise<Invitation> {\n return this.request(`/collections/${collectionId}/invitations`, {\n method: 'POST',\n authRequired: true,\n body: JSON.stringify({ email, role }),\n });\n }\n\n async listInvitations(collectionId: string): Promise<InvitationsResponse> {\n return this.request(`/collections/${collectionId}/invitations`, {\n method: 'GET',\n authRequired: true,\n });\n }\n\n async acceptInvitation(invitationId: string): Promise<{ success: true; role: CollectionRole }> {\n return this.request(`/invitations/${invitationId}/accept`, {\n method: 'POST',\n authRequired: true,\n });\n }\n\n async declineInvitation(invitationId: string): Promise<SuccessResponse> {\n return this.request(`/invitations/${invitationId}/decline`, {\n method: 'POST',\n authRequired: true,\n });\n }\n\n async revokeInvitation(invitationId: string): Promise<SuccessResponse> {\n return this.request(`/invitations/${invitationId}`, {\n method: 'DELETE',\n authRequired: true,\n });\n }\n\n // ---------------------------------------------------------------------------\n // Current user\n // ---------------------------------------------------------------------------\n\n async getMyCollections(): Promise<MyCollectionsResponse> {\n return this.request('/me/collections', { method: 'GET', authRequired: true });\n }\n\n async getMyInvitations(): Promise<InvitationsResponse> {\n return this.request('/me/invitations', { method: 'GET', authRequired: true });\n }\n\n // ---------------------------------------------------------------------------\n // PI permissions\n // ---------------------------------------------------------------------------\n\n async getPiPermissions(pi: string): Promise<PiPermissions> {\n return this.request(`/pi/${pi}/permissions`, { method: 'GET' });\n }\n}\n"],"mappings":"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","names":[]}