{"id":24618312,"url":"https://github.com/2061360308/s3imagehosting","last_synced_at":"2026-05-17T20:02:51.159Z","repository":{"id":273338495,"uuid":"919218488","full_name":"2061360308/S3ImageHosting","owner":"2061360308","description":"纯前端、浏览器可用、超轻量的基于对象存储的图床管理工具，支持腾讯云COS阿里云OSS七牛云Kodo等兼容亚马逊S3接口的各大平台。 | A pure front-end, browser-compatible, ultra-lightweight image hosting management tool based on object storage, supporting major platforms compatible with Amazon S3 interface such as Tencent Cloud COS, Alibaba Cloud OSS, and Qiniu Cloud Kodo.","archived":false,"fork":false,"pushed_at":"2025-01-25T11:50:57.000Z","size":486,"stargazers_count":30,"open_issues_count":0,"forks_count":4,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-03-05T13:26:31.870Z","etag":null,"topics":["cos","imagehosting","kodo","oss","s3","s3-storage"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/2061360308.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-01-20T01:25:04.000Z","updated_at":"2026-02-09T11:17:46.000Z","dependencies_parsed_at":"2025-01-20T13:26:29.032Z","dependency_job_id":"1bf1443d-05e9-46e8-90af-e8821c7fe72c","html_url":"https://github.com/2061360308/S3ImageHosting","commit_stats":null,"previous_names":["2061360308/s3-image-hosting","2061360308/s3imagehosting"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/2061360308/S3ImageHosting","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/2061360308%2FS3ImageHosting","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/2061360308%2FS3ImageHosting/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/2061360308%2FS3ImageHosting/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/2061360308%2FS3ImageHosting/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/2061360308","download_url":"https://codeload.github.com/2061360308/S3ImageHosting/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/2061360308%2FS3ImageHosting/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33153662,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-17T09:28:26.183Z","status":"ssl_error","status_checked_at":"2026-05-17T09:27:52.702Z","response_time":107,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cos","imagehosting","kodo","oss","s3","s3-storage"],"created_at":"2025-01-24T23:51:37.398Z","updated_at":"2026-05-17T20:02:51.134Z","avatar_url":"https://github.com/2061360308.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# S3ImageHosting\n\n![License](https://img.shields.io/badge/license-MIT-blue.svg)\n![Version](https://img.shields.io/badge/version-1.0.0-brightgreen.svg)\n![Build](https://img.shields.io/badge/build-passing-green.svg)\n![PRs Welcome](https://img.shields.io/badge/PRs-welcome-yellowgreen.svg)\n![TypeScript](https://img.shields.io/badge/TypeScript-4.0+-blue.svg)\n![Stars](https://img.shields.io/github/stars/2061360308/S3-Image-Hosting.svg?color=yellow\u0026style=flat)\n![Forks](https://img.shields.io/github/forks/2061360308/S3ImageHosting.svg?color=orange\u0026style=flat)\n![Issues](https://img.shields.io/github/issues/2061360308/S3ImageHosting.svg?color=red)\n\n\u003e 纯前端、浏览器可用、超轻量的基于对象存储的图床管理工具\n\n\u003ctable style=\"width: 100%;\" align=\"center\"\u003e\n  \u003ctr\u003e\n    \u003ctd colspan=\"2\" align=\"center\"\u003e\n      \u003ch2\u003e目录\u003c/h2\u003e\n    \u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd style=\"text-align: left; display: inline-block;\"\u003e\n      \u003cp\u003e\u003ca href='#特性-🚀'\u003e特性 🚀\u003c/a\u003e\u003c/p\u003e\n      \u003cp\u003e\u003ca href='#测试结果-✅'\u003e测试结果 ✅\u003c/a\u003e\u003c/p\u003e\n      \u003cp\u003e\u003ca href='#使用方法-📚'\u003e使用方法 📚\u003c/a\u003e\u003c/p\u003e\n      \u003cp\u003e\u003ca href='#警告-⚠️'\u003e警告 ⚠️\u003c/a\u003e\u003c/p\u003e\n      \u003cp\u003e\u003ca href='#开发贡献-🛠️'\u003e开发\u0026贡献 🛠️\u003c/a\u003e\u003c/p\u003e\n      \u003cp\u003e\u003ca href='#协议授权-📄'\u003e协议\u0026授权 📄\u003c/a\u003e\u003c/p\u003e\n      \u003cp\u003e\u003ca href='#鸣谢-🙏'\u003e鸣谢 🙏\u003c/a\u003e\u003c/p\u003e\n    \u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\n## 特性 🚀\n\n1. [纯前端，浏览器可用](#纯前端浏览器可用)\n2. [超轻量](#超轻量)\n3. [高扩展](#高扩展)\n4. [功能全面](#功能全面)\n5. [多种服务支持](#多种服务支持)\n6. [TypeScript 类型齐全](#typescript-类型齐全)\n7. [注释详尽](#注释详尽)\n8. [完整测试用例](#完整测试用例)\n9. [模块化设计](#模块化设计)\n\n### 纯前端，浏览器可用\n\n纯前端语言编写，可直接在浏览器中调用，无需后端支持，无需配置复杂服务器。\n\n### 超轻量\n\n只提供基础的接口包装，未压缩前体积仅 **42.54KB**，加载速度快，性能优异。\n\n### 高扩展\n\n区别于传统图床项目，该库仅是**针对性**地将对象储存包装为了可以方便使用的图床相关的实用接口，开发者可以根据需要自由扩展和定制功能，以满足特定的业务需求。用户也不必担心迁移平台时的复杂问题，同使用此项目的图床可以直接迁移，就算迁移其他图床也能方便的解析本类图床产生的数据，保证数据不丢失\n\n### 功能全面\n\n近**20 个**方法，提供包括上传图片、删除图片、生成图片在线链接、依据标签或相册筛选、根据创建时间查看图片等超多实用功能。\n\n### 多种服务支持\n\n基于对象储存构建，使用亚马逊 S3 标准接口，可兼容大部分主流平台，如：\n\n- 腾讯云 COS\n- 阿里云 OSS\n- 七牛云 Kodo\n- 亚马逊 S3\n\n### TypeScript 类型齐全\n\n提供完整的 TypeScript 类型定义，增强开发体验和代码可靠性，减少运行时错误。\n\n### 注释详尽\n\n代码注释详尽，便于理解和维护，帮助开发者快速上手和二次开发。\n\n### 完整测试用例\n\n提供完整的测试用例，确保代码质量和稳定性，方便开发者进行单元测试和集成测试。\n\n### 模块化设计\n\n所有静态方法均独立编写，并在 `index.ts` 中统一导入和注册，便于阅读源码、修改和灵活使用静态方法。\n\n## 测试结果 ✅\n\n\u003e 使用 vitest 编写测试，所有测试均在`src/test`目录下\n\n![test result](docs/images/test_result.png)\n\n\u003cdiv align=\"center\"\u003e\n\u003ca href=\"docs/testResult.md\"\u003e@测试用例 详细输出内容\u003c/a\u003e\n\u003c/div\u003e\n\n## 使用方法 📚\n\n初始化方法示例如下\n\n```ts\nexport const settings: Settings = {\n  bucket: process.env.BUCKET as string, // 储存桶名称\n  endpoint: process.env.ENDPOINT as string, // 服务端点/服务地址/服务 URL\n  region: process.env.REGION as string, // 储存桶地区\n  accessKeyId: process.env.ACCESS_KEY_ID as string, // accessKeyId\n  secretAccessKey: process.env.SECRET_ACCESS_KEY as string, // secretAccessKey\n};\n\nconst s3 = new S3ImageHosting(settings);\n```\n\n可以参考各大厂商的说明文档\n\n- [腾讯云 COS](https://cloud.tencent.com/document/product/436/41284)\n- [阿里云 OSS](https://help.aliyun.com/zh/oss/developer-reference/compatibility-with-amazon-s3-1/)\n- [七牛云 Kodo](https://developer.qiniu.com/kodo/4086/aws-s3-compatible)\n- [亚马逊 S3](https://docs.aws.amazon.com/zh_cn/AmazonS3/latest/userguide/Welcome.html)\n\n以下给出`S3ImageHosting`的方法模型\n\n```ts\nclass S3ImageHosting extends S3ImageHostingMethods {\n  readonly version: string;\n  settings: Settings;\n  client: S3Client;\n  constructor(settings: Settings);\n  isExistImage: (key: string) =\u003e Promise\u003cboolean\u003e;\n  uploadImage: (\n    fileData: Blob | Buffer | Uint8Array,\n    fileType: _ImageType1,\n    create: Date,\n    update: Date,\n    album: string,\n    tags: string[]\n  ) =\u003e Promise\u003c_UploadImageResult1\u003e;\n  deleteImage: (hash: string) =\u003e Promise\u003cboolean\u003e;\n  getImageMetadata: (hash: string) =\u003e Promise\u003cMetadata\u003e;\n  getImageSignedUrl: (hash: string, expiresIn?: number) =\u003e Promise\u003cstring\u003e;\n  getAllAlbumNames: () =\u003e Promise\u003cstring[]\u003e;\n  addAlbum: (album: Array\u003cstring\u003e) =\u003e Promise\u003cboolean\u003e;\n  removeAlbum: (album: Array\u003cstring\u003e) =\u003e Promise\u003cboolean\u003e;\n  listAlbumItems: (\n    albumName: string,\n    page: number,\n    pageSize: number\n  ) =\u003e Promise\u003c_PaginatedResult1\u003cstring\u003e\u003e;\n  albumAddImages: (albumName: string, keys: string[]) =\u003e Promise\u003cboolean\u003e;\n  albumRemoveImages: (albumName: string, keys: string[]) =\u003e Promise\u003cboolean\u003e;\n  getAllTagNames: () =\u003e Promise\u003cstring[]\u003e;\n  addTag: (tag: Array\u003cstring\u003e) =\u003e Promise\u003cboolean\u003e;\n  removeTag: (tag: Array\u003cstring\u003e) =\u003e Promise\u003cboolean\u003e;\n  listTagItems: (\n    tagName: string,\n    page: number,\n    pageSize: number\n  ) =\u003e Promise\u003c_PaginatedResult1\u003cstring\u003e\u003e;\n  tagAddImages: (tagName: string, keys: string[]) =\u003e Promise\u003cboolean\u003e;\n  tagRemoveImages: (tagName: string, keys: string[]) =\u003e Promise\u003cboolean\u003e;\n  listCratedAtItems: (\n    page: number,\n    pageSize: number\n  ) =\u003e Promise\u003c_PaginatedResult1\u003cstring\u003e\u003e;\n}\n```\n\n大部分方法都有对应的静态方法，可以灵活调用\n\n```ts\nclass S3ImageHostingMethods {\n  static isExistImageStatic: (\n    client: S3Client,\n    bucketName: string,\n    hash: string\n  ) =\u003e Promise\u003cboolean\u003e;\n  static createMatadataStatic: (\n    create: Date,\n    update: Date,\n    album: string,\n    tags: string[]\n  ) =\u003e Metadata;\n  static uploadImageStatic: (\n    client: S3Client,\n    bucketName: string,\n    fileData: Blob | Buffer | Uint8Array,\n    fileType: ImageType,\n    metadata: Metadata\n  ) =\u003e Promise\u003cUploadImageResult\u003e;\n  static deleteImageStatic: (\n    client: S3Client,\n    bucketName: string,\n    hash: string\n  ) =\u003e Promise\u003cboolean\u003e;\n  static getImageMetadataStatic: (\n    client: S3Client,\n    bucketName: string,\n    hash: string\n  ) =\u003e Promise\u003cMetadata\u003e;\n  static getImageSignedUrlStatic: (\n    client: S3Client,\n    bucketName: string,\n    hash: string,\n    expiresIn?: number\n  ) =\u003e Promise\u003cstring\u003e;\n  static getAllAlbumNamesStatic: (\n    client: S3Client,\n    bucketName: string\n  ) =\u003e Promise\u003cArray\u003cstring\u003e\u003e;\n  static addAlbumStatic: (\n    client: S3Client,\n    bucketName: string,\n    addNames: Array\u003cstring\u003e\n  ) =\u003e Promise\u003cboolean\u003e;\n  static removeAlbumStatic: (\n    client: S3Client,\n    bucketName: string,\n    removeNames: Array\u003cstring\u003e\n  ) =\u003e Promise\u003cboolean\u003e;\n  static listAlbumItemsStatic: (\n    client: S3Client,\n    bucketName: string,\n    albumName: string,\n    page: number,\n    pageSize: number\n  ) =\u003e Promise\u003cPaginatedResult\u003cstring\u003e\u003e;\n  static albumAddImagesStatic: (\n    client: S3Client,\n    bucketName: string,\n    albumName: string,\n    imageHashs: Array\u003cstring\u003e\n  ) =\u003e Promise\u003cboolean\u003e;\n  static albumRemoveImagesStatic: (\n    client: S3Client,\n    bucketName: string,\n    albumName: string,\n    imageHashs: Array\u003cstring\u003e\n  ) =\u003e Promise\u003cboolean\u003e;\n  static getAllTagNamesStatic: (\n    client: S3Client,\n    bucketName: string\n  ) =\u003e Promise\u003cArray\u003cstring\u003e\u003e;\n  static addTagStatic: (\n    client: S3Client,\n    bucketName: string,\n    addNames: Array\u003cstring\u003e\n  ) =\u003e Promise\u003cboolean\u003e;\n  static removeTagStatic: (\n    client: S3Client,\n    bucketName: string,\n    removeNames: Array\u003cstring\u003e\n  ) =\u003e Promise\u003cboolean\u003e;\n  static listTagItemsStatic: (\n    client: S3Client,\n    bucketName: string,\n    TagName: string,\n    page: number,\n    pageSize: number\n  ) =\u003e Promise\u003cPaginatedResult\u003cstring\u003e\u003e;\n  static tagAddImagesStatic: (\n    client: S3Client,\n    bucketName: string,\n    TagName: string,\n    imageHashs: Array\u003cstring\u003e\n  ) =\u003e Promise\u003cboolean\u003e;\n  static tagRemoveImagesStatic: (\n    client: S3Client,\n    bucketName: string,\n    TagName: string,\n    imageHashs: Array\u003cstring\u003e\n  ) =\u003e Promise\u003cboolean\u003e;\n  static listCratedAtItemsStatic: (\n    client: S3Client,\n    bucketName: string,\n    page: number,\n    pageSize: number\n  ) =\u003e Promise\u003cPaginatedResult\u003cstring\u003e\u003e;\n}\n```\n\n## 警告！！ ⚠️\n\n### isExistImage()\n\n根据测试脚本 `upload\u0026delete.test.ts` 的测试结果来看，删除操作结束后立即检测图片是否存在可能会返回错误的结果。\n\n删除操作（`deleteImage`）虽然是在等待请求后进行返回，但是由于对象储存是一个分布式系统，某些操作（如删除对象）可能会有短暂的延迟，导致在删除操作完成后立即检查对象是否存在时（`isExistImage`），仍然可能返回 true。\n\n为了确保删除操作已经完全生效，可以在删除操作后添加一个短暂的延迟，然后再检查对象是否存在。在当前源码中，我在测试函数`upload\u0026delete.test.ts`中暂时添加了 500ms 的延时，来避免这个问题。但请大家理解这不保证是绝对安全的，我认为这个值应该由后期开发者根据自己业务对速率的需求进行调整，或者你应该尽量避免在进行删除操作后立即检测图片是否存在。\n\n```js\ndescribe(\"isExist\", () =\u003e {\n  it(\"isExist should be false\", async () =\u003e {\n    // 添加一个短暂的延迟，确保删除操作已经完全生效\n    await new Promise((resolve) =\u003e setTimeout(resolve, 500));\n\n    let result = await imageHosting.isExistImage(\"94e2635af500225d\");\n    console.log(\"isExist result: \", result);\n    expect(result).toBeFalsy();\n  });\n});\n```\n\n\u003e 其他地方也可能有些许延时，请在开发过程中注意类似这种情况\n\n## 开发\u0026贡献 🛠️\n\n\u003e 参与开发请先 fork 本项目到个人仓库，然后再拉取到本地。如果你不确定是否要添加某项功能，可以先发起讨论询问大家意见。\n\n进行打包构建的方法\n\n```bash\npnpm install\npnpm run build\n```\n\n运行测试的方法\n\n\u003e 了解本项目使用方法也可以参考测试方法中的使用方法\n\n```bash\npnpm run test:base  // 基础初始化类测试\npnpm run test:uploadDelete  // 图片上传下载，生成在线链接测试\npnpm run test:album  // 测试相册相关功能\npnpm run test:tag  // 测试标签相关功能\npnpm run test:metadata  // 测试图片元数据相关\n```\n\n## 协议\u0026授权 📄\n\n项目使用 MIT 开源协议。\n\n## 鸣谢 🙏\n\n### vitest\n\n[vitest](https://vitest.dev/) 是一个快速、现代的前端测试框架，具有极高的性能和丰富的功能。它与 Vite 紧密集成，支持 TypeScript、ESM 和现代浏览器特性，提供了出色的开发体验。\n\n### parcel\n\n[parcel](https://parceljs.org/) 是一个零配置的快速打包工具，支持现代 JavaScript、TypeScript、CSS 和 HTML 等多种资源类型。它具有快速的热模块替换（HMR）功能，能够显著提升开发效率，并且支持代码拆分和优化，生成高性能的生产构建。\n\n通过使用 vitest 和 parcel，帮助我能够快速构建和测试项目，提升开发效率和代码质量。\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F2061360308%2Fs3imagehosting","html_url":"https://awesome.ecosyste.ms/projects/github.com%2F2061360308%2Fs3imagehosting","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F2061360308%2Fs3imagehosting/lists"}