npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@dd-code/oss-uploader

v0.1.14

Published

Upload local directories to OSS (currently Huawei OBS) with pluggable middleware and providers.

Readme

OSS Uploader

将本地目录上传到对象存储(当前支持华为云 OBS)的 npm 包,提供 CLI 与库两种使用方式。采用中间件 + Provider 抽象,便于后续切换或接入其他云厂商(如阿里云 OSS、AWS S3)。


功能特性

  • 目录上传:按本地目录结构上传到指定 Bucket,远端 key 规则为 basePrefix / env / pathPrefix / 相对路径
  • 同名跳过:上传前按前缀调用 OBS listObjects 拉取已有 key,内存 Set 判断是否存在,仅 1 次(或少量)列表请求,不再逐文件 head,大幅提速。
  • 强制覆盖:环境变量 FILE_RE_WHITE_LIST(JSON 数组)中匹配到的 key 始终上传、不跳过。
  • 过滤规则:支持 --include / --exclude 通配符(如 **/*.js**/*.map),使用 micromatch
  • 上传进度:控制台显示进度条(当前/总数、百分比),基于 cli-progress
  • CDN 地址:可选配置 OBS_CDN_BASE_URL,上传完成后控制台打印每个文件的访问 URL。
  • 可切换 Provider:通过环境变量 OSS_PROVIDER 与单一配置文件 ProviderConfigResolverImpl 即可切换云厂商,无需改业务代码。

环境要求

  • Node.js:>= 18
  • 包管理:npm / pnpm / yarn 均可

安装

# 从本地或私有 registry 安装(请将 @your-scope/oss-uploader 替换为实际包名与版本)
npm install @your-scope/oss-uploader

# 或在本仓库根目录
pnpm install
pnpm run build

配置

所有配置通过环境变量读取,不依赖 .env 文件(若使用 dotenv 可在进程内自行加载)。

华为 OBS(当前默认)

| 变量名 | 必填 | 说明 | |--------|------|------| | OBS_ENDPOINT | 是 | OBS 服务地址,如 https://obs.cn-north-4.myhuaweicloud.com | | OBS_ACCESS_KEY | 是 | 访问密钥 AK | | OBS_SECRET_KEY | 是 | 访问密钥 SK | | OBS_REGION | 否 | 区域,如 cn-north-4 | | OBS_BASE_PREFIX | 否 | 所有对象 key 的基础前缀(仅在配置中,不通过 CLI 暴露),如 company/project-a | | OBS_CDN_BASE_URL | 否 | CDN 加速根地址,用于上传完成后拼出访问 URL,如 https://cdn.example.com | | FILE_RE_WHITE_LIST | 否 | JSON 数组字符串,key 包含其中任一项则强制上传不跳过,如 ["index.html","sw.js"] |

多云与切换

| 变量名 | 必填 | 说明 | |--------|------|------| | OSS_PROVIDER | 否 | 当前使用的存储,默认 huawei。后续可扩展 aliyunaws 等。 |

示例 .env.example(可复制为 .env 并按实际填写):

# 华为 OBS
OBS_ENDPOINT=https://obs.cn-north-4.myhuaweicloud.com
OBS_ACCESS_KEY=your-access-key-id
OBS_SECRET_KEY=your-secret-access-key
OBS_REGION=cn-north-4
OBS_BASE_PREFIX=company/project-a
OBS_CDN_BASE_URL=https://cdn.example.com

# 可选:强制覆盖的 key 片段(JSON 数组)
# FILE_RE_WHITE_LIST=["index.html","sw.js"]

# 可选:切换存储厂商
# OSS_PROVIDER=huawei

使用方式

一、命令行(CLI)

安装后可通过 oss-uploader 命令上传本地目录(若未全局安装,可使用 npx oss-uploaderpnpm exec oss-uploader)。

# 基本用法:上传 ./dist 到指定 bucket
oss-uploader ./dist -b my-bucket --path-prefix app/v1/

# 带 include/exclude
oss-uploader ./dist -b my-bucket --path-prefix app/v1/ \
  --include "**/*.js" --include "**/*.css" \
  --exclude "**/*.map"

# 指定环境标识(会参与 key 拼接)
npx oss-uploader ./dist -e dev --path-prefix web/app

CLI 参数说明

| 参数 | 简写 | 必填 | 说明 | |------|------|------|------| | localDir | - | 是 | 本地目录路径 | | --bucket | -b | 否 | Bucket 名称,默认 hr-uat | | --env | -e | 否 | 环境标识,参与 key 拼接,默认 dev | | --path-prefix | - | 否 | 业务路径前缀,拼在 base/env 之后 | | --include | - | 否 | 包含的文件模式,可多次 | | --exclude | - | 否 | 排除的文件模式,可多次 |

上传过程中会显示进度条(当前/总数、百分比),结束后输出:成功/失败/跳过的 key 列表;若配置了 CDN 会打印访问地址。


二、作为库使用

包入口仅暴露一个上传方法 upload 及类型 UploadOptionsUploadResult,内部配置与 Reporter 固定(从环境变量读取,进度输出到控制台)。

import { upload, type UploadOptions, type UploadResult } from '@dd-code/oss-uploader';

const result: UploadResult = await upload({
  localDir: './dist',
  bucket: 'my-bucket',
  env: 'prod',
  pathPrefix: 'app/v1',
  include: ['**/*.js', '**/*.css'],
  exclude: ['**/*.map'],
});

console.log(`总数: ${result.total}, 成功: ${result.success.length}, 失败: ${result.failed.length}, 跳过: ${result.skipped.length}`);

需要自定义 Reporter(如对接企业微信、钉钉)时,可直接使用中间件层 uploadDirectory 并传入 reporter(见源码 middleware/OssService.ts)。


远端 Key 规则

单个文件的远端 key 由以下部分按顺序拼接(空段不参与):

basePrefix / env / pathPrefix / 相对路径
  • basePrefix:来自配置 OBS_BASE_PREFIX,仅在配置中设置,不通过 CLI 暴露,默认都会带上前缀。
  • env:CLI 的 --env 或库入参的 env
  • pathPrefix:CLI 的 --path-prefix 或库入参的 pathPrefix
  • 相对路径:相对 localDir 的路径,保持目录结构。

示例:basePrefix=company/projenv=prodpathPrefix=web、本地文件 dist/js/app.js → 远端 key:company/proj/prod/web/js/app.js


架构与设计

分层结构

┌─────────────────────────────────────────────────────────┐
│  CLI / 业务代码                                           │
│  CLI 调用 uploadDirectory,库调用 upload(options)         │
└───────────────────────────┬─────────────────────────────┘
                            │
┌───────────────────────────▼─────────────────────────────┐
│  中间件层:OssService                                     │
│  解析配置、创建 StorageClient、组装 DirectoryUploadFlow   │
└───────────────────────────┬─────────────────────────────┘
                            │
┌───────────────────────────▼─────────────────────────────┐
│  流程层:UploadService / DirectoryUploadFlow              │
│  收集文件 → 过滤 → listObjectKeys 拉取已有 key →          │
│  逐文件 Set 判断 / head 回退 → putObject → Reporter       │
└───────────────────────────┬─────────────────────────────┘
                            │
┌───────────────────────────▼─────────────────────────────┐
│  Provider 层:StorageClient 实现(如 HuaweiObsClient)   │
│  listObjectKeys、headObject、putObject 对应 OBS API      │
└─────────────────────────────────────────────────────────┘

设计模式简述

  • Facade:对外只暴露 upload(options),内部固定配置与 Reporter。
  • Template MethodUploadService 定义「收集 → 过滤 → 上传 → 上报」骨架,DirectoryUploadFlow 继承并执行。
  • Strategy / Adapter:各云厂商实现 StorageClient(含可选 listObjectKeys),由 StorageFactory 按配置创建。

目录结构(源码)

src/
├── index.ts                 # 包入口,仅导出 upload / UploadOptions / UploadResult
├── cli.ts                   # CLI 入口(oss-uploader)
├── config/
│   ├── types.ts             # 配置与 Provider 类型
│   ├── EnvConfigResolverImpl.ts
│   ├── ProviderConfigResolverImpl.ts
│   └── loadObsCredentialsFromUrl.ts
├── core/
│   ├── StorageClient.ts     # 存储客户端接口(含可选 listObjectKeys)
│   ├── StorageFactory.ts
│   ├── UploadService.ts     # 上传流程基类(收集 → list/head 判断 → put)
│   ├── DirectoryUploadFlow.ts
│   ├── reporter.ts          # Reporter 与 ConsoleReporter(含进度条)
│   ├── filters.ts
│   └── urlHelper.ts
├── middleware/
│   └── OssService.ts        # 统一 API,解析配置并调用 Flow
└── providers/
    └── huawei/
        └── HuaweiObsClient.ts   # OBS 的 listObjectKeys / headObject / putObject

扩展与二次开发

切换云厂商(如阿里云 OSS)

  1. src/config/types.ts 中扩展 ProviderType 与对应配置类型(如 AliyunOssConfig)、在 ProviderConfig 中增加分支。
  2. src/config/ProviderConfigResolverImpl.tsresolve() 中增加 case 'aliyun',从环境变量读取阿里云配置,返回 { providerConfig, basePrefix, cdnBaseUrl }
  3. src/core/StorageFactory.ts 中增加 case 'aliyun',创建阿里云 Provider 实例。
  4. src/providers/ 下新增对应客户端,实现 StorageClientheadObjectputObject,可选实现 listObjectKeys 以启用「先 list 再判断」的加速逻辑。

业务侧只需设置 OSS_PROVIDER=aliyun 及对应环境变量,无需改 OssService / CLI。

自定义 Reporter

实现接口(含可选 onProgress):

interface Reporter {
  onStart?(context: { env?, bucket, basePrefix, pathPrefix, localDir, cdnBaseUrl? }): void | Promise<void>;
  onProgress?(current: number, total: number): void | Promise<void>;
  onFileResult?(result: UploadFileResult): void | Promise<void>;
  onComplete?(summary: UploadSummary): void | Promise<void>;
}

需直接使用中间件层 uploadDirectory 并传入 reporter(包入口 upload() 不暴露 reporter 参数),详见 middleware/OssService.ts

工具方法

  • 包入口仅导出 uploadUploadOptionsUploadResultbuildCdnAccessUrl 等工具在内部使用,若需在业务中拼 CDN URL 可参考 core/urlHelper.ts

构建与发布

# 安装依赖
pnpm install

# 构建(Rollup 输出 dist/index.cjs、dist/cli.cjs 等)
pnpm run build

# 监听模式
pnpm run dev

发布前请将 package.json 中的 name 改为实际 scope 与包名(当前为 @dd-code/oss-uploader),按需配置 publishConfig 与 registry。