@socketsecurity/lib 6.0.8 → 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 +28 -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 +31 -17
- package/dist/ai/route.js +35 -19
- package/dist/ai/spawn.d.mts +34 -1
- package/dist/ai/spawn.js +115 -3
- 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 +19 -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 +19253 -13937
- package/dist/bin/resolve.js +1 -1
- 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 +11 -34
- 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 +5 -1
- package/dist/compression/gzip.d.ts +6 -2
- package/dist/compression/gzip.js +7 -2
- package/dist/config/layers.d.ts +53 -0
- package/dist/config/layers.js +83 -0
- 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/caller-info.js +1 -1
- 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-cache.js +1 -1
- package/dist/dlx/binary-resolution.js +8 -5
- package/dist/dlx/firewall.js +1 -1
- package/dist/dlx/lockfile.js +1 -1
- package/dist/eco/npm/npm/parse-lockfile.js +3 -2
- package/dist/eco/npm/vlt/exec.d.ts +1 -1
- package/dist/eco/npm/vlt/exec.js +1 -1
- package/dist/eco/npm/yarnpkg/yarn/parse-lockfile.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 +37 -3
- package/dist/env/rewire.js +60 -29
- 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/env/xdg.d.ts +17 -0
- package/dist/env/xdg.js +21 -1
- package/dist/errors/predicates.d.ts +3 -2
- package/dist/errors/predicates.js +5 -3
- package/dist/events/exit/_internal.d.ts +1 -23
- package/dist/external/@npmcli/package-json.js +3570 -4905
- 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/@yarnpkg/extensions.js +1 -1
- 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 +42 -35
- 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 +28934 -31885
- 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/tar-fs.js +63 -16
- 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/detect-platform-arch.js +1 -1
- 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 +5 -3
- 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 +8 -4
- 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/python/uv-install.d.ts +89 -0
- package/dist/external-tools/python/uv-install.js +165 -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 +30 -0
- package/dist/external-tools/skillspector/from-uv.js +56 -0
- package/dist/external-tools/skillspector/resolve.d.ts +18 -3
- package/dist/external-tools/skillspector/resolve.js +21 -8
- package/dist/external-tools/skillspector/types.d.ts +3 -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 +36 -0
- package/dist/external-tools/uv/asset-names.js +73 -0
- package/dist/external-tools/uv/from-download.d.ts +17 -0
- package/dist/external-tools/uv/from-download.js +50 -0
- package/dist/external-tools/uv/from-path.d.ts +5 -0
- package/dist/external-tools/uv/from-path.js +22 -0
- package/dist/external-tools/uv/from-vfs.d.ts +7 -0
- package/dist/external-tools/uv/from-vfs.js +26 -0
- package/dist/external-tools/uv/resolve.d.ts +28 -0
- package/dist/external-tools/uv/resolve.js +64 -0
- package/dist/external-tools/uv/types.d.ts +24 -0
- package/dist/external-tools/uv/types.js +2 -0
- package/dist/fleet/repo-config.d.ts +55 -0
- package/dist/fleet/repo-config.js +81 -0
- 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/copy.d.ts +88 -0
- package/dist/fs/copy.js +89 -0
- 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 +2 -2
- package/dist/git/_internal.js +7 -3
- 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/refs.js +10 -15
- 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/globs/_internal.js +1 -1
- package/dist/http-request/_internal.d.ts +1 -1
- package/dist/http-request/browser.d.ts +6 -0
- package/dist/http-request/browser.js +4 -3
- package/dist/http-request/checksum-file.js +1 -1
- package/dist/http-request/download.js +2 -0
- package/dist/http-request/headers.d.ts +1 -1
- package/dist/http-request/headers.js +2 -2
- 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 +127 -78
- package/dist/integrity.js +170 -84
- 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 +10 -5
- package/dist/logger/colors.js +7 -14
- 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/logger/symbols-builder.js +7 -8
- package/dist/logger/symbols.js +8 -8
- 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/module.d.ts +73 -2
- package/dist/node/module.js +97 -12
- 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/objects/predicates.js +1 -1
- package/dist/packages/exports.js +2 -2
- package/dist/packages/isolation.js +1 -1
- package/dist/packages/manifest.d.ts +29 -0
- package/dist/packages/manifest.js +44 -9
- package/dist/packages/metadata-extensions.js +2 -4
- package/dist/packages/normalize.js +1 -1
- package/dist/packages/provenance.d.ts +8 -0
- package/dist/packages/provenance.js +10 -2
- package/dist/packages/specs.js +1 -1
- 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/_internal.d.ts +1 -7
- package/dist/paths/_internal.js +9 -15
- package/dist/paths/conversion.js +1 -1
- 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/normalize.js +1 -1
- package/dist/paths/predicates.js +2 -1
- package/dist/paths/resolve.js +19 -14
- package/dist/paths/socket.d.ts +81 -30
- package/dist/paths/socket.js +102 -28
- package/dist/perf/metrics.js +1 -1
- package/dist/perf/report.js +5 -3
- 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/regexps/spec.js +1 -1
- package/dist/releases/socket-btm-binary-naming.js +12 -1
- package/dist/schema/validate.js +1 -1
- package/dist/secrets/_internal.d.ts +1 -1
- package/dist/secrets/_internal.js +1 -1
- package/dist/secrets/broker.d.ts +35 -0
- package/dist/secrets/broker.js +72 -0
- package/dist/secrets/find.d.ts +8 -6
- package/dist/secrets/find.js +17 -3
- package/dist/secrets/keychain.d.ts +10 -1
- package/dist/secrets/keychain.js +10 -1
- package/dist/secrets/rc.js +1 -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/detect.js +1 -1
- package/dist/smol/http.d.ts +2 -0
- package/dist/smol/http.js +3 -1
- package/dist/smol/https.d.ts +2 -0
- package/dist/smol/https.js +3 -1
- package/dist/smol/manifest.js +1 -1
- package/dist/smol/path.js +1 -1
- package/dist/smol/primordial.js +1 -1
- package/dist/smol/purl.js +1 -1
- package/dist/smol/versions.js +1 -1
- package/dist/smol/vfs.js +1 -1
- package/dist/sorts/_internal.d.ts +2 -4
- package/dist/sorts/_internal.js +1 -7
- package/dist/sorts/semver.js +2 -2
- package/dist/spinner/create-spinner-class.js +1 -1
- package/dist/spinner/format.js +2 -4
- package/dist/stdio/footer.js +8 -7
- package/dist/stdio/progress.js +1 -1
- package/dist/stdio/prompts.d.ts +8 -23
- package/dist/stdio/prompts.js +28 -52
- package/dist/strings/format.js +1 -1
- package/dist/strings/predicates.d.ts +2 -2
- package/dist/strings/search.js +2 -2
- 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 +18 -3
- package/dist/themes/context.js +28 -14
- 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 -0
- package/package.json +271 -40
|
@@ -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;
|
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Type surface for the npm metadata client (`./meta`, `./meta-cache`,
|
|
3
|
+
* `./meta-slice`) — the raw packument shapes accepted from the registry, the
|
|
4
|
+
* slimmed shapes the client returns, and the options/result records for the
|
|
5
|
+
* derived helpers (`getVersions`, `getLatestVersion`, `getBatch`, …). Pure
|
|
6
|
+
* types, no runtime side effects.
|
|
7
|
+
*/
|
|
8
|
+
import type { TtlCache } from '../cache/ttl/types';
|
|
9
|
+
import type { HttpRequestOptions } from '../http-request/node';
|
|
10
|
+
/**
|
|
11
|
+
* Per-name/per-batch failure shape returned by `getBatch` in place of a
|
|
12
|
+
* `PackumentMetaSlim` entry when a fetch fails and `throwOnError` is `false`.
|
|
13
|
+
*/
|
|
14
|
+
export interface PackageError {
|
|
15
|
+
error: string;
|
|
16
|
+
name: string;
|
|
17
|
+
status?: number | undefined;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Options for `getBatch`. Extends the single-package fetch options — every
|
|
21
|
+
* name in the batch shares the same registry/variant/cache/http adapter.
|
|
22
|
+
*/
|
|
23
|
+
export interface BatchOptions extends GetPackumentSlimOptions {
|
|
24
|
+
/**
|
|
25
|
+
* Number of packages fetched concurrently.
|
|
26
|
+
*
|
|
27
|
+
* @default 8
|
|
28
|
+
*/
|
|
29
|
+
concurrency?: number | undefined;
|
|
30
|
+
/**
|
|
31
|
+
* When `true`, every item is still attempted (nothing is aborted
|
|
32
|
+
* in-flight), but once every item has settled, the error from the
|
|
33
|
+
* LOWEST-INDEX failed item is thrown — deterministic regardless of settle
|
|
34
|
+
* order. When `false` (default), failures are captured as `PackageError`
|
|
35
|
+
* entries at their original index.
|
|
36
|
+
*
|
|
37
|
+
* @default false
|
|
38
|
+
*/
|
|
39
|
+
throwOnError?: boolean | undefined;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Index-preserving element of `getBatch`'s return array — either the slimmed
|
|
43
|
+
* packument or a `PackageError` for that name.
|
|
44
|
+
*/
|
|
45
|
+
export type BatchResult = PackageError | PackumentMetaSlim;
|
|
46
|
+
/**
|
|
47
|
+
* Options shared by every `getPackumentSlim`-backed helper.
|
|
48
|
+
*/
|
|
49
|
+
export interface GetPackumentSlimOptions {
|
|
50
|
+
/**
|
|
51
|
+
* Cache instance backing the fetch. Defaults to a lazily-created module
|
|
52
|
+
* singleton (`prefix: 'npm-meta'`, 15-minute TTL). Pass a dedicated instance
|
|
53
|
+
* (`createNpmMetaCache`) for test isolation or a non-default TTL.
|
|
54
|
+
*/
|
|
55
|
+
cache?: TtlCache | undefined;
|
|
56
|
+
/**
|
|
57
|
+
* Bypass a cached entry and refetch — unless the entry is younger than 30
|
|
58
|
+
* seconds, in which case the cached value is still served (coalesces bursts
|
|
59
|
+
* of forced refreshes into one upstream fetch).
|
|
60
|
+
*
|
|
61
|
+
* @default false
|
|
62
|
+
*/
|
|
63
|
+
force?: boolean | undefined;
|
|
64
|
+
/**
|
|
65
|
+
* Injectable HTTP adapter, mirroring `NpmHttpOptions` from `./registry`.
|
|
66
|
+
* Defaults to `httpJson` from `../http-request/node`.
|
|
67
|
+
*/
|
|
68
|
+
http?: NpmMetaHttpAdapter | undefined;
|
|
69
|
+
/**
|
|
70
|
+
* Registry base URL.
|
|
71
|
+
*
|
|
72
|
+
* @default 'https://registry.npmjs.org'
|
|
73
|
+
*/
|
|
74
|
+
registry?: string | undefined;
|
|
75
|
+
/**
|
|
76
|
+
* Forwarded to the HTTP adapter.
|
|
77
|
+
*/
|
|
78
|
+
retries?: number | undefined;
|
|
79
|
+
/**
|
|
80
|
+
* Forwarded to the HTTP adapter.
|
|
81
|
+
*/
|
|
82
|
+
timeout?: number | undefined;
|
|
83
|
+
/**
|
|
84
|
+
* `'abbreviated'` (default) omits `_npmUser` trust signals and most
|
|
85
|
+
* metadata — cheap, used for version listing. `'full'` is required to read
|
|
86
|
+
* `trustedPublisher` / `staged` / `integrity` / `shasum`.
|
|
87
|
+
*
|
|
88
|
+
* @default 'abbreviated'
|
|
89
|
+
*/
|
|
90
|
+
variant?: PackumentVariant | undefined;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Options for `getVersions` / `getLatestVersion` — semver filtering layered on
|
|
94
|
+
* top of the base fetch options.
|
|
95
|
+
*/
|
|
96
|
+
export interface GetVersionsOptions extends GetPackumentSlimOptions {
|
|
97
|
+
/**
|
|
98
|
+
* Time floor — only versions published at or after this instant are kept
|
|
99
|
+
* (inclusive). Accepts an ISO 8601 string OR a numeric epoch (a `number` or
|
|
100
|
+
* a numeric string matching `/^\d+$/`) — a string is treated as an epoch
|
|
101
|
+
* ONLY when it is entirely digits; anything else is parsed as an ISO 8601
|
|
102
|
+
* date, so a date string is never misread as an epoch. Throws `RangeError`
|
|
103
|
+
* (via `toEpochMs`) when the value is neither. A version with no recorded
|
|
104
|
+
* publish time is EXCLUDED rather than included by default: it cannot be
|
|
105
|
+
* proven to satisfy the floor, and for a time-based filter a false negative
|
|
106
|
+
* (unfairly dropped) is the safer failure mode than a false positive
|
|
107
|
+
* (unfairly kept).
|
|
108
|
+
*/
|
|
109
|
+
after?: string | number | undefined;
|
|
110
|
+
/**
|
|
111
|
+
* Whether `range` may match a prerelease version (`2.0.0-beta.0`) even when
|
|
112
|
+
* the range itself has no prerelease component. Passed explicitly to every
|
|
113
|
+
* semver call this module makes — never left to the vendored semver's
|
|
114
|
+
* implicit default.
|
|
115
|
+
*
|
|
116
|
+
* @default false
|
|
117
|
+
*/
|
|
118
|
+
includePrerelease?: boolean | undefined;
|
|
119
|
+
/**
|
|
120
|
+
* Loose semver parsing for `range`.
|
|
121
|
+
*
|
|
122
|
+
* @default false
|
|
123
|
+
*/
|
|
124
|
+
loose?: boolean | undefined;
|
|
125
|
+
/**
|
|
126
|
+
* Maturity filter in days — only versions whose publish time is at least
|
|
127
|
+
* this many days old are kept. The publish time is anchored to the END of
|
|
128
|
+
* its UTC day before `minAgeDays` is added (Socket soak-window semantics), so
|
|
129
|
+
* a version published at any point during a UTC day matures at the same
|
|
130
|
+
* wall-clock instant. Like `after`, a version with no recorded publish time
|
|
131
|
+
* is excluded.
|
|
132
|
+
*/
|
|
133
|
+
minAgeDays?: number | undefined;
|
|
134
|
+
/**
|
|
135
|
+
* A semver range, an exact version, or a dist-tag name — resolved in that
|
|
136
|
+
* priority order against the packument (npm forbids a dist-tag name that is
|
|
137
|
+
* also valid semver, so the three never collide):
|
|
138
|
+
*
|
|
139
|
+
* 1. A dist-tag key (e.g. `"beta"`) resolves to the single version it points to.
|
|
140
|
+
* Throws `PackumentNotFoundError` if that version is missing from the
|
|
141
|
+
* packument (a stale or inconsistent packument).
|
|
142
|
+
* 2. An exact, valid semver version resolves to itself. Throws
|
|
143
|
+
* `PackumentNotFoundError` if it isn't in the packument — `getVersions`
|
|
144
|
+
* never falls back to the full list on a specific miss.
|
|
145
|
+
* 3. Anything else is treated as a semver range filter. Versions that don't
|
|
146
|
+
* satisfy it are dropped; an empty result (not an error) when nothing
|
|
147
|
+
* matches, since a narrow-but-valid range matching zero versions is not a
|
|
148
|
+
* "not found" case.
|
|
149
|
+
*/
|
|
150
|
+
range?: string | undefined;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Result of `getVersions` — the filtered version list plus enough context
|
|
154
|
+
* (`time`, `distTags`) that callers rarely need a second fetch.
|
|
155
|
+
*/
|
|
156
|
+
export interface GetVersionsResult {
|
|
157
|
+
distTags: Record<string, string>;
|
|
158
|
+
time: Record<string, string>;
|
|
159
|
+
versions: string[];
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Result of `getLatestVersion`.
|
|
163
|
+
*/
|
|
164
|
+
export interface LatestVersionResult {
|
|
165
|
+
distTags: Record<string, string>;
|
|
166
|
+
publishedAt: string | undefined;
|
|
167
|
+
version: string;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Injectable HTTP adapter for the metadata client. Signature-compatible with
|
|
171
|
+
* `httpJson` from `../http-request/node` so the default is a direct reference.
|
|
172
|
+
*/
|
|
173
|
+
export interface NpmMetaHttpAdapter {
|
|
174
|
+
json<T>(url: string, options?: HttpRequestOptions | undefined): Promise<T>;
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* The slimmed packument this client returns — top-level fields plus the
|
|
178
|
+
* per-version map from `sliceVersionMeta`.
|
|
179
|
+
*/
|
|
180
|
+
export interface PackumentMetaSlim {
|
|
181
|
+
distTags: Record<string, string>;
|
|
182
|
+
/**
|
|
183
|
+
* `Date.now()` at fetch time (not the registry's `time.modified`) — lets
|
|
184
|
+
* callers reason about cache freshness without inspecting the cache layer.
|
|
185
|
+
*/
|
|
186
|
+
lastSynced: number;
|
|
187
|
+
name: string;
|
|
188
|
+
timeCreated?: string | undefined;
|
|
189
|
+
timeModified?: string | undefined;
|
|
190
|
+
versions: Record<string, PackumentVersionMetaSlim>;
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* `'abbreviated'` matches npm's `Accept: application/vnd.npm.install-v1+json`
|
|
194
|
+
* fast packument (no `_npmUser`); `'full'` is the plain packument.
|
|
195
|
+
*/
|
|
196
|
+
export type PackumentVariant = 'abbreviated' | 'full';
|
|
197
|
+
/**
|
|
198
|
+
* Slimmed per-version metadata — `sliceVersionMeta`'s output shape for one
|
|
199
|
+
* version entry.
|
|
200
|
+
*/
|
|
201
|
+
export interface PackumentVersionMetaSlim {
|
|
202
|
+
attestations?: unknown | undefined;
|
|
203
|
+
deprecated?: string | undefined;
|
|
204
|
+
engines?: Record<string, string> | undefined;
|
|
205
|
+
integrity?: string | undefined;
|
|
206
|
+
shasum?: string | undefined;
|
|
207
|
+
/**
|
|
208
|
+
* Boolean form of `_npmUser?.approver` — `true` when the version was
|
|
209
|
+
* published through a staged/approval flow.
|
|
210
|
+
*/
|
|
211
|
+
staged?: boolean | undefined;
|
|
212
|
+
tarball?: string | undefined;
|
|
213
|
+
time: string;
|
|
214
|
+
/**
|
|
215
|
+
* Boolean form of `_npmUser?.trustedPublisher`.
|
|
216
|
+
*/
|
|
217
|
+
trustedPublisher?: boolean | undefined;
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Raw `_npmUser` shape from a full-variant packument version entry.
|
|
221
|
+
*/
|
|
222
|
+
export interface RawNpmUser {
|
|
223
|
+
approver?: unknown | undefined;
|
|
224
|
+
trustedPublisher?: boolean | undefined;
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Raw packument JSON as received from the registry — the input to
|
|
228
|
+
* `slicePackument` / `sliceVersionMeta`.
|
|
229
|
+
*
|
|
230
|
+
* Deliberately separate from `./registry`'s `PackumentRecord` /
|
|
231
|
+
* `PackumentVersion` / `PackumentVersionDist` hierarchy, not an oversight:
|
|
232
|
+
* this client needs `_npmUser`, `engines`, and the full `dist.integrity` /
|
|
233
|
+
* `dist.shasum` fields (for `getVersionTrustInfo` and the
|
|
234
|
+
* abbreviated-vs-full variant split), none of which `./registry`'s
|
|
235
|
+
* browser-safe, Trusted-Publisher-detection-only surface carries. The two
|
|
236
|
+
* hierarchies are NOT meant to be interchangeable — passing a `./registry`
|
|
237
|
+
* `PackumentVersion` where a `RawPackumentVersion` is expected needs an
|
|
238
|
+
* explicit re-shape, since `PackumentVersion`'s `engines` and other extra
|
|
239
|
+
* fields resolve through its `[field: string]: unknown` index signature.
|
|
240
|
+
* `test/unit/npm/meta-types.test.mts` type-checks the fields the two
|
|
241
|
+
* hierarchies DO intentionally share, so a future edit to either side can't
|
|
242
|
+
* silently break that overlap.
|
|
243
|
+
*/
|
|
244
|
+
export interface RawPackument {
|
|
245
|
+
'dist-tags'?: Record<string, string> | undefined;
|
|
246
|
+
name?: string | undefined;
|
|
247
|
+
time?: Record<string, string> | undefined;
|
|
248
|
+
versions?: Record<string, RawPackumentVersion> | undefined;
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Raw per-version entry from a packument. `_npmUser` is present only on the
|
|
252
|
+
* `'full'` variant.
|
|
253
|
+
*/
|
|
254
|
+
export interface RawPackumentVersion {
|
|
255
|
+
_npmUser?: RawNpmUser | undefined;
|
|
256
|
+
deprecated?: string | undefined;
|
|
257
|
+
dist?: RawVersionDist | undefined;
|
|
258
|
+
engines?: Record<string, string> | undefined;
|
|
259
|
+
[field: string]: unknown;
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Raw `dist` shape from a packument version entry.
|
|
263
|
+
*/
|
|
264
|
+
export interface RawVersionDist {
|
|
265
|
+
attestations?: unknown | undefined;
|
|
266
|
+
integrity?: string | undefined;
|
|
267
|
+
shasum?: string | undefined;
|
|
268
|
+
tarball?: string | undefined;
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* Per-version trust signals returned by `getVersionTrustInfo`. `approver`
|
|
272
|
+
* mirrors `PackumentVersionMetaSlim.staged` — named for its source field
|
|
273
|
+
* (`_npmUser.approver`) since this helper is specifically about trust
|
|
274
|
+
* provenance rather than general slimmed metadata.
|
|
275
|
+
*/
|
|
276
|
+
export interface VersionTrustInfo {
|
|
277
|
+
approver?: boolean | undefined;
|
|
278
|
+
attestations?: unknown | undefined;
|
|
279
|
+
integrity?: string | undefined;
|
|
280
|
+
shasum?: string | undefined;
|
|
281
|
+
trustedPublisher?: boolean | undefined;
|
|
282
|
+
}
|