@apicity/har

中文文档
0.27.0发布于 2026/11/06MITTypeScriptES Module零依赖近 30 天下载 2569

HAR 1.2 serialization, secret scrubbing and Polly recording identity.

原始使用文档
文档目录3 节
  1. Repository integration
  2. Cost evidence
  3. Exchange analysis helpers

@apicity/har

Dependency-free Node.js HAR 1.2 serialization, secret scrubbing and opt-in request/response capture. createHarCapture provides an injectable fetch, call scopes, optional global installation, and scrubbed files with a JSONL index. See the capture guide for setup and retention details.

import { exchangeToEntry, scrubHar, pollyEntryId } from "@apicity/har";

declare const request: Request; // the request you sent
declare const response: Response; // its response, body unread

const entry = await exchangeToEntry(request, response, {
  startedAt: new Date(),
  durationMs: 120,
});
entry._id = pollyEntryId(entry);
  • createHarCapture({ dir, mode: "all" | "failures", providers?, maxBodyBytes?, maxSummarizeBytes?, sseTailBytes?, context?, onError?, clock?, idFactory? }) returns { fetch, call, install, flush, close }. Wrap provider work in call({ provider, endpoint, input, context?, estimate? }, fn) and await close() before exit; a call's context is merged shallowly over the capture's context for that call only. estimate (usd, source, rateAsOf, warnings, breakdown, status) is written to log._apicity.estimate and as estimateUsd in index.jsonl. input is written with each data URL or base64 field over 1024 characters, and each byte array, replaced by a placeholder of its hash, decoded size and media type. Capture is disabled after a write error without changing the provider result. A body that fails mid-read does not disable it: the exchange is saved with bodyTruncated, and responseCut for a response, and the call's outcome is network_error.
  • exchangeToEntry(request: Request, responseOrError: Response | Error, timing, options?) reads clones and returns a scrubbed entry. Timing has startedAt, durationMs and optional HAR timings. Options are maxBodyBytes (262144 by default), maxSummarizeBytes (16 MiB), sseTailBytes (64 KiB), streamed and role. Binary and oversized bodies become SHA-256, byte-count and MIME-type placeholders, except a JSON request up to maxSummarizeBytes whose text fits the cap once its media is summarized. Multipart files become name/type/size summaries. Inline data URLs and long base64 are summarized. A text stream over the cap keeps its first maxBodyBytes and last sseTailBytes, in whole lines joined by an : apicity-gap <n> bytes dropped comment; _apicity.streamed and bodyTruncated describe them. A body that fails mid-read keeps what arrived: a stream's whole lines, or a placeholder for anything that does not parse as a whole JSON document. A network error produces status 0; call-level error metadata belongs in log._apicity. streamIncomplete marks a wire ending without a newline or without final usage in a recognized Anthropic, OpenAI or Google stream; it also marks a whole retained JSON response that does not parse, even when the transport reports clean EOF. Such JSON is saved only as a hash/size placeholder. It sets bodyTruncated and keeps cost evidence unsettled. Unclassifiable frames or lines over 1 MiB in a recognized protocol are incomplete. This is independent of retention caps and responseCut (transport failure): complete final usage followed by a transport failure can still settle. Legacy captures without streamIncomplete retain their existing cost semantics. Bodies must be unused and streams must eventually finish; an aborted request cancels its capture copy so it cannot hold up flushing.
  • scrubEntry(entry) and scrubHar(har) mutate and return their argument. Scrubbing covers provider credentials in headers, URLs, JSON and form-encoded bodies, cookies, response account metadata and _apicity input/estimate/context/error fields. It preserves prompts and ordinary payloads. It is not a general personal-data anonymizer.
  • pollyEntryId(entry, options?) hashes the identifying fields using the repository's default harness matching rules. Custom matching requires excludeHeaders, headers: false, or body: false as appropriate. The URL is normalized as Polly's url-parse and qs normalize it: keys are sorted and RFC 3986 escaped, repeated, valueless and bracket keys are kept, and the fragment is dropped. Summarized bodies cannot reproduce the identity of their original raw bytes, nor can a query part with a malformed percent escape once a Request has re-encoded it. A recorded URL with an unclosed [ or more than five bracket levels in a key hashes as a new request to that URL would, not as recorded: Polly's re-serialization is not stable there.
  • pollyRecordingDir(name) implements Polly's per-segment slug and FNV-1a hash.
  • HAR types: Har, HarLog, HarEntry, HarRequest, HarResponse, HarContent, HarPostData, HarNameValue, HarCookie, HarPage, HarCacheEntry, HarTimings, ApicityCallMetadata, and ApicityEntryMetadata.
  • Options: ExchangeTiming, ExchangeOptions, PollyIdentityOptions.

Compatibility exports for the recording tools: redactPersistedHarSecrets, persistSafeTextRequestBody, summarizeJsonRequestBodyMedia, summarizeMultipartFormData, summarizeMultipartRequestBody, redactedRequestId, PersistedHarRecording, REDACTED_HAR_VALUE, HarHeaderLike, HarCookieLike, HarRequestLike, HarResponseLike, HarRecordingLike, isSensitiveRequestHeaderName, isSensitiveResponseHeaderName, scrubSensitiveRequestHeaders, scrubSensitiveResponseHeaders, scrubRequestCookies, scrubResponseCookies, scrubSensitiveResponse, scrubPolymarketAuthArtifacts, scrubSensitiveRecording, PERSISTED_REQUEST_HEADER_PLACEHOLDERS, persistedRequestHeaderPlaceholder, redactFalCheckpoints, findUnredactedRequestSecrets, and findLiveFalCheckpoints.

Repository integration

The package owns the rules. tests/harness.ts and tests/har-scrub.ts are compatibility exports; the Vitest source alias runs against this package. Standalone HAR viewer/report/Telegram tools import the same source through har-data.ts and har-scrub.ts using a relative path, so tsx also works from outside the repository without a package build or a Vitest alias. gen:shared copies src/har-secrets.mjs to scripts/lib/har-secrets.mjs (the shared-source manifest pins it). This committed, generated copy lets gen:examples:check, lint:recordings and doc-gen:check run on a clean checkout before any package build. gen:shared:check prevents drift. No runtime package dependency or build-on-import is needed by those scripts.

Cost evidence

entryToProviderExchange turns one HAR entry into the exchange shape extractActual in @apicity/cost reads: lower-cased header names, parsed JSON or SSE data frames, and a null requestBody for a captured placeholder. This package does not import @apicity/cost; the shapes match structurally.

import { entryToProviderExchange, type HarEntry } from "@apicity/har";

declare const entry: HarEntry;

const exchange = entryToProviderExchange(entry, {
  provider: "openai",
  dotPath: "v1.responses",
});
exchange.responseHeaders["content-type"];

provider falls back to the one that owns the request's host.

Exchange analysis helpers

exchangeSucceeded(provider, entry) requires HTTP 2xx and rejects KIE and xAI failure envelopes. responseObject(entry) decodes JSON object responses, including base64 HAR content.

findMatchingRow(entry, rows, {provider}) first matches full URLs, then uses a provider-scoped path match, then matches full URLs again with fal's {endpoint_id} spanning whole path segments (fal-ai/flux/dev). Rows carry provider, method, dotPath and fullUrl. matchHarEntryStrict, matchHarEntryLenient, matchHarEntrySpanning and compileTsvUrlPattern expose the individual matching operations. These are the canonical implementations also synced to the repository scripts.

版本与发布记录

@apicity/har 共发布 14 个版本,首次发布于 2026/10/24;过去 12 个月发布了 14 个版本。

版本发布日期距今
0.27.0latest2026/11/061 天前
0.26.02026/11/053 天前
0.25.02026/11/034 天前
0.24.12026/11/025 天前
0.24.02026/11/016 天前
0.23.12026/11/016 天前

关于 @apicity/har 的常见问题

@apicity/har 是什么?

HAR 1.2 serialization, secret scrubbing and Polly recording identity.

如何安装 @apicity/har?

在项目目录运行 npm install @apicity/har,或使用 pnpm add / yarn add / bun add。

@apicity/har 支持 TypeScript 吗?

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

@apicity/har 支持 ESM 还是 CommonJS?

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

@apicity/har 需要什么版本的 Node.js?

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

@apicity/har 可以商用吗?

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

@apicity/har 的下载量有多少?

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

@apicity/har 还在维护吗?

最新版本 0.27.0 发布于 2026/11/06(1 天前);至今共发布 14 个版本,其中过去 12 个月发布了 14 个;首次发布于 2026/10/24。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。