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

@trimjs/web-app

v0.2.2

Published

web app sdk for nas

Readme

@trimjs/web-app

一个用于应用与基座平台通讯的 SDK。

简介

@trimjs/web-app 是一个跨平台通讯 SDK,让你的应用能够轻松调用基座平台的能力。

核心特性:

  • 🌐 跨平台支持 - 同时支持在 Web iframe 和 App WebView 中运行
  • 🎯 统一 API - 提供统一的接口调用基座平台能力(如设置标题、打开文件等)
  • 🔧 自动兼容 - 开发者无需关心底层平台差异,SDK 自动处理兼容性
  • 📦 开箱即用 - 简单初始化即可使用,无需复杂配置

安装

使用 npm、yarn 或 pnpm 安装:

# npm
npm install @trimjs/web-app

# yarn
yarn add @trimjs/web-app

# pnpm
pnpm add @trimjs/web-app

快速开始

基础使用

import { TrimApp } from "@trimjs/web-app";

// 创建实例
const app = new TrimApp();

// 调用方法
await app.setTitle("我的应用");

完整示例

import { TrimApp } from "@trimjs/web-app";

// 创建实例
const app = new TrimApp({
  debug: true, // 开启调试模式,会输出日志
});

// 设置应用标题
await app.setTitle("我的应用");

// 打开文件
await app.openFile("/path/to/file.pdf");

// 打开文件管理器
await app.openFileManager("/path/to/folder");

// 设置退出页面提示
await app.setExitPageTips({
  title: "确认退出?",
  content: "你有未保存的更改",
});

// 获取平台配置
const config = await app.getPlatformConfig();
console.log("主题:", config.theme);
console.log("语言:", config.language);
console.log("日期格式:", config.format.date);
console.log("时间格式:", config.format.time);

// 请求接口(仅 Web 平台)
if (app.isWeb) {
  const response = await app.query({
    api: "xxx.FileStation.List",
    method: "list",
    version: 2,
    params: { folder_path: "/home" },
  });
  console.log("文件列表:", response);
}

// 选择文件
const selectedFiles = await app.pickFile({
  multiple: true,
  accept: [".pdf", ".doc", ".docx"],
  title: "选择文档文件",
});
console.log("选中的文件:", selectedFiles);

注意:所有方法都会自动等待 SDK 初始化完成,你可以直接调用,无需手动等待。

API 文档

TrimApp

构造函数

new TrimApp(options?: TrimAppOptions)

创建 TrimApp 实例。

参数:

  • options (可选) - 配置选项
    • debug?: boolean - 是否开启调试模式,默认 false

示例:

// 不带配置
const app = new TrimApp();

// 开启调试模式
const app = new TrimApp({ debug: true });

setTitle

async setTitle(title: string): Promise<void | null>

设置应用标题。

参数:

  • title: string - 标题文本

返回值:

  • 成功时返回 Promise<void>
  • 失败时返回 Promise<null>

示例:

await app.setTitle("我的应用");

openFile

async openFile(path: string): Promise<void | null>

通过应用打开指定文件。

参数:

  • path: string - 文件路径

返回值:

  • 成功时返回 Promise<void>
  • 失败时返回 Promise<null>

示例:

await app.openFile("/path/to/document.pdf");

openFileManager

async openFileManager(path: string): Promise<void | null>

打开文件管理器并定位到指定路径。

参数:

  • path: string - 文件夹路径

返回值:

  • 成功时返回 Promise<void>
  • 失败时返回 Promise<null>

示例:

await app.openFileManager("/path/to/folder");

setExitPageTips

async setExitPageTips(params?: { title?: string; content?: string }): Promise<void | null>

设置退出页面时的提示信息。

参数:

  • params (可选) - 提示参数
    • title?: string - 提示标题
    • content?: string - 提示内容

返回值:

  • 成功时返回 Promise<void>
  • 失败时返回 Promise<null>

示例:

// 设置提示
await app.setExitPageTips({
  title: "确认退出?",
  content: "你有未保存的更改",
});

// 清除提示
await app.setExitPageTips();

getPlatformConfig

async getPlatformConfig(): Promise<PlatformConfig>

获取平台配置信息,包括主题、语言、日期时间格式等。

返回值:

  • Promise<PlatformConfig> - 平台配置对象

PlatformConfig 结构:

interface PlatformConfig {
  theme: "dark" | "light"; // 主题模式
  language: string; // 语言代码,如 "zh-CN"、"en-US"
  appVersion?: string; // 应用版本号
  systemVersion: string; // 系统版本号
  format: {
    date?: string; // 日期格式,如 "YYYY-MM-DD"、"MM-DD-YYYY"
    time?: string; // 时间格式,"12h" 或 "24h"
  };
}

示例:

const config = await app.getPlatformConfig();

// 根据主题调整 UI
if (config.theme === "dark") {
  document.body.classList.add("dark-mode");
}

// 根据语言设置国际化
i18n.setLocale(config.language);

// 根据日期格式格式化日期
const dateFormatter = new Intl.DateTimeFormat(config.language, {
  dateStyle: "short",
});

close

async close(): Promise<void>

关闭应用。

返回值:

  • Promise<void>

示例:

app.close();

ready

async ready(): Promise<void>

等待 SDK 初始化完成。虽然所有方法都会自动等待初始化,但在某些场景下你可能需要显式等待。

返回值:

  • Promise<void> - 初始化完成时 resolve

示例:

const app = new TrimApp();

// 显式等待初始化完成
await app.ready();

// 现在可以安全地访问属性
console.log("当前平台:", app.isWeb ? "Web" : "Mobile");

getOptions

getOptions(): TrimAppOptions

获取当前配置选项。

返回值:

  • TrimAppOptions - 当前配置对象

示例:

const options = app.getOptions();
console.log("调试模式:", options.debug);

setOptions

setOptions(options: Partial<TrimAppOptions>): void

更新配置选项。

参数:

  • options: Partial<TrimAppOptions> - 要更新的配置项

示例:

// 开启调试模式
app.setOptions({ debug: true });

// 关闭调试模式
app.setOptions({ debug: false });

query

async query<T>(params: any, config?: QueryConfig): Promise<ResponseData<T>>

请求接口(仅支持 Web 平台)。用于调用 NAS 系统的 API。

参数:

  • params: any - 请求参数,通常包含 API 名称、方法、版本等信息
  • config?: QueryConfig - 可选配置
    • timer?: boolean - 是否是定时器请求
    • observable?: boolean - 是否返回 Observable
    • skipPreflight?: boolean - 是否跳过预检请求
    • autoFailTips?: boolean - 是否自动显示失败提示

返回值:

  • Promise<ResponseData<T>> - 响应数据

ResponseData 结构:

interface ResponseData<T> {
  reqid: string; // 请求 ID
  result: ResponseStatus; // 响应状态:'succ' | 'fail' | 'cancel' | 'doing'
  taskId?: string; // 任务 ID(如果适用)
  type?: string; // 类型
  errmsg?: string; // 错误消息
  errno?: number; // 错误码
  extra?: string; // 额外信息
  // ... 其他 T 类型的字段
}

注意:

  • 此方法仅在 Web 平台(iframe)中可用
  • 在移动端调用会抛出错误

示例:

// 调用文件列表 API
const response = await app.query({
  api: "x'x'x.FileStation.List",
  method: "list",
  version: 2,
  params: {
    folder_path: "/home",
    additional: ["size", "time", "perm", "type"],
  },
});

if (response.result === "succ") {
  console.log("文件列表:", response);
} else {
  console.error("请求失败:", response.errmsg);
}

// 使用配置选项
const response2 = await app.query(
  { api: "xxxx", method: "query", version: 1 },
  {
    timer: false,
    autoFailTips: true,
  }
);

pickFile

async pickFile(params: FilePickerParams): Promise<string[]>

打开文件选择器,让用户选择文件或文件夹。

参数:

  • params: FilePickerParams - 文件选择器参数
    • multiple?: boolean - 是否多选,默认 false
    • directory?: boolean - 是否选择文件夹,默认 false
    • accept?: string[] - 接受的文件类型,如 ['.pdf', '.doc', '.docx']
    • sidebarGroup?: string[] - 侧边栏分组,可选值:'myFiles''otherShare''external''remote''favorites''storage''torrent''team',默认 ['myFiles']
    • disabledPaths?: string[] - 不可选的路径列表
    • selectablePatterns?: [string, string][] - 可选择的正则表达式(预留)
    • expandFiles?: Array<{ title: string; extension: string }> - 扩充搜索的文件类型
    • creatable?: boolean - 是否允许创建文件夹,默认 true
    • title?: string - 对话框标题,默认 '选择文件''选择文件夹'
    • okText?: string - 确认按钮文本,默认 '确定'

返回值:

  • Promise<string[]> - 选中的文件路径数组

示例:

// 选择单个文件
const files = await app.pickFile({
  multiple: false,
  accept: [".pdf", ".doc", ".docx"],
  title: "选择文档文件",
});
console.log("选中的文件:", files[0]);

// 选择多个文件
const multipleFiles = await app.pickFile({
  multiple: true,
  accept: [".jpg", ".png", ".gif"],
  title: "选择图片文件",
});
console.log("选中的文件:", multipleFiles);

// 选择文件夹
const folders = await app.pickFile({
  directory: true,
  title: "选择文件夹",
});
console.log("选中的文件夹:", folders[0]);

// 限制侧边栏范围
const files = await app.pickFile({
  multiple: true,
  sidebarGroup: ["myFiles", "favorites"],
  accept: [".txt", ".md"],
});

// 禁用某些路径
const files = await app.pickFile({
  disabledPaths: ["/vol1/1000/private", "/vol2/1000/temp"],
  accept: [".pdf"],
});

callAppMethod

async callAppMethod<T>(fn: string, params?: string): Promise<T | null>

调用移动端 App 的方法(仅移动端可用)。

参数:

  • fn: string - 要调用的方法名
  • params?: string - 方法参数(JSON 字符串)

返回值:

  • Promise<T | null> - 方法返回结果,失败时返回 null

注意:

  • 此方法仅在移动端(WebView)中可用
  • 在 Web 平台调用会返回 null
  • 建议使用 SDK 提供的标准方法(如 setTitleopenFile 等),而不是直接调用此方法

示例:

// 调用自定义方法
const result = await app.callAppMethod<{ success: boolean }>(
  "customMethod",
  JSON.stringify({ key: "value" })
);

实例属性

isWeb

readonly isWeb: boolean

判断当前运行环境是否为 Web 平台。

  • true - 运行在 Web iframe 中
  • false - 运行在移动端 WebView 中

示例:

const app = new TrimApp();
await app.ready();

if (app.isWeb) {
  console.log("运行在 Web 平台");
  // Web 平台特有逻辑
} else {
  console.log("运行在移动端");
  // 移动端特有逻辑
}

配置选项

TrimAppOptions

interface TrimAppOptions {
  /** 是否开启调试模式,开启后会输出日志 */
  debug?: boolean;
}

选项说明:

  • debug (可选) - 是否开启调试模式
    • 类型:boolean
    • 默认值:false
    • 说明:开启后会在控制台输出 SDK 运行日志,方便调试

示例:

// 开启调试模式
const app = new TrimApp({ debug: true });

// 运行时切换调试模式
app.setOptions({ debug: false });

PlatformConfig

interface PlatformConfig {
  theme: "dark" | "light"; // 主题模式
  language: string; // 语言代码,如 "zh-CN"、"en-US"
  appVersion?: string; // 应用版本号
  systemVersion: string; // 系统版本号
  format: {
    date?: string; // 日期格式,如 "YYYY-MM-DD"、"MM-DD-YYYY"、"DD-MM-YYYY"、"YYYY/MM/DD"、"MM/DD/YYYY"、"DD/MM/YYYY"
    time?: string; // 时间格式,"12h" 或 "24h"
  };
}

字段说明:

  • theme - 当前主题模式
    • "dark" - 深色模式
    • "light" - 浅色模式
  • language - 语言代码,遵循 BCP 47 标准
    • 常见值:"zh-CN"(简体中文)、"en-US"(美式英语)等
  • appVersion (可选) - 应用版本号
  • systemVersion - 系统版本号
  • format.date (可选) - 日期格式
    • 支持格式:"YYYY-MM-DD""MM-DD-YYYY""DD-MM-YYYY""YYYY/MM/DD""MM/DD/YYYY""DD/MM/YYYY"
  • format.time (可选) - 时间格式
    • "12h" - 12 小时制
    • "24h" - 24 小时制

平台差异

Web 平台(iframe)

在 Web 平台中,SDK 通过 postmate 与父窗口(OS)进行通信。

支持的方法:

  • setTitle - 设置标题
  • setExitPageTips - 设置退出提示
  • openFile - 打开文件
  • openFileManager - 打开文件管理器
  • getPlatformConfig - 获取平台配置
  • close - 关闭应用
  • query - 请求接口
  • pickFile - 选择文件

移动端平台(WebView)

在移动端平台中,SDK 通过 flutter_inappwebview 与原生 App 进行通信。

支持的方法:

  • setTitle - 设置标题
  • setExitPageTips - 设置退出提示
  • openFile - 打开文件
  • openFileManager - 打开文件管理器
  • getPlatformConfig - 获取平台配置
  • close - 关闭页面
  • query - 不支持(会抛出错误)
  • pickFile - 选择文件
  • callAppMethod - 调用自定义 App 方法

类型导出

SDK 导出了以下类型,方便你在 TypeScript 项目中使用:

import type { TrimAppOptions, PlatformConfig } from "@trimjs/web-app";

如果需要使用其他类型(如 FilePickerParamsQueryConfigResponseData),可以从 @fn/micro-app-postmate 导入:

import type {
  FilePickerParams,
  QueryConfig,
  ResponseData,
} from "@fn/micro-app-postmate/src/child/type";
import type { ResponseData as ResponseDataType } from "@fn/micro-app-postmate/src/child/os-type";

使用场景

场景 1:根据平台配置调整 UI

const app = new TrimApp({ debug: true });
const config = await app.getPlatformConfig();

// 根据主题切换 UI
if (config.theme === "dark") {
  document.body.classList.add("dark-mode");
}

// 根据语言设置国际化
i18n.setLocale(config.language);

// 根据日期格式显示日期
const dateFormat = config.format.date || "YYYY-MM-DD";
const formattedDate = dayjs().format(dateFormat);

场景 2:文件上传功能

// 让用户选择文件
const selectedFiles = await app.pickFile({
  multiple: true,
  accept: [".jpg", ".png", ".pdf"],
  title: "选择要上传的文件",
});

if (selectedFiles && selectedFiles.length > 0) {
  // 处理选中的文件
  for (const filePath of selectedFiles) {
    console.log("上传文件:", filePath);
    // 执行上传逻辑...
  }
}

场景 3:调用 NAS API

// 仅在 Web 平台调用 API
if (app.isWeb) {
  try {
    const response = await app.query({
      api: "xxx.FileStation.List",
      method: "list",
      version: 2,
      params: {
        folder_path: "/home",
        additional: ["size", "time", "perm"],
      },
    });

    if (response.result === "succ") {
      console.log("文件列表获取成功");
    }
  } catch (error) {
    console.error("API 调用失败:", error);
  }
}

场景 4:页面退出确认

// 在用户有未保存数据时设置退出提示
app.setExitPageTips({
  title: "确认离开?",
  content: "您有未保存的更改,确定要离开吗?",
});

// 保存数据后清除提示
async function saveData() {
  // 保存逻辑...
  await app.setExitPageTips(); // 清除提示
}

注意事项

  1. 初始化时机:SDK 会在创建实例时自动初始化,所有方法都会自动等待初始化完成,无需手动调用 ready()

  2. 平台检测:SDK 会自动检测运行环境(Web 或移动端),通过 isWeb 属性可以判断当前平台。

  3. 错误处理:某些方法在特定平台可能不可用(如 query 在移动端),调用前建议检查 isWeb 属性。

  4. 调试模式:开启 debug 选项后,SDK 会在控制台输出详细的运行日志,方便开发和调试。

  5. 异步方法:所有与平台交互的方法都是异步的,记得使用 await.then() 处理。

  6. 文件选择器pickFile 方法会打开系统文件选择器,用户可能取消选择,返回的数组可能为空,记得处理这种情况。

  7. API 请求query 方法返回的 ResponseData 包含 result 字段,需要检查状态是否为 'succ' 来判断请求是否成功。

常见问题

Q: 如何判断当前运行在哪个平台?

A: 使用 isWeb 属性:

const app = new TrimApp();
await app.ready();

if (app.isWeb) {
  console.log("运行在 Web 平台");
} else {
  console.log("运行在移动端");
}

Q: 为什么调用某些方法会报错?

A: 某些方法只在特定平台可用:

  • query() 仅在 Web 平台可用
  • 在移动端调用这些方法会抛出错误

建议在调用前检查平台:

if (app.isWeb) {
  await app.query();
} else {
  console.log("当前平台不支持 query 方法");
}

Q: 如何等待 SDK 初始化完成?

A: 虽然所有方法都会自动等待初始化,但如果你需要显式等待:

const app = new TrimApp();
await app.ready();
// 现在可以安全地使用所有功能

Q: pickFile 返回空数组是什么意思?

A: 如果用户取消了文件选择,pickFile 会返回空数组。记得处理这种情况:

const files = await app.pickFile({ multiple: true });
if (files.length === 0) {
  console.log("用户取消了选择");
  return;
}
// 处理选中的文件...

Q: 如何调试 SDK 的问题?

A: 开启 debug 模式,SDK 会在控制台输出详细日志:

const app = new TrimApp({ debug: true });
// 现在所有操作都会输出日志

Q: query 方法返回的 result 字段有哪些值?

A: result 字段可能的值:

  • 'succ' - 成功
  • 'fail' - 失败
  • 'cancel' - 用户取消
  • 'doing' - 任务进行中
const response = await app.query({
  /* ... */
});
if (response.result === "succ") {
  // 处理成功情况
} else if (response.result === "fail") {
  // 处理失败情况
  console.error("错误:", response.errmsg);
}

Q: 可以在移动端使用 query 方法吗?

A: 不可以。query 方法仅在 Web 平台可用。在移动端调用会抛出错误。如果需要调用 API,建议在 Web 平台使用,或者通过 callAppMethod 调用移动端原生方法。

开发

# 安装依赖
pnpm install

# 开发模式
pnpm dev

# 构建
pnpm build

# 类型检查
pnpm typecheck

# 代码检查
pnpm lint

许可证

MIT