{"_id":"@ahhaohho/s3-upload-sdk","name":"@ahhaohho/s3-upload-sdk","dist-tags":{"latest":"1.0.1"},"versions":{"1.0.1":{"name":"@ahhaohho/s3-upload-sdk","version":"1.0.1","description":"S3 + CloudFront presigned URL SDK for AhhaOhho platform","main":"dist/index.js","types":"dist/index.d.ts","scripts":{"build":"tsc","prepublishOnly":"npm run build","test":"echo \"Error: no test specified\" && exit 1"},"keywords":["s3","presigned-url","cloudfront","upload","aws","ahhaohho"],"author":{"name":"AhhaOhho"},"license":"ISC","repository":{"type":"git","url":"git+https://github.com/Future-Lab-META/npm-s3-upload-sdk.git"},"dependencies":{"axios":"^1.6.0"},"devDependencies":{"@types/node":"^20.0.0","typescript":"^5.0.0"},"_id":"@ahhaohho/s3-upload-sdk@1.0.1","bugs":{"url":"https://github.com/Future-Lab-META/npm-s3-upload-sdk/issues"},"homepage":"https://github.com/Future-Lab-META/npm-s3-upload-sdk#readme","_nodeVersion":"22.17.1","_npmVersion":"10.9.2","dist":{"integrity":"sha512-ucyX/rfu/aNr/h3NVXDrZ6zcDZBthAQx4l25o3DTWVzLznlouRn1VfiqTJkko2eO9tzbC0z1Bixv3JbI4T5j+Q==","shasum":"8341ab7c8a6c02d8c3a5c5a1c28edc03d697a8f7","tarball":"https://registry.npmjs.org/@ahhaohho/s3-upload-sdk/-/s3-upload-sdk-1.0.1.tgz","fileCount":8,"unpackedSize":20533,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIDk+GbpAlXP647p8bPY33cZitCZlXJ6OJfSFpTUGdJe3AiA86sN7+QGII5SIK1Y0T5u9NcBcDF3s1A8Ko2vcsBenfg=="}]},"_npmUser":{"name":"doooosoooo","email":"doosoo.jung@gmail.com"},"directories":{},"maintainers":[{"name":"doooosoooo","email":"doosoo.jung@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/s3-upload-sdk_1.0.1_1762819827997_0.9478809614597596"},"_hasShrinkwrap":false}},"time":{"created":"2025-11-11T00:10:27.893Z","1.0.1":"2025-11-11T00:10:28.173Z","modified":"2025-11-11T00:10:28.479Z"},"maintainers":[{"name":"doooosoooo","email":"doosoo.jung@gmail.com"}],"description":"S3 + CloudFront presigned URL SDK for AhhaOhho platform","homepage":"https://github.com/Future-Lab-META/npm-s3-upload-sdk#readme","keywords":["s3","presigned-url","cloudfront","upload","aws","ahhaohho"],"repository":{"type":"git","url":"git+https://github.com/Future-Lab-META/npm-s3-upload-sdk.git"},"author":{"name":"AhhaOhho"},"bugs":{"url":"https://github.com/Future-Lab-META/npm-s3-upload-sdk/issues"},"license":"ISC","readme":"# @ahhaohho/s3-upload-sdk\n\nS3 + CloudFront presigned URL SDK for AhhaOhho platform. This SDK allows clients to upload files directly to S3 using presigned URLs and get CloudFront URLs for the uploaded files.\n\n## Features\n\n- 🚀 Direct upload to S3 using presigned URLs\n- ☁️ CloudFront URL support for fast content delivery\n- 📦 TypeScript support with full type definitions\n- 📊 Upload progress tracking\n- 🔄 Multiple file upload support\n- ✅ File validation (size, type)\n- 🔐 Authorization token support\n\n## Installation\n\n```bash\nnpm install @ahhaohho/s3-upload-sdk\n```\n\n## Usage\n\n### Basic Usage\n\n```typescript\nimport { S3UploadClient } from '@ahhaohho/s3-upload-sdk';\n\n// Initialize the client\nconst uploadClient = new S3UploadClient({\n  apiBaseUrl: 'https://api.ahhaohho.com',\n  authToken: 'your-auth-token', // Optional\n});\n\n// Upload a file\nconst fileInput = document.getElementById('fileInput') as HTMLInputElement;\nconst file = fileInput.files[0];\n\ntry {\n  const result = await uploadClient.upload({\n    file: file,\n    folder: 'announcements', // Folder in S3\n    onProgress: (progress) => {\n      console.log(`Upload progress: ${progress}%`);\n    },\n  });\n\n  console.log('File uploaded successfully!');\n  console.log('CloudFront URL:', result.url);\n  console.log('S3 Key:', result.key);\n  console.log('File size:', result.size, 'bytes');\n} catch (error) {\n  console.error('Upload failed:', error);\n}\n```\n\n### Upload with Custom Filename\n\n```typescript\nconst result = await uploadClient.upload({\n  file: file,\n  folder: 'profiles',\n  filename: 'user-avatar', // Will be: user-avatar-1234567890-abc123.jpg\n  contentType: 'image/jpeg',\n});\n```\n\n### Upload Multiple Files\n\n```typescript\nconst files = Array.from(fileInput.files);\n\nconst results = await uploadClient.uploadMultiple(\n  files.map((file) => ({\n    file,\n    folder: 'announcements',\n  }))\n);\n\nconst urls = results.map((r) => r.url);\nconsole.log('All files uploaded:', urls);\n```\n\n### File Validation\n\n```typescript\nconst validation = uploadClient.validateFile(\n  file,\n  5, // Max 5MB\n  ['image/jpeg', 'image/png', 'image/gif'] // Allowed types\n);\n\nif (!validation.valid) {\n  alert(validation.error);\n  return;\n}\n\n// Proceed with upload\nconst result = await uploadClient.upload({\n  file,\n  folder: 'announcements',\n});\n```\n\n### Update Auth Token\n\n```typescript\n// Update token after login\nuploadClient.setAuthToken(newToken);\n```\n\n### React Example\n\n```tsx\nimport React, { useState } from 'react';\nimport { S3UploadClient } from '@ahhaohho/s3-upload-sdk';\n\nconst uploadClient = new S3UploadClient({\n  apiBaseUrl: process.env.REACT_APP_API_URL,\n});\n\nfunction ImageUploader() {\n  const [uploading, setUploading] = useState(false);\n  const [progress, setProgress] = useState(0);\n  const [imageUrl, setImageUrl] = useState('');\n\n  const handleUpload = async (e: React.ChangeEvent<HTMLInputElement>) => {\n    const file = e.target.files?.[0];\n    if (!file) return;\n\n    // Validate file\n    const validation = uploadClient.validateFile(file, 10, [\n      'image/jpeg',\n      'image/jpg',\n      'image/png',\n      'image/gif',\n    ]);\n\n    if (!validation.valid) {\n      alert(validation.error);\n      return;\n    }\n\n    try {\n      setUploading(true);\n      setProgress(0);\n\n      const result = await uploadClient.upload({\n        file,\n        folder: 'announcements',\n        onProgress: (p) => setProgress(p),\n      });\n\n      setImageUrl(result.url);\n      alert('Upload successful!');\n    } catch (error) {\n      console.error('Upload failed:', error);\n      alert('Upload failed');\n    } finally {\n      setUploading(false);\n    }\n  };\n\n  return (\n    <div>\n      <input\n        type=\"file\"\n        accept=\"image/*\"\n        onChange={handleUpload}\n        disabled={uploading}\n      />\n      {uploading && <div>Upload progress: {progress}%</div>}\n      {imageUrl && <img src={imageUrl} alt=\"Uploaded\" />}\n    </div>\n  );\n}\n\nexport default ImageUploader;\n```\n\n### Vue Example\n\n```vue\n<template>\n  <div>\n    <input\n      type=\"file\"\n      accept=\"image/*\"\n      @change=\"handleUpload\"\n      :disabled=\"uploading\"\n    />\n    <div v-if=\"uploading\">Upload progress: {{ progress }}%</div>\n    <img v-if=\"imageUrl\" :src=\"imageUrl\" alt=\"Uploaded\" />\n  </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref } from 'vue';\nimport { S3UploadClient } from '@ahhaohho/s3-upload-sdk';\n\nconst uploadClient = new S3UploadClient({\n  apiBaseUrl: import.meta.env.VITE_API_URL,\n});\n\nconst uploading = ref(false);\nconst progress = ref(0);\nconst imageUrl = ref('');\n\nconst handleUpload = async (e: Event) => {\n  const target = e.target as HTMLInputElement;\n  const file = target.files?.[0];\n  if (!file) return;\n\n  // Validate file\n  const validation = uploadClient.validateFile(file, 10, [\n    'image/jpeg',\n    'image/jpg',\n    'image/png',\n    'image/gif',\n  ]);\n\n  if (!validation.valid) {\n    alert(validation.error);\n    return;\n  }\n\n  try {\n    uploading.value = true;\n    progress.value = 0;\n\n    const result = await uploadClient.upload({\n      file,\n      folder: 'announcements',\n      onProgress: (p) => (progress.value = p),\n    });\n\n    imageUrl.value = result.url;\n    alert('Upload successful!');\n  } catch (error) {\n    console.error('Upload failed:', error);\n    alert('Upload failed');\n  } finally {\n    uploading.value = false;\n  }\n};\n</script>\n```\n\n## API Reference\n\n### `S3UploadClient`\n\n#### Constructor\n\n```typescript\nnew S3UploadClient(config: S3UploadConfig)\n```\n\n**Parameters:**\n- `config.apiBaseUrl` (string): Base URL of your API server\n- `config.authToken` (string, optional): Authorization token\n- `config.headers` (object, optional): Custom headers\n\n#### Methods\n\n##### `upload(options: UploadOptions): Promise<UploadResult>`\n\nUpload a single file.\n\n**Parameters:**\n- `options.file` (File | Blob): File to upload\n- `options.folder` (string): Folder path in S3\n- `options.filename` (string, optional): Custom filename\n- `options.contentType` (string, optional): Content type (MIME type)\n- `options.onProgress` (function, optional): Progress callback\n\n**Returns:**\n- `url` (string): CloudFront URL\n- `key` (string): S3 key\n- `size` (number): File size in bytes\n\n##### `uploadMultiple(files: UploadOptions[]): Promise<UploadResult[]>`\n\nUpload multiple files in parallel.\n\n##### `validateFile(file, maxSizeMB, allowedTypes): { valid: boolean, error?: string }`\n\nValidate file before upload.\n\n##### `setAuthToken(token: string): void`\n\nUpdate authorization token.\n\n## Server-side Setup (Backend Only)\n\n**Important**: AWS credentials are ONLY needed on your API server, NOT in the client SDK.\n\nThe SDK communicates with your API server, which then generates presigned URLs using AWS credentials.\n\nYou need to implement a presigned URL endpoint on your backend server:\n\n```typescript\n// Example Express endpoint\napp.post('/communities/s3/presigned-url', async (req, res) => {\n  const { folder, filename, contentType } = req.body;\n\n  // Generate presigned URL using AWS SDK\n  const s3 = new S3Client({ region: 'ap-northeast-2' });\n  const key = `raw/${folder}/${filename}`;\n\n  const command = new PutObjectCommand({\n    Bucket: 'your-bucket-name',\n    Key: key,\n    ContentType: contentType,\n  });\n\n  const uploadUrl = await getSignedUrl(s3, command, { expiresIn: 300 });\n  const publicUrl = `https://your-cloudfront-domain.cloudfront.net/${key}`;\n\n  res.json({\n    type: 'success',\n    status: 200,\n    data: {\n      uploadUrl,\n      publicUrl,\n      key,\n      expiresIn: 300,\n    },\n    message: null,\n  });\n});\n```\n\nSee the [server implementation guide](./SERVER_SETUP.md) for detailed instructions.\n\n## Error Handling\n\n```typescript\ntry {\n  const result = await uploadClient.upload({ file, folder: 'announcements' });\n} catch (error) {\n  if (error.code === 'PRESIGNED_URL_ERROR') {\n    console.error('Failed to get presigned URL:', error.message);\n  } else if (error.code === 'S3_UPLOAD_ERROR') {\n    console.error('Failed to upload to S3:', error.message);\n  } else {\n    console.error('Unknown error:', error);\n  }\n}\n```\n\n## TypeScript Support\n\nThis package is written in TypeScript and includes type definitions.\n\n```typescript\nimport type { UploadResult, UploadOptions } from '@ahhaohho/s3-upload-sdk';\n```\n\n## License\n\nISC\n\n## Contributing\n\nIssues and pull requests are welcome!\n","readmeFilename":"README.md","_rev":"1-400d9b8b7d2332309abaf43c3f091dbe"}