@socketsecurity/lib 6.0.9 → 6.0.10
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 +6 -0
- package/README.md +8 -9
- package/dist/abort/signal.d.ts +1 -1
- package/dist/abort/signal.js +1 -1
- package/dist/ai/agent-context.d.mts +1 -1
- package/dist/ai/agent-context.js +3 -2
- package/dist/ai/backends.d.mts +3 -3
- package/dist/ai/backends.js +2 -2
- package/dist/ai/billing-context.d.mts +74 -0
- package/dist/ai/billing-context.js +129 -0
- package/dist/ai/credentials.d.mts +39 -5
- package/dist/ai/credentials.js +61 -6
- package/dist/ai/discover.d.mts +4 -0
- package/dist/ai/discover.js +4 -0
- package/dist/ai/exec.d.mts +1 -1
- package/dist/ai/exec.js +1 -1
- package/dist/ai/http.d.mts +8 -8
- package/dist/ai/http.js +6 -6
- package/dist/ai/profiles.d.mts +9 -10
- package/dist/ai/profiles.js +0 -5
- package/dist/ai/role.d.mts +58 -0
- package/dist/ai/role.js +96 -0
- package/dist/ai/route-heuristic.d.mts +177 -0
- package/dist/ai/route-heuristic.js +194 -0
- package/dist/ai/route.d.mts +10 -9
- package/dist/ai/route.js +14 -13
- package/dist/ai/spawn.d.mts +2 -1
- package/dist/ai/spawn.js +25 -2
- package/dist/ai/subagent-status.d.mts +2 -0
- package/dist/ai/subagent-status.js +2 -0
- package/dist/ai/tier.d.mts +1 -1
- package/dist/ai/types.d.mts +9 -2
- package/dist/ai/worktree.d.mts +1 -1
- package/dist/ai/worktree.js +3 -2
- package/dist/argv/parse.d.ts +2 -0
- package/dist/argv/parse.js +2 -0
- package/dist/bin/_internal.d.ts +1 -1
- package/dist/bin/_internal.js +1 -1
- package/dist/bin/prim.cjs +446 -300
- package/dist/bin/shadow.js +2 -1
- package/dist/bin/which.d.ts +28 -3
- package/dist/bin/which.js +45 -3
- package/dist/cacache/_internal.d.ts +10 -2
- package/dist/cacache/_internal.js +6 -10
- package/dist/cache/ttl/_internal.d.ts +33 -0
- package/dist/cache/ttl/_internal.js +68 -0
- package/dist/cache/ttl/browser.d.ts +56 -0
- package/dist/cache/ttl/browser.js +257 -0
- package/dist/cache/ttl/store.js +10 -33
- package/dist/cache/ttl/types.d.ts +46 -3
- package/dist/checks/primordials-defaults.d.ts +5 -5
- package/dist/checks/primordials-defaults.js +5 -5
- package/dist/checks/primordials.d.ts +1 -1
- package/dist/checks/primordials.js +25 -17
- package/dist/cli/check-primordials.d.ts +6 -1
- package/dist/cli/check-primordials.js +14 -5
- package/dist/cli/check.js +1 -1
- package/dist/cli/socket-lib.d.ts +1 -1
- package/dist/cli/socket-lib.js +3 -3
- package/dist/colors/socket-palette.d.ts +1 -1
- package/dist/compression/brotli.d.ts +6 -2
- package/dist/compression/brotli.js +4 -0
- package/dist/compression/gzip.d.ts +6 -2
- package/dist/compression/gzip.js +6 -1
- package/dist/config/layers.d.ts +4 -4
- package/dist/config/layers.js +4 -4
- package/dist/constants/agents.d.ts +3 -0
- package/dist/constants/agents.js +3 -0
- package/dist/constants/node.d.ts +14 -0
- package/dist/constants/node.js +14 -0
- package/dist/constants/package-default-node-range.js +1 -5
- package/dist/constants/packages.d.ts +5 -0
- package/dist/constants/packages.js +5 -0
- package/dist/constants/platform.d.ts +1 -1
- package/dist/constants/platform.js +1 -1
- package/dist/constants/socket.js +1 -1
- package/dist/constants/typescript.d.ts +5 -0
- package/dist/constants/typescript.js +5 -0
- package/dist/debug/_internal.d.ts +22 -7
- package/dist/debug/_internal.js +33 -15
- package/dist/debug/namespace.js +11 -8
- package/dist/debug/output.d.ts +12 -1
- package/dist/debug/output.js +33 -16
- package/dist/dlx/binary-resolution.js +7 -4
- package/dist/eco/npm/npm/parse-lockfile.js +2 -1
- package/dist/eco/npm/vlt/exec.d.ts +1 -1
- package/dist/eco/npm/vlt/exec.js +1 -1
- package/dist/env/agents.d.ts +6 -0
- package/dist/env/agents.js +29 -0
- package/dist/env/flags.d.ts +12 -0
- package/dist/env/flags.js +23 -0
- package/dist/env/github-status.js +2 -2
- package/dist/env/providers.d.ts +6 -0
- package/dist/env/providers.js +23 -0
- package/dist/env/proxy.js +1 -1
- package/dist/env/rewire.d.ts +32 -0
- package/dist/env/rewire.js +55 -23
- package/dist/env/runtimes.d.ts +9 -0
- package/dist/env/runtimes.js +53 -0
- package/dist/env/socket-cli.d.ts +5 -2
- package/dist/env/socket-cli.js +6 -3
- package/dist/errors/predicates.d.ts +3 -2
- package/dist/errors/predicates.js +5 -3
- package/dist/errors/stack.js +2 -1
- package/dist/events/exit/_internal.d.ts +1 -23
- package/dist/external/@npmcli/package-json.js +179 -88
- package/dist/external/@npmcli/promise-spawn.js +2 -2
- package/dist/external/@sinclair/typebox/value.js +5 -4
- package/dist/external/@socketregistry/yocto-spinner.js +3 -3
- package/dist/external/adm-zip.d.ts +82 -0
- package/dist/external/adm-zip.js +2 -2
- package/dist/external/cacache.d.ts +87 -0
- package/dist/external/debug.d.ts +22 -0
- package/dist/external/debug.js +11 -4
- package/dist/external/del.d.ts +1 -0
- package/dist/external/external-pack.d.ts +12 -0
- package/dist/external/external-pack.js +41 -34
- package/dist/external/fast-glob.d.ts +8 -0
- package/dist/external/fast-sort.d.ts +1 -0
- package/dist/external/get-east-asian-width.d.ts +5 -0
- package/dist/external/get-east-asian-width.js +8 -1
- package/dist/external/has-flag.d.ts +1 -0
- package/dist/external/inquirer-pack.d.ts +18 -0
- package/dist/external/libnpmexec.d.ts +35 -0
- package/dist/external/libnpmpack.d.ts +1 -0
- package/dist/external/make-fetch-happen.d.ts +13 -0
- package/dist/external/normalize-package-data.d.ts +4 -0
- package/dist/external/npm-core.d.ts +14 -0
- package/dist/external/npm-pack.d.ts +24 -0
- package/dist/external/npm-pack.js +1551 -1867
- package/dist/external/npm-package-arg.d.ts +4 -0
- package/dist/external/p-map.js +8 -1
- package/dist/external/pacote.d.ts +15 -0
- package/dist/external/pico-pack.d.ts +16 -0
- package/dist/external/pico-pack.js +38 -23
- package/dist/external/picomatch.d.ts +96 -0
- package/dist/external/pony-cause.d.ts +14 -0
- package/dist/external/semver.d.ts +60 -0
- package/dist/external/semver.js +1459 -4
- package/dist/external/shell-quote.d.ts +51 -0
- package/dist/external/shell-quote.js +55 -15
- package/dist/external/signal-exit.d.ts +1 -0
- package/dist/external/spdx-correct.d.ts +4 -0
- package/dist/external/spdx-expression-parse.d.ts +4 -0
- package/dist/external/spdx-pack.d.ts +10 -0
- package/dist/external/std-env.d.ts +284 -0
- package/dist/external/std-env.js +323 -0
- package/dist/external/streaming-iterables.d.ts +11 -0
- package/dist/external/supports-color.d.ts +1 -0
- package/dist/external/tar-fs.d.ts +31 -0
- package/dist/external/validate-npm-package-name.d.ts +4 -0
- package/dist/external/which.d.ts +25 -0
- package/dist/external/which.js +2 -2
- package/dist/external/yargs-parser.d.ts +2 -0
- package/dist/external/yargs-parser.js +11 -3
- package/dist/external/yoctocolors-cjs.d.ts +51 -0
- package/dist/external-tools/bazel/asset-names.d.ts +1 -1
- package/dist/external-tools/bazel/from-download.d.ts +1 -1
- package/dist/external-tools/bazel/resolve.d.ts +3 -0
- package/dist/external-tools/bazel/resolve.js +3 -0
- package/dist/external-tools/cdxgen/asset-names.d.ts +5 -5
- package/dist/external-tools/cdxgen/asset-names.js +3 -3
- package/dist/external-tools/cdxgen/from-download.d.ts +2 -2
- package/dist/external-tools/cdxgen/from-download.js +1 -1
- package/dist/external-tools/cdxgen/resolve.d.ts +4 -1
- package/dist/external-tools/cdxgen/resolve.js +4 -1
- package/dist/external-tools/cdxgen/types.d.ts +1 -1
- package/dist/external-tools/from-download.d.ts +2 -2
- package/dist/external-tools/from-download.js +1 -1
- package/dist/external-tools/janus/asset-names.d.ts +4 -1
- package/dist/external-tools/janus/asset-names.js +3 -0
- package/dist/external-tools/janus/from-download.d.ts +3 -3
- package/dist/external-tools/janus/from-download.js +2 -2
- package/dist/external-tools/janus/resolve.d.ts +3 -0
- package/dist/external-tools/janus/resolve.js +3 -0
- package/dist/external-tools/jre/asset-names.d.ts +3 -1
- package/dist/external-tools/jre/asset-names.js +2 -0
- package/dist/external-tools/jre/from-download.d.ts +1 -1
- package/dist/external-tools/manifest.d.ts +5 -3
- package/dist/external-tools/manifest.js +4 -2
- package/dist/external-tools/opengrep/asset-names.d.ts +1 -1
- package/dist/external-tools/opengrep/resolve.d.ts +3 -0
- package/dist/external-tools/opengrep/resolve.js +3 -0
- package/dist/external-tools/python/asset-names.d.ts +3 -1
- package/dist/external-tools/python/asset-names.js +7 -3
- package/dist/external-tools/python/pin.js +3 -1
- package/dist/external-tools/python/resolve.d.ts +3 -0
- package/dist/external-tools/python/resolve.js +3 -0
- package/dist/external-tools/sbt/resolve.d.ts +3 -0
- package/dist/external-tools/sbt/resolve.js +3 -0
- package/dist/external-tools/skillspector/from-uv.d.ts +1 -1
- package/dist/external-tools/synp/resolve.d.ts +3 -0
- package/dist/external-tools/synp/resolve.js +3 -0
- package/dist/external-tools/trivy/asset-names.d.ts +1 -1
- package/dist/external-tools/trivy/resolve.d.ts +3 -0
- package/dist/external-tools/trivy/resolve.js +3 -0
- package/dist/external-tools/trufflehog/asset-names.d.ts +4 -1
- package/dist/external-tools/trufflehog/asset-names.js +3 -0
- package/dist/external-tools/trufflehog/from-download.d.ts +1 -1
- package/dist/external-tools/trufflehog/resolve.d.ts +3 -0
- package/dist/external-tools/trufflehog/resolve.js +3 -0
- package/dist/external-tools/uv/asset-names.d.ts +1 -1
- package/dist/external-tools/uv/resolve.d.ts +3 -0
- package/dist/external-tools/uv/resolve.js +3 -0
- package/dist/fleet/repo-config.d.ts +8 -6
- package/dist/fleet/repo-config.js +8 -6
- package/dist/fs/_internal.d.ts +1 -1
- package/dist/fs/_internal.js +1 -1
- package/dist/fs/access.d.ts +2 -0
- package/dist/fs/access.js +2 -0
- package/dist/fs/allowed-dirs-cache.js +5 -3
- package/dist/fs/find.js +1 -2
- package/dist/fs/inspect.d.ts +2 -2
- package/dist/fs/read-file.js +3 -4
- package/dist/fs/safe.js +1 -1
- package/dist/git/_internal.js +5 -1
- package/dist/github/commit.d.ts +92 -0
- package/dist/github/commit.js +113 -0
- package/dist/github/ghsa.js +1 -1
- package/dist/github/refs-graphql.js +1 -1
- package/dist/github/request.js +1 -1
- package/dist/github/token.d.ts +5 -2
- package/dist/github/token.js +6 -4
- package/dist/github/workflow-runs.d.ts +107 -0
- package/dist/github/workflow-runs.js +98 -0
- package/dist/http-request/_internal.d.ts +1 -1
- package/dist/http-request/browser.d.ts +6 -0
- package/dist/http-request/browser.js +3 -2
- package/dist/http-request/download.js +2 -0
- package/dist/http-request/headers.d.ts +1 -1
- package/dist/http-request/headers.js +1 -1
- package/dist/http-request/request-attempt.js +6 -3
- package/dist/http-request/request-types.d.ts +10 -1
- package/dist/http-request/request.js +2 -2
- package/dist/http-request/user-agent.d.ts +23 -2
- package/dist/http-request/user-agent.js +48 -6
- package/dist/integrity.d.ts +3 -1
- package/dist/integrity.js +3 -1
- package/dist/json/format.js +4 -1
- package/dist/logger/_internal.d.ts +13 -15
- package/dist/logger/_internal.js +21 -21
- package/dist/logger/colors.d.ts +9 -3
- package/dist/logger/colors.js +6 -13
- package/dist/logger/console-methods.js +2 -2
- package/dist/logger/console.d.ts +1 -0
- package/dist/logger/console.js +9 -9
- package/dist/logger/node.js +2 -1
- package/dist/native-messaging/install.js +1 -1
- package/dist/native-messaging/rate-limit.d.ts +4 -1
- package/dist/native-messaging/rate-limit.js +4 -1
- package/dist/node/events.d.ts +3 -0
- package/dist/node/events.js +3 -0
- package/dist/node/fs.d.ts +1 -1
- package/dist/node/timers-promises.d.ts +3 -0
- package/dist/node/timers-promises.js +3 -0
- package/dist/node/url.d.ts +3 -0
- package/dist/node/url.js +3 -0
- package/dist/npm/meta-cache.d.ts +183 -0
- package/dist/npm/meta-cache.js +318 -0
- package/dist/npm/meta-slice.d.ts +27 -0
- package/dist/npm/meta-slice.js +68 -0
- package/dist/npm/meta-types.d.ts +282 -0
- package/dist/npm/meta-types.js +2 -0
- package/dist/npm/meta.d.ts +125 -0
- package/dist/npm/meta.js +347 -0
- package/dist/npm/registry.d.ts +212 -0
- package/dist/npm/registry.js +284 -0
- package/dist/objects/getters.d.ts +1 -1
- package/dist/objects/getters.js +1 -1
- package/dist/packages/manifest.js +6 -7
- package/dist/packages/metadata-extensions.js +2 -4
- package/dist/packages/provenance.d.ts +8 -0
- package/dist/packages/provenance.js +8 -0
- package/dist/packages/tarball.js +1 -2
- package/dist/packages/validation.d.ts +0 -10
- package/dist/packages/validation.js +0 -14
- package/dist/paths/exts.d.ts +30 -0
- package/dist/paths/exts.js +30 -0
- package/dist/paths/filenames.d.ts +6 -0
- package/dist/paths/filenames.js +6 -0
- package/dist/paths/globs.d.ts +6 -0
- package/dist/paths/globs.js +6 -0
- package/dist/paths/resolve.js +19 -14
- package/dist/paths/socket.d.ts +8 -8
- package/dist/paths/socket.js +8 -8
- package/dist/perf/report.js +4 -2
- package/dist/pkg-ext/data.js +0 -2
- package/dist/primordials/globals.d.ts +1 -1
- package/dist/primordials/globals.js +1 -1
- package/dist/primordials/headers.d.ts +13 -1
- package/dist/primordials/headers.js +13 -1
- package/dist/primordials/process.d.ts +1 -1
- package/dist/primordials/process.js +1 -1
- package/dist/primordials/url.d.ts +18 -0
- package/dist/primordials/url.js +18 -0
- package/dist/process/spawn/child.js +3 -5
- package/dist/promises/_internal.d.ts +1 -1
- package/dist/promises/_internal.js +1 -2
- package/dist/promises/options.js +3 -3
- package/dist/releases/socket-btm-binary-naming.js +12 -1
- package/dist/secrets/_internal.d.ts +1 -1
- package/dist/secrets/_internal.js +1 -1
- package/dist/secrets/find.d.ts +2 -2
- package/dist/secrets/find.js +2 -2
- package/dist/secrets/keychain.d.ts +10 -1
- package/dist/secrets/keychain.js +10 -1
- package/dist/secrets/socket-api-token.d.ts +1 -1
- package/dist/secrets/socket-api-token.js +1 -1
- package/dist/secrets/types.d.ts +1 -1
- package/dist/smol/http.d.ts +2 -0
- package/dist/smol/http.js +2 -0
- package/dist/smol/https.d.ts +2 -0
- package/dist/smol/https.js +2 -0
- package/dist/sorts/_internal.d.ts +2 -3
- package/dist/sorts/_internal.js +1 -3
- package/dist/spinner/format.js +2 -4
- package/dist/stdio/footer.js +8 -7
- package/dist/stdio/prompts.d.ts +8 -15
- package/dist/stdio/prompts.js +18 -29
- package/dist/strings/predicates.d.ts +2 -2
- package/dist/strings/search.js +1 -1
- package/dist/strings/types.d.ts +4 -0
- package/dist/strings/width.d.ts +1 -0
- package/dist/strings/width.js +17 -8
- package/dist/themes/context.d.ts +13 -0
- package/dist/themes/context.js +23 -8
- package/dist/versions/_internal.d.ts +43 -13
- package/dist/versions/_internal.js +27 -15
- package/dist/versions/compare.d.ts +16 -10
- package/dist/versions/compare.js +36 -16
- package/dist/versions/parse.js +1 -1
- package/dist/versions/range.js +3 -2
- package/dist/words/pluralize.js +4 -1
- package/llms.txt +63 -750
- package/package.json +200 -35
|
@@ -5,6 +5,9 @@ const require_constants_runtime = require('../constants/runtime.js');
|
|
|
5
5
|
|
|
6
6
|
//#region src/node/timers-promises.ts
|
|
7
7
|
let timersPromises;
|
|
8
|
+
/**
|
|
9
|
+
* @unused No internal or Socket consumers (exercised only by its unit tests).
|
|
10
|
+
*/
|
|
8
11
|
function getNodeTimersPromises() {
|
|
9
12
|
if (!require_constants_runtime.IS_NODE) return;
|
|
10
13
|
return timersPromises ??= /*@__PURE__*/ require("timers/promises");
|
package/dist/node/url.d.ts
CHANGED
package/dist/node/url.js
CHANGED
|
@@ -5,6 +5,9 @@ const require_constants_runtime = require('../constants/runtime.js');
|
|
|
5
5
|
|
|
6
6
|
//#region src/node/url.ts
|
|
7
7
|
let cachedUrl;
|
|
8
|
+
/**
|
|
9
|
+
* @unused No internal or Socket consumers (exercised only by its unit tests).
|
|
10
|
+
*/
|
|
8
11
|
function getNodeUrl() {
|
|
9
12
|
if (!require_constants_runtime.IS_NODE) return;
|
|
10
13
|
return cachedUrl ??= /*@__PURE__*/ require("url");
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Cached packument fetch — `getPackumentSlim` wires the pure slicer
|
|
3
|
+
* (`./meta-slice`) to an injectable HTTP adapter and the repo's
|
|
4
|
+
* `createTtlCache` (memo + cacache persistence + in-flight dedupe via
|
|
5
|
+
* `getOrFetch`). Every `getPackumentSlim`-backed cache is actually three
|
|
6
|
+
* `TtlCache` instances sharing one cacache directory (`getCachePeers`): the
|
|
7
|
+
* primary cache (the object callers hold), a persisted long-TTL last
|
|
8
|
+
* known-good store (`-stale` prefix, `STALE_TTL_MS`), and a short-TTL
|
|
9
|
+
* storm-control marker (`-storm` prefix, `STALE_SERVE_TTL_MS`). Three
|
|
10
|
+
* failure-handling policies layer on top:
|
|
11
|
+
*
|
|
12
|
+
* - **`force`** bypasses a cached entry EXCEPT when it was written within the
|
|
13
|
+
* last 30 seconds, so a burst of forced refreshes coalesces into one
|
|
14
|
+
* upstream fetch instead of hammering the registry. A forced refresh NEVER
|
|
15
|
+
* removes the existing entry before fetching — on failure, whatever was
|
|
16
|
+
* cached before the call is untouched, and serve-stale-on-error (below)
|
|
17
|
+
* still has the persisted last-known-good value to fall back on.
|
|
18
|
+
* - **Negative caching** is narrow and short: only a definitive HTTP 404
|
|
19
|
+
* (package/version genuinely absent) is cached, for `NEGATIVE_TTL_MS`, and
|
|
20
|
+
* only when the persisted stale store holds no known-good data for that
|
|
21
|
+
* key. A transient error (network failure, 5xx) is NEVER negative-cached,
|
|
22
|
+
* and a still-fresh negative entry is discarded rather than trusted the
|
|
23
|
+
* moment known-good data exists in the persisted stale store — a retry
|
|
24
|
+
* always outranks a cached "not found" over real data.
|
|
25
|
+
* - **Serve-stale-on-error**: every successful fetch also persists the
|
|
26
|
+
* `PackumentMetaSlim` to the stale store, independent of the primary
|
|
27
|
+
* entry's own TTL — `STALE_TTL_MS` (7 days) comfortably outlives it, so the
|
|
28
|
+
* value survives both the primary entry's expiry and a process restart. If
|
|
29
|
+
* a later refresh fails for ANY reason — including a fresh 404 — the
|
|
30
|
+
* persisted value is served instead of propagating the error, and the
|
|
31
|
+
* storm-control marker is (re)written so a burst of callers within
|
|
32
|
+
* `STALE_SERVE_TTL_MS` is served without re-hitting a registry that just
|
|
33
|
+
* failed. ETag revalidation requires a header-capable HTTP adapter; the
|
|
34
|
+
* current `NpmMetaHttpAdapter` is header-less by design so test doubles and
|
|
35
|
+
* `httpJson` stay interchangeable with the rest of the npm client surface —
|
|
36
|
+
* see `NpmMetaHttpAdapter`.
|
|
37
|
+
*/
|
|
38
|
+
import type { GetPackumentSlimOptions, NpmMetaHttpAdapter, PackumentMetaSlim, PackumentVariant } from './meta-types';
|
|
39
|
+
import type { TtlCache, TtlCacheOptions } from '../cache/ttl/types';
|
|
40
|
+
/**
|
|
41
|
+
* A cached, successfully-fetched packument.
|
|
42
|
+
*/
|
|
43
|
+
export interface CachedPackumentHit {
|
|
44
|
+
cachedAt: number;
|
|
45
|
+
kind: 'hit';
|
|
46
|
+
meta: PackumentMetaSlim;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* A cached definitive-404 result — narrow and short-lived (`NEGATIVE_TTL_MS`);
|
|
50
|
+
* see the file-level doc for when this is written.
|
|
51
|
+
*/
|
|
52
|
+
export interface CachedPackumentMiss {
|
|
53
|
+
cachedAt: number;
|
|
54
|
+
kind: 'miss';
|
|
55
|
+
status: number;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* The value shape stored per cache key — either a successful fetch or a
|
|
59
|
+
* short-lived negative (404) result.
|
|
60
|
+
*/
|
|
61
|
+
export type CachedPackumentEntry = CachedPackumentHit | CachedPackumentMiss;
|
|
62
|
+
/**
|
|
63
|
+
* Thrown by `getPackumentSlim` (and the `getVersions` / `getLatestVersion`
|
|
64
|
+
* exact-version / dist-tag lookups) when a specific package, version, or tag
|
|
65
|
+
* is definitively absent. Carries `status` so `extractHttpStatus` reports it
|
|
66
|
+
* the same way as a real `HttpResponseError`.
|
|
67
|
+
*/
|
|
68
|
+
export declare class PackumentNotFoundError extends Error {
|
|
69
|
+
packageName: string;
|
|
70
|
+
status: number;
|
|
71
|
+
constructor(packageName: string, status: number, message?: string | undefined);
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Build the cache key for one (registry, name, variant) tuple. Normalizes
|
|
75
|
+
* `registry` first (`normalizeRegistryUrl`) so two spellings of the same
|
|
76
|
+
* registry collapse to one key.
|
|
77
|
+
*/
|
|
78
|
+
export declare function buildMetaCacheKey(registry: string, name: string, variant: PackumentVariant): string;
|
|
79
|
+
/**
|
|
80
|
+
* Deep-clone a `PackumentMetaSlim` via a JSON round-trip — plain
|
|
81
|
+
* JSON-roundtrippable data (strings, numbers, booleans, records), so this is
|
|
82
|
+
* 3-5x faster than `structuredClone` and avoids the HTML structured-clone
|
|
83
|
+
* algorithm entirely. Used at every public read boundary so no two callers
|
|
84
|
+
* ever hold a reference to the same cached object.
|
|
85
|
+
*/
|
|
86
|
+
export declare function cloneMeta(meta: PackumentMetaSlim): PackumentMetaSlim;
|
|
87
|
+
/**
|
|
88
|
+
* Companion long-TTL (persisted stale) and short-TTL (storm-control) caches
|
|
89
|
+
* that back one primary `TtlCache` instance — see the file-level doc.
|
|
90
|
+
*/
|
|
91
|
+
export interface NpmMetaCachePeers {
|
|
92
|
+
stale: TtlCache;
|
|
93
|
+
storm: TtlCache;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Create a dedicated npm-meta cache instance — same `prefix` /
|
|
97
|
+
* default-`ttl` as the module singleton, overridable per-call. Use this (vs.
|
|
98
|
+
* the default singleton) for test isolation or a non-default TTL. Also
|
|
99
|
+
* creates and registers this instance's persisted-stale + storm-control
|
|
100
|
+
* companions (`registerCachePeers`).
|
|
101
|
+
*/
|
|
102
|
+
export declare function createNpmMetaCache(options?: TtlCacheOptions | undefined): TtlCache;
|
|
103
|
+
/**
|
|
104
|
+
* The uncached fetch attempt for one packument, run through the negative-cache
|
|
105
|
+
* decision: on success, persists the result to `staleCache` and returns a
|
|
106
|
+
* `hit`; on a definitive 404 with no persisted stale data, returns a `miss`
|
|
107
|
+
* (a normal, non-throwing outcome the caller decides how to cache); any other
|
|
108
|
+
* failure (transient error, or a 404 when stale data DOES exist) rethrows so
|
|
109
|
+
* the caller's serve-stale-on-error path can take over.
|
|
110
|
+
*/
|
|
111
|
+
export declare function fetchAndCacheEntry(name: string, key: string, fetchOptions: ResolvedPackumentFetchOptions, staleCache: TtlCache): Promise<CachedPackumentEntry>;
|
|
112
|
+
/**
|
|
113
|
+
* `GetPackumentSlimOptions` with every field the fetch path needs resolved to
|
|
114
|
+
* a concrete value (defaults applied) — the shape `fetchPackumentSlim` and
|
|
115
|
+
* `getPackumentSlim`'s cache-key logic operate on internally.
|
|
116
|
+
*/
|
|
117
|
+
export interface ResolvedPackumentFetchOptions {
|
|
118
|
+
http: NpmMetaHttpAdapter;
|
|
119
|
+
registry: string;
|
|
120
|
+
retries: number;
|
|
121
|
+
timeout?: number | undefined;
|
|
122
|
+
variant: PackumentVariant;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* The uncached fetch — GET the packument with the variant's `Accept` header
|
|
126
|
+
* and slice it. Split out so `getPackumentSlim`'s cache-key / force logic
|
|
127
|
+
* stays readable. Throws (never negative-caches itself — that decision is
|
|
128
|
+
* `getPackumentSlim`'s, which has the context to know whether stale data
|
|
129
|
+
* already exists for this key).
|
|
130
|
+
*/
|
|
131
|
+
export declare function fetchPackumentSlim(name: string, resolved: ResolvedPackumentFetchOptions): Promise<PackumentMetaSlim>;
|
|
132
|
+
/**
|
|
133
|
+
* Resolve the persisted-stale + storm-control companions for a primary cache
|
|
134
|
+
* instance, creating them lazily (under the default prefix) for a `TtlCache`
|
|
135
|
+
* that wasn't created via `createNpmMetaCache`.
|
|
136
|
+
*/
|
|
137
|
+
export declare function getCachePeers(cache: TtlCache): NpmMetaCachePeers;
|
|
138
|
+
/**
|
|
139
|
+
* The module-level default cache instance, created lazily on first use.
|
|
140
|
+
*/
|
|
141
|
+
export declare function getDefaultMetaCache(): TtlCache;
|
|
142
|
+
/**
|
|
143
|
+
* Fetch a package's packument, slice it down to `PackumentMetaSlim`, and
|
|
144
|
+
* cache the result. Concurrent calls for the same (registry, name, variant)
|
|
145
|
+
* dedupe to a single upstream request via the cache's `getOrFetch`. See the
|
|
146
|
+
* file-level doc for the `force` / negative-cache / serve-stale-on-error
|
|
147
|
+
* policies.
|
|
148
|
+
*
|
|
149
|
+
* @throws {PackumentNotFoundError} When the registry returns a definitive 404
|
|
150
|
+
* and no previously-good data exists for this key to serve instead.
|
|
151
|
+
*/
|
|
152
|
+
export declare function getPackumentSlim(name: string, options?: GetPackumentSlimOptions | undefined): Promise<PackumentMetaSlim>;
|
|
153
|
+
/**
|
|
154
|
+
* Look up the persisted last known-good value for `key`, if any — backed by
|
|
155
|
+
* `STALE_TTL_MS` (7 days), independent of the primary cache's own TTL, and
|
|
156
|
+
* readable from a fresh process. Returns a fresh clone so no two callers ever
|
|
157
|
+
* share a reference to the same cached object.
|
|
158
|
+
*/
|
|
159
|
+
export declare function getStaleMeta(cache: TtlCache, key: string): Promise<PackumentMetaSlim | undefined>;
|
|
160
|
+
/**
|
|
161
|
+
* Normalize a registry base URL so two spellings of the same registry
|
|
162
|
+
* collapse to one cache key and one request URL: lowercase the scheme+host,
|
|
163
|
+
* and ensure exactly one trailing slash. Falls back to the input unchanged
|
|
164
|
+
* when it isn't a parseable absolute URL.
|
|
165
|
+
*/
|
|
166
|
+
export declare function normalizeRegistryUrl(registry: string): string;
|
|
167
|
+
/**
|
|
168
|
+
* Create and register the persisted-stale + storm-control companion caches
|
|
169
|
+
* for `cache` under `prefix`.
|
|
170
|
+
*/
|
|
171
|
+
export declare function registerCachePeers(cache: TtlCache, prefix: string): NpmMetaCachePeers;
|
|
172
|
+
/**
|
|
173
|
+
* Persist `meta` as the last known-good value for `key`, independent of the
|
|
174
|
+
* primary entry's own TTL/expiry.
|
|
175
|
+
*/
|
|
176
|
+
export declare function rememberStaleMeta(cache: TtlCache, key: string, meta: PackumentMetaSlim): Promise<void>;
|
|
177
|
+
/**
|
|
178
|
+
* Serve-stale-on-error: look up the persisted last known-good value and, when
|
|
179
|
+
* found, (re)write the storm-control marker so a burst of callers within
|
|
180
|
+
* `STALE_SERVE_TTL_MS` is served without re-hitting a registry that just
|
|
181
|
+
* failed.
|
|
182
|
+
*/
|
|
183
|
+
export declare function serveStaleOnFailure(staleCache: TtlCache, stormCache: TtlCache, key: string): Promise<PackumentMetaSlim | undefined>;
|
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/* Socket Lib - Built with rolldown */
|
|
3
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
4
|
+
const require_primordials_json = require('../primordials/json.js');
|
|
5
|
+
const require_primordials_url = require('../primordials/url.js');
|
|
6
|
+
const require_http_request_response_types = require('../http-request/response-types.js');
|
|
7
|
+
const require_http_request_node = require('../http-request/node.js');
|
|
8
|
+
const require_cache_ttl_store = require('../cache/ttl/store.js');
|
|
9
|
+
const require_npm_meta_slice = require('./meta-slice.js');
|
|
10
|
+
const require_npm_registry = require('./registry.js');
|
|
11
|
+
|
|
12
|
+
//#region src/npm/meta-cache.ts
|
|
13
|
+
/**
|
|
14
|
+
* @file Cached packument fetch — `getPackumentSlim` wires the pure slicer
|
|
15
|
+
* (`./meta-slice`) to an injectable HTTP adapter and the repo's
|
|
16
|
+
* `createTtlCache` (memo + cacache persistence + in-flight dedupe via
|
|
17
|
+
* `getOrFetch`). Every `getPackumentSlim`-backed cache is actually three
|
|
18
|
+
* `TtlCache` instances sharing one cacache directory (`getCachePeers`): the
|
|
19
|
+
* primary cache (the object callers hold), a persisted long-TTL last
|
|
20
|
+
* known-good store (`-stale` prefix, `STALE_TTL_MS`), and a short-TTL
|
|
21
|
+
* storm-control marker (`-storm` prefix, `STALE_SERVE_TTL_MS`). Three
|
|
22
|
+
* failure-handling policies layer on top:
|
|
23
|
+
*
|
|
24
|
+
* - **`force`** bypasses a cached entry EXCEPT when it was written within the
|
|
25
|
+
* last 30 seconds, so a burst of forced refreshes coalesces into one
|
|
26
|
+
* upstream fetch instead of hammering the registry. A forced refresh NEVER
|
|
27
|
+
* removes the existing entry before fetching — on failure, whatever was
|
|
28
|
+
* cached before the call is untouched, and serve-stale-on-error (below)
|
|
29
|
+
* still has the persisted last-known-good value to fall back on.
|
|
30
|
+
* - **Negative caching** is narrow and short: only a definitive HTTP 404
|
|
31
|
+
* (package/version genuinely absent) is cached, for `NEGATIVE_TTL_MS`, and
|
|
32
|
+
* only when the persisted stale store holds no known-good data for that
|
|
33
|
+
* key. A transient error (network failure, 5xx) is NEVER negative-cached,
|
|
34
|
+
* and a still-fresh negative entry is discarded rather than trusted the
|
|
35
|
+
* moment known-good data exists in the persisted stale store — a retry
|
|
36
|
+
* always outranks a cached "not found" over real data.
|
|
37
|
+
* - **Serve-stale-on-error**: every successful fetch also persists the
|
|
38
|
+
* `PackumentMetaSlim` to the stale store, independent of the primary
|
|
39
|
+
* entry's own TTL — `STALE_TTL_MS` (7 days) comfortably outlives it, so the
|
|
40
|
+
* value survives both the primary entry's expiry and a process restart. If
|
|
41
|
+
* a later refresh fails for ANY reason — including a fresh 404 — the
|
|
42
|
+
* persisted value is served instead of propagating the error, and the
|
|
43
|
+
* storm-control marker is (re)written so a burst of callers within
|
|
44
|
+
* `STALE_SERVE_TTL_MS` is served without re-hitting a registry that just
|
|
45
|
+
* failed. ETag revalidation requires a header-capable HTTP adapter; the
|
|
46
|
+
* current `NpmMetaHttpAdapter` is header-less by design so test doubles and
|
|
47
|
+
* `httpJson` stay interchangeable with the rest of the npm client surface —
|
|
48
|
+
* see `NpmMetaHttpAdapter`.
|
|
49
|
+
*/
|
|
50
|
+
const NPM_REGISTRY = "https://registry.npmjs.org";
|
|
51
|
+
const ACCEPT_ABBREVIATED = "application/vnd.npm.install-v1+json; q=1.0, application/json; q=0.8, */*";
|
|
52
|
+
const ACCEPT_FULL = "application/json";
|
|
53
|
+
const CACHE_PREFIX = "npm-meta";
|
|
54
|
+
const DEFAULT_TTL_MS = 900 * 1e3;
|
|
55
|
+
const FORCE_MIN_AGE_MS = 3e4;
|
|
56
|
+
const NEGATIVE_TTL_MS = 45e3;
|
|
57
|
+
const STALE_TTL_MS = 10080 * 60 * 1e3;
|
|
58
|
+
const STALE_SERVE_TTL_MS = 6e4;
|
|
59
|
+
const DEFAULT_RETRIES = 2;
|
|
60
|
+
const MAX_RETRIES = 5;
|
|
61
|
+
/**
|
|
62
|
+
* Thrown by `getPackumentSlim` (and the `getVersions` / `getLatestVersion`
|
|
63
|
+
* exact-version / dist-tag lookups) when a specific package, version, or tag
|
|
64
|
+
* is definitively absent. Carries `status` so `extractHttpStatus` reports it
|
|
65
|
+
* the same way as a real `HttpResponseError`.
|
|
66
|
+
*/
|
|
67
|
+
var PackumentNotFoundError = class extends Error {
|
|
68
|
+
packageName;
|
|
69
|
+
status;
|
|
70
|
+
constructor(packageName, status, message) {
|
|
71
|
+
super(message ?? `getPackumentSlim: "${packageName}" not found (registry returned ${status}).`);
|
|
72
|
+
this.name = "PackumentNotFoundError";
|
|
73
|
+
this.packageName = packageName;
|
|
74
|
+
this.status = status;
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
/**
|
|
78
|
+
* Build the cache key for one (registry, name, variant) tuple. Normalizes
|
|
79
|
+
* `registry` first (`normalizeRegistryUrl`) so two spellings of the same
|
|
80
|
+
* registry collapse to one key.
|
|
81
|
+
*/
|
|
82
|
+
function buildMetaCacheKey(registry, name, variant) {
|
|
83
|
+
return `${normalizeRegistryUrl(registry)}:${name}:${variant}`;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Deep-clone a `PackumentMetaSlim` via a JSON round-trip — plain
|
|
87
|
+
* JSON-roundtrippable data (strings, numbers, booleans, records), so this is
|
|
88
|
+
* 3-5x faster than `structuredClone` and avoids the HTML structured-clone
|
|
89
|
+
* algorithm entirely. Used at every public read boundary so no two callers
|
|
90
|
+
* ever hold a reference to the same cached object.
|
|
91
|
+
*/
|
|
92
|
+
function cloneMeta(meta) {
|
|
93
|
+
return require_primordials_json.JSONParse(require_primordials_json.JSONStringify(meta));
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Maps a primary cache instance to its persisted-stale + storm-control
|
|
97
|
+
* companions. Keyed by the `TtlCache` instance (not a plain module
|
|
98
|
+
* singleton) so distinct cache instances — e.g. one per test — never see
|
|
99
|
+
* each other's stale/storm data.
|
|
100
|
+
*/
|
|
101
|
+
const cachePeers = /* @__PURE__ */ new WeakMap();
|
|
102
|
+
/**
|
|
103
|
+
* Create a dedicated npm-meta cache instance — same `prefix` /
|
|
104
|
+
* default-`ttl` as the module singleton, overridable per-call. Use this (vs.
|
|
105
|
+
* the default singleton) for test isolation or a non-default TTL. Also
|
|
106
|
+
* creates and registers this instance's persisted-stale + storm-control
|
|
107
|
+
* companions (`registerCachePeers`).
|
|
108
|
+
*/
|
|
109
|
+
function createNpmMetaCache(options) {
|
|
110
|
+
const opts = {
|
|
111
|
+
__proto__: null,
|
|
112
|
+
...options
|
|
113
|
+
};
|
|
114
|
+
const prefix = opts.prefix ?? CACHE_PREFIX;
|
|
115
|
+
const cache = require_cache_ttl_store.createTtlCache({
|
|
116
|
+
prefix,
|
|
117
|
+
ttl: DEFAULT_TTL_MS,
|
|
118
|
+
...opts
|
|
119
|
+
});
|
|
120
|
+
registerCachePeers(cache, prefix);
|
|
121
|
+
return cache;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* The uncached fetch attempt for one packument, run through the negative-cache
|
|
125
|
+
* decision: on success, persists the result to `staleCache` and returns a
|
|
126
|
+
* `hit`; on a definitive 404 with no persisted stale data, returns a `miss`
|
|
127
|
+
* (a normal, non-throwing outcome the caller decides how to cache); any other
|
|
128
|
+
* failure (transient error, or a 404 when stale data DOES exist) rethrows so
|
|
129
|
+
* the caller's serve-stale-on-error path can take over.
|
|
130
|
+
*/
|
|
131
|
+
async function fetchAndCacheEntry(name, key, fetchOptions, staleCache) {
|
|
132
|
+
try {
|
|
133
|
+
const meta = await fetchPackumentSlim(name, fetchOptions);
|
|
134
|
+
await staleCache.set(key, meta);
|
|
135
|
+
return {
|
|
136
|
+
cachedAt: Date.now(),
|
|
137
|
+
kind: "hit",
|
|
138
|
+
meta
|
|
139
|
+
};
|
|
140
|
+
} catch (e) {
|
|
141
|
+
if (e instanceof require_http_request_response_types.HttpResponseError && e.response.status === 404 && await staleCache.get(key) === void 0) return {
|
|
142
|
+
cachedAt: Date.now(),
|
|
143
|
+
kind: "miss",
|
|
144
|
+
status: 404
|
|
145
|
+
};
|
|
146
|
+
throw e;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* The uncached fetch — GET the packument with the variant's `Accept` header
|
|
151
|
+
* and slice it. Split out so `getPackumentSlim`'s cache-key / force logic
|
|
152
|
+
* stays readable. Throws (never negative-caches itself — that decision is
|
|
153
|
+
* `getPackumentSlim`'s, which has the context to know whether stale data
|
|
154
|
+
* already exists for this key).
|
|
155
|
+
*/
|
|
156
|
+
async function fetchPackumentSlim(name, resolved) {
|
|
157
|
+
const accept = resolved.variant === "full" ? ACCEPT_FULL : ACCEPT_ABBREVIATED;
|
|
158
|
+
const url = `${normalizeRegistryUrl(resolved.registry)}${require_npm_registry.encodeRegistryName(name)}`;
|
|
159
|
+
return require_npm_meta_slice.slicePackument(await resolved.http.json(url, {
|
|
160
|
+
headers: { Accept: accept },
|
|
161
|
+
retries: resolved.retries,
|
|
162
|
+
timeout: resolved.timeout
|
|
163
|
+
}));
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Resolve the persisted-stale + storm-control companions for a primary cache
|
|
167
|
+
* instance, creating them lazily (under the default prefix) for a `TtlCache`
|
|
168
|
+
* that wasn't created via `createNpmMetaCache`.
|
|
169
|
+
*/
|
|
170
|
+
function getCachePeers(cache) {
|
|
171
|
+
return cachePeers.get(cache) ?? registerCachePeers(cache, CACHE_PREFIX);
|
|
172
|
+
}
|
|
173
|
+
let defaultMetaCache;
|
|
174
|
+
/**
|
|
175
|
+
* The module-level default cache instance, created lazily on first use.
|
|
176
|
+
*/
|
|
177
|
+
function getDefaultMetaCache() {
|
|
178
|
+
if (defaultMetaCache === void 0) defaultMetaCache = createNpmMetaCache();
|
|
179
|
+
return defaultMetaCache;
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Fetch a package's packument, slice it down to `PackumentMetaSlim`, and
|
|
183
|
+
* cache the result. Concurrent calls for the same (registry, name, variant)
|
|
184
|
+
* dedupe to a single upstream request via the cache's `getOrFetch`. See the
|
|
185
|
+
* file-level doc for the `force` / negative-cache / serve-stale-on-error
|
|
186
|
+
* policies.
|
|
187
|
+
*
|
|
188
|
+
* @throws {PackumentNotFoundError} When the registry returns a definitive 404
|
|
189
|
+
* and no previously-good data exists for this key to serve instead.
|
|
190
|
+
*/
|
|
191
|
+
async function getPackumentSlim(name, options) {
|
|
192
|
+
const opts = {
|
|
193
|
+
__proto__: null,
|
|
194
|
+
...options
|
|
195
|
+
};
|
|
196
|
+
const cache = opts.cache ?? getDefaultMetaCache();
|
|
197
|
+
const registry = normalizeRegistryUrl(opts.registry ?? NPM_REGISTRY);
|
|
198
|
+
const variant = opts.variant ?? "abbreviated";
|
|
199
|
+
const retries = Math.min(opts.retries ?? DEFAULT_RETRIES, MAX_RETRIES);
|
|
200
|
+
const key = buildMetaCacheKey(registry, name, variant);
|
|
201
|
+
const { stale: staleCache, storm: stormCache } = getCachePeers(cache);
|
|
202
|
+
const fetchOptions = {
|
|
203
|
+
http: opts.http ?? { json: require_http_request_node.httpJson },
|
|
204
|
+
registry,
|
|
205
|
+
retries,
|
|
206
|
+
timeout: opts.timeout,
|
|
207
|
+
variant
|
|
208
|
+
};
|
|
209
|
+
if (opts.force) {
|
|
210
|
+
const cached = await cache.get(key);
|
|
211
|
+
if (cached?.kind === "hit" && Date.now() - cached.cachedAt <= FORCE_MIN_AGE_MS) return cloneMeta(cached.meta);
|
|
212
|
+
let result;
|
|
213
|
+
try {
|
|
214
|
+
result = await fetchAndCacheEntry(name, key, fetchOptions, staleCache);
|
|
215
|
+
} catch (e) {
|
|
216
|
+
const stale = await serveStaleOnFailure(staleCache, stormCache, key);
|
|
217
|
+
if (stale !== void 0) return cloneMeta(stale);
|
|
218
|
+
throw e;
|
|
219
|
+
}
|
|
220
|
+
await cache.set(key, result);
|
|
221
|
+
if (result.kind === "miss") throw new PackumentNotFoundError(name, result.status);
|
|
222
|
+
return cloneMeta(result.meta);
|
|
223
|
+
}
|
|
224
|
+
const storming = await stormCache.get(key);
|
|
225
|
+
if (storming !== void 0) return cloneMeta(storming);
|
|
226
|
+
const existing = await cache.get(key);
|
|
227
|
+
if (existing?.kind === "miss") {
|
|
228
|
+
if (Date.now() - existing.cachedAt <= NEGATIVE_TTL_MS && await staleCache.get(key) === void 0) throw new PackumentNotFoundError(name, existing.status);
|
|
229
|
+
await cache.delete(key);
|
|
230
|
+
}
|
|
231
|
+
let entry;
|
|
232
|
+
try {
|
|
233
|
+
entry = await cache.getOrFetch(key, () => fetchAndCacheEntry(name, key, fetchOptions, staleCache));
|
|
234
|
+
} catch (e) {
|
|
235
|
+
const stale = await serveStaleOnFailure(staleCache, stormCache, key);
|
|
236
|
+
if (stale !== void 0) return cloneMeta(stale);
|
|
237
|
+
throw e;
|
|
238
|
+
}
|
|
239
|
+
if (entry.kind === "miss") throw new PackumentNotFoundError(name, entry.status);
|
|
240
|
+
return cloneMeta(entry.meta);
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Look up the persisted last known-good value for `key`, if any — backed by
|
|
244
|
+
* `STALE_TTL_MS` (7 days), independent of the primary cache's own TTL, and
|
|
245
|
+
* readable from a fresh process. Returns a fresh clone so no two callers ever
|
|
246
|
+
* share a reference to the same cached object.
|
|
247
|
+
*/
|
|
248
|
+
async function getStaleMeta(cache, key) {
|
|
249
|
+
const found = await getCachePeers(cache).stale.get(key);
|
|
250
|
+
return found === void 0 ? void 0 : cloneMeta(found);
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Normalize a registry base URL so two spellings of the same registry
|
|
254
|
+
* collapse to one cache key and one request URL: lowercase the scheme+host,
|
|
255
|
+
* and ensure exactly one trailing slash. Falls back to the input unchanged
|
|
256
|
+
* when it isn't a parseable absolute URL.
|
|
257
|
+
*/
|
|
258
|
+
function normalizeRegistryUrl(registry) {
|
|
259
|
+
try {
|
|
260
|
+
const url = new require_primordials_url.URLCtor(registry);
|
|
261
|
+
return `${`${url.protocol}//${url.host}`.toLowerCase()}${url.pathname.endsWith("/") ? url.pathname : `${url.pathname}/`}${url.search}`;
|
|
262
|
+
} catch {
|
|
263
|
+
return registry;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Create and register the persisted-stale + storm-control companion caches
|
|
268
|
+
* for `cache` under `prefix`.
|
|
269
|
+
*/
|
|
270
|
+
function registerCachePeers(cache, prefix) {
|
|
271
|
+
const peers = {
|
|
272
|
+
stale: require_cache_ttl_store.createTtlCache({
|
|
273
|
+
prefix: `${prefix}-stale`,
|
|
274
|
+
ttl: STALE_TTL_MS
|
|
275
|
+
}),
|
|
276
|
+
storm: require_cache_ttl_store.createTtlCache({
|
|
277
|
+
prefix: `${prefix}-storm`,
|
|
278
|
+
ttl: STALE_SERVE_TTL_MS
|
|
279
|
+
})
|
|
280
|
+
};
|
|
281
|
+
cachePeers.set(cache, peers);
|
|
282
|
+
return peers;
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* Persist `meta` as the last known-good value for `key`, independent of the
|
|
286
|
+
* primary entry's own TTL/expiry.
|
|
287
|
+
*/
|
|
288
|
+
async function rememberStaleMeta(cache, key, meta) {
|
|
289
|
+
await getCachePeers(cache).stale.set(key, cloneMeta(meta));
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* Serve-stale-on-error: look up the persisted last known-good value and, when
|
|
293
|
+
* found, (re)write the storm-control marker so a burst of callers within
|
|
294
|
+
* `STALE_SERVE_TTL_MS` is served without re-hitting a registry that just
|
|
295
|
+
* failed.
|
|
296
|
+
*/
|
|
297
|
+
async function serveStaleOnFailure(staleCache, stormCache, key) {
|
|
298
|
+
const priorGood = await staleCache.get(key);
|
|
299
|
+
if (priorGood === void 0) return;
|
|
300
|
+
await stormCache.set(key, priorGood);
|
|
301
|
+
return priorGood;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
//#endregion
|
|
305
|
+
exports.PackumentNotFoundError = PackumentNotFoundError;
|
|
306
|
+
exports.buildMetaCacheKey = buildMetaCacheKey;
|
|
307
|
+
exports.cloneMeta = cloneMeta;
|
|
308
|
+
exports.createNpmMetaCache = createNpmMetaCache;
|
|
309
|
+
exports.fetchAndCacheEntry = fetchAndCacheEntry;
|
|
310
|
+
exports.fetchPackumentSlim = fetchPackumentSlim;
|
|
311
|
+
exports.getCachePeers = getCachePeers;
|
|
312
|
+
exports.getDefaultMetaCache = getDefaultMetaCache;
|
|
313
|
+
exports.getPackumentSlim = getPackumentSlim;
|
|
314
|
+
exports.getStaleMeta = getStaleMeta;
|
|
315
|
+
exports.normalizeRegistryUrl = normalizeRegistryUrl;
|
|
316
|
+
exports.registerCachePeers = registerCachePeers;
|
|
317
|
+
exports.rememberStaleMeta = rememberStaleMeta;
|
|
318
|
+
exports.serveStaleOnFailure = serveStaleOnFailure;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Pure slicing of a raw npm packument into the client's slim shapes — no
|
|
3
|
+
* network, no cache. `sliceVersionMeta` handles one version's `dist` /
|
|
4
|
+
* `_npmUser` fields; `slicePackument` wraps it with the top-level packument
|
|
5
|
+
* fields (`name`, `distTags`, `time.created` / `time.modified`).
|
|
6
|
+
*/
|
|
7
|
+
import type { PackumentMetaSlim, PackumentVersionMetaSlim, RawPackument, RawPackumentVersion } from './meta-types';
|
|
8
|
+
/**
|
|
9
|
+
* Slice one raw version entry into its `PackumentVersionMetaSlim` shape.
|
|
10
|
+
*
|
|
11
|
+
* `trustedPublisher` / `staged` are only set when `_npmUser` is present on the
|
|
12
|
+
* entry (i.e. the packument was fetched with `variant: 'full'`) — on the
|
|
13
|
+
* abbreviated variant, trust signals are unknown rather than `false`.
|
|
14
|
+
*/
|
|
15
|
+
export declare function sliceOneVersion(entry: RawPackumentVersion, publishedAt: string | undefined): PackumentVersionMetaSlim;
|
|
16
|
+
/**
|
|
17
|
+
* Slice a raw packument into `PackumentMetaSlim` — the top-level fields the
|
|
18
|
+
* client keeps (`name`, `distTags` with a guaranteed `latest` key,
|
|
19
|
+
* `timeCreated` / `timeModified`, `lastSynced`) plus the per-version map from
|
|
20
|
+
* `sliceVersionMeta`.
|
|
21
|
+
*/
|
|
22
|
+
export declare function slicePackument(packument: RawPackument): PackumentMetaSlim;
|
|
23
|
+
/**
|
|
24
|
+
* Slice every version entry in a raw packument into `PackumentVersionMetaSlim`
|
|
25
|
+
* records, keyed by version string.
|
|
26
|
+
*/
|
|
27
|
+
export declare function sliceVersionMeta(packument: RawPackument): Record<string, PackumentVersionMetaSlim>;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/* Socket Lib - Built with rolldown */
|
|
3
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
4
|
+
|
|
5
|
+
//#region src/npm/meta-slice.ts
|
|
6
|
+
/**
|
|
7
|
+
* Slice one raw version entry into its `PackumentVersionMetaSlim` shape.
|
|
8
|
+
*
|
|
9
|
+
* `trustedPublisher` / `staged` are only set when `_npmUser` is present on the
|
|
10
|
+
* entry (i.e. the packument was fetched with `variant: 'full'`) — on the
|
|
11
|
+
* abbreviated variant, trust signals are unknown rather than `false`.
|
|
12
|
+
*/
|
|
13
|
+
function sliceOneVersion(entry, publishedAt) {
|
|
14
|
+
const dist = entry.dist;
|
|
15
|
+
const npmUser = entry._npmUser;
|
|
16
|
+
const slim = { time: publishedAt ?? "" };
|
|
17
|
+
if (entry.deprecated !== void 0) slim.deprecated = entry.deprecated;
|
|
18
|
+
if (entry.engines !== void 0) slim.engines = entry.engines;
|
|
19
|
+
if (dist?.integrity !== void 0) slim.integrity = dist.integrity;
|
|
20
|
+
if (dist?.shasum !== void 0) slim.shasum = dist.shasum;
|
|
21
|
+
if (dist?.tarball !== void 0) slim.tarball = dist.tarball;
|
|
22
|
+
if (dist?.attestations !== void 0) slim.attestations = dist.attestations;
|
|
23
|
+
if (npmUser !== void 0) {
|
|
24
|
+
slim.trustedPublisher = !!npmUser.trustedPublisher;
|
|
25
|
+
slim.staged = !!npmUser.approver;
|
|
26
|
+
}
|
|
27
|
+
return slim;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Slice a raw packument into `PackumentMetaSlim` — the top-level fields the
|
|
31
|
+
* client keeps (`name`, `distTags` with a guaranteed `latest` key,
|
|
32
|
+
* `timeCreated` / `timeModified`, `lastSynced`) plus the per-version map from
|
|
33
|
+
* `sliceVersionMeta`.
|
|
34
|
+
*/
|
|
35
|
+
function slicePackument(packument) {
|
|
36
|
+
const rawDistTags = packument["dist-tags"] ?? {};
|
|
37
|
+
return {
|
|
38
|
+
distTags: {
|
|
39
|
+
latest: rawDistTags["latest"] ?? "",
|
|
40
|
+
...rawDistTags
|
|
41
|
+
},
|
|
42
|
+
lastSynced: Date.now(),
|
|
43
|
+
name: packument.name ?? "",
|
|
44
|
+
timeCreated: packument.time?.["created"],
|
|
45
|
+
timeModified: packument.time?.["modified"],
|
|
46
|
+
versions: sliceVersionMeta(packument)
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Slice every version entry in a raw packument into `PackumentVersionMetaSlim`
|
|
51
|
+
* records, keyed by version string.
|
|
52
|
+
*/
|
|
53
|
+
function sliceVersionMeta(packument) {
|
|
54
|
+
const rawVersions = packument.versions ?? {};
|
|
55
|
+
const time = packument.time ?? {};
|
|
56
|
+
const result = {};
|
|
57
|
+
const versions = Object.keys(rawVersions);
|
|
58
|
+
for (let i = 0, { length } = versions; i < length; i += 1) {
|
|
59
|
+
const version = versions[i];
|
|
60
|
+
result[version] = sliceOneVersion(rawVersions[version], time[version]);
|
|
61
|
+
}
|
|
62
|
+
return result;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
//#endregion
|
|
66
|
+
exports.sliceOneVersion = sliceOneVersion;
|
|
67
|
+
exports.slicePackument = slicePackument;
|
|
68
|
+
exports.sliceVersionMeta = sliceVersionMeta;
|