com.jimuwd.xian.registry-proxy 1.0.29 → 1.0.31

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.
Files changed (3) hide show
  1. package/dist/index.js +37 -28
  2. package/package.json +1 -1
  3. package/src/index.ts +45 -32
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { createServer } from 'http';
3
3
  import { createServer as createHttpsServer } from 'https';
4
- import { readFileSync, promises as fsPromises } from 'fs';
4
+ import { promises as fsPromises, readFileSync } from 'fs';
5
5
  import { load } from 'js-yaml';
6
6
  import fetch from 'node-fetch';
7
7
  import { homedir } from 'os';
@@ -78,13 +78,14 @@ function removeRegistryPrefix(tarballUrl, registries) {
78
78
  }
79
79
  throw new Error(`Can't find tarball url ${tarballUrl} does not match given registries ${normalizedRegistries}`);
80
80
  }
81
- async function loadProxyConfig(proxyConfigPath = './.registry-proxy.yml') {
81
+ async function readProxyConfig(proxyConfigPath = './.registry-proxy.yml') {
82
82
  const resolvedPath = resolvePath(proxyConfigPath);
83
83
  try {
84
84
  const content = await readFile(resolvedPath, 'utf8');
85
85
  const config = load(content);
86
86
  if (!config.registries) {
87
- throw new Error('Missing required "registries" field in config');
87
+ console.error('Missing required "registries" field in config');
88
+ process.exit(1);
88
89
  }
89
90
  return config;
90
91
  }
@@ -93,7 +94,7 @@ async function loadProxyConfig(proxyConfigPath = './.registry-proxy.yml') {
93
94
  process.exit(1);
94
95
  }
95
96
  }
96
- async function loadYarnConfig(path) {
97
+ async function readYarnConfig(path) {
97
98
  try {
98
99
  const content = await readFile(resolvePath(path), 'utf8');
99
100
  return load(content);
@@ -103,38 +104,46 @@ async function loadYarnConfig(path) {
103
104
  return {};
104
105
  }
105
106
  }
106
- async function loadRegistries(proxyConfigPath = './.registry-proxy.yml', localYarnConfigPath = './.yarnrc.yml', globalYarnConfigPath = join(homedir(), '.yarnrc.yml')) {
107
+ async function loadProxyInfo(proxyConfigPath = './.registry-proxy.yml', localYarnConfigPath = './.yarnrc.yml', globalYarnConfigPath = join(homedir(), '.yarnrc.yml')) {
107
108
  const [proxyConfig, localYarnConfig, globalYarnConfig] = await Promise.all([
108
- loadProxyConfig(proxyConfigPath),
109
- loadYarnConfig(localYarnConfigPath),
110
- loadYarnConfig(globalYarnConfigPath)
109
+ readProxyConfig(proxyConfigPath),
110
+ readYarnConfig(localYarnConfigPath),
111
+ readYarnConfig(globalYarnConfigPath)
111
112
  ]);
112
113
  const registryMap = new Map();
113
- for (const [url, regConfig] of Object.entries(proxyConfig.registries)) {
114
- const normalizedUrl = normalizeUrl(url);
115
- let token = regConfig?.npmAuthToken;
114
+ for (const [proxiedRegUrl, proxyRegConfig] of Object.entries(proxyConfig.registries)) {
115
+ const normalizedProxiedRegUrl = normalizeUrl(proxiedRegUrl);
116
+ let token = proxyRegConfig?.npmAuthToken;
116
117
  if (!token) {
117
118
  const yarnConfigs = [localYarnConfig, globalYarnConfig];
118
- for (const config of yarnConfigs) {
119
- const registryConfig = config.npmRegistries?.[normalizedUrl] ||
120
- config.npmRegistries?.[url];
121
- if (registryConfig?.npmAuthToken) {
122
- token = registryConfig.npmAuthToken;
123
- break;
119
+ for (const yarnConfig of yarnConfigs) {
120
+ if (yarnConfig.npmRegistries) {
121
+ const foundEntry = Object.entries(yarnConfig.npmRegistries)
122
+ .find(([registryUrl]) => normalizedProxiedRegUrl === normalizeUrl(registryUrl));
123
+ if (foundEntry) {
124
+ const [, registryConfig] = foundEntry;
125
+ if (registryConfig?.npmAuthToken) {
126
+ token = registryConfig.npmAuthToken;
127
+ break;
128
+ }
129
+ }
124
130
  }
125
131
  }
126
132
  }
127
- registryMap.set(normalizedUrl, { url: normalizedUrl, token });
133
+ registryMap.set(normalizedProxiedRegUrl, { url: normalizedProxiedRegUrl, token });
128
134
  }
129
- return Array.from(registryMap.values());
135
+ const registries = Array.from(registryMap.values());
136
+ const https = proxyConfig.https;
137
+ const basePath = removeEndingSlashAndForceStartingSlash(proxyConfig.basePath);
138
+ return { registries, https, basePath };
130
139
  }
131
140
  export async function startProxyServer(proxyConfigPath, localYarnConfigPath, globalYarnConfigPath, port = 0) {
132
- const proxyConfig = await loadProxyConfig(proxyConfigPath);
133
- const registries = await loadRegistries(proxyConfigPath, localYarnConfigPath, globalYarnConfigPath);
134
- const basePathPrefixedWithSlash = removeEndingSlashAndForceStartingSlash(proxyConfig.basePath);
141
+ const proxyInfo = await loadProxyInfo(proxyConfigPath, localYarnConfigPath, globalYarnConfigPath);
142
+ const registries = proxyInfo.registries;
143
+ const basePathPrefixedWithSlash = removeEndingSlashAndForceStartingSlash(proxyInfo.basePath);
135
144
  console.log('Active registries:', registries.map(r => r.url));
136
145
  console.log('Proxy base path:', basePathPrefixedWithSlash);
137
- console.log('HTTPS:', !!proxyConfig.https);
146
+ console.log('HTTPS:', !!proxyInfo.https);
138
147
  let proxyPort;
139
148
  const requestHandler = async (req, res) => {
140
149
  if (!req.url || !req.headers.host) {
@@ -142,7 +151,7 @@ export async function startProxyServer(proxyConfigPath, localYarnConfigPath, glo
142
151
  res.writeHead(400).end('Invalid Request');
143
152
  return;
144
153
  }
145
- const fullUrl = new URL(req.url, `${proxyConfig.https ? 'https' : 'http'}://${req.headers.host}`);
154
+ const fullUrl = new URL(req.url, `${proxyInfo.https ? 'https' : 'http'}://${req.headers.host}`);
146
155
  console.log(`Proxy server received request on ${fullUrl.toString()}`);
147
156
  if (!fullUrl.pathname.startsWith(basePathPrefixedWithSlash)) {
148
157
  console.error(`Path ${fullUrl.pathname} does not match basePath ${basePathPrefixedWithSlash}`);
@@ -184,7 +193,7 @@ export async function startProxyServer(proxyConfigPath, localYarnConfigPath, glo
184
193
  if (data.versions) {
185
194
  const requestHeadersHostFromYarnClient = req.headers.host || 'localhost:' + proxyPort;
186
195
  console.log("Request headers.host from yarn client is", requestHeadersHostFromYarnClient);
187
- const proxyBaseUrlNoSuffixedWithSlash = `${proxyConfig.https ? 'https' : 'http'}://${requestHeadersHostFromYarnClient}${basePathPrefixedWithSlash === '/' ? '' : basePathPrefixedWithSlash}`;
196
+ const proxyBaseUrlNoSuffixedWithSlash = `${proxyInfo.https ? 'https' : 'http'}://${requestHeadersHostFromYarnClient}${basePathPrefixedWithSlash === '/' ? '' : basePathPrefixedWithSlash}`;
188
197
  console.log("proxyBaseUrlNoSuffixedWithSlash", proxyBaseUrlNoSuffixedWithSlash);
189
198
  for (const version in data.versions) {
190
199
  const dist = data.versions[version]?.dist;
@@ -225,8 +234,8 @@ export async function startProxyServer(proxyConfigPath, localYarnConfigPath, glo
225
234
  }
226
235
  };
227
236
  let server;
228
- if (proxyConfig.https) {
229
- const { key, cert } = proxyConfig.https;
237
+ if (proxyInfo.https) {
238
+ const { key, cert } = proxyInfo.https;
230
239
  const keyPath = resolvePath(key);
231
240
  const certPath = resolvePath(cert);
232
241
  try {
@@ -260,7 +269,7 @@ export async function startProxyServer(proxyConfigPath, localYarnConfigPath, glo
260
269
  proxyPort = address.port;
261
270
  const portFile = join(process.env.PROJECT_ROOT || process.cwd(), '.registry-proxy-port');
262
271
  writeFile(portFile, proxyPort.toString()).catch(e => console.error('Failed to write port file:', e));
263
- console.log(`Proxy server running on ${proxyConfig.https ? 'https' : 'http'}://localhost:${proxyPort}${basePathPrefixedWithSlash}`);
272
+ console.log(`Proxy server running on ${proxyInfo.https ? 'https' : 'http'}://localhost:${proxyPort}${basePathPrefixedWithSlash}`);
264
273
  resolve(server);
265
274
  });
266
275
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "com.jimuwd.xian.registry-proxy",
3
- "version": "1.0.29",
3
+ "version": "1.0.31",
4
4
  "type": "module",
5
5
  "description": "A lightweight npm registry proxy with fallback support",
6
6
  "main": "dist/index.js",
package/src/index.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
- import {createServer, Server as HttpServer, IncomingMessage, ServerResponse, OutgoingHttpHeaders} from 'http';
2
+ import {createServer, IncomingMessage, OutgoingHttpHeaders, Server as HttpServer, ServerResponse} from 'http';
3
3
  import {createServer as createHttpsServer, Server as HttpsServer} from 'https';
4
- import {readFileSync, promises as fsPromises} from 'fs';
4
+ import {promises as fsPromises, readFileSync} from 'fs';
5
5
  import {AddressInfo} from 'net';
6
6
  import {load} from 'js-yaml';
7
7
  import fetch, {Response} from 'node-fetch';
@@ -35,6 +35,12 @@ interface RegistryInfo {
35
35
  token?: string;
36
36
  }
37
37
 
38
+ interface ProxyInfo {
39
+ registries: RegistryInfo[];
40
+ https?: HttpsConfig;
41
+ basePath?: string;
42
+ }
43
+
38
44
  interface PackageVersion {
39
45
  dist?: { tarball?: string };
40
46
  }
@@ -115,13 +121,14 @@ function removeRegistryPrefix(tarballUrl: string, registries: RegistryInfo[]): s
115
121
  throw new Error(`Can't find tarball url ${tarballUrl} does not match given registries ${normalizedRegistries}`)
116
122
  }
117
123
 
118
- async function loadProxyConfig(proxyConfigPath = './.registry-proxy.yml'): Promise<ProxyConfig> {
124
+ async function readProxyConfig(proxyConfigPath = './.registry-proxy.yml'): Promise<ProxyConfig> {
119
125
  const resolvedPath = resolvePath(proxyConfigPath);
120
126
  try {
121
127
  const content = await readFile(resolvedPath, 'utf8');
122
128
  const config = load(content) as ProxyConfig;
123
129
  if (!config.registries) {
124
- throw new Error('Missing required "registries" field in config');
130
+ console.error('Missing required "registries" field in config');
131
+ process.exit(1);
125
132
  }
126
133
  return config;
127
134
  } catch (e) {
@@ -130,7 +137,7 @@ async function loadProxyConfig(proxyConfigPath = './.registry-proxy.yml'): Promi
130
137
  }
131
138
  }
132
139
 
133
- async function loadYarnConfig(path: string): Promise<YarnConfig> {
140
+ async function readYarnConfig(path: string): Promise<YarnConfig> {
134
141
  try {
135
142
  const content = await readFile(resolvePath(path), 'utf8');
136
143
  return load(content) as YarnConfig;
@@ -140,36 +147,42 @@ async function loadYarnConfig(path: string): Promise<YarnConfig> {
140
147
  }
141
148
  }
142
149
 
143
- async function loadRegistries(
150
+ async function loadProxyInfo(
144
151
  proxyConfigPath = './.registry-proxy.yml',
145
152
  localYarnConfigPath = './.yarnrc.yml',
146
153
  globalYarnConfigPath = join(homedir(), '.yarnrc.yml')
147
- ): Promise<RegistryInfo[]> {
154
+ ): Promise<ProxyInfo> {
148
155
  const [proxyConfig, localYarnConfig, globalYarnConfig] = await Promise.all([
149
- loadProxyConfig(proxyConfigPath),
150
- loadYarnConfig(localYarnConfigPath),
151
- loadYarnConfig(globalYarnConfigPath)
156
+ readProxyConfig(proxyConfigPath),
157
+ readYarnConfig(localYarnConfigPath),
158
+ readYarnConfig(globalYarnConfigPath)
152
159
  ]);
153
-
154
160
  const registryMap = new Map<string, RegistryInfo>();
155
- for (const [url, regConfig] of Object.entries(proxyConfig.registries)) {
156
- const normalizedUrl = normalizeUrl(url);
157
- let token = regConfig?.npmAuthToken;
158
-
161
+ for (const [proxiedRegUrl, proxyRegConfig] of Object.entries(proxyConfig.registries)) {
162
+ const normalizedProxiedRegUrl = normalizeUrl(proxiedRegUrl);
163
+ let token = proxyRegConfig?.npmAuthToken;
159
164
  if (!token) {
160
165
  const yarnConfigs = [localYarnConfig, globalYarnConfig];
161
- for (const config of yarnConfigs) {
162
- const registryConfig = config.npmRegistries?.[normalizedUrl] ||
163
- config.npmRegistries?.[url];
164
- if (registryConfig?.npmAuthToken) {
165
- token = registryConfig.npmAuthToken;
166
- break;
166
+ for (const yarnConfig of yarnConfigs) {
167
+ if (yarnConfig.npmRegistries) {
168
+ const foundEntry = Object.entries(yarnConfig.npmRegistries)
169
+ .find(([registryUrl]) => normalizedProxiedRegUrl === normalizeUrl(registryUrl))
170
+ if (foundEntry) {
171
+ const [, registryConfig] = foundEntry;
172
+ if (registryConfig?.npmAuthToken) {
173
+ token = registryConfig.npmAuthToken;
174
+ break;
175
+ }
176
+ }
167
177
  }
168
178
  }
169
179
  }
170
- registryMap.set(normalizedUrl, {url: normalizedUrl, token});
180
+ registryMap.set(normalizedProxiedRegUrl, {url: normalizedProxiedRegUrl, token});
171
181
  }
172
- return Array.from(registryMap.values());
182
+ const registries = Array.from(registryMap.values());
183
+ const https = proxyConfig.https;
184
+ const basePath = removeEndingSlashAndForceStartingSlash(proxyConfig.basePath);
185
+ return {registries, https, basePath};
173
186
  }
174
187
 
175
188
  export async function startProxyServer(
@@ -178,13 +191,13 @@ export async function startProxyServer(
178
191
  globalYarnConfigPath?: string,
179
192
  port: number = 0
180
193
  ): Promise<HttpServer | HttpsServer> {
181
- const proxyConfig = await loadProxyConfig(proxyConfigPath);
182
- const registries = await loadRegistries(proxyConfigPath, localYarnConfigPath, globalYarnConfigPath);
183
- const basePathPrefixedWithSlash: string = removeEndingSlashAndForceStartingSlash(proxyConfig.basePath);
194
+ const proxyInfo = await loadProxyInfo(proxyConfigPath, localYarnConfigPath, globalYarnConfigPath);
195
+ const registries = proxyInfo.registries;
196
+ const basePathPrefixedWithSlash: string = removeEndingSlashAndForceStartingSlash(proxyInfo.basePath);
184
197
 
185
198
  console.log('Active registries:', registries.map(r => r.url));
186
199
  console.log('Proxy base path:', basePathPrefixedWithSlash);
187
- console.log('HTTPS:', !!proxyConfig.https);
200
+ console.log('HTTPS:', !!proxyInfo.https);
188
201
 
189
202
  let proxyPort: number;
190
203
 
@@ -195,7 +208,7 @@ export async function startProxyServer(
195
208
  return;
196
209
  }
197
210
 
198
- const fullUrl = new URL(req.url, `${proxyConfig.https ? 'https' : 'http'}://${req.headers.host}`);
211
+ const fullUrl = new URL(req.url, `${proxyInfo.https ? 'https' : 'http'}://${req.headers.host}`);
199
212
  console.log(`Proxy server received request on ${fullUrl.toString()}`)
200
213
  if (!fullUrl.pathname.startsWith(basePathPrefixedWithSlash)) {
201
214
  console.error(`Path ${fullUrl.pathname} does not match basePath ${basePathPrefixedWithSlash}`);
@@ -239,7 +252,7 @@ export async function startProxyServer(
239
252
  if (data.versions) {
240
253
  const requestHeadersHostFromYarnClient = req.headers.host || 'localhost:' + proxyPort;
241
254
  console.log("Request headers.host from yarn client is", requestHeadersHostFromYarnClient);
242
- const proxyBaseUrlNoSuffixedWithSlash = `${proxyConfig.https ? 'https' : 'http'}://${requestHeadersHostFromYarnClient}${basePathPrefixedWithSlash === '/' ? '' : basePathPrefixedWithSlash}`;
255
+ const proxyBaseUrlNoSuffixedWithSlash = `${proxyInfo.https ? 'https' : 'http'}://${requestHeadersHostFromYarnClient}${basePathPrefixedWithSlash === '/' ? '' : basePathPrefixedWithSlash}`;
243
256
  console.log("proxyBaseUrlNoSuffixedWithSlash", proxyBaseUrlNoSuffixedWithSlash);
244
257
  for (const version in data.versions) {
245
258
  const dist = data.versions[version]?.dist;
@@ -277,8 +290,8 @@ export async function startProxyServer(
277
290
  };
278
291
 
279
292
  let server: HttpServer | HttpsServer;
280
- if (proxyConfig.https) {
281
- const {key, cert} = proxyConfig.https;
293
+ if (proxyInfo.https) {
294
+ const {key, cert} = proxyInfo.https;
282
295
  const keyPath = resolvePath(key);
283
296
  const certPath = resolvePath(cert);
284
297
  try {
@@ -311,7 +324,7 @@ export async function startProxyServer(
311
324
  proxyPort = address.port;
312
325
  const portFile = join(process.env.PROJECT_ROOT || process.cwd(), '.registry-proxy-port');
313
326
  writeFile(portFile, proxyPort.toString()).catch(e => console.error('Failed to write port file:', e));
314
- console.log(`Proxy server running on ${proxyConfig.https ? 'https' : 'http'}://localhost:${proxyPort}${basePathPrefixedWithSlash}`);
327
+ console.log(`Proxy server running on ${proxyInfo.https ? 'https' : 'http'}://localhost:${proxyPort}${basePathPrefixedWithSlash}`);
315
328
  resolve(server);
316
329
  });
317
330
  });