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

in-page-bom

v0.1.0

Published

Page-local BOM: whitelist window ops (reload/back) and read-only viewport/href inspect.

Readme

in-page-bom

页内 BOM 组件:白名单窗口操作 + 窗口级只读感知。
In-page BOM library: allowlisted window operations plus read-only viewport / URL inspect.

绑定一个 window,对其做白名单 BOM 操作,并现读视口与地址。
Binds one window for allowlisted BOM operations and live viewport / URL inspect.

| 中文 | English | |------|---------| | 1. 组件介绍 | 1. Introduction | | 2. 安装 | 2. Install | | 3. 怎么用 | 3. Quick start | | 4. 用法与参数 | 4. API and parameters | | 5. 回包、错误码与效果 | 5. Results, errors, and effects | | 6. 生命周期 | 6. Lifecycle | | 7. 本地开发 | 7. Local development |


中文

1. 组件介绍

in-page-bom 是浏览器端 npm 库。调用方传入(或默认)一个 window,库对这个浏览上下文提供:

  1. 只读感知 inspect():每次现读视口宽高、devicePixelRatio、完整 location.href
  2. 白名单操作 run()reloadlocation.reload())和 backhistory.back())。

典型用途:编排层需要刷新当前浏览上下文,或读取当前 iframe / 窗口的尺寸和 URL。reload 表示已对绑定窗口发起重载;下一份文档里有什么,由页面自己决定。命令在白名单且窗口有效时即执行。

| 项目 | 说明 | |------|------| | 运行环境 | 浏览器(或 iframe 的 contentWindow) | | 模块形态 | ESM + .d.ts,零运行时依赖 | | 公开入口 | createBom{ inspect, run } | | 副作用 | location.reload / history.back | | 失败 | 稳定 error.code |

2. 安装

需要能解析 ESM 的宿主,以及浏览器 Window 类型(TypeScript 请启用 DOM lib)。Node 版本 ≥ 18 仅约束本仓库的构建/测试工具链。

发布后(包名 in-page-bom):

npm install in-page-bom
# 或 pnpm add in-page-bom / yarn add in-page-bom

本仓库尚未 npm publish 时,用本地路径:

cd in-page-bom
npm install
npm run build

# 在宿主项目
npm install file:../in-page-bom

安装产物是 dist/exports 指向 dist/index.jsdist/index.d.ts)。从 git 源码引用前先 npm run build。零运行时依赖。

3. 怎么用

最小闭环:创建实例 → 现读窗口 → 必要时 reload(成功后实例退役)。

import { createBom } from "in-page-bom";

const bom = createBom({ window });

const seen = bom.inspect();
if (!seen.ok) {
  // INSTANCE_RETIRED / WINDOW_GONE
  console.error(seen.error.code, seen.error.message);
} else {
  // 完整 href,不要把 query 里的 secret 打进日志
  const { width, height, dpr } = seen.inspect.viewport;
  const href = seen.inspect.href;
}

const step = await bom.run({ type: "reload" });
if (step.ok && step.retired) {
  // 不要再对同一个 bom.inspect() / run() 走成功路径
  // 页面重载后重新 createBom(通常伴随文档换代)
}

嵌入式 App(外壳 + iframe)传入 iframe 的 contentWindow

const iframe = document.querySelector("iframe");
if (iframe?.contentWindow) {
  const bom = createBom({ window: iframe.contentWindow });
  await bom.run({ type: "reload" }); // 刷新该 iframe
}

省略 window 时绑定 globalThis(浏览器里即当前页 window):

const bom = createBom();

4. 用法与参数

4.1 createBom(options?)

function createBom(options?: ICreateBomOptions): IBom;

| 参数 | 类型 | 必填 | 默认 | 含义 | |------|------|------|------|------| | options | ICreateBomOptions | 否 | {} | 创建选项 | | options.window | Window | 否 | globalThis | 绑定的浏览上下文。所有 inspect / run 只作用于它 |

返回 IBom

| 方法 | 同步性 | 作用 | |------|--------|------| | inspect() | 同步 | 现读 viewport + href | | run(command) | Promise | 执行白名单命令;reload 发起后即 resolve,不等新文档 ready |

一个 createBom 对应一个 Window、一份 retired 标志。换窗口或换代必须再调一次 createBom

4.2 inspect()

每次从绑定 window 现读。V1 字段来自 innerWidth / innerHeight / devicePixelRatio

成功:

{
  ok: true,
  inspect: {
    viewport: { width: 1280, height: 720, dpr: 2 },
    href: "https://example.test/app?token=secret"
  }
}

| 字段 | 类型 | 来源 / 约束 | |------|------|-------------| | ok | true | 读到了窗口 | | inspect.viewport.width | number | window.innerWidth | | inspect.viewport.height | number | window.innerHeight | | inspect.viewport.dpr | number | window.devicePixelRatio | | inspect.href | string | location.href 真值;脱敏由编排做 |

失败(判别联合,TypeScript 可收窄):

{ ok: false, error: { code: "INSTANCE_RETIRED" | "WINDOW_GONE", message: string } }

效果: 只读。两次 inspect 之间若视口或地址变了,第二次跟新值。

4.3 run(command)

type TBomCommand = { type: "reload" } | { type: "back" };

run(command: TBomCommand): Promise<IBomStepResult>

| command.type | 浏览器动作 | 何时用 | |----------------|------------|--------| | "reload" | location.reload() | 刷新绑定窗口的当前文档 | | "back" | history.back() | 历史可退时后退一帧 |

运行时未知 type 会得到 INVALID_COMMAND

reload

const step = await bom.run({ type: "reload" });

| 步骤 | 行为 | |------|------| | 校验 | 未 retired、窗口仍可读 | | 记录 | inspectBefore = 执行前的窗口摘要 | | 调用 | location.reload() | | 回包 | 立刻 ok: true, retired: true不等 新文档 load |

reload() 抛错:ok: falseretired: false,码 DISPATCH_FAILED,实例仍可继续 inspect

back

const step = await bom.run({ type: "back" });

| 条件 | 效果 | |------|------| | history.length <= 1 | NOT_ALLOWEDhistory.back() 未发出 | | 可退且文档仍在(如同文档 pushState) | ok: true, retired: false | | 可退且调用后窗口已不可读 | ok: true, retired: true | | history.back() 抛错 | DISPATCH_FAILED,不退役 |

同文档 hash / pushState 的 href 变化仍视为同一代。父页绑 iframe、跨文档后退时,本步回包可能仍是 retired: false;文档 pagehide(非 bfcache)后实例退役,之后 inspectINSTANCE_RETIRED

先造可退历史再 back(playground / iframe 内):

iframe.contentWindow.history.pushState({}, "", "?step=2");
await bom.run({ type: "back" });

4.4 典型组合

只读当前 iframe 尺寸和地址:

const bom = createBom({ window: iframe.contentWindow! });
const seen = bom.inspect();
if (seen.ok) {
  layoutTo(seen.inspect.viewport);
}

编排侧刷新:

const step = await bom.run({ type: "reload" });
if (!step.ok) {
  // INVALID_COMMAND / WINDOW_GONE / INSTANCE_RETIRED / DISPATCH_FAILED
  return;
}
// reload 成功后重新 createBom

退役后换新实例:

await bom.run({ type: "reload" });
const next = createBom({ window: iframe.contentWindow! });
next.inspect(); // 新一代

5. 回包、错误码与效果

IBomStepResult

| 字段 | 类型 | 含义 | |------|------|------| | ok | boolean | 本步是否完成合同副作用。校验失败必须是 false | | command | "reload" \| "back" \| string | 实际看到的 type;未知命令保留原字符串 | | retired | boolean | 本步是否把实例标为退役。reload 一旦调用成功必须为 true;校验失败(未调用)必须为 false | | inspectBefore | IBomInspect \| null | 执行前摘要;窗口已不可读或校验过早失败时为 null | | error | IBomError(可选) | ok: false 时带稳定 code |

注意:ok 不是判别联合。失败时用 step.error?.code 分支。后续 run 若已退役,回包里的 retired 仍可能是 false(表示这一步没有再调用 reload);实例已死看 INSTANCE_RETIRED

ok / retired 对照

| 情况 | ok | retired | 副作用 | |------|------|-----------|--------| | reload 已调用 | true | true | 已 location.reload() | | reload 未调用(校验失败) | false | false | 无 | | back 成功且文档仍在 | true | false | 已 history.back() | | back 成功且当时已能判断将卸载 | true | true | 已 history.back() | | 未知命令 | false | false | 无 | | history.length <= 1 | false | false | 无 |

错误码 TBomErrorCode

| code | 出现在 | 含义 | 副作用 | |--------|--------|------|--------| | INVALID_COMMAND | run | 未知 type | 无 | | WINDOW_GONE | inspect / run | 窗口已 closed 或读 location / 尺寸抛错 | 无 | | INSTANCE_RETIRED | inspect / run | 本实例已因 reload(或卸载 / pagehide)退役 | 无 | | NOT_ALLOWED | run({ type: "back" }) | history.length <= 1 | 无 | | DISPATCH_FAILED | run | 白名单 API 抛错,页面仍在 | 实例仍可用 |

error.message 给人看,不要当协议字段解析。

示例回包

reload 成功:

{
  "ok": true,
  "command": "reload",
  "retired": true,
  "inspectBefore": {
    "viewport": { "width": 1280, "height": 720, "dpr": 2 },
    "href": "https://example.test/app"
  }
}

无处可退:

{
  "ok": false,
  "command": "back",
  "retired": false,
  "inspectBefore": { "viewport": { "width": 1280, "height": 720, "dpr": 2 }, "href": "https://example.test/app" },
  "error": { "code": "NOT_ALLOWED", "message": "history.back is not allowed because history.length <= 1." }
}

6. 生命周期

createBom({ window })
  → 活着:inspect / run(reload|back)
  → run(reload) 成功:立刻 retired
  → 绑定文档 pagehide(非 bfcache):retired
  → 窗口 closed / 不可读:WINDOW_GONE(若尚未 retired)
  → 已 retired:inspect / run → INSTANCE_RETIRED
  → 新文档 / 新会话:再次 createBom

| 场景 | 旧实例 | |------|--------| | reload 已调用 | 立即退役,不要等 load | | 同文档 back | 通常仍活着 | | 跨文档 back(父页绑 iframe) | 本步可能仍 retired: falsepagehide 后退役 | | 用户在 iframe 里手动刷新 | pagehide 后退役 | | bfcache(pagehide.persisted) | 不退役,同一文档可能被唤回 |

成功 reload 之后,同一实例按退役处理;新文档上再 createBom

7. 本地开发

npm install
npm run typecheck
npm run lint
npm test
npm run build
npm run playground

Playground:父页绑定 iframe。Inspect → Reload → 再 Inspect 应为 INSTANCE_RETIRED;「重新 createBom」后才能读新文档。Back 前可先「Push iframe history」。


English

1. Introduction

in-page-bom is a browser npm library. You bind one window (or take the default). On that browsing context it provides:

  1. Read-only inspect via inspect(): live viewport size, devicePixelRatio, and the full location.href.
  2. Allowlisted ops via run(): reload (location.reload()) and back (history.back()).

Typical use: refresh the current browsing context, or read iframe/window size and URL. reload means a reload was issued on the bound window; what the next document contains is up to the page. Allowlisted commands run while the window is valid.

| Item | Detail | |------|--------| | Runtime | Browser (or an iframe contentWindow) | | Package | ESM + .d.ts, zero runtime dependencies | | Public surface | createBom{ inspect, run } | | Side effects | location.reload / history.back | | Failures | Stable error.code |

2. Install

Needs an ESM host and the DOM Window type (enable the TypeScript DOM lib). engines.node >= 18 applies to this repo’s toolchain, not to the browser runtime.

When published (in-page-bom):

npm install in-page-bom
# or pnpm add in-page-bom / yarn add in-page-bom

Before publish, use a local path:

cd in-page-bom
npm install
npm run build

# in the host app
npm install file:../in-page-bom

The published files are dist/ (exportsdist/index.js and dist/index.d.ts). If you consume git sources, run npm run build first. Zero runtime dependencies.

3. Quick start

Create → inspect → reload when needed (the instance retires on successful reload).

import { createBom } from "in-page-bom";

const bom = createBom({ window });

const seen = bom.inspect();
if (!seen.ok) {
  // INSTANCE_RETIRED / WINDOW_GONE
  console.error(seen.error.code, seen.error.message);
} else {
  // Full href — do not log query secrets
  const { width, height, dpr } = seen.inspect.viewport;
  const href = seen.inspect.href;
}

const step = await bom.run({ type: "reload" });
if (step.ok && step.retired) {
  // Do not keep calling inspect/run on this instance as a live session
  // createBom again after reload (usually a new document)
}

Embedded apps (chrome + iframe) pass the iframe contentWindow:

const iframe = document.querySelector("iframe");
if (iframe?.contentWindow) {
  const bom = createBom({ window: iframe.contentWindow });
  await bom.run({ type: "reload" }); // reloads that iframe
}

Omit window to bind globalThis (the page window in a browser):

const bom = createBom();

4. API and parameters

4.1 createBom(options?)

function createBom(options?: ICreateBomOptions): IBom;

| Parameter | Type | Required | Default | Meaning | |-----------|------|----------|---------|---------| | options | ICreateBomOptions | no | {} | Create options | | options.window | Window | no | globalThis | Bound browsing context. Every inspect / run uses this object only |

IBom methods:

| Method | Sync | Role | |--------|------|------| | inspect() | sync | Live viewport + href | | run(command) | Promise | Allowlisted command. reload resolves as soon as it is issued, without waiting for the next document |

One createBom call binds one Window and one retired flag. A new window or generation needs a new createBom.

4.2 inspect()

Reads the bound window every time. V1 fields come from innerWidth / innerHeight / devicePixelRatio.

Success:

{
  ok: true,
  inspect: {
    viewport: { width: 1280, height: 720, dpr: 2 },
    href: "https://example.test/app?token=secret"
  }
}

| Field | Type | Source / constraint | |-------|------|---------------------| | ok | true | Window was readable | | inspect.viewport.width | number | window.innerWidth | | inspect.viewport.height | number | window.innerHeight | | inspect.viewport.dpr | number | window.devicePixelRatio | | inspect.href | string | Live location.href; redaction is the caller’s job |

Failure (discriminated union):

{ ok: false, error: { code: "INSTANCE_RETIRED" | "WINDOW_GONE", message: string } }

Effect: read-only. If size or href changes between two calls, the second call follows the new values.

4.3 run(command)

type TBomCommand = { type: "reload" } | { type: "back" };

run(command: TBomCommand): Promise<IBomStepResult>

| command.type | Browser action | When | |----------------|----------------|------| | "reload" | location.reload() | Reload the bound document | | "back" | history.back() | Go back one history entry when allowed |

Unknown runtime type values return INVALID_COMMAND.

reload

const step = await bom.run({ type: "reload" });

| Step | Behavior | |------|----------| | Guard | Not retired; window still readable | | Snapshot | inspectBefore = pre-op inspect | | Call | location.reload() | | Result | Immediately ok: true, retired: truedoes not wait for load |

If reload() throws: ok: false, retired: false, DISPATCH_FAILED; the instance remains usable for inspect.

back

const step = await bom.run({ type: "back" });

| Condition | Effect | |-----------|--------| | history.length <= 1 | NOT_ALLOWED; history.back() is not issued | | Can go back; document still here (e.g. same-document pushState) | ok: true, retired: false | | Can go back; window already unreadable after the call | ok: true, retired: true | | history.back() throws | DISPATCH_FAILED; not retired |

Same-document hash / pushState href changes stay the same generation. For a parent-bound iframe, a cross-document back may still report retired: false on that step; after pagehide (not bfcache) the instance retires and later inspect returns INSTANCE_RETIRED.

Seed history, then back (playground / iframe):

iframe.contentWindow.history.pushState({}, "", "?step=2");
await bom.run({ type: "back" });

4.4 Common recipes

Read iframe size and URL only:

const bom = createBom({ window: iframe.contentWindow! });
const seen = bom.inspect();
if (seen.ok) {
  layoutTo(seen.inspect.viewport);
}

Orchestrated refresh:

const step = await bom.run({ type: "reload" });
if (!step.ok) {
  // INVALID_COMMAND / WINDOW_GONE / INSTANCE_RETIRED / DISPATCH_FAILED
  return;
}
// After a successful reload, createBom again

New instance after retire:

await bom.run({ type: "reload" });
const next = createBom({ window: iframe.contentWindow! });
next.inspect(); // next generation

5. Results, errors, and effects

IBomStepResult

| Field | Type | Meaning | |-------|------|---------| | ok | boolean | Whether this step completed the contracted side effect. Validation failures must be false | | command | "reload" \| "back" \| string | Observed type; unknown commands keep the original string | | retired | boolean | Whether this step retired the instance. Successful reload must be true; validation failure (not called) must be false | | inspectBefore | IBomInspect \| null | Pre-op snapshot; null if the window was already unreadable | | error | IBomError (optional) | Present on ok: false with a stable code |

ok is not a discriminated union—branch on step.error?.code. A later run on a retired instance may still report retired: false (this step did not call reload again); liveness is INSTANCE_RETIRED.

ok / retired

| Case | ok | retired | Side effect | |------|------|-----------|-------------| | reload invoked | true | true | location.reload() | | reload not invoked (guard failed) | false | false | none | | back succeeded; document still here | true | false | history.back() | | back succeeded; unload already detectable | true | true | history.back() | | Unknown command | false | false | none | | history.length <= 1 | false | false | none |

Error codes

| code | Where | Meaning | Side effect | |--------|-------|---------|-------------| | INVALID_COMMAND | run | Unknown type | none | | WINDOW_GONE | inspect / run | closed or reads throw | none | | INSTANCE_RETIRED | inspect / run | Retired after reload / unload / pagehide | none | | NOT_ALLOWED | run({ type: "back" }) | history.length <= 1 | none | | DISPATCH_FAILED | run | Allowlisted API threw; page still here | instance still usable |

Treat error.message as human text, not a protocol field.

Example payloads

Successful reload:

{
  "ok": true,
  "command": "reload",
  "retired": true,
  "inspectBefore": {
    "viewport": { "width": 1280, "height": 720, "dpr": 2 },
    "href": "https://example.test/app"
  }
}

Nothing to go back to:

{
  "ok": false,
  "command": "back",
  "retired": false,
  "inspectBefore": { "viewport": { "width": 1280, "height": 720, "dpr": 2 }, "href": "https://example.test/app" },
  "error": { "code": "NOT_ALLOWED", "message": "history.back is not allowed because history.length <= 1." }
}

6. Lifecycle

createBom({ window })
  → live: inspect / run(reload|back)
  → successful run(reload): retired immediately
  → bound document pagehide (not bfcache): retired
  → window closed / unreadable: WINDOW_GONE (if not already retired)
  → retired: inspect / run → INSTANCE_RETIRED
  → new document / session: createBom again

| Scenario | Old instance | |----------|----------------| | reload invoked | Retired immediately; do not wait for load | | Same-document back | Usually still live | | Cross-document back (parent holds iframe) | Step may still be retired: false; retires after pagehide | | User refreshes the iframe | Retires after pagehide | | bfcache (pagehide.persisted) | Not retired; the same document may return |

After a successful reload, treat this instance as retired; call createBom again on the new document.

7. Local development

npm install
npm run typecheck
npm run lint
npm test
npm run build
npm run playground

Playground: parent page binds the iframe. Inspect → Reload → Inspect again should be INSTANCE_RETIRED. Use “重新 createBom” for a new generation. Push iframe history before Back.


文档 / Docs

| 文档 | 用途 | |------|------| | docs/README.md | 文档中心 / doc hub | | docs/AI与人类/需求拟定/ | 需求基线 / requirements (in progress) | | docs/AI与人类/规范和原则/ | 失败方向 / fail-closed principles | | AGENTS.md | Agent 实施入口 |

状态 / Status: P0–P2 已落地(createBom / inspect / reload / back、契约测试、ESM 骨架)。尚未 npm publish。