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

@lark-apaas/file-service

v0.1.1

Published

File Service Core Package

Downloads

1,832

Readme

@lark-apaas/file-service

File Service Core Package - 一个基于 TypeScript 实现的 Node.js 文件服务 SDK,提供文件上传、下载、管理等完整功能。

特性

  • TypeScript 编写,提供完整的类型定义
  • 支持文件上传(支持 Buffer、Blob、File、Stream 等多种格式)
  • 支持文件下载(Blob 和 Stream 两种模式,Blob 模式限制 50MB)
  • 文件列表查询和搜索
  • 文件元数据获取
  • 文件删除
  • 签名 URL 生成
  • 获取当前应用对应的 bucket

环境要求

  • Node.js >= 18.0.0

安装

npm install @lark-apaas/file-service

或使用 yarn:

yarn add @lark-apaas/file-service

快速开始

import { FileService } from '@lark-apaas/file-service';

// 创建 FileService 实例
const fileService = new FileService(fetchClient);

// 上传文件
const result = await fileService.upload({
  appId: 'your-app-id',
  bucketId: 'your-bucket-id',
  fileBody: file,
  options: {
    fileName: 'example.txt',
    contentType: 'text/plain'
  }
});

// 下载文件
const { content, metadata } = await fileService.download({
  appId: 'your-app-id',
  bucketId: 'your-bucket-id',
  filePath: 'path/to/file.txt'
});

API 文档

初始化

new FileService(fetchClient: FetchClient)

创建 FileService 实例。

参数:

  • fetchClient: FetchClient - HTTP 客户端实例
interface FetchClient {
  request(config: RequestInit): Promise<Response>;
}

文件上传

upload(params: UploadParams): Promise<CallbackData | undefined>

上传文件到指定的 bucket。

参数:

interface UploadParams {
  appId: string;          // 应用 ID
  bucketId: string;       // 存储桶 ID
  fileBody: FileBody;     // 文件内容
  options?: UploadOptions; // 上传选项
}

type FileBody =
  | ArrayBuffer
  | Blob
  | Buffer
  | File
  | NodeJS.ArrayBufferView
  | NodeJS.ReadableStream      // Node.js 可读流
  | ReadableStream<Uint8Array> // Web 可读流
  | string;

interface UploadOptions {
  filePath?: string;           // 文件路径(可选)
  fileName?: string;           // 文件名(可选)
  cacheControl?: string | number; // 缓存控制(可选)
  contentType?: string;        // 内容类型(可选)
  upsert?: boolean;            // 是否覆盖已存在的文件(可选)
  contentDisposition?: string; // 内容处置(可选)
}

返回值:

interface CallbackData {
  bucketID: string;    // 存储桶 ID
  filePath: string;    // 文件路径
  downloadURL: string; // 下载 URL
  fileName: string;    // 文件名
}

示例:

const result = await fileService.upload({
  appId: 'app-123',
  bucketId: 'bucket-456',
  fileBody: fileBuffer,
  options: {
    fileName: 'document.pdf',
    contentType: 'application/pdf',
    upsert: true
  }
});

console.log(result.downloadURL); // 文件下载地址

文件下载

download(params: DownloadParams): FileDownloadBuilder

下载文件,返回 Builder 对象支持链式调用。

参数:

interface DownloadParams {
  appId: string;    // 应用 ID
  bucketId: string; // 存储桶 ID
  filePath: string; // 文件路径
}

返回值:

返回 FileDownloadBuilder 实例,支持以下两种使用方式:

1. 作为 Promise 使用(默认返回 Blob)
Promise<DownloadResult<Blob>>

interface DownloadResult<T> {
  content: T;                  // 文件内容
  metadata: FileMeta | null;   // 文件元数据
}

限制:

  • Blob 模式下文件大小不能超过 50MB,超过 50MB 请使用 asStream() 方法
2. 使用 asStream() 方法获取流
download(params).asStream(): Promise<DownloadResult<ReadableStream>>

FileMeta 类型定义:

interface FileMeta {
  id: string;           // 文件 ID
  name: string;         // 文件名
  filePath: string;     // 文件路径
  metadata: {
    contentLength: string; // 文件大小
    mimeType: string;      // MIME 类型
  } & Record<string, string>;
  downloadURL: string;  // 下载 URL
  createdAt: string;    // 创建时间
  createdBy: User;      // 创建者
  updatedAt: string;    // 更新时间
  updatedBy: User;      // 更新者
  bucketID: string;     // 存储桶 ID
}

interface User {
  avatar: string;    // 用户头像
  status: UserStatus; // 用户状态
  userID: number;    // 用户 ID
  email: string;     // 用户邮箱
  name: string;      // 用户名称
  userType: string;  // 用户类型
}

enum UserStatus {
  active = 1,
  inactive,
}

示例:

// 方式 1: 下载为 Blob (文件大小需小于 50MB)
const { content, metadata } = await fileService.download({
  appId: 'app-123',
  bucketId: 'bucket-456',
  filePath: 'documents/file.pdf'
});

console.log(metadata.name); // 文件名
console.log(metadata.metadata.contentLength); // 文件大小

// 方式 2: 下载为 Stream (推荐用于大文件)
const { content: stream, metadata } = await fileService.download({
  appId: 'app-123',
  bucketId: 'bucket-456',
  filePath: 'documents/large-file.pdf'
}).asStream();

// 使用流
stream.pipeTo(writableStream);

创建签名 URL

createSignedUrl(params: SignedUrlParams): Promise<string>

为文件创建临时访问的签名 URL。

参数:

interface SignedUrlParams {
  appId: string;     // 应用 ID
  bucketId: string;  // 存储桶 ID
  filePath: string;  // 文件路径
  expiresIn: number; // 过期时间(秒)
}

返回值:

string // 签名后的 URL

示例:

const signedUrl = await fileService.createSignedUrl({
  appId: 'app-123',
  bucketId: 'bucket-456',
  filePath: 'documents/file.pdf',
  expiresIn: 3600 // 1小时后过期
});

console.log(signedUrl); // https://...

文件列表

list(params: ListParams): Promise<ListResponse>

获取指定前缀的文件列表。

参数:

interface ListParams {
  appId: string;              // 应用 ID
  bucketId: string;           // 存储桶 ID
  prefix: string;             // 文件路径前缀
  searchOptions?: SearchOptions; // 搜索选项(可选)
}

interface SearchOptions {
  /**
   * 返回的文件数量限制
   * @default 100
   */
  maxKeys?: number;

  /**
   * 分页标记,用于获取下一页
   */
  continuationToken?: string;

  /**
   * 排序选项
   */
  sortBy?: SortBy;
}

interface SortBy {
  column?: string; // 排序列名
  order?: string;  // 排序顺序(asc/desc)
}

返回值:

interface ListResponse {
  attachments: FileMeta[]; // 文件列表
  hasMore: boolean;        // 是否还有更多文件
}

示例:

// 基础查询
const result = await fileService.list({
  appId: 'app-123',
  bucketId: 'bucket-456',
  prefix: 'documents/'
});

console.log(result.attachments); // 文件数组
console.log(result.hasMore); // 是否有更多

// 带分页和排序
const result = await fileService.list({
  appId: 'app-123',
  bucketId: 'bucket-456',
  prefix: 'documents/',
  searchOptions: {
    maxKeys: 50,
    sortBy: {
      column: 'createdAt',
      order: 'desc'
    }
  }
});

删除文件

remove(params: RemoveParams): Promise<FileMeta[]>

删除指定的文件。

参数:

interface RemoveParams {
  appId: string;       // 应用 ID
  bucketId: string;    // 存储桶 ID
  filePaths: string[]; // 要删除的文件路径数组
}

返回值:

FileMeta[] // 已删除的文件元数据数组

示例:

const deletedFiles = await fileService.remove({
  appId: 'app-123',
  bucketId: 'bucket-456',
  filePaths: [
    'documents/file1.pdf',
    'documents/file2.pdf'
  ]
});

console.log(`已删除 ${deletedFiles.length} 个文件`);

获取文件元数据

getFileMetadata(params: MetadataParams): Promise<FileMeta | null>

获取指定文件的元数据信息。

参数:

interface MetadataParams {
  appId: string;    // 应用 ID
  bucketId: string; // 存储桶 ID
  filePath: string; // 文件路径
}

返回值:

FileMeta | null // 文件元数据,如果文件不存在则返回 null

示例:

const metadata = await fileService.getFileMetadata({
  appId: 'app-123',
  bucketId: 'bucket-456',
  filePath: 'documents/file.pdf'
});

if (metadata) {
  console.log(metadata.name); // 文件名
  console.log(metadata.metadata.contentLength); // 文件大小
  console.log(metadata.metadata.mimeType); // MIME 类型
  console.log(metadata.createdAt); // 创建时间
} else {
  console.log('文件不存在');
}

获取默认 Bucket

getDefaultBucket(appId: string): Promise<string>

获取应用的默认存储桶 ID。

参数:

appId: string // 应用 ID

返回值:

string // 默认存储桶 ID

示例:

const defaultBucketId = await fileService.getDefaultBucket('app-123');
console.log(defaultBucketId); // bucket-456

类型定义

完整类型导出

export {
  FileService,
  FileDownloadBuilder,
  StreamDownloadBuilder,
  // 类型
  FileBody,
  ApiResponse,
  User,
  UserStatus,
  FileMeta,
  UploadOptions,
  SortBy,
  SearchOptions,
  FetchClient,
  RequestConfig,
  CustomError,
  DownloadResult,
  PreUploadResponse,
  CallbackResponse,
  GetPublishedV2Response,
  DownloadInnerResponse,
  ListResponse,
  RemoveResponse,
  GetMetaResponse
};

错误处理

SDK 可能抛出以下错误:

HttpError

HTTP 请求失败时抛出。

class HttpError extends Error {
  status: string | number; // HTTP 状态码或错误代码
  message: string;         // 错误消息
  body?: string;           // 响应体内容(可选)
}

常见错误

  • Blob 下载超限: Can't download file blob larger than 50MB, use asStream() instead.
  • 上传失败: preUpload failed, uploadURL or uploadID is empty
  • 下载失败: download failed, status: xxx
  • Bucket 不存在: No bucket found from remote for appId xxx
  • 文件不存在: 返回 null 而不抛出错误

示例:

try {
  await fileService.upload({
    appId: 'app-123',
    bucketId: 'bucket-456',
    fileBody: largeFile
  });
} catch (error) {
  if (error instanceof Error) {
    console.error(error.message);
  }
}

高级用法

自定义 FetchClient

import { FileService } from '@lark-apaas/file-service';

const customFetchClient = {
  async request(config: RequestInit): Promise<Response> {
    // 自定义请求逻辑,例如添加认证头
    const headers = {
      ...config.headers,
      'Authorization': 'Bearer your-token'
    };

    return fetch(config.url, {
      ...config,
      headers
    });
  }
};

const fileService = new FileService(customFetchClient);

流式上传

支持使用 Node.js Readable Stream 或 Web ReadableStream 上传文件:

import { Readable } from 'stream';

// 方式 1: 使用 Node.js Readable Stream
const nodeStream = Readable.from(['Hello', ' ', 'World']);
await fileService.upload({
  appId: 'app-123',
  bucketId: 'bucket-456',
  fileBody: nodeStream,
  options: {
    fileName: 'stream-file.txt',
    contentType: 'text/plain'
  }
});

// 方式 2: 使用自定义 Readable Stream
const customStream = new Readable({
  read() {
    this.push('custom data');
    this.push(null); // 结束流
  }
});
await fileService.upload({
  appId: 'app-123',
  bucketId: 'bucket-456',
  fileBody: customStream,
  options: { fileName: 'custom-stream.txt' }
});

// 方式 3: 使用生成器创建流
async function* dataGenerator() {
  yield 'chunk1';
  yield 'chunk2';
  yield 'chunk3';
}
const generatorStream = Readable.from(dataGenerator());
await fileService.upload({
  appId: 'app-123',
  bucketId: 'bucket-456',
  fileBody: generatorStream,
  options: { fileName: 'generator-file.txt' }
});

流式下载大文件

// 下载大文件并保存到磁盘
const { content: stream } = await fileService.download({
  appId: 'app-123',
  bucketId: 'bucket-456',
  filePath: 'large-file.zip'
}).asStream();

// Node.js 环境
import { createWriteStream } from 'fs';
import { Readable } from 'stream';

const fileStream = createWriteStream('output.zip');
Readable.fromWeb(stream).pipe(fileStream);

批量操作

// 批量上传
const files = [file1, file2, file3];
const uploadPromises = files.map(file =>
  fileService.upload({
    appId: 'app-123',
    bucketId: 'bucket-456',
    fileBody: file,
    options: { fileName: file.name }
  })
);
const results = await Promise.all(uploadPromises);

// 批量删除
const filePaths = results.map(r => r.filePath);
await fileService.remove({
  appId: 'app-123',
  bucketId: 'bucket-456',
  filePaths
});

许可证

MIT


更新日志

0.0.1-alpha.10

  • 初始发布版本
  • 支持文件上传、下载、列表、删除等核心功能
  • 提供完整的 TypeScript 类型定义