@gainratio/browser

中文文档
0.4.6发布于 2026/11/11MITTypeScriptES Module构建来源已验证近 30 天下载 5019

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

中文使用文档
文档目录8 节
  1. 试试看
  2. 如何运作
  3. 它不会做的
  4. 什么时候用别的东西
  5. 安装
  6. 开发
  7. 详细情况
  8. 许可证

@ gainratio/ 浏览器

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

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

文档 : 浏览器. contratio.com • 妇女 开始 • 妇女 实例

CI npm License

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

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

技术文件: 建筑 • 妇女 API 指南 • 妇女 开始开发者 • 妇女 警卫

试试看

你需要节点22.13或更新,和 页:1 运行 Python 工具 签名的数据。 这大约需要一分钟.

  1. 制作一个项目并安装软件包, 加上 Vite 服务页面 :

    mkdir signed-data-demo && cd signed-data-demo
    npm init -y
    npm install @gainratio/browser vite
    
  2. 与 edgeproc 从 Python 命令 edge-proc 软件包 :

    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

    import "@gainratio/browser/worker";
    

    main.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

    <!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

    重新装入页面 。 它现在说 verified v1 (0 fetched, 1 reused): 检查的副本是 已存储在浏览器中, 因此没有再下载 .

  5. 现在玩一面糟糕的镜子。 更改所存储数据块的一个字节 :

    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"

    refused (integrity): chunk 34fa454858ceada20cfa0cd5236eb70f90e1021ed3bd03a6c9d5332597b3cc12 failed content-address check
    

    需要一个私人窗口, 因为您正常的窗口已经持有选中的副本 不再下载该作品。 运行 node -e 线条将再次取消更改.

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

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

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}`));
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 块 这改变了。 更多进去 建筑 财务报告和审定财务报表 浏览器中的 SQL。 。 。 .

它不会做的

  • 它不签署或公布数据. 你需要一个出版商 今天,这是 蟒 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 库,它使用相同的捆绑格式
在不移动页面的情况下更改的船载数据, 并且希望页面拒绝您没有签名的任何内容这个包

安装

npm install @gainratio/browser

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

除主要进口外,还有用于工人入境的分路径进口,未捆绑用途, 矢量搜索, 和 SQLite 状态 。 这个 API 指南 列出所有例子.

开发

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

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的交叉浏览器测试). 见 开始开发者 对于一个代码地图, 已知的本地陷阱, 以及第一次改变.

详细情况

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

许可证

麻省理工学院. 见 自由主义。 。 。 .

版本与发布记录

@gainratio/browser 共发布 13 个版本,首次发布于 2026/10/03;过去 12 个月发布了 13 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
0.4.6latest2026/11/115 天前
0.4.52026/11/087 天前
0.4.42026/11/0214 天前
0.4.32026/10/2521 天前
0.4.22026/10/1730 天前
0.4.12026/10/071 个月前

其他发布通道:bootstrap → 0.0.0-bootstrap.0。

关于 @gainratio/browser 的常见问题

@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 和提交记录判断。