# @gainratio/browser 中文文档

规范地址：https://npmcn.com/package/%40gainratio/browser/

版本：0\.4\.6
npm 元数据更新时间：2026-11-10T18:23:54.608Z
中文译文更新时间：2026-11-15T21:10:04.497Z
软件包许可：MIT

本文由上游 README 翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/%40gainratio/browser
原文对照：https://npmcn.com/package/%40gainratio/browser/?lang=original
项目主页：https://github.com/gainratio/edgeproc-browser#readme
源码仓库：https://github.com/gainratio/edgeproc-browser

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：2.8 MB，286 个文件
- 模块格式：ES Module
- TypeScript 类型：包内自带
- Node.js 要求：\>=22\.13
- 运行依赖：3 个
- 首次发布：2026-10-02T16:29:03.222Z
- 最新版本发布：2026-11-10T18:23:54.248Z
- 近 30 天下载量：5019（2026-10-16 至 2026-11-14，npm 官方下载统计）
- 已发布版本数：13（近 12 个月 13 个）

## 中文简介

对于 Web 开发者: 请检查下载的数据由您签名而不更改的浏览器, 然后保存到离线使用 .

## 安装

```sh
npm install @gainratio/browser
```

也可以使用：`pnpm add @gainratio/browser`、`yarn add @gainratio/browser`、`bun add @gainratio/browser`

## README

# @ gainratio/ 浏览器

对于 Web 开发者: 请检查下载的数据由您签名而不更改的浏览器, 然后保存到离线使用 .

**`npm install @gainratio/browser`** (第0.4.6版; `@edgeproc/browser` 是旧名, 已贬值)

**文档 :** [浏览器. contratio.com](https://browser.gainratio.com/) • 妇女 [开始](https://browser.gainratio.com/docs/) • 妇女 [实例](https://browser.gainratio.com/examples/)

[![CI](https://github.com/gainratio/edgeproc-browser/actions/workflows/ci.yml/badge.svg)](https://github.com/gainratio/edgeproc-browser/actions/workflows/ci.yml) [![npm](https://img.shields.io/npm/v/@gainratio/browser)](https://www.npmjs.com/package/@gainratio/browser) [![License](https://img.shields.io/github/license/gainratio/edgeproc-browser)](https://npmcn.com/package/%40gainratio/browser/LICENSE)

许多网络应用下载数据文件,并在页面内与他们合作:一个产品目录,a 搜索索引,价格列表,模型. 该页面信任服务器或CDN发送回的任何内容 . 如果镜像为旧副本服务,或者文件在路上被更改或缩短,则应用程序使用它 无论如何,没有人注意到.

此软件包让页面检查数据本身 。 你公布数据一次 这个 页面在背景线条( Web Worker)中下载,检查您的签名和 拒绝任何不符合要求的东西 它把检查的副本放在 浏览器,所以下一次访问的下载仅是更改了哪些内容,仍然在下线工作. [阿尔马梅什](https://github.com/gainratio/almamesh) 用它来下载它的图表引擎.

**技术文件:** [建筑](https://npmcn.com/package/%40gainratio/browser/docs/ARCHITECTURE.md) • 妇女 [API 指南](https://npmcn.com/package/%40gainratio/browser/docs/API.md) • 妇女 [开始开发者](https://npmcn.com/package/%40gainratio/browser/docs/GETTING_STARTED.md) • 妇女 [警卫](https://npmcn.com/package/%40gainratio/browser/SECURITY.md)

## 试试看

你需要节点22.13或更新,和 [页:1](https://docs.astral.sh/uv/) 运行 Python 工具 签名的数据。 这大约需要一分钟.

1.  制作一个项目并安装软件包, 加上 Vite 服务页面 :
    
    ```bash
    mkdir signed-data-demo && cd signed-data-demo
    npm init -y
    npm install @gainratio/browser vite
    ```
    
2.  与 `edgeproc` 从 Python 命令 [`edge-proc`](https://github.com/gainratio/edge-proc) 软件包 :
    
    ```bash
    mkdir data
    echo '{"sku": "A-100", "name": "Blue mug", "price": 12.5}' > data/prices.json
    uvx --from 'edge-proc[bundles]' edgeproc keygen --out keys
    uvx --from 'edge-proc[bundles]' edgeproc publish --src data --origin-dir public/bundle \
      --key keys/private.key --bundle-id prices --version v1 --sequence 1
    cp keys/public.key public/public.key
    ```
    
    `keygen` 指纹 `wrote keys/private.key and keys/public.key` 和钥匙身份. `publish` 将签名的指针打印为 JSON. `public/bundle` 现在持有该指针( a)`latest`页:1 文件列表( e)`manifest/`)和数据为零(`chunk/`) (中文(简体) ). 保留 `--sequence 1`页:1 浏览器拒绝一个没有序列号的捆绑, 你每次提高它 发布.
    
3.  增加一页. 创建这三个文件 :
    
    `edgeproc.worker.js`
    
    ```js
    import "@gainratio/browser/worker";
    ```
    
    `main.js`
    
    ```js
    import { EngineClient } from "@gainratio/browser";
    import EdgeProcWorker from "./edgeproc.worker.js?worker";
    
    const out = document.querySelector("#out");
    const client = new EngineClient(new EdgeProcWorker());
    try {
      const result = await client.sync("/bundle", "/public.key");
      const bytes = await client.readFile("prices.json");
      out.textContent = `verified ${result.version} (${result.chunksFetched} fetched, ${result.chunksReused} reused)\n` +
        new TextDecoder().decode(bytes);
    } catch (error) {
      out.textContent = `refused (${error.code}): ${error.message}`;
    }
    ```
    
    `index.html`
    
    ```html
    <!doctype html>
    <h1>Signed data check</h1>
    <pre id="out" style="white-space: pre-wrap; word-break: break-all">checking...</pre>
    <script type="module" src="/main.js"></script>
    ```
    
4.  运行 `npx vite` 并开放http://localhost:5173. 页面下载捆绑,检查它, 并显示文件 :
    
    ![The demo page after a good download: "verified v1 (1 fetched, 0 reused)" followed by the contents of prices.json](https://npmcn.com/package/%40gainratio/browser/docs/assets/try-it-verified.png)
    
    重新装入页面 。 它现在说 `verified v1 (0 fetched, 1 reused)`: 检查的副本是 已存储在浏览器中, 因此没有再下载 .
    
5.  现在玩一面糟糕的镜子。 更改所存储数据块的一个字节 :
    
    ```bash
    node -e "const fs=require('fs'),d='public/bundle/chunk/',p=d+fs.readdirSync(d)[0],b=fs.readFileSync(p);b[9]^=1;fs.writeFileSync(p,b)"
    ```
    
    在一个新的私人窗口中打开 http://localhost:5173。 页面拒绝数据而不是 显示它:
    
    ![The same page with the changed file: "refused (integrity): chunk 34fa4548... failed content-address check"](https://npmcn.com/package/%40gainratio/browser/docs/assets/try-it-refused.png)
    
    ```text
    refused (integrity): chunk 34fa454858ceada20cfa0cd5236eb70f90e1021ed3bd03a6c9d5332597b3cc12 failed content-address check
    ```
    
    需要一个私人窗口, 因为您正常的窗口已经持有选中的副本 不再下载该作品。 运行 `node -e` 线条将再次取消更改.
    

没有浏览器吗? 节点的相同检查

检查核心也在节点运行. 另存为 `check.mjs` 在同一文件夹中运行 `node check.mjs` (数据不变). "服务器"是一个读取本地 文件,第二次运行会翻转它所服务的每一件文件中的一个字节:

```js
import { readFile } from "node:fs/promises";
import { MemoryCacheStore, materializeFile, syncIndex, verifyEd25519 } from "@gainratio/browser";

const key = new Uint8Array(await readFile("public/public.key"));
const verify = (message, signature) => verifyEd25519(key, message, signature);
// Stands in for a web server: "/bundle/latest" is read from public/bundle/latest.
const server = async (url) => new Uint8Array(await readFile(`public${url}`));
// A bad mirror: flips one byte in every data chunk it serves.
const tampered = async (url) => {
  const bytes = await server(url);
  if (url.includes("/chunk/")) bytes[9] ^= 1;
  return bytes;
};

const store = new MemoryCacheStore();
const ok = await syncIndex({ baseUrl: "/bundle", store, fetchBytes: server, verify });
const manifest = JSON.parse(new TextDecoder().decode(await store.getManifest(ok.manifestHash)));
const bytes = await materializeFile(store, manifest, "prices.json");
console.log(`accepted ${ok.version}: ${new TextDecoder().decode(bytes).trim()}`);

await syncIndex({ baseUrl: "/bundle", store: new MemoryCacheStore(), fetchBytes: tampered, verify })
  .catch((error) => console.log(`refused: ${error.name}: ${error.message}`));
```

```text
accepted v1: {"sku": "A-100", "name": "Blue mug", "price": 12.5}
refused: IntegrityError: chunk 34fa454858ceada20cfa0cd5236eb70f90e1021ed3bd03a6c9d5332597b3cc12 failed content-address check
```

## 如何运作

出版商将您的文件切成块, 每个作品的名称 以散列的内容 签名一个小指针文件,以命名棋子列表。 您的页面给出了捆绑的 URL 和公钥 URL 到一个 Web Worker。 工人检查指针的签名 您的密钥, 拒绝比它已有的更老的指针, 然后下载 残片不见了, 检查每个与它的散列。 只有在一切过去的时候 新版本替换了浏览器存储中的旧版本: OPFS上的一个SQLite数据库, 或拒绝OPFS(该副本在下个会话中被重新下载)的记忆中。 过 `cacheFallback: "none"` 拒绝回扣:同步后立即拒绝回扣 `EngineStorageUnavailableError` 而不下载任何内容。 任意 失败是输入错误, 最后的好版本会保留 .

工作人員也把每个网络请求都报告回页面,这样你就可以数了 他们。 当你的捆绑包含 `.sqlite` 数据库(例如产品目录或 引用数据集),工作人打开了以全文在 OPFS 中验证的 SQLite 文件 搜索( FTS5 )、 JSON1 和向量搜索, 以及未来的更新只下载 64 KB 块 这改变了。 更多进去 [建筑](https://npmcn.com/package/%40gainratio/browser/docs/ARCHITECTURE.md) 财务报告和审定财务报表 [浏览器中的 SQL](https://npmcn.com/package/%40gainratio/browser/docs/sql.md)。 。 。 .

## 它不会做的

-   **它不签署或公布数据.** 你需要一个出版商 今天,这是 蟒 `edgeproc publish` 命令上显示.
-   **数据流动方式之一**从发布器到浏览器。 它不同步用户编辑回一个 服务器.
-   **它不知道你的数据是什么意思.** 它会递给你的应用检查字节 他们是什么 这取决于你.
-   **它不能保护一个被损坏的页面.** 恶意浏览器扩展或攻击者 控制您的公用钥匙 URL, 是无法联系的。 从自己处为 HTTPS 提供密钥 站点,与数据不同。 将私钥从网络服务器上关闭.
-   **Chromium获得完整的浏览器套件;Firefox和WebKit获得一个交叉浏览器测试.** 单位 CI,Firefox和WebKit运行 OPFS 打开,内存倒计时,一个SQL回程, 出/入和内存图示检测。 Playwright 的 WebKit 拒绝 OPFS, 所以这里有 测试 `opfs-unavailable` 倒计时,不是OPFS本身. 真正的Safari没有测试.
-   **早释.** 0.1.1是第一个版本 `@gainratio/browser` 和第一个 由CI发布 npm出处. `@edgeproc/browser` 0.1.0 手头出版 无出处;此名被贬.
-   可选的 SQLite app- state 商店需要交叉发端的页面(COOP和COEP) (原始内容存档于2018-10-21). Headers. 其他的包裹没有.

## 什么时候用别的东西

| 狦 | 使用 |
| --- | --- |
| 完全信任您的服务器和每个 CDN 在两者之间 | 平面 `fetch` 超过 HTTPS |
| 拥有一些您在构建时可以放入 HTML 的文件 | 分资源`integrity=` 在脚本或链接标签上) |
| 想要你的应用程序自己的代码和页面离线工作 | 服务- 员工缓存, 如 Workbox |
| 需要用户编辑才能返回共享服务器 | 同步的主机数据库 |
| 用 Python 运行设备, 而不是浏览器 | 活猫 [`edge-proc`](https://github.com/gainratio/edge-proc) 库,它使用相同的捆绑格式 |
| 在不移动页面的情况下更改的船载数据, 并且希望页面拒绝您没有签名的任何内容 | 这个包 |

## 安装

```bash
npm install @gainratio/browser
```

此 README 文档 0.4. 6 , 它与 `main` 时间 写作的时间。 Pnpm和Bun也会工作。 换句话说 `pnpm add github:gainratio/edgeproc-browser#<commit-sha>`。 。 。 .

除主要进口外,还有用于工人入境的分路径进口,未捆绑用途, 矢量搜索, 和 SQLite 状态 。 这个 [API 指南](https://npmcn.com/package/%40gainratio/browser/docs/API.md) 列出所有例子.

## 开发

使用节点 24 (节点 26 打破了 corepack pnpm shim)和 pnpm 11.5.0 通过 corepack:

```bash
git clone https://github.com/gainratio/edgeproc-browser
cd edgeproc-browser
corepack enable
pnpm install --frozen-lockfile
pnpm gate
```

`pnpm gate` 运行 lint, 类型检查, 构建, 检查已承诺 `dist/` 匹配一个 干净的建筑, 和单位测试覆盖。 这是相同的指令CI运行,并带走 在一分钟内. `pnpm test:browser` 运行CI也运行的真浏览器测试(Chrimium,外加Firefox和WebKit的交叉浏览器测试). 见 [开始开发者](https://npmcn.com/package/%40gainratio/browser/docs/GETTING_STARTED.md) 对于一个代码地图, 已知的本地陷阱, 以及第一次改变.

## 详细情况

-   [建筑](https://npmcn.com/package/%40gainratio/browser/docs/ARCHITECTURE.md): 捆绑格式、检查什么、每次拒绝 和那些试验所证实的.
-   [交互式架构映射](https://npmcn.com/package/%40gainratio/browser/docs/architecture/index.html): 可单击 运行时间.
-   [API 指南](https://npmcn.com/package/%40gainratio/browser/docs/API.md): 配备 Vite 、 密钥环和密钥旋转、 计数的工人设置 网络请求,向量搜索,SQLite app状态,以及每个选项.
-   [开始开发者](https://npmcn.com/package/%40gainratio/browser/docs/GETTING_STARTED.md)设置,运行检查,和制作 a 第一个变化.
-   [SQLite 状态商店](https://npmcn.com/package/%40gainratio/browser/docs/sqlite-state.md):迁移,备份,信头和所有权.
-   [SQLite 内存简介](https://npmcn.com/package/%40gainratio/browser/docs/memory-profile.md):页面缓存和堆积限制大小到设备.
-   [浏览器中的 SQL](https://npmcn.com/package/%40gainratio/browser/docs/sql.md):一个OPFS SQLite数据库,有FTS5,JSON1和向量, 在图书馆的工人.
-   [密码句文件](https://npmcn.com/package/%40gainratio/browser/docs/seal.md): 以密码句加密备份为标准年龄 文件编号 `age` 命令行工具也可以打开.
-   [依赖关系](https://npmcn.com/package/%40gainratio/browser/docs/dependencies.md):为什么每个依赖在这里.
-   [警卫](https://npmcn.com/package/%40gainratio/browser/SECURITY.md):威胁模型,关键旋转,以及如何报告脆弱性.
-   [捐款额](https://npmcn.com/package/%40gainratio/browser/CONTRIBUTING.md):什么是变化需要,什么被推后.
-   [变动情况](https://npmcn.com/package/%40gainratio/browser/CHANGELOG.md):每个版本的变化.

## 许可证

麻省理工学院. 见 [自由主义](https://npmcn.com/package/%40gainratio/browser/LICENSE)。 。 。 .

## 常见问题

### @gainratio/browser 是什么？

对于 Web 开发者: 请检查下载的数据由您签名而不更改的浏览器, 然后保存到离线使用 \.

### 如何安装 @gainratio/browser？

在项目目录运行 npm install @gainratio/browser，或使用 pnpm add / yarn add / bun add。

### @gainratio/browser 支持 TypeScript 吗？

支持。包内自带 TypeScript 类型声明（package\.json 声明了 types 入口），安装后即可获得类型提示，无需再安装 @types 包。

### @gainratio/browser 支持 ESM 还是 CommonJS？

以 ES Module 形式发布，推荐使用 import 引入。在 CommonJS 项目中，Node\.js 20\.19\+ / 22\.12\+ 可以直接 require\(\) 不含顶层 await 的 ES Module，更早的版本需要改用动态 import\(\)。

### @gainratio/browser 需要什么版本的 Node\.js？

package\.json 的 engines 字段要求 Node\.js \>=22\.13。版本不符时 npm 默认只给出警告，开启 engine-strict 后会拒绝安装。

### @gainratio/browser 可以商用吗？

@gainratio/browser 使用 MIT 许可。宽松许可：允许商业使用、修改和再分发，通常只需在分发时保留原版权与许可声明。以上为概括，不构成法律意见，请以许可原文为准。

### @gainratio/browser 的下载量有多少？

根据 npm 官方下载统计，@gainratio/browser 在 2026/10/16 – 2026/11/14 这 30 天内被下载 5,019 次，日均约 167 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入，适合横向比较热度，不能直接等同于使用人数。

### @gainratio/browser 还在维护吗？

最新版本 0\.4\.6 发布于 2026/11/11（5 天前）；至今共发布 13 个版本，其中过去 12 个月发布了 13 个；首次发布于 2026/10/03。发布频率只是参考信号：功能稳定的工具可能很少需要更新，建议结合源码仓库的 issue 和提交记录判断。

