@pnpm/network.auth-header 1101.1.0 → 1101.1.2

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.
@@ -1,2 +1,8 @@
1
- import type { RegistryConfig } from '@pnpm/types';
2
- export declare function getAuthHeadersFromCreds(configByUri: Record<string, RegistryConfig>): Record<string, string>;
1
+ import { type RegistryConfig } from '@pnpm/types';
2
+ export interface AuthHeaders {
3
+ authHeaderValueByURI: Record<string, string>;
4
+ scopedAuthHeaderValueByURI: Record<string, Record<string, string>>;
5
+ }
6
+ export type AuthHeadersByScope = Record<string, Record<string, string>>;
7
+ export declare function getAuthHeadersFromCreds(configByUri: Record<string, RegistryConfig>): AuthHeaders;
8
+ export declare function getAuthHeadersByScope(authHeaders: AuthHeaders): AuthHeadersByScope;
@@ -1,14 +1,51 @@
1
1
  import { spawnSync } from 'node:child_process';
2
2
  import { PnpmError } from '@pnpm/error';
3
+ import { DEFAULT_REGISTRY_SCOPE } from '@pnpm/types';
3
4
  export function getAuthHeadersFromCreds(configByUri) {
4
- const authHeaderValueByURI = {};
5
+ const authHeaders = {
6
+ authHeaderValueByURI: {},
7
+ scopedAuthHeaderValueByURI: {},
8
+ };
5
9
  for (const [uri, registryConfig] of Object.entries(configByUri)) {
6
- const header = credsToHeader(registryConfig.creds);
10
+ const normalizedUri = normalizeAuthKey(uri);
11
+ const header = credsToHeader(registryConfig[DEFAULT_REGISTRY_SCOPE]);
7
12
  if (header) {
8
- authHeaderValueByURI[uri] = header;
13
+ authHeaders.authHeaderValueByURI[normalizedUri] = header;
9
14
  }
15
+ for (const scope of getRegistryScopes(registryConfig)) {
16
+ if (scope === DEFAULT_REGISTRY_SCOPE)
17
+ continue;
18
+ const scopedCreds = registryConfig[scope];
19
+ const scopedHeader = credsToHeader(scopedCreds);
20
+ if (scopedHeader) {
21
+ authHeaders.scopedAuthHeaderValueByURI[normalizedUri] ??= {};
22
+ authHeaders.scopedAuthHeaderValueByURI[normalizedUri][scope] = scopedHeader;
23
+ }
24
+ }
25
+ }
26
+ return authHeaders;
27
+ }
28
+ export function getAuthHeadersByScope(authHeaders) {
29
+ const result = {};
30
+ for (const [registryURI, authHeader] of Object.entries(authHeaders.authHeaderValueByURI)) {
31
+ result[registryURI] ??= {};
32
+ result[registryURI][DEFAULT_REGISTRY_SCOPE] = authHeader;
10
33
  }
11
- return authHeaderValueByURI;
34
+ for (const [registryURI, scopedAuthHeaders] of Object.entries(authHeaders.scopedAuthHeaderValueByURI)) {
35
+ result[registryURI] ??= {};
36
+ for (const [scope, authHeader] of Object.entries(scopedAuthHeaders)) {
37
+ result[registryURI][scope] = authHeader;
38
+ }
39
+ }
40
+ return result;
41
+ }
42
+ function getRegistryScopes(registryConfig) {
43
+ return Object.keys(registryConfig).filter((scope) => scope.startsWith('@'));
44
+ }
45
+ function normalizeAuthKey(uri) {
46
+ if (!uri)
47
+ return uri;
48
+ return uri.endsWith('/') ? uri : `${uri}/`;
12
49
  }
13
50
  function credsToHeader(creds) {
14
51
  if (!creds)
package/lib/index.d.ts CHANGED
@@ -1,4 +1,7 @@
1
1
  import type { RegistryConfig } from '@pnpm/types';
2
- import { getAuthHeadersFromCreds } from './getAuthHeadersFromConfig.js';
3
- export { getAuthHeadersFromCreds };
4
- export declare function createGetAuthHeaderByURI(configByUri: Record<string, RegistryConfig>): (uri: string) => string | undefined;
2
+ import { type AuthHeaders, type AuthHeadersByScope, getAuthHeadersByScope, getAuthHeadersFromCreds } from './getAuthHeadersFromConfig.js';
3
+ export { type AuthHeaders, type AuthHeadersByScope, getAuthHeadersByScope, getAuthHeadersFromCreds };
4
+ interface GetAuthHeaderOptions {
5
+ pkgName?: string;
6
+ }
7
+ export declare function createGetAuthHeaderByURI(configByUri: Record<string, RegistryConfig>): (uri: string, opts?: GetAuthHeaderOptions) => string | undefined;
package/lib/index.js CHANGED
@@ -1,15 +1,19 @@
1
1
  import { nerfDart } from '@pnpm/config.nerf-dart';
2
- import { getAuthHeadersFromCreds } from './getAuthHeadersFromConfig.js';
2
+ import { getAuthHeadersByScope, getAuthHeadersFromCreds } from './getAuthHeadersFromConfig.js';
3
3
  import { removePort } from './helpers/removePort.js';
4
- // Re-exported so callers that need the whole nerf-darted-URI header map
5
- // (e.g. forwarding every registry credential to the pnpr install
6
- // accelerator) can build it without re-implementing `credsToHeader`.
7
- export { getAuthHeadersFromCreds };
4
+ // Re-exported so callers can build the same URL/scoped credential lookup
5
+ // without re-implementing `credsToHeader`.
6
+ export { getAuthHeadersByScope, getAuthHeadersFromCreds };
8
7
  export function createGetAuthHeaderByURI(configByUri) {
9
8
  const authHeaders = getAuthHeadersFromCreds(configByUri);
10
- if (Object.keys(authHeaders).length === 0)
9
+ const registryURIs = Object.keys(authHeaders.authHeaderValueByURI);
10
+ const scopedAuthHeaderValueByScope = getScopedAuthHeaderValueByScope(authHeaders.scopedAuthHeaderValueByURI);
11
+ if (registryURIs.length === 0 && Object.keys(scopedAuthHeaderValueByScope).length === 0)
11
12
  return (uri) => basicAuth(new URL(uri));
12
- return getAuthHeaderByURI.bind(null, authHeaders, getMaxParts(Object.keys(authHeaders)));
13
+ return getAuthHeaderByURI.bind(null, authHeaders, {
14
+ maxParts: getMaxParts(registryURIs),
15
+ scopedAuthHeaderValueByScope,
16
+ });
13
17
  }
14
18
  function getMaxParts(uris) {
15
19
  return uris.reduce((max, uri) => {
@@ -17,7 +21,24 @@ function getMaxParts(uris) {
17
21
  return parts > max ? parts : max;
18
22
  }, 0);
19
23
  }
20
- function getAuthHeaderByURI(authHeaders, maxParts, uri) {
24
+ function getScopedAuthHeaderValueByScope(authHeaders) {
25
+ const result = {};
26
+ for (const [uri, scopedAuthHeaders] of Object.entries(authHeaders)) {
27
+ const parts = uri.split('/').length;
28
+ for (const [scope, authHeader] of Object.entries(scopedAuthHeaders)) {
29
+ const scopedAuthHeaderLookup = result[scope] ??= {
30
+ authHeaderValueByURI: {},
31
+ maxParts: 0,
32
+ };
33
+ scopedAuthHeaderLookup.authHeaderValueByURI[uri] = authHeader;
34
+ if (parts > scopedAuthHeaderLookup.maxParts) {
35
+ scopedAuthHeaderLookup.maxParts = parts;
36
+ }
37
+ }
38
+ }
39
+ return result;
40
+ }
41
+ function getAuthHeaderByURI(authHeaders, lookup, uri, opts) {
21
42
  if (!uri.endsWith('/')) {
22
43
  uri += '/';
23
44
  }
@@ -25,6 +46,17 @@ function getAuthHeaderByURI(authHeaders, maxParts, uri) {
25
46
  const basic = basicAuth(parsedUri);
26
47
  if (basic)
27
48
  return basic;
49
+ const scope = getScope(opts?.pkgName);
50
+ const scopedAuthHeaderLookup = scope ? lookup.scopedAuthHeaderValueByScope[scope] : undefined;
51
+ if (scopedAuthHeaderLookup) {
52
+ const scopedAuth = getAuthHeaderByNerfedURI(scopedAuthHeaderLookup.authHeaderValueByURI, scopedAuthHeaderLookup.maxParts, uri);
53
+ if (scopedAuth)
54
+ return scopedAuth;
55
+ }
56
+ return getAuthHeaderByNerfedURI(authHeaders.authHeaderValueByURI, lookup.maxParts, uri);
57
+ }
58
+ function getAuthHeaderByNerfedURI(authHeaders, maxParts, uri) {
59
+ const parsedUri = new URL(uri);
28
60
  const nerfed = nerfDart(uri);
29
61
  const parts = nerfed.split('/');
30
62
  for (let i = Math.min(parts.length, maxParts) - 1; i >= 3; i--) {
@@ -34,10 +66,18 @@ function getAuthHeaderByURI(authHeaders, maxParts, uri) {
34
66
  }
35
67
  const urlWithoutPort = removePort(parsedUri);
36
68
  if (urlWithoutPort !== uri) {
37
- return getAuthHeaderByURI(authHeaders, maxParts, urlWithoutPort);
69
+ return getAuthHeaderByNerfedURI(authHeaders, maxParts, urlWithoutPort);
38
70
  }
39
71
  return undefined;
40
72
  }
73
+ function getScope(pkgName) {
74
+ if (!pkgName?.startsWith('@'))
75
+ return undefined;
76
+ const index = pkgName.indexOf('/');
77
+ if (index <= 1)
78
+ return undefined;
79
+ return pkgName.slice(0, index);
80
+ }
41
81
  function basicAuth(uri) {
42
82
  if (!uri.username && !uri.password)
43
83
  return undefined;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pnpm/network.auth-header",
3
- "version": "1101.1.0",
3
+ "version": "1101.1.2",
4
4
  "description": "Gets the authorization header for the given URI",
5
5
  "keywords": [
6
6
  "pnpm",
@@ -28,14 +28,14 @@
28
28
  "!*.map"
29
29
  ],
30
30
  "dependencies": {
31
- "@pnpm/config.nerf-dart": "^1.0.1",
31
+ "@pnpm/config.nerf-dart": "^2.0.1",
32
32
  "@pnpm/error": "1100.0.0",
33
- "@pnpm/types": "1101.3.0"
33
+ "@pnpm/types": "1101.3.2"
34
34
  },
35
35
  "devDependencies": {
36
- "@jest/globals": "30.3.0",
36
+ "@jest/globals": "30.4.1",
37
37
  "safe-buffer": "5.2.1",
38
- "@pnpm/network.auth-header": "1101.1.0"
38
+ "@pnpm/network.auth-header": "1101.1.2"
39
39
  },
40
40
  "engines": {
41
41
  "node": ">=22.13"