com.jimuwd.xian.registry-proxy 1.0.1 → 1.0.3
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/README.MD +76 -34
- package/dist/index.js +9 -12
- package/package.json +1 -1
- package/src/index.ts +14 -16
package/README.MD
CHANGED
|
@@ -3,53 +3,56 @@
|
|
|
3
3
|
|
|
4
4
|
## 项目简介
|
|
5
5
|
|
|
6
|
-
`com.jimuwd.xian.registry-proxy` 是一个轻量级的 npm 代理服务器,旨在为 Node.js 项目提供多 registry 的代理和 fallback
|
|
6
|
+
`com.jimuwd.xian.registry-proxy` 是一个轻量级的 npm 代理服务器,旨在为 Node.js 项目提供多 registry 的代理和 fallback 机制。它通过读取独立的配置文件 `.registry-proxy.yml`,将多个 npm registry(如公共 registry、私有仓库等)代理到一个本地端口(默认 `4873`),并支持在 `.registry-proxy.yml` 中 token 缺失时从 Yarn 配置文件(本地 `.yarnrc.yml` 和全局 `~/.yarnrc.yml`)回退获取认证信息。
|
|
7
7
|
主要功能:
|
|
8
8
|
- **多 registry 代理**:将多个 npm registry 统一代理到本地端口,提供单一访问入口。
|
|
9
9
|
- **Fallback 机制**:按配置顺序尝试多个 registry,直到找到可用包。
|
|
10
|
-
- **灵活的 token
|
|
10
|
+
- **灵活的 token 管理**:优先使用 `.registry-proxy.yml` 中的 `npmAuthToken`,缺失时从 Yarn 配置文件读取。
|
|
11
11
|
- **优雅关闭**:支持通过 SIGTERM 信号优雅停止服务。
|
|
12
12
|
|
|
13
|
-
这个工具特别适合需要同时访问多个 npm
|
|
13
|
+
这个工具特别适合需要同时访问多个 npm 源的开发场景,尤其在 CI/CD 或本地开发中,能提高依赖安装的稳定性和效率。
|
|
14
14
|
|
|
15
15
|
---
|
|
16
16
|
|
|
17
17
|
## 快速上手指南
|
|
18
18
|
|
|
19
19
|
### 安装
|
|
20
|
-
在你的业务项目中,将 `com.jimuwd.xian.registry-proxy` 添加为开发依赖。假设你的私有 Yarn 仓库地址为 `https://
|
|
20
|
+
在你的业务项目中,将 `com.jimuwd.xian.registry-proxy` 添加为开发依赖。假设你的私有 Yarn 仓库地址为 `https://repo.jimuwd.com/jimuwd/~npm/`:
|
|
21
21
|
|
|
22
22
|
```bash
|
|
23
|
-
yarn add --dev com.jimuwd.xian.registry-proxy --registry https://
|
|
23
|
+
yarn add --dev com.jimuwd.xian.registry-proxy --registry https://repo.jimuwd.com/jimuwd/~npm/
|
|
24
24
|
```
|
|
25
25
|
|
|
26
26
|
### 配置
|
|
27
|
-
1.
|
|
28
|
-
|
|
27
|
+
1. **代理配置文件 `.registry-proxy.yml`**
|
|
28
|
+
在业务项目根目录创建 `.registry-proxy.yml`,指定需要代理的 registry 列表。每个 registry 必须至少是一个空对象 `{}`,否则会导致解析错误:
|
|
29
29
|
```yaml
|
|
30
|
-
|
|
30
|
+
registries:
|
|
31
31
|
"http://localhost:4873/":
|
|
32
32
|
npmAuthToken: "local-token" # 可选
|
|
33
33
|
"https://registry.npmjs.org/":
|
|
34
|
-
# token
|
|
35
|
-
"https://
|
|
34
|
+
{} # 无 token 时使用空对象
|
|
35
|
+
"https://repo.jimuwd.com/jimuwd/~npm/":
|
|
36
36
|
npmAuthToken: "private-token" # 可选
|
|
37
|
-
|
|
37
|
+
```
|
|
38
38
|
|
|
39
|
+
2. **本地 `.yarnrc.yml`**
|
|
40
|
+
在项目根目录创建或编辑 `.yarnrc.yml`,指定 Yarn 使用本地代理地址:
|
|
41
|
+
```yaml
|
|
39
42
|
npmRegistryServer: "http://localhost:4873/"
|
|
40
43
|
unsafeHttpWhitelist:
|
|
41
44
|
- "localhost"
|
|
42
45
|
```
|
|
43
46
|
|
|
44
|
-
|
|
45
|
-
|
|
47
|
+
3. **全局 `~/.yarnrc.yml`(可选)**
|
|
48
|
+
如果 `.registry-proxy.yml` 未提供某些 registry 的 token,可以在用户主目录下的 `.yarnrc.yml` 配置回退 token:
|
|
46
49
|
```yaml
|
|
47
50
|
npmRegistries:
|
|
48
51
|
"https://registry.npmjs.org/":
|
|
49
52
|
npmAuthToken: "global-npm-token"
|
|
50
|
-
"https://
|
|
53
|
+
"https://repo.jimuwd.com/jimuwd/~npm/":
|
|
51
54
|
npmAuthToken: "global-private-token"
|
|
52
|
-
npmAlwaysAuth: true
|
|
55
|
+
npmAlwaysAuth: true # 可选,控制 Yarn 行为
|
|
53
56
|
```
|
|
54
57
|
|
|
55
58
|
### 使用
|
|
@@ -59,7 +62,7 @@ yarn add --dev com.jimuwd.xian.registry-proxy --registry https://your-private-re
|
|
|
59
62
|
#!/bin/bash
|
|
60
63
|
|
|
61
64
|
# 启动代理服务器并记录 PID
|
|
62
|
-
yarn run registry-proxy .yarnrc.yml ~/.yarnrc.yml &
|
|
65
|
+
yarn run registry-proxy .registry-proxy.yml .yarnrc.yml ~/.yarnrc.yml &
|
|
63
66
|
PROXY_PID=$!
|
|
64
67
|
|
|
65
68
|
# 等待代理服务器启动,最多 10 秒
|
|
@@ -94,7 +97,7 @@ yarn add --dev com.jimuwd.xian.registry-proxy --registry https://your-private-re
|
|
|
94
97
|
```json
|
|
95
98
|
{
|
|
96
99
|
"scripts": {
|
|
97
|
-
"start-proxy": "registry-proxy .yarnrc.yml ~/.yarnrc.yml",
|
|
100
|
+
"start-proxy": "registry-proxy .registry-proxy.yml .yarnrc.yml ~/.yarnrc.yml",
|
|
98
101
|
"install": "bash start-proxy.sh"
|
|
99
102
|
}
|
|
100
103
|
}
|
|
@@ -134,11 +137,11 @@ com.jimuwd.xian.registry-proxy/
|
|
|
134
137
|
|
|
135
138
|
### 功能实现
|
|
136
139
|
1. **配置加载(`loadRegistries`)**:
|
|
137
|
-
-
|
|
138
|
-
-
|
|
139
|
-
-
|
|
140
|
-
-
|
|
141
|
-
-
|
|
140
|
+
- **代理配置文件**:从指定路径(默认 `./.registry-proxy.yml`)读取 `registries`,提取 `registryUrl` 和 `npmAuthToken`。
|
|
141
|
+
- **Yarn 配置文件回退**:如果 `.registry-proxy.yml` 中 token 缺失,依次从本地 `.yarnrc.yml`(默认 `./.yarnrc.yml`)和全局 `~/.yarnrc.yml`(默认 `~/.yarnrc.yml`)读取对应 `registryUrl` 的 `npmAuthToken`。
|
|
142
|
+
- **安全设计**:将 `registryUrl` 和 token 配置独立于 `.registry-proxy.yml`,避免敏感信息直接写入 Yarn 配置文件并提交到代码仓库。回退到 Yarn 配置的 token(尤其是全局配置)进一步降低安全隐患。
|
|
143
|
+
- **优先级**:`.registry-proxy.yml` token > 本地 `.yarnrc.yml` token > 全局 `~/.yarnrc.yml` token > 无 token。
|
|
144
|
+
- **错误处理**:`.registry-proxy.yml` 必须存在且包含 `registries`,否则退出。
|
|
142
145
|
|
|
143
146
|
2. **代理逻辑**:
|
|
144
147
|
- **服务器**:使用 Node.js 的 `http.createServer` 创建本地 HTTP 服务,默认监听 `4873` 端口。
|
|
@@ -154,27 +157,42 @@ com.jimuwd.xian.registry-proxy/
|
|
|
154
157
|
- **模块系统**:`"module": "nodenext"`,兼容 Node.js v20+。
|
|
155
158
|
- **依赖**:
|
|
156
159
|
- `node-fetch@^3.3.2`:发起 HTTP 请求。
|
|
157
|
-
- `js-yaml@^4.1.0`:解析 `.yarnrc.yml` 文件。
|
|
160
|
+
- `js-yaml@^4.1.0`:解析 `.registry-proxy.yml` 和 `.yarnrc.yml` 文件。
|
|
158
161
|
- **Node.js 版本**:推荐 v14+,测试于 v20.17.0。
|
|
159
162
|
|
|
160
163
|
### CLI 参数
|
|
161
164
|
```bash
|
|
162
|
-
registry-proxy [
|
|
165
|
+
registry-proxy [proxyConfigPath] [localYarnConfigPath] [globalYarnConfigPath] [port]
|
|
163
166
|
```
|
|
164
|
-
- `
|
|
165
|
-
- `
|
|
167
|
+
- `proxyConfigPath`:代理配置文件路径,默认 `./.registry-proxy.yml`。
|
|
168
|
+
- `localYarnConfigPath`:本地 Yarn 配置文件路径,默认 `./.yarnrc.yml`。
|
|
169
|
+
- `globalYarnConfigPath`:全局 Yarn 配置文件路径,默认 `~/.yarnrc.yml`。
|
|
166
170
|
- `port`:代理服务器端口,默认 `4873`。
|
|
167
171
|
|
|
168
172
|
示例:
|
|
169
173
|
```bash
|
|
170
|
-
yarn run registry-proxy ./custom.yml ~/.custom.yml 54321
|
|
174
|
+
yarn run registry-proxy ./custom-registry.yml ./custom-yarn.yml ~/.custom-yarn.yml 54321
|
|
171
175
|
```
|
|
172
176
|
|
|
173
177
|
### 配置说明
|
|
174
|
-
-
|
|
175
|
-
-
|
|
176
|
-
-
|
|
177
|
-
|
|
178
|
+
- **`.registry-proxy.yml`**:
|
|
179
|
+
- 使用 `registries` 字段定义代理的 registry 列表,与 Yarn 的 `npmRegistries` 区分。
|
|
180
|
+
- **格式要求**:每个 `registryUrl` 后必须跟一个对象(至少是 `{}`),否则解析为 `null` 会导致运行时错误。例如:
|
|
181
|
+
```yaml
|
|
182
|
+
registries:
|
|
183
|
+
"https://repo.jimuwd.com/jimuwd/~npm/": {} # 正确
|
|
184
|
+
"https://repo.jimuwd.com/jimuwd/~npm/": # 错误,会解析为 null
|
|
185
|
+
```
|
|
186
|
+
- 示例:
|
|
187
|
+
```yaml
|
|
188
|
+
registries:
|
|
189
|
+
"https://repo.jimuwd.com/jimuwd/~npm/":
|
|
190
|
+
npmAuthToken: "private-token"
|
|
191
|
+
```
|
|
192
|
+
- **注意**:无需配置 `npmAlwaysAuth`,此项仅适用于 Yarn 的 `.yarnrc.yml`,对代理行为无影响。
|
|
193
|
+
- **`.yarnrc.yml`**:
|
|
194
|
+
- 仅用于设置 `npmRegistryServer` 和回退 token。
|
|
195
|
+
- 如果需要强制认证,可在回退的 Yarn 配置中添加 `npmAlwaysAuth: true`。
|
|
178
196
|
|
|
179
197
|
### 注意事项
|
|
180
198
|
1. **端口冲突**:
|
|
@@ -182,12 +200,12 @@ yarn run registry-proxy ./custom.yml ~/.custom.yml 54321
|
|
|
182
200
|
- 检查端口占用:`lsof -i :4873`。
|
|
183
201
|
- 可通过参数指定其他端口(如 `54321`)。
|
|
184
202
|
2. **配置文件格式**:
|
|
185
|
-
- 确保 `.
|
|
203
|
+
- 确保 `.registry-proxy.yml` 包含 `registries` 字段,`.yarnrc.yml` 包含 `npmRegistryServer`。
|
|
186
204
|
3. **日志**:
|
|
187
205
|
- 当前通过 `console.log` 输出启动信息,可扩展为文件日志。
|
|
188
206
|
4. **安全性**:
|
|
189
207
|
- 代理运行于本地,未开放外部访问,确保 `unsafeHttpWhitelist` 配置正确。
|
|
190
|
-
-
|
|
208
|
+
- 优先将 token 放入 `.registry-proxy.yml` 或全局 `.yarnrc.yml`,避免提交到代码仓库。
|
|
191
209
|
|
|
192
210
|
### 开发与发布
|
|
193
211
|
1. **构建**:
|
|
@@ -196,7 +214,31 @@ yarn run registry-proxy ./custom.yml ~/.custom.yml 54321
|
|
|
196
214
|
```
|
|
197
215
|
2. **发布到私有仓库**:
|
|
198
216
|
```bash
|
|
199
|
-
yarn publish --registry https://
|
|
217
|
+
yarn publish --registry https://repo.jimuwd.com/jimuwd/~npm/
|
|
200
218
|
```
|
|
201
219
|
|
|
202
220
|
---
|
|
221
|
+
|
|
222
|
+
### 测试流程
|
|
223
|
+
1. **更新 `.registry-proxy.yml`**:
|
|
224
|
+
```yaml
|
|
225
|
+
registries:
|
|
226
|
+
"https://repo.jimuwd.com/jimuwd/~npm/": {}
|
|
227
|
+
"https://registry.npmjs.org/": {}
|
|
228
|
+
```
|
|
229
|
+
2. **构建并发布**:
|
|
230
|
+
```bash
|
|
231
|
+
cd registry-proxy
|
|
232
|
+
yarn install
|
|
233
|
+
yarn build
|
|
234
|
+
yarn publish --registry https://repo.jimuwd.com/jimuwd/~npm/
|
|
235
|
+
```
|
|
236
|
+
3. **更新业务项目**:
|
|
237
|
+
```bash
|
|
238
|
+
cd your-business-project
|
|
239
|
+
yarn add com.jimuwd.xian.registry-proxy@latest --registry https://repo.jimuwd.com/jimuwd/~npm/
|
|
240
|
+
```
|
|
241
|
+
4. **运行**:
|
|
242
|
+
```bash
|
|
243
|
+
bash start-proxy.sh
|
|
244
|
+
```
|
package/dist/index.js
CHANGED
|
@@ -6,7 +6,6 @@ import fetch from 'node-fetch';
|
|
|
6
6
|
import { homedir } from 'os';
|
|
7
7
|
import { join } from 'path';
|
|
8
8
|
async function loadRegistries(proxyConfigPath = './.registry-proxy.yml', localYarnConfigPath = './.yarnrc.yml', globalYarnConfigPath = join(homedir(), '.yarnrc.yml')) {
|
|
9
|
-
// 读取独立的 .registry-proxy.yml
|
|
10
9
|
let proxyConfig = { registries: {} };
|
|
11
10
|
try {
|
|
12
11
|
const proxyYamlContent = await readFile(proxyConfigPath, 'utf8');
|
|
@@ -15,14 +14,13 @@ async function loadRegistries(proxyConfigPath = './.registry-proxy.yml', localYa
|
|
|
15
14
|
}
|
|
16
15
|
catch (e) {
|
|
17
16
|
console.error(`Failed to load ${proxyConfigPath}: ${e.message}`);
|
|
18
|
-
process.exit(1);
|
|
17
|
+
process.exit(1);
|
|
19
18
|
}
|
|
20
19
|
if (!proxyConfig.registries || !Object.keys(proxyConfig.registries).length) {
|
|
21
20
|
console.error(`No registries found in ${proxyConfigPath}`);
|
|
22
21
|
process.exit(1);
|
|
23
22
|
}
|
|
24
|
-
|
|
25
|
-
let localYarnConfig = {};
|
|
23
|
+
let localYarnConfig = { npmRegistries: {} };
|
|
26
24
|
try {
|
|
27
25
|
const localYamlContent = await readFile(localYarnConfigPath, 'utf8');
|
|
28
26
|
localYarnConfig = load(localYamlContent);
|
|
@@ -31,8 +29,7 @@ async function loadRegistries(proxyConfigPath = './.registry-proxy.yml', localYa
|
|
|
31
29
|
catch (e) {
|
|
32
30
|
console.warn(`Failed to load ${localYarnConfigPath}: ${e.message}`);
|
|
33
31
|
}
|
|
34
|
-
|
|
35
|
-
let globalYarnConfig = {};
|
|
32
|
+
let globalYarnConfig = { npmRegistries: {} };
|
|
36
33
|
try {
|
|
37
34
|
const globalYamlContent = await readFile(globalYarnConfigPath, 'utf8');
|
|
38
35
|
globalYarnConfig = load(globalYamlContent);
|
|
@@ -41,16 +38,16 @@ async function loadRegistries(proxyConfigPath = './.registry-proxy.yml', localYa
|
|
|
41
38
|
catch (e) {
|
|
42
39
|
console.warn(`Failed to load ${globalYarnConfigPath}: ${e.message}`);
|
|
43
40
|
}
|
|
44
|
-
// 从 .registry-proxy.yml 获取 registries,并回退读取 token
|
|
45
41
|
const registries = Object.entries(proxyConfig.registries).map(([url, regConfig]) => {
|
|
46
|
-
let token
|
|
47
|
-
|
|
48
|
-
|
|
42
|
+
let token;
|
|
43
|
+
if (regConfig && 'npmAuthToken' in regConfig) {
|
|
44
|
+
token = regConfig.npmAuthToken?.replace(/\${(.+)}/, (_, key) => process.env[key] || '') || regConfig.npmAuthToken;
|
|
45
|
+
}
|
|
46
|
+
if (!token && localYarnConfig.npmRegistries?.[url] && 'npmAuthToken' in localYarnConfig.npmRegistries[url]) {
|
|
49
47
|
token = localYarnConfig.npmRegistries[url].npmAuthToken?.replace(/\${(.+)}/, (_, key) => process.env[key] || '') || localYarnConfig.npmRegistries[url].npmAuthToken;
|
|
50
48
|
console.log(`Token for ${url} not found in ${proxyConfigPath}, using local Yarn config`);
|
|
51
49
|
}
|
|
52
|
-
|
|
53
|
-
if (!token && globalYarnConfig.npmRegistries && globalYarnConfig.npmRegistries[url]) {
|
|
50
|
+
if (!token && globalYarnConfig.npmRegistries?.[url] && 'npmAuthToken' in globalYarnConfig.npmRegistries[url]) {
|
|
54
51
|
token = globalYarnConfig.npmRegistries[url].npmAuthToken?.replace(/\${(.+)}/, (_, key) => process.env[key] || '') || globalYarnConfig.npmRegistries[url].npmAuthToken;
|
|
55
52
|
console.log(`Token for ${url} not found in local Yarn config, using global Yarn config`);
|
|
56
53
|
}
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -7,11 +7,10 @@ import { homedir } from 'os';
|
|
|
7
7
|
import { join } from 'path';
|
|
8
8
|
|
|
9
9
|
interface RegistryConfig { npmAuthToken?: string; }
|
|
10
|
-
interface ProxyConfig { registries: Record<string, RegistryConfig>; }
|
|
11
|
-
interface YarnConfig { npmRegistries?: Record<string, RegistryConfig>; }
|
|
10
|
+
interface ProxyConfig { registries: Record<string, RegistryConfig | null>; }
|
|
11
|
+
interface YarnConfig { npmRegistries?: Record<string, RegistryConfig | null>; }
|
|
12
12
|
|
|
13
13
|
async function loadRegistries(proxyConfigPath = './.registry-proxy.yml', localYarnConfigPath = './.yarnrc.yml', globalYarnConfigPath = join(homedir(), '.yarnrc.yml')): Promise<{ url: string; token?: string }[]> {
|
|
14
|
-
// 读取独立的 .registry-proxy.yml
|
|
15
14
|
let proxyConfig: ProxyConfig = { registries: {} };
|
|
16
15
|
try {
|
|
17
16
|
const proxyYamlContent = await readFile(proxyConfigPath, 'utf8');
|
|
@@ -19,7 +18,7 @@ async function loadRegistries(proxyConfigPath = './.registry-proxy.yml', localYa
|
|
|
19
18
|
console.log(`Loaded proxy config from ${proxyConfigPath}`);
|
|
20
19
|
} catch (e) {
|
|
21
20
|
console.error(`Failed to load ${proxyConfigPath}: ${(e as Error).message}`);
|
|
22
|
-
process.exit(1);
|
|
21
|
+
process.exit(1);
|
|
23
22
|
}
|
|
24
23
|
|
|
25
24
|
if (!proxyConfig.registries || !Object.keys(proxyConfig.registries).length) {
|
|
@@ -27,8 +26,7 @@ async function loadRegistries(proxyConfigPath = './.registry-proxy.yml', localYa
|
|
|
27
26
|
process.exit(1);
|
|
28
27
|
}
|
|
29
28
|
|
|
30
|
-
|
|
31
|
-
let localYarnConfig: YarnConfig = {};
|
|
29
|
+
let localYarnConfig: YarnConfig = { npmRegistries: {} };
|
|
32
30
|
try {
|
|
33
31
|
const localYamlContent = await readFile(localYarnConfigPath, 'utf8');
|
|
34
32
|
localYarnConfig = load(localYamlContent) as YarnConfig;
|
|
@@ -37,8 +35,7 @@ async function loadRegistries(proxyConfigPath = './.registry-proxy.yml', localYa
|
|
|
37
35
|
console.warn(`Failed to load ${localYarnConfigPath}: ${(e as Error).message}`);
|
|
38
36
|
}
|
|
39
37
|
|
|
40
|
-
|
|
41
|
-
let globalYarnConfig: YarnConfig = {};
|
|
38
|
+
let globalYarnConfig: YarnConfig = { npmRegistries: {} };
|
|
42
39
|
try {
|
|
43
40
|
const globalYamlContent = await readFile(globalYarnConfigPath, 'utf8');
|
|
44
41
|
globalYarnConfig = load(globalYamlContent) as YarnConfig;
|
|
@@ -47,19 +44,20 @@ async function loadRegistries(proxyConfigPath = './.registry-proxy.yml', localYa
|
|
|
47
44
|
console.warn(`Failed to load ${globalYarnConfigPath}: ${(e as Error).message}`);
|
|
48
45
|
}
|
|
49
46
|
|
|
50
|
-
// 从 .registry-proxy.yml 获取 registries,并回退读取 token
|
|
51
47
|
const registries = Object.entries(proxyConfig.registries).map(([url, regConfig]) => {
|
|
52
|
-
let token
|
|
48
|
+
let token: string | undefined;
|
|
49
|
+
|
|
50
|
+
if (regConfig && 'npmAuthToken' in regConfig) {
|
|
51
|
+
token = regConfig.npmAuthToken?.replace(/\${(.+)}/, (_, key) => process.env[key] || '') || regConfig.npmAuthToken;
|
|
52
|
+
}
|
|
53
53
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
token = localYarnConfig.npmRegistries[url].npmAuthToken?.replace(/\${(.+)}/, (_, key) => process.env[key] || '') || localYarnConfig.npmRegistries[url].npmAuthToken;
|
|
54
|
+
if (!token && localYarnConfig.npmRegistries?.[url] && 'npmAuthToken' in localYarnConfig.npmRegistries[url]) {
|
|
55
|
+
token = localYarnConfig.npmRegistries[url]!.npmAuthToken?.replace(/\${(.+)}/, (_, key) => process.env[key] || '') || localYarnConfig.npmRegistries[url]!.npmAuthToken;
|
|
57
56
|
console.log(`Token for ${url} not found in ${proxyConfigPath}, using local Yarn config`);
|
|
58
57
|
}
|
|
59
58
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
token = globalYarnConfig.npmRegistries[url].npmAuthToken?.replace(/\${(.+)}/, (_, key) => process.env[key] || '') || globalYarnConfig.npmRegistries[url].npmAuthToken;
|
|
59
|
+
if (!token && globalYarnConfig.npmRegistries?.[url] && 'npmAuthToken' in globalYarnConfig.npmRegistries[url]) {
|
|
60
|
+
token = globalYarnConfig.npmRegistries[url]!.npmAuthToken?.replace(/\${(.+)}/, (_, key) => process.env[key] || '') || globalYarnConfig.npmRegistries[url]!.npmAuthToken;
|
|
63
61
|
console.log(`Token for ${url} not found in local Yarn config, using global Yarn config`);
|
|
64
62
|
}
|
|
65
63
|
|