tosijs-ui 1.7.4 → 1.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +78 -0
- package/dist/doc-browser.d.ts +3 -1
- package/dist/doc-browser.js +37 -24
- package/dist/doc-system/nav-tree.d.ts +24 -5
- package/dist/doc-system/nav-tree.js +0 -0
- package/dist/doc-system/site/audit-guard.d.ts +124 -0
- package/dist/doc-system/site/audit-guard.js +555 -0
- package/dist/doc-system/site/dev-server.js +59 -3
- package/dist/doc-system/site/index.d.ts +4 -0
- package/dist/doc-system/site/index.js +2 -0
- package/dist/doc-system/site/open-browser.d.ts +53 -0
- package/dist/doc-system/site/open-browser.js +231 -0
- package/dist/doc-system/site/orchestrator.d.ts +3 -1
- package/dist/doc-system/site/orchestrator.js +13 -1
- package/dist/doc-system/site/site-config.d.ts +41 -0
- package/dist/hydrate/{ajs-language-qm5w38ae.js → ajs-language-xvpytqfm.js} +2 -2
- package/dist/hydrate/{code-editor-cm-95n31m4f.js → code-editor-cm-59je4d8g.js} +6 -6
- package/dist/hydrate/{code-editor-cm-95n31m4f.js.map → code-editor-cm-59je4d8g.js.map} +4 -4
- package/dist/hydrate/hydrate.js +53 -53
- package/dist/hydrate/hydrate.js.map +5 -5
- package/dist/hydrate/index-iife-2q1gndgz.js +27 -0
- package/dist/hydrate/{index-iife-kwhe0yt8.js.map → index-iife-2q1gndgz.js.map} +3 -3
- package/dist/hydrate/{index-iife-ype8sch3.js → index-iife-xv69gy4m.js} +6 -6
- package/dist/hydrate/index-iife-xv69gy4m.js.map +12 -0
- package/dist/hydrate/{index-0ps8jzdn.js → index-vk8ek4jm.js} +2 -2
- package/dist/iife.js +63 -63
- package/dist/iife.js.map +9 -9
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/llms.txt +1 -1
- package/package.json +17 -13
- package/tls/create-dev-certs.sh +1 -1
- package/dist/hydrate/index-iife-kwhe0yt8.js +0 -27
- package/dist/hydrate/index-iife-ype8sch3.js.map +0 -12
- /package/dist/hydrate/{ajs-language-qm5w38ae.js.map → ajs-language-xvpytqfm.js.map} +0 -0
- /package/dist/hydrate/{index-0ps8jzdn.js.map → index-vk8ek4jm.js.map} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,83 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.8.0
|
|
4
|
+
|
|
5
|
+
> **Read this first if you use `tosijs-ui/site`.** This release adds a **dependency-audit
|
|
6
|
+
> gate that is ON BY DEFAULT and can fail your build** — on advisories in _your_ dependency
|
|
7
|
+
> tree, not ours. That is deliberate, and there are three ways out (below). Minor, not patch,
|
|
8
|
+
> precisely because `bun run build` can now exit 1 where it previously didn't.
|
|
9
|
+
|
|
10
|
+
- **New: dependency-audit gate** (`src/doc-system/site/audit-guard.ts`, exported from
|
|
11
|
+
`tosijs-ui/site`). `bun audit` knows the registry advisory database; nothing in a normal
|
|
12
|
+
build ever asked it, so a high-severity advisory in a transitive dep stayed invisible until
|
|
13
|
+
someone ran it by hand. Now it's asked at the point a human is looking.
|
|
14
|
+
- **Runs synchronously in every mode** — inside `buildSite` for `bun run build` / `--test`,
|
|
15
|
+
and in `devServer` **just before it binds the port** (it throws, so the server never comes
|
|
16
|
+
up). Sub-second in practice; a gate you wait for can't be raced. **Watch rebuilds never
|
|
17
|
+
audit** — that would put a network call in your edit loop and break offline dev.
|
|
18
|
+
- **What blocks:** any advisory at or above `level` (default `high`) that isn't gated.
|
|
19
|
+
Consumer-facing and developer-facing advisories block **alike** — a dev-only dependency
|
|
20
|
+
still runs on your machine, and the escape hatch makes over-blocking cheap.
|
|
21
|
+
- **Three ways out:** `audit: { allow: [{ advisory, reason, expires }] }` to accept a risk
|
|
22
|
+
**on a deadline** (an expired or malformed gate stops suppressing, so it comes back for
|
|
23
|
+
review instead of living in an allowlist nobody re-reads); `audit: { mode: 'warn' }` to
|
|
24
|
+
report without failing; `audit: false` or `TOSIJS_AUDIT=off` to disable.
|
|
25
|
+
- **Fails open, never closed, when it can't check** — offline, registry down, `bun` too old,
|
|
26
|
+
or past its 20s timeout: it warns and proceeds. It fails **closed** only on a real finding.
|
|
27
|
+
- **Not downgraded in CI.** Unlike the machine-health preflight (a heuristic about someone's
|
|
28
|
+
local box), an advisory is deterministic and environment-independent.
|
|
29
|
+
- **Findings are grouped, sorted worst-first, and annotated** with the _nature_ of the risk
|
|
30
|
+
(`LEAK/ALTER` / `DoS-only` / `DoS?+ESCALATABLE` / `UNCLASSIFIED`), parsed from the CVSS
|
|
31
|
+
vector (3.x and 4.0) plus CWEs. Annotation only — it never changes what blocks, and it
|
|
32
|
+
fails **closed**: ~20% of real advisories carry no CVSS vector at all, and those skew
|
|
33
|
+
severe. Sub-threshold advisories are listed compactly (previously collected and never
|
|
34
|
+
shown), plus an **advisories-per-package tally** — a dependency that keeps producing them
|
|
35
|
+
is a code smell worth replacing rather than patching.
|
|
36
|
+
- **Fix (issue #24, reported by a consumer): nav `order` now sorts numerically.** Section nav
|
|
37
|
+
and the generated `<!-- toc -->` built a zero-padded *string* key and compared it lexically,
|
|
38
|
+
so a fractional order silently sorted to the **end** of its section — `order: 1.5` landed
|
|
39
|
+
after `2`, `3`, … because `"01.5" > "0002"` as text. "Insert a page at N.5" reads like a
|
|
40
|
+
supported idiom and did the opposite with no warning. The same padding capped `order` at 4
|
|
41
|
+
digits (10000+ overflowed the width) and mis-sorted negatives. `pinnedSort` is now a
|
|
42
|
+
multi-key comparator (pin bucket → numeric order → title → filename), which fixes all three.
|
|
43
|
+
**Removed `navSortKey`** (the string-key builder) — it was never in a public index, but was
|
|
44
|
+
reachable via the `./*` subpath, so: technically breaking. A string key cannot express this
|
|
45
|
+
ordering, so there is no corrected version of it.
|
|
46
|
+
- **`src/doc-system/nav-tree.ts` was a binary file.** The old sort key joined title and
|
|
47
|
+
filename with a raw NUL byte, which makes macOS `grep` silently match **nothing** in that
|
|
48
|
+
file (exit 1, no message) — so searching it for any symbol came back empty and the sort bug
|
|
49
|
+
above was effectively unfindable. The comparator needs no delimiter; the NUL is gone.
|
|
50
|
+
- **New: `openBrowser`** site-config option — opens the doc site on dev-server start, reusing
|
|
51
|
+
an existing tab on macOS rather than piling up new ones.
|
|
52
|
+
- **New: `DEV_NO_WATCH=1`** serves the built site without watching. The E2E lane used to run
|
|
53
|
+
`bun start`, so a file watcher stayed live for the whole suite and could `rm -rf docs/` and
|
|
54
|
+
regenerate underneath a test mid-navigation — the lane flaked against its own build system,
|
|
55
|
+
which presents as a product bug.
|
|
56
|
+
- **New public API on `tosijs-ui/site`:** `auditDependencies`, `reportAudit`,
|
|
57
|
+
`resolveAuditMode`, `classifyRisk`, `groupAdvisories`, `openBrowser`, plus their types.
|
|
58
|
+
`buildSite` takes an optional second argument (`{ skipAudit }`).
|
|
59
|
+
- **Fix: `bun run test-browser` no longer reports success on a failed build.** It computed the
|
|
60
|
+
build result and launched the test run regardless, so a failing build (or a blocking
|
|
61
|
+
advisory) still went green. One-shot modes now exit 1.
|
|
62
|
+
- **Fix: the E2E lane can register ServiceWorkers over the dev cert.** `ignoreHTTPSErrors` is a
|
|
63
|
+
browser-_context_ option and never covered a ServiceWorker's own script fetch, so the
|
|
64
|
+
import-resolver worker failed to register and `hydration.pw.ts` caught it as a console error.
|
|
65
|
+
Chromium now launches with `--ignore-certificate-errors`.
|
|
66
|
+
- **Dependency pins:** `overrides` for `flatted` (`>=3.4.2`) and `brace-expansion` (`>=5.0.8`)
|
|
67
|
+
clear live high-severity advisories. Added `.github/dependabot.yml` so advisories published
|
|
68
|
+
later against an unchanged lockfile still surface.
|
|
69
|
+
- Includes the unpublished 1.7.5 (header-logo sizing) — npm goes 1.7.4 → 1.8.0.
|
|
70
|
+
|
|
71
|
+
## 1.7.5
|
|
72
|
+
|
|
73
|
+
- **Header logo size/spacing are now CSS-tunable** (follow-up to 1.7.4). The brand mark no
|
|
74
|
+
longer hard-wires a pixel height inline; it carries a `.logo-mark` class driven by two
|
|
75
|
+
variables — `--tosi-logo-mark-size` (default **32px**, was a fixed 40px) and
|
|
76
|
+
`--tosi-logo-mark-gap` (default 10px) — for icon, `<img>`, and inline-`<svg>` logos alike.
|
|
77
|
+
(Icon `<svg>`s take their height from `--tosi-icon-size`, set inline by `makeIcon()`, so the
|
|
78
|
+
class points that knob at the same variable rather than fighting the inline height.) Retune a
|
|
79
|
+
logo from CSS instead of editing the build.
|
|
80
|
+
|
|
3
81
|
## 1.7.4
|
|
4
82
|
|
|
5
83
|
- **Configurable header logo.** A new `logo` option lets a doc site set the brand mark shown
|
package/dist/doc-browser.d.ts
CHANGED
|
@@ -67,7 +67,9 @@ export interface DocBrowserOptions {
|
|
|
67
67
|
* - an image URL / path / data: URI (rendered as an `<img>`)
|
|
68
68
|
* - a raw inline `<svg …>…</svg>` string
|
|
69
69
|
* Omit to fall back to the tosijs-ui logo when `projectLinks.tosijs` is set,
|
|
70
|
-
* or to no mark at all otherwise.
|
|
70
|
+
* or to no mark at all otherwise. Size and spacing are CSS-tunable via
|
|
71
|
+
* `--tosi-logo-mark-size` (default 32px) and `--tosi-logo-mark-gap` (default
|
|
72
|
+
* 10px) on the `.logo-mark` element.
|
|
71
73
|
*/
|
|
72
74
|
logo?: string;
|
|
73
75
|
navSize?: number;
|
package/dist/doc-browser.js
CHANGED
|
@@ -257,9 +257,9 @@ const testIndicatorStyleSpec = {
|
|
|
257
257
|
// The brand mark shown left of the site title. `logo` (from config) may name a
|
|
258
258
|
// known icon, be an inline `<svg>` string, or be an image URL; when absent we
|
|
259
259
|
// keep the legacy behavior — the tosijs-ui logo iff this is a tosijs project,
|
|
260
|
-
// else nothing.
|
|
261
|
-
|
|
262
|
-
|
|
260
|
+
// else nothing. Size and spacing are class-driven (`.logo-mark`, see
|
|
261
|
+
// logoMarkStyleSpec) so a consumer retunes them with one CSS variable each,
|
|
262
|
+
// rather than a hard-wired pixel value.
|
|
263
263
|
// `icons` is a Proxy that returns a factory for ANY string (unknown names get a
|
|
264
264
|
// placeholder glyph), so we can't ask it whether a name is real — we route by the
|
|
265
265
|
// shape of the string instead: an inline `<svg>` renders as-is, a URL/path/data:
|
|
@@ -274,33 +274,44 @@ function looksLikeImageUrl(s) {
|
|
|
274
274
|
/\.(png|jpe?g|gif|webp|avif|svg|ico)(\?.*)?$/i.test(s));
|
|
275
275
|
}
|
|
276
276
|
function logoMark(logo, projectLinks) {
|
|
277
|
+
let mark = null;
|
|
277
278
|
if (logo) {
|
|
278
279
|
if (logo.trimStart().startsWith('<')) {
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
height: `${LOGO_SIZE}px`,
|
|
283
|
-
marginRight: `${LOGO_GAP}px`,
|
|
284
|
-
},
|
|
285
|
-
});
|
|
286
|
-
holder.innerHTML = logo;
|
|
287
|
-
return holder;
|
|
280
|
+
// Inline <svg>: wrap in a flex holder so `.logo-mark`'s height sizes it.
|
|
281
|
+
mark = span({ style: { display: 'inline-flex', alignItems: 'center' } });
|
|
282
|
+
mark.innerHTML = logo;
|
|
288
283
|
}
|
|
289
|
-
if (looksLikeImageUrl(logo)) {
|
|
290
|
-
|
|
291
|
-
src: logo,
|
|
292
|
-
alt: '',
|
|
293
|
-
style: { height: `${LOGO_SIZE}px`, marginRight: `${LOGO_GAP}px` },
|
|
294
|
-
});
|
|
284
|
+
else if (looksLikeImageUrl(logo)) {
|
|
285
|
+
mark = img({ src: logo, alt: '' });
|
|
295
286
|
}
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
}
|
|
287
|
+
else {
|
|
288
|
+
mark = icons[logo]();
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
else if (projectLinks.tosijs) {
|
|
292
|
+
mark = icons.tosiUi();
|
|
299
293
|
}
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
294
|
+
// No mark → an empty span with NO class, so it carries no margin (the title
|
|
295
|
+
// stays flush; a flex `gap` on the header link couldn't do that).
|
|
296
|
+
if (!mark)
|
|
297
|
+
return span();
|
|
298
|
+
mark.classList.add('logo-mark');
|
|
299
|
+
return mark;
|
|
303
300
|
}
|
|
301
|
+
const logoMarkStyleSpec = {
|
|
302
|
+
'.logo-mark': {
|
|
303
|
+
height: 'var(--tosi-logo-mark-size, 32px)',
|
|
304
|
+
// An icon <svg> takes its height from --tosi-icon-size, set INLINE on the svg
|
|
305
|
+
// by makeIcon() — which beats a class `height` rule. Point that knob at the
|
|
306
|
+
// same variable so one --tosi-logo-mark-size drives an icon, an <img>, or an
|
|
307
|
+
// inline <svg> alike.
|
|
308
|
+
_tosiIconSize: 'var(--tosi-logo-mark-size, 32px)',
|
|
309
|
+
marginRight: 'var(--tosi-logo-mark-gap, 10px)',
|
|
310
|
+
flexShrink: '0',
|
|
311
|
+
},
|
|
312
|
+
// Inline-<svg> logos are wrapped in a flex holder; scale the embedded svg to it.
|
|
313
|
+
'.logo-mark > svg': { height: '100%', width: 'auto' },
|
|
314
|
+
};
|
|
304
315
|
// Monotonic per-page counter so each createDocBrowser() call gets a distinct
|
|
305
316
|
// tosi() registry key (see stateKey below) and two browsers can't share state.
|
|
306
317
|
let docBrowserSeq = 0;
|
|
@@ -1190,6 +1201,8 @@ export function createDocBrowser(options) {
|
|
|
1190
1201
|
showDoc(currentDoc);
|
|
1191
1202
|
// Inject test indicator styles
|
|
1192
1203
|
StyleSheet('test-indicators', testIndicatorStyleSpec);
|
|
1204
|
+
// Header brand-mark sizing (icon / <img> / inline-<svg>), one CSS var each.
|
|
1205
|
+
StyleSheet('doc-logo-mark', logoMarkStyleSpec);
|
|
1193
1206
|
// Floating widget for test status
|
|
1194
1207
|
const testWidget = button({
|
|
1195
1208
|
class: 'test-widget',
|
|
@@ -14,12 +14,31 @@ export interface NavNode<T extends NavDoc = NavDoc> {
|
|
|
14
14
|
depth: number;
|
|
15
15
|
}
|
|
16
16
|
/**
|
|
17
|
-
* Total
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
17
|
+
* Total order: pin bucket (top<none<bottom), then `order` (NUMERIC, default 500),
|
|
18
|
+
* then title, then filename. The filename tiebreak guarantees a stable total order
|
|
19
|
+
* even for equal titles — required so the generated TOC blocks are idempotent (no
|
|
20
|
+
* build-to-build churn).
|
|
21
|
+
*
|
|
22
|
+
* This is a multi-key COMPARATOR, not a concatenated string key, and that is the
|
|
23
|
+
* whole point (issue #24, reported by a consumer). The old version built
|
|
24
|
+
* `bucket + String(order).padStart(4,'0') + title + filename` and compared it
|
|
25
|
+
* lexically, so `order` sorted as TEXT:
|
|
26
|
+
*
|
|
27
|
+
* order 1 -> "0001"
|
|
28
|
+
* order 2 -> "0002"
|
|
29
|
+
* order 1.5 -> String(1.5) = "1.5" -> padStart(4,'0') = "01.5"
|
|
30
|
+
*
|
|
31
|
+
* and lexically "01.5" > "0002" (at index 1, '1' > '0'), so a doc at 1.5 sorted
|
|
32
|
+
* AFTER 2, 3, ... — last in its section. "Insert a page at N.5" reads like a
|
|
33
|
+
* supported idiom and silently did the opposite, with no warning. The same padding
|
|
34
|
+
* also capped `order` at 4 digits (10000+ overflowed the width) and mis-sorted
|
|
35
|
+
* negatives. Comparing numbers as numbers fixes all three.
|
|
36
|
+
*
|
|
37
|
+
* The old key also joined title and filename with a raw NUL byte, which made this
|
|
38
|
+
* file BINARY: macOS grep then silently matches nothing in it (exit 1, no message),
|
|
39
|
+
* so searching this file for any symbol came back empty and the padStart bug was
|
|
40
|
+
* effectively unfindable. A comparator needs no delimiter, so the NUL is gone.
|
|
21
41
|
*/
|
|
22
|
-
export declare function navSortKey(doc: NavDoc): string;
|
|
23
42
|
export declare function pinnedSort(a: NavDoc, b: NavDoc): number;
|
|
24
43
|
/**
|
|
25
44
|
* Build the forest of top-level nav nodes. Children are grouped under their
|
|
Binary file
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
export type AuditSeverity = 'info' | 'low' | 'moderate' | 'high' | 'critical';
|
|
2
|
+
export type AuditMode = 'fail' | 'warn' | 'off';
|
|
3
|
+
/** One advisory as `bun audit --json` reports it, flattened with its package. */
|
|
4
|
+
export interface AuditAdvisory {
|
|
5
|
+
package: string;
|
|
6
|
+
id: number;
|
|
7
|
+
url: string;
|
|
8
|
+
title: string;
|
|
9
|
+
severity: AuditSeverity;
|
|
10
|
+
vulnerableVersions?: string;
|
|
11
|
+
/** GHSA id parsed from `url`, e.g. 'GHSA-25h7-pfq9-p65f' (if present) */
|
|
12
|
+
ghsa?: string;
|
|
13
|
+
/** what KIND of harm this is — annotation only, never changes whether it blocks */
|
|
14
|
+
risk?: Classification;
|
|
15
|
+
}
|
|
16
|
+
export type RiskNature =
|
|
17
|
+
/** C or I impact — can leak or alter data / execute code */
|
|
18
|
+
'compromise'
|
|
19
|
+
/** availability-only — resource exhaustion, hang, crash */
|
|
20
|
+
| 'dos'
|
|
21
|
+
/** no or unparseable vector, or an escalatable CWE — assume the worst */
|
|
22
|
+
| 'unknown';
|
|
23
|
+
export interface Classification {
|
|
24
|
+
nature: RiskNature;
|
|
25
|
+
/** short label for the report line */
|
|
26
|
+
label: string;
|
|
27
|
+
/** what drove the call, so the reader can second-guess it */
|
|
28
|
+
basis: string;
|
|
29
|
+
}
|
|
30
|
+
/** Classify one advisory's nature from its CVSS vector + CWEs. Fails CLOSED. */
|
|
31
|
+
export declare function classifyRisk(raw: {
|
|
32
|
+
cvss?: {
|
|
33
|
+
vectorString?: string;
|
|
34
|
+
} | null;
|
|
35
|
+
cwe?: string[] | null;
|
|
36
|
+
}): Classification;
|
|
37
|
+
/**
|
|
38
|
+
* A time-boxed exception. A gate suppresses a matching advisory ONLY while it is
|
|
39
|
+
* valid and unexpired — after `expires` it stops suppressing and the build fails
|
|
40
|
+
* again, which is the point: an accepted risk gets re-evaluated on a deadline
|
|
41
|
+
* rather than living forever in an allowlist nobody re-reads.
|
|
42
|
+
*/
|
|
43
|
+
export interface AuditGate {
|
|
44
|
+
/** GHSA id, the numeric advisory id, or a package name (package match is broad) */
|
|
45
|
+
advisory: string;
|
|
46
|
+
/** why this is temporarily allowed — required, non-empty */
|
|
47
|
+
reason: string;
|
|
48
|
+
/** YYYY-MM-DD; on/after this date the gate no longer suppresses — required */
|
|
49
|
+
expires: string;
|
|
50
|
+
}
|
|
51
|
+
export interface AuditConfig {
|
|
52
|
+
/** 'fail' (default) blocks the build; 'warn' reports and proceeds; 'off' skips it */
|
|
53
|
+
mode?: AuditMode;
|
|
54
|
+
/** minimum severity that blocks, default 'high' */
|
|
55
|
+
level?: AuditSeverity;
|
|
56
|
+
/** time-boxed exceptions */
|
|
57
|
+
allow?: AuditGate[];
|
|
58
|
+
}
|
|
59
|
+
export interface GatedFinding {
|
|
60
|
+
advisory: AuditAdvisory;
|
|
61
|
+
reason: string;
|
|
62
|
+
/** whole days until the gate expires (active gate) */
|
|
63
|
+
daysLeft?: number;
|
|
64
|
+
/** whole days since the gate expired (expired gate) */
|
|
65
|
+
daysAgo?: number;
|
|
66
|
+
}
|
|
67
|
+
export interface AuditResult {
|
|
68
|
+
/** did the audit actually run and parse? false => fail-open, treated as pass */
|
|
69
|
+
ran: boolean;
|
|
70
|
+
/** no blocking findings (or couldn't run) */
|
|
71
|
+
ok: boolean;
|
|
72
|
+
mode: AuditMode;
|
|
73
|
+
level: AuditSeverity;
|
|
74
|
+
/** at/above threshold and NOT suppressed — these fail the build */
|
|
75
|
+
blocking: AuditAdvisory[];
|
|
76
|
+
/** suppressed by a valid, unexpired gate */
|
|
77
|
+
gated: GatedFinding[];
|
|
78
|
+
/** matched a gate whose expiry has passed — NOT suppressed (also in `blocking`) */
|
|
79
|
+
expired: GatedFinding[];
|
|
80
|
+
/** gates that are structurally invalid (missing reason/expires) — ignored */
|
|
81
|
+
invalid: Array<{
|
|
82
|
+
gate: AuditGate;
|
|
83
|
+
problem: string;
|
|
84
|
+
}>;
|
|
85
|
+
/** valid gates that matched no current advisory — safe to delete */
|
|
86
|
+
stale: AuditGate[];
|
|
87
|
+
/** findings below the blocking threshold (reported, never blocking) */
|
|
88
|
+
belowThreshold: AuditAdvisory[];
|
|
89
|
+
}
|
|
90
|
+
/** Injectable subprocess seam for tests. */
|
|
91
|
+
export type AuditRunner = () => Promise<string>;
|
|
92
|
+
export declare const AUDIT_TIMEOUT_MS = 20000;
|
|
93
|
+
/**
|
|
94
|
+
* Parse `bun audit --json` output — `{ "<pkg>": [advisory, …] }` — into a flat
|
|
95
|
+
* advisory list. Returns null when the text is not a JSON object (offline, an
|
|
96
|
+
* error dump, an incompatible bun): the caller reads null as "couldn't check".
|
|
97
|
+
*/
|
|
98
|
+
export declare function parseAuditJson(text: string): AuditAdvisory[] | null;
|
|
99
|
+
/** Resolve the effective mode from config + the TOSIJS_AUDIT env override. */
|
|
100
|
+
export declare function resolveAuditMode(config: boolean | AuditConfig | undefined): AuditMode;
|
|
101
|
+
/** Test-only: forget the per-process audit memo. */
|
|
102
|
+
export declare function resetAuditMemo(): void;
|
|
103
|
+
/**
|
|
104
|
+
* Run `bun audit`, classify findings against the configured threshold and the
|
|
105
|
+
* time-boxed allowlist, and return a structured verdict. Never exits.
|
|
106
|
+
*
|
|
107
|
+
* Memoized per process (see above) unless `opts.runAudit` is injected.
|
|
108
|
+
*/
|
|
109
|
+
export declare function auditDependencies(config: boolean | AuditConfig | undefined, opts?: {
|
|
110
|
+
now?: Date;
|
|
111
|
+
runAudit?: AuditRunner;
|
|
112
|
+
}): Promise<AuditResult>;
|
|
113
|
+
export interface GroupedAdvisory {
|
|
114
|
+
advisory: AuditAdvisory;
|
|
115
|
+
/** every vulnerable range this advisory matched for this package */
|
|
116
|
+
ranges: string[];
|
|
117
|
+
}
|
|
118
|
+
export declare function groupAdvisories(advisories: AuditAdvisory[]): GroupedAdvisory[];
|
|
119
|
+
/**
|
|
120
|
+
* Print the verdict. Blocking findings first (why the build is failing), then
|
|
121
|
+
* active gates, expired/invalid gates, stale gates, and — when blocking — the
|
|
122
|
+
* due-diligence footer. Returns nothing; the caller decides what to do with `ok`.
|
|
123
|
+
*/
|
|
124
|
+
export declare function reportAudit(result: AuditResult, label?: string): void;
|