The kingfisher-secret-scanner npm SDK 1.0.1 is a stable release.
It exposes Kingfisher's Rust components in-process through napi-rs and Node-API.
Install with npm and import/require kingfisher-secret-scanner in JavaScript. No
Python interpreter, CLI process, or separate Kingfisher installation is involved.
The SDK version is independent of the CLI, Python SDK and published Rust crate
versions. The same distribution name on PyPI is the separate Python SDK:
install with pip and import kingfisher_sdk, not the npm package. Neither SDK
distributes the CLI. See source and examples and the
Rust and Python embedding guides.
Kingfisher Workbench is a complete, commented SDK application: working-tree and Git-history scans, live progress, redacted HTML reports, and separately enabled validation and revocation.
From a built checkout, run
node examples/kingfisher-workbench/scripts/checkout.mjs demo in javascript/ and open the printed
loopback URL. The demo creates a temporary repository and validates only synthetic
credentials against a local mock provider. Revocation requires browser confirmation
and changes mock state only. Real-repository runs default to offline detection and
redacted reports; see the app's walkthrough before enabling external operations.
For an LLM/agent: read this section, choose one recipe, check its side effects, and run the corresponding source file. Do not infer permission for network calls, credential disclosure, revocation, package publication, or release tags from a request to scan.
| Goal | Read/run | External effects |
|---|---|---|
| Learn text, bytes and file detection | Quickstart | None; synthetic local fixtures |
| Configure YAML/TOML and exact selectors | Custom rules | None |
| Bound/cancel async operations | Controls | None |
| Scan a local project as redacted JSONL | Project pipeline | Local reads and possible temporary extraction |
| Expand compressed content explicitly | Archive pipeline | Synthetic local content and possible temporary extraction |
| Scan committed, historical, diff or index data | Git scopes | Read-only local repository |
| Learn validation and revocation without live credentials | Local mock workflow | Loopback HTTP; optional in-memory mock mutation |
| Scan one file with built-ins (CommonJS) | Content | Local reads only |
| Compose filesystem/archive/content stages (CommonJS) | Inputs | Local reads and possible temporary extraction |
| Scan a local HEAD snapshot (CommonJS) | Git | Read-only local repository |
| Inspect catalog metadata and CLI detection controls | Rules and controls | Offline rule loading and detection |
| Prepare trusted custom-rule operations | Validate/revoke | Offline by default; provider requests and mutation require separate flags/authorization |
| Use TypeScript in an application | TypeScript recipe, typed source | Local detection |
| Configure/release on npm | npm publishing setup | Explicit account changes, registry writes and release tags |
First build and test the checkout with a
supported Node runtime. Then run these commands from
javascript/. No npm account or real credential is required.
node examples/quickstart.mjs
node examples/custom-rules.mjs
node examples/controlled-scan.mjs
node examples/scan-project.mjs
node examples/archive-content.mjs
node examples/local-workflow.mjs
npm run test:types
node --experimental-strip-types examples/typed-scan.mtsThe example walkthrough explains each command, its inputs, output fields, success/failure signals, side effects and production adaptations. The quickstart reports three phases with one synthetic, redacted finding in each. The mock's default summary has one validation request and zero revocations. These are demonstrations, not extra built-in detectors or production credentials. The project recipe uses its teaching rule only with no arguments; supplying local paths selects the full built-in catalog for a realistic scan.
After publication, create an application directory and run:
npm init -y
npm install kingfisher-secret-scanner@1.0.1 --ignore-scriptsUse import { Scanner } from 'kingfisher-secret-scanner' in a .mjs file,
or const { Scanner } = require('kingfisher-secret-scanner') in a .cjs file.
Checkout examples use ../index.mjs / ../index.cjs; replace those imports when
copying them into an application and copy their fixtures too. Consumers do not
need Rust, Python, the CLI, or a local native-source build.
import { Scanner } from "kingfisher-secret-scanner";
const configurationText = "ordinary application configuration";
const scanner = await Scanner.create(); // Load/compile once, then reuse.
try {
const findings = await scanner.scan(configurationText, { path: "config.env" });
for (const finding of findings) {
if (finding.visible) console.log(finding.toJSON()); // Redacted by default.
}
} finally {
await scanner.close();
}scan() accepts text, Buffer, or Uint8Array, including typed-array slices.
SharedArrayBuffer-backed inputs require an explicit non-shared copy, such as
Buffer.from(sharedView), so concurrent worker writes cannot race native reads.
Native calls snapshot input bytes before asynchronous scanning, so later caller
mutation cannot change the submitted input. scanFile() reads one local file;
it does not recurse, extract archives, fetch sources, or validate credentials.
Its filename is authoritative: a path override is rejected, and attributes.path
must match that filename. Only regular files are accepted; FIFOs/devices are not
scan inputs. On Unix the opened handle is checked after a nonblocking open so a
file-to-FIFO swap cannot occupy a worker indefinitely. File reads happen in the
native worker into bounded, owned memory, with controls checked between reads.
Concurrent truncation does not invalidate native memory; the read is not an atomic
filesystem snapshot, so external writes can change the
bytes observed while reading. Individual reads and decoding remain cooperative.
An empty successful result means no matches under the selected rules, not proof
that the input contains no secrets. Errors reject rather than becoming empty scans.
Prerequisite: complete the installed-package setup after publication. This minimal consumer is separate from the checkout examples. Add the TypeScript development tools:
npm install --save-dev typescript @types/nodeCreate tsconfig.json at the application root:
{
"compilerOptions": {
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"types": ["node"],
"lib": ["ES2022", "ESNext.Disposable"],
"strict": true,
"rootDir": "src",
"outDir": "dist"
},
"include": ["src/**/*.mts"]
}Create src/scan.mts (the .mts extension selects ESM):
import { Scanner, ScanInput, type ScanResultReport } from "kingfisher-secret-scanner";
const scanner = await Scanner.create({ maxInputBytes: 16 * 1024 * 1024 });
try {
const input = new ScanInput({ path: "config.env", data: "ordinary configuration" });
const result = await scanner.scanInput(input, { timeoutMs: 5000 });
const report: ScanResultReport = result.toJSON();
console.log(JSON.stringify(report));
} finally {
await scanner.close();
}npm exec -- tsc -p tsconfig.json
node dist/scan.mjsExpected: one JSON object containing input and findings; the sample normally
has findings: []. Replace the data with authorized input, not your compiler flags.
Native packages must remain external in bundlers and be shipped for the actual
runtime OS/CPU; do not bundle the .node file into a browser or edge isolate.
Initialize once, bound application work, and close on graceful shutdown:
import { Scanner } from "kingfisher-secret-scanner";
const scanner = await Scanner.create({
maxInputBytes: 16 * 1024 * 1024,
maxPendingOperations: 4,
dedup: false
});
export async function inspectBuffer(text, path, signal) {
// Keep original Finding objects private; return only redacted report data.
const findings = await scanner.scan(text, { path, signal, timeoutMs: 5000 });
return findings.filter(f => f.visible).map(f => f.toJSON());
}
export async function closeScanner() {
await scanner.close();
}This is a module fragment, not an HTTP server. Your caller must limit concurrent
submissions, authorize inputs and invoke closeScanner() during shutdown.
Catch AbortError and TimeoutError before their KingfisherError base class;
never convert failures into “no secrets.” Caller callbacks retain their original
exceptions rather than being relabeled as native failures.
| Error code | Meaning / response |
|---|---|
ERR_KINGFISHER_CANCELLED |
Cooperative cancellation (AbortError); inspect cause for a signal reason |
ERR_KINGFISHER_TIMEOUT |
Total deadline elapsed (TimeoutError); bound work before retrying |
ERR_KINGFISHER_BUSY |
Pending-operation limit or concurrent iterator pull; reduce concurrency |
ERR_KINGFISHER_CLOSED |
Object is closed; create a new instance |
ERR_KINGFISHER_LIMIT |
Input/transform budget exceeded; review authorized limits |
ERR_KINGFISHER_IO |
Native filesystem/input failure; fix the input or permissions |
ERR_KINGFISHER_RULES |
Rule loading/compilation failure; fix the trusted rules |
ERR_KINGFISHER_VERSION |
Native and JS package versions differ; reinstall matching packages |
ERR_KINGFISHER_SCAN, ERR_KINGFISHER_INPUT, ERR_KINGFISHER_EXTRACTION |
Scan, Git input or extraction failed; no complete coverage claim |
ERR_KINGFISHER_ANALYSIS |
Explicit analysis failed; do not infer permissions |
ERR_KINGFISHER_REVOCATION_FAILED, ERR_KINGFISHER_REVOCATION_UNKNOWN |
Failed or indeterminate mutation; inspect outcomeUnknown and verify provider state |
ERR_KINGFISHER_NATIVE |
Other native failure; retain diagnostics, do not assume an empty scan |
Argument mistakes use TypeError or RangeError. Error codes alone never authorize
a credential mutation retry: an interrupted submitted action may already have succeeded.
All subpaths share one native addon and the same classes:
| Import | API |
|---|---|
kingfisher-secret-scanner |
All public exports, including the SDK version string |
kingfisher-secret-scanner/core |
Finding, shannonEntropy, version, errors |
kingfisher-secret-scanner/rules |
Rules |
kingfisher-secret-scanner/scanner |
Scanner, DetectionScanner, DetectionPolicy, CancellationToken, ScanResult |
kingfisher-secret-scanner/inputs |
ScanInput, filesystem, expandArchives, expandContent, gitHistory |
kingfisher-secret-scanner/git |
gitInputs, gitHistory |
kingfisher-secret-scanner/validation |
Validator, ValidationResult |
kingfisher-secret-scanner/revocation |
Revoker, RevocationPlan |
CommonJS require() and ESM named/default imports are supported at the root and
all listed subpaths, with TypeScript declarations. For example,
import sdk from 'kingfisher-secret-scanner' exposes sdk.Scanner, the same class
as a named ESM import or CommonJS require().
Rules.load({ paths: ["company.yml", "team.toml"], builtins: false }) loads custom
Kingfisher YAML or Betterleaks TOML using the shared Rust loader. Directories may
contain both formats. Custom TOML IDs gain the custom. prefix. metadata(),
detail(exactId) and resolve(selector) are offline. Selection supports exact
IDs, unambiguous display names and ID families, never fuzzy execution.
The shared catalog includes betterleaks.generic-api-key at static low confidence, retaining all
rejection filters but no confidence-upgrade branch. The default Rules.load() uses medium
confidence and excludes it before native regex compilation; use
Rules.load({ confidence: "low" }) to include it.
For dependency-aware selection, opt into
Rules.load({ confidence: "high", includeDependencies: true }): compile high-confidence
roots plus their transitive declared depends_on_rule helpers, including lower-confidence
visible or invisible helpers. Unrelated lower-confidence rules remain excluded before
compilation. includeDependencies defaults to false; existing loading behavior is unchanged.
betterleaks.generic-credential-uri stays medium; generic-password and generic-username
remain excluded from the catalog.
All rules use their configured confidence; there are no dynamic upgrades, demotions, or runtime
confidence variants. Existing custom YAML/TOML rules still load without edits. Legacy
one-string-argument setConfidence(...) and filter.setConfidence(...) calls are inert string
passthroughs; rejection filters and association helpers remain active.
Rules use the shared compiled database cache by default. cacheDir overrides
KF_RULE_CACHE_DIR and the platform cache directory; cache: false bypasses it.
cacheStatus is loaded, stored or bypassed. Only use trusted cache directories;
native/CPU-incompatible entries are recompiled. Keep a reusable scanner in application state.
Use the rules subpath to inspect the catalog without creating a scanner:
import { Rules } from 'kingfisher-secret-scanner/rules';
const rules = await Rules.load(); // Bundled catalog; offline.
const catalog = rules.metadata();
const definition = rules.detail(catalog[0].id);The rules subpath still requires the native addon; it is not a standalone, native-free JavaScript/JSON catalog export.
Rule patterns are not guaranteed to work with JavaScript RegExp. The
pattern and detection_regex fields returned by detail() target Kingfisher's
native matching pipeline, including Vectorscan/Hyperscan, not JavaScript's regex
engine. Some patterns may compile with new RegExp(...), but syntax, flags and
matching semantics are not guaranteed to be compatible across the catalog.
Successful compilation alone does not establish equivalent detection.
Regex matching alone also omits rule behavior such as secret capture selection,
entropy checks, filters, checksum requirements and nearby credential components.
Use the SDK's Scanner or DetectionScanner for Kingfisher detection behavior.
Reusing definitions in a JavaScript-only engine requires compatibility/conversion
work and per-rule tests, not just exporting the patterns.
- Legacy
Scannerdetection defaults match the existing embedding APIs: Base64 enabled, deduplication and scan-time redaction off, and rule-specific entropy.DetectionScanneror an explicitDetectionPolicyopts into CLI matching, inline ignores, bounded nested Base64 decoding and HTML/CSS context checks. - Node scanning has a 64 MiB per-input cap by default; set
maxInputBytes: nullexplicitly for unlimited input.maxPendingOperationsdefaults to 8 per scanner/validator/revoker. Excess calls fail withERR_KINGFISHER_BUSY. The binding bounds blocking native work to at most four workers across instances. The cold rule-compilation path uses an 8 MiB worker stack for deep regexes, including on Windows; ordinary scans retain the reusable native worker pool. timeoutMsis a positive total operation deadline in milliseconds.signalaccepts anAbortSignal;cancellationaccepts a reusableCancellationToken. Cancellation is cooperative, including when work waits for a worker. Individual reads, copies, decoding, compilation and native operations cannot be preempted. A discarded Promise does not cancel work. Use a separate process for a hard limit. Cancellation rejects withAbortError/ERR_KINGFISHER_CANCELLED; deadlines reject withTimeoutError/ERR_KINGFISHER_TIMEOUT. Revocation preserves these codes and addsoutcomeUnknown: truewhen submission may already have occurred; interruption does not prove that a credential was not revoked.close()cancels the object's pending operations and awaits their completion;Symbol.asyncDisposesupportsawait using. Close before terminating a Node worker. Abrupt worker termination is not a supported native cancellation protocol.toJSON()and default inspection redact secrets and captures. Raw.secret,.captures, ortoObject({ redact: false })access is explicit. Redaction is not secure erasure of earlier copies. Reports still contain sensitive correlation metadata.- Locations use zero-based, end-exclusive byte offsets, one-based lines and zero-based byte columns. UTF-16/32 input may be normalized to UTF-8; Base64 locations identify the encoded outer region. Do not treat offsets as JS string indices. Fingerprints are lossless, opaque hexadecimal strings, not JavaScript numbers or stable persisted identifiers.
import { Scanner, filesystem, expandArchives, expandContent } from "kingfisher-secret-scanner";
const scanner = await Scanner.create();
try {
const inputs = expandContent(expandArchives(filesystem(["project"]), { depth: 2 }));
for await (const result of scanner.scanInputs(inputs)) {
console.log(result.toJSON()); // Keeps the input path/provenance; omits payloads.
}
} finally {
await scanner.close();
}Filesystem and Git enumerators are pull-based async iterators. They do not run
the Kingfisher CLI or a Git subprocess, fetch repositories, read CLI configuration,
or mutate caller repositories. Filesystem enumeration honors local ignore files,
skips symlinks and .git, and reads content only when scanned or transformed.
Invalid, missing or unreadable root inputs throw. Recoverable nested
walk/ignore failures emit a process warning and continue; pass an
onWarning({ path, reason }) callback to record them or throw your own error to
require complete enumeration. Reasons are walk_error and ignore_error; raw
native error text is not exposed. Callback exceptions propagate unchanged. The
project recipe writes structured warnings
to stderr and exits 1 for incomplete enumeration, even while readable inputs
continue producing redacted JSONL on stdout.
Filesystem paths must be representable as Unicode strings: enumeration rejects
invalid UTF-8 names on Unix and unpaired UTF-16 surrogates on Windows rather than
silently reopening a different filename. Rename such files or read their bytes
with a platform-native path API and use scanner.scan(). Git inputs instead
retain original filename bytes in rawPath and scan blob bytes without reopening
the displayed path.
Git supports history, snapshot, diff and staged scopes; skipped blobs emit explicit
warnings. Controls cover preparation and the iterator lifetime, including consumer time.
scanInputs(), expandArchives() and expandContent() likewise share one deadline
from the first pull through iterator completion, not a fresh timeout per input.
They check controls before resumed work and after a producer finishes; they cannot
preempt an awaited caller-provided producer that has not settled.
Call return() or use for await to release iterator resources.
Archive expansion is explicit and completes a whole root before yielding any
members. Depth defaults to one and is bounded to 32; the per-root cumulative
output/entry budgets default to 256 MiB and 10,000. Budgets include nested layers
and inspected entries. Malformed or unsafe TAR/ZIP/ASAR members and staging
failures reject the whole root without partial members. Non-archives and depth: 0
pass through without eagerly reading their payload. These caps are not total
process-memory bounds. Content extraction supports SQLite and Python
bytecode, plus opt-in PDF text; it never executes bytecode or PDF actions.
Malformed supported content falls back with a safe diagnostic unless strict: true;
budget and interruption failures always propagate.
Transforms preserve original repository/commit/blob provenance while assigning
logical member paths. Offsets refer to extracted content. Git commit is a selected
occurrence, not proof of first introduction. Git timestamps are decimal strings to
retain arbitrary i64 values exactly. Default representations omit payloads, commit
messages and emails. tempDir should name a protected parent: staging is private
on Unix and inherits the parent's Windows DACL. Plaintext can survive crashes;
use encrypted or memory-backed storage when needed.
import { Validator, Revoker } from "kingfisher-secret-scanner";
const validator = new Validator({ concurrency: 4, httpFallbacks: false });
const revoker = await Revoker.create({ rules: scanner.rules });
try {
// Keep complete findings from one input, including invisible helpers.
const results = await validator.validate(findings);
for (const result of results) {
if (result.finding.visible) console.log(result.toJSON());
}
// Only after separate, explicit authorization:
// await revoker.revoke(results[0], { confirm: true });
} finally {
await validator.close();
await revoker.close();
}To authorize only a subset, retain the full original batch and pass exact original
objects as candidates (for example, after loading high-confidence roots with
includeDependencies: true):
const candidates = findings.filter(f => f.visible && f.confidence === "high");
const results = await validator.validate(findings, { candidates, timeoutMs: 30_000 });Candidates must be unique members of that same-input batch, not redacted reports or
reconstructed objects. Only candidates receive validation results/provider checks;
all original helpers remain available for dependency resolution. candidates: []
performs no checks while still honoring cancellation/deadlines. Omitting the option
preserves existing whole-batch validation behavior. Results retain their original
private snapshots for later authorized analysis/revocation.
Selected candidates are preflighted like plan.validate(): a candidate with a
missing, ambiguous or unrenderable input (for example, an unset template variable)
is skipped with a diagnostic reason before any provider request. Whole-batch
validation without candidates may still send that request. candidates takes
original Finding objects, not the records in RevocationPlan.candidates.
That fragment assumes existing scanner and complete same-input findings.
For a fully runnable version, start with the local mock.
It verifies preparation sends no requests, validates a synthetic credential, and
requires --confirm-demo-revoke before changing only its own in-memory state.
For real providers, prefer a separate approval step:
- Load trusted rules and inspect their credential destinations.
- Detect one input and keep all its original findings, including invisible helpers.
- With authorization, call
validator.validate(findings). - Report
outcome,reason,httpStatus,revocationReady, and diagnostics usingtoJSON(). - Only after separate mutation approval, pass the original verified-active
result to
revoker.revoke(result, { confirm: true }). - Treat an unknown submitted mutation as potentially successful; verify its state out of band before deciding whether another mutation is safe.
Do not revoke every scan finding, trust a saved JSON report as an action snapshot,
or use a 200 status/revocationSupported boolean as proof of activity.
verified_active is a live provider outcome; locally_derived, assumed,
unavailable, and skipped are not equivalent to live verification.
Validation may send credentials to provider URLs defined by trusted rules. It
never runs revocation or analysis automatically. maxResponseBytes defaults to
1 MiB per response; 0 disables the response-size cap, rather than blocking
responses. Keep a finite cap for untrusted or large responses. Use structured outcomes:
unexpected success bodies, rate limits and transport failures are not inactive
credentials. validator.analyze(result) explicitly uses the rule's analysis
program and original private evidence; provider bodies/evidence are never in
ordinary validation reports. Analysis may make additional authorized provider
requests; it is not an automatic part of validation.
inspect() and Revoker.prepare() / prepareFromFile() are offline. Preparation
returns candidates and input diagnostics, not proof of activity; plan.validate()
is explicit. revoke() requires an original, verified-active native snapshot and
confirm: true; JSON reports cannot authorize it. revokeSecret() is a separate
direct-primary API. revokeMany() is sequential and deduplicates exact original
action/input snapshots, not fingerprints. Interrupted submitted actions are
unknown; cancellation/timeout errors retain their normal .code plus
outcomeUnknown: true. revokeMany() errors also retain safe completed statuses
and pendingIndices. Check these fields, verify state out of band, and never
automatically retry an unknown mutation.
Existing YAML/TOML rules need no edits. HTTP fallbacks require explicit
httpFallbacks: true on the validator. Both primary-logic reuse switches default
to false; validation reuse does not imply revocation reuse or inherit target URLs.
Result-based revocation uses the accepted environment and original action snapshot,
without revalidation or mutation failover. Caller-supplied VALIDATION_* endpoint
state is rejected by direct revocation. See fallback semantics.
This is a native Node SDK, not a browser/WASM package. Initial build targets
are macOS x64/ARM64, Linux glibc x64/ARM64, and Windows MSVC x64/ARM64. Node-API 8
provides ABI compatibility; release support still depends on actual Node/OS/CPU
tests. Supported Node majors are 22, 24 and 26 only, with a tested minimum
of 22.13.0. The npm engines constraint is ^22.13.0 || ^24.0.0 || ^26.0.0, not
an open-ended range. CI tests six pinned runtimes: 22.13.0, 22.23.4, 24.0.0,
24.22.2, 26.0.0 and 26.13.0. Native builds also need Rust 1.99 and the
native build prerequisites.
Linux artifacts require glibc 2.35+ and a GCC 11-compatible libstdc++ runtime
(GLIBCXX 3.4.29 / CXXABI 1.3.13 or newer); CI audits symbol versions on both Linux
architectures. Windows consumers require the architecture-matched VC++ v14
Redistributable 14.44+ (VS 2022 baseline; newer compatible runtimes work).
Neither musl nor other Node majors, Bun, Deno or browser-only/edge hosts are claimed
supported. Node-API compatibility alone is not a tested support guarantee.
A VS Code desktop or remote workspace extension can import the npm SDK without
WASM. Use a Node main entry and extensionKind: ["workspace"] so scanning runs
where the workspace lives. A Codespaces browser UI can use its remote Node host;
standalone vscode.dev / github.dev cannot load this addon. Webviews communicate
with the extension host rather than loading native code themselves.
Include the matching .node and loader/dependencies in platform-specific VSIX
packages, mark the native package external in JS bundlers, and test VS Code's
bundled runtime. Scan editor buffers for unsaved content, debounce changes, cancel
obsolete work and convert UTF-8 byte offsets to VS Code's UTF-16 document positions.
No extension or VSIX is published as part of this SDK preparation.
Use a supported Node runtime, Rust 1.99 and the native prerequisites. From the repository root:
cd javascript
npm ci --ignore-scripts
npm run build:debug
npm test
npm run test:typesThen choose a runnable recipe. These commands build and test locally; they do not publish packages.
npm run build uses the unwind-capable node-release Cargo profile. Native
functions contain synchronous Rust panics, and asynchronous workers reject on
failure; this does not contain a native crash or make abrupt worker termination safe.
Builds use the locked Cargo dependencies and generate the private
loader/declarations and the host .node file. Public
declarations and integration tests cover the facade independently.
The SDK pins published Vectorscan 0.1.4. Cargo verifies native archives using
checksums embedded in the immutable sys crate; ordinary builds need no local
HYPERSCAN_ROOT override. See the native build guide
for MSVC SDK/linker prerequisites, explicit source builds and ABI/CRT requirements.
npm run test:package verifies a clean, offline installation of sealed release
tarballs with the genuine host addon, including CJS/ESM subpaths and license files.
It requires prior artifact collection and npm run pack:release; it does not build
or repack packages. A host-only check does not establish support for other targets.
All six native artifacts and seven exact tarballs verified on the supported
runtime matrix are required for publication.
After locked native dependency changes, use make notices from the repository
root to regenerate the exact third-party crate/version union across all workspace
members, features and targets, including normal/build dependencies and proc macros.
It excludes dev-only/first-party crates, removes stale Cargo entries and preserves
independent non-Cargo notices. Use pinned cargo-bundle-licenses 4.2.0 and
fetched Cargo dependencies. Run npm run check:notices from javascript/ (or root
make check-notices) for a read-only check; missing, stale or incomplete license
texts fail closed. See the
contributor notices workflow.
The publishing guide covers
npm trusted publishing, GitHub environment setup, SDK version updates and
failed-job recovery. Reviewed npm-vX.Y.Z tags build
all six native artifacts, seal packages once, and verify the exact tarballs in a
separate six-host/runtime-matrix job. The publisher uses pinned Node 24.22.2
and npm 11.21.1 to publish those same bytes through protected GitHub OIDC.
PRs, branch pushes and ordinary manual checks never publish. The guide is the
canonical source for account/trust setup, exact tool versions and partial-release
recovery; no account changes or publication happen merely by building the SDK.
