com.jimuwd.xian.registry-proxy 1.0.28 → 1.0.30
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/dist/index.js +24 -21
- package/package.json +1 -1
- package/src/index.ts +33 -26
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 {
|
|
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
|
|
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
|
-
|
|
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
|
|
97
|
+
async function readYarnConfig(path) {
|
|
97
98
|
try {
|
|
98
99
|
const content = await readFile(resolvePath(path), 'utf8');
|
|
99
100
|
return load(content);
|
|
@@ -103,11 +104,11 @@ async function loadYarnConfig(path) {
|
|
|
103
104
|
return {};
|
|
104
105
|
}
|
|
105
106
|
}
|
|
106
|
-
async function
|
|
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
|
-
|
|
109
|
-
|
|
110
|
-
|
|
109
|
+
readProxyConfig(proxyConfigPath),
|
|
110
|
+
readYarnConfig(localYarnConfigPath),
|
|
111
|
+
readYarnConfig(globalYarnConfigPath)
|
|
111
112
|
]);
|
|
112
113
|
const registryMap = new Map();
|
|
113
114
|
for (const [url, regConfig] of Object.entries(proxyConfig.registries)) {
|
|
@@ -126,15 +127,18 @@ async function loadRegistries(proxyConfigPath = './.registry-proxy.yml', localYa
|
|
|
126
127
|
}
|
|
127
128
|
registryMap.set(normalizedUrl, { url: normalizedUrl, token });
|
|
128
129
|
}
|
|
129
|
-
|
|
130
|
+
const registries = Array.from(registryMap.values());
|
|
131
|
+
const https = proxyConfig.https;
|
|
132
|
+
const basePath = removeEndingSlashAndForceStartingSlash(proxyConfig.basePath);
|
|
133
|
+
return { registries, https, basePath };
|
|
130
134
|
}
|
|
131
135
|
export async function startProxyServer(proxyConfigPath, localYarnConfigPath, globalYarnConfigPath, port = 0) {
|
|
132
|
-
const
|
|
133
|
-
const registries =
|
|
134
|
-
const basePathPrefixedWithSlash =
|
|
136
|
+
const proxyInfo = await loadProxyInfo(proxyConfigPath, localYarnConfigPath, globalYarnConfigPath);
|
|
137
|
+
const registries = proxyInfo.registries;
|
|
138
|
+
const basePathPrefixedWithSlash = removeEndingSlashAndForceStartingSlash(proxyInfo.basePath);
|
|
135
139
|
console.log('Active registries:', registries.map(r => r.url));
|
|
136
140
|
console.log('Proxy base path:', basePathPrefixedWithSlash);
|
|
137
|
-
console.log('HTTPS:', !!
|
|
141
|
+
console.log('HTTPS:', !!proxyInfo.https);
|
|
138
142
|
let proxyPort;
|
|
139
143
|
const requestHandler = async (req, res) => {
|
|
140
144
|
if (!req.url || !req.headers.host) {
|
|
@@ -142,15 +146,14 @@ export async function startProxyServer(proxyConfigPath, localYarnConfigPath, glo
|
|
|
142
146
|
res.writeHead(400).end('Invalid Request');
|
|
143
147
|
return;
|
|
144
148
|
}
|
|
145
|
-
const fullUrl = new URL(req.url, `${
|
|
149
|
+
const fullUrl = new URL(req.url, `${proxyInfo.https ? 'https' : 'http'}://${req.headers.host}`);
|
|
150
|
+
console.log(`Proxy server received request on ${fullUrl.toString()}`);
|
|
146
151
|
if (!fullUrl.pathname.startsWith(basePathPrefixedWithSlash)) {
|
|
147
152
|
console.error(`Path ${fullUrl.pathname} does not match basePath ${basePathPrefixedWithSlash}`);
|
|
148
153
|
res.writeHead(404).end('Not Found');
|
|
149
154
|
return;
|
|
150
155
|
}
|
|
151
|
-
const relativePathPrefixedWithSlash = basePathPrefixedWithSlash
|
|
152
|
-
? fullUrl.pathname.slice(basePathPrefixedWithSlash.length)
|
|
153
|
-
: fullUrl.pathname;
|
|
156
|
+
const relativePathPrefixedWithSlash = basePathPrefixedWithSlash === '/' ? fullUrl.pathname : fullUrl.pathname.slice(basePathPrefixedWithSlash.length);
|
|
154
157
|
console.log(`Proxying: ${relativePathPrefixedWithSlash}`);
|
|
155
158
|
const fetchPromises = registries.map(async ({ url, token }) => {
|
|
156
159
|
await limiter.acquire();
|
|
@@ -185,7 +188,7 @@ export async function startProxyServer(proxyConfigPath, localYarnConfigPath, glo
|
|
|
185
188
|
if (data.versions) {
|
|
186
189
|
const requestHeadersHostFromYarnClient = req.headers.host || 'localhost:' + proxyPort;
|
|
187
190
|
console.log("Request headers.host from yarn client is", requestHeadersHostFromYarnClient);
|
|
188
|
-
const proxyBaseUrlNoSuffixedWithSlash = `${
|
|
191
|
+
const proxyBaseUrlNoSuffixedWithSlash = `${proxyInfo.https ? 'https' : 'http'}://${requestHeadersHostFromYarnClient}${basePathPrefixedWithSlash === '/' ? '' : basePathPrefixedWithSlash}`;
|
|
189
192
|
console.log("proxyBaseUrlNoSuffixedWithSlash", proxyBaseUrlNoSuffixedWithSlash);
|
|
190
193
|
for (const version in data.versions) {
|
|
191
194
|
const dist = data.versions[version]?.dist;
|
|
@@ -226,8 +229,8 @@ export async function startProxyServer(proxyConfigPath, localYarnConfigPath, glo
|
|
|
226
229
|
}
|
|
227
230
|
};
|
|
228
231
|
let server;
|
|
229
|
-
if (
|
|
230
|
-
const { key, cert } =
|
|
232
|
+
if (proxyInfo.https) {
|
|
233
|
+
const { key, cert } = proxyInfo.https;
|
|
231
234
|
const keyPath = resolvePath(key);
|
|
232
235
|
const certPath = resolvePath(cert);
|
|
233
236
|
try {
|
|
@@ -261,7 +264,7 @@ export async function startProxyServer(proxyConfigPath, localYarnConfigPath, glo
|
|
|
261
264
|
proxyPort = address.port;
|
|
262
265
|
const portFile = join(process.env.PROJECT_ROOT || process.cwd(), '.registry-proxy-port');
|
|
263
266
|
writeFile(portFile, proxyPort.toString()).catch(e => console.error('Failed to write port file:', e));
|
|
264
|
-
console.log(`Proxy server running on ${
|
|
267
|
+
console.log(`Proxy server running on ${proxyInfo.https ? 'https' : 'http'}://localhost:${proxyPort}${basePathPrefixedWithSlash}`);
|
|
265
268
|
resolve(server);
|
|
266
269
|
});
|
|
267
270
|
});
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {createServer, Server as HttpServer,
|
|
2
|
+
import {createServer, IncomingMessage, OutgoingHttpHeaders, Server as HttpServer, ServerResponse} from 'http';
|
|
3
3
|
import {createServer as createHttpsServer, Server as HttpsServer} from 'https';
|
|
4
|
-
import {
|
|
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
|
}
|
|
@@ -74,7 +80,7 @@ class ConcurrencyLimiter {
|
|
|
74
80
|
|
|
75
81
|
const limiter = new ConcurrencyLimiter(3);
|
|
76
82
|
|
|
77
|
-
function removeEndingSlashAndForceStartingSlash(str: string): string {
|
|
83
|
+
function removeEndingSlashAndForceStartingSlash(str: string | undefined | null): string {
|
|
78
84
|
if (!str) return '/';
|
|
79
85
|
let trimmed = str.trim();
|
|
80
86
|
if (trimmed === '/') return '/';
|
|
@@ -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
|
|
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
|
-
|
|
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
|
|
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,22 +147,20 @@ async function loadYarnConfig(path: string): Promise<YarnConfig> {
|
|
|
140
147
|
}
|
|
141
148
|
}
|
|
142
149
|
|
|
143
|
-
async function
|
|
150
|
+
async function loadProxyInfo(
|
|
144
151
|
proxyConfigPath = './.registry-proxy.yml',
|
|
145
152
|
localYarnConfigPath = './.yarnrc.yml',
|
|
146
153
|
globalYarnConfigPath = join(homedir(), '.yarnrc.yml')
|
|
147
|
-
): Promise<
|
|
154
|
+
): Promise<ProxyInfo> {
|
|
148
155
|
const [proxyConfig, localYarnConfig, globalYarnConfig] = await Promise.all([
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
156
|
+
readProxyConfig(proxyConfigPath),
|
|
157
|
+
readYarnConfig(localYarnConfigPath),
|
|
158
|
+
readYarnConfig(globalYarnConfigPath)
|
|
152
159
|
]);
|
|
153
|
-
|
|
154
160
|
const registryMap = new Map<string, RegistryInfo>();
|
|
155
161
|
for (const [url, regConfig] of Object.entries(proxyConfig.registries)) {
|
|
156
162
|
const normalizedUrl = normalizeUrl(url);
|
|
157
163
|
let token = regConfig?.npmAuthToken;
|
|
158
|
-
|
|
159
164
|
if (!token) {
|
|
160
165
|
const yarnConfigs = [localYarnConfig, globalYarnConfig];
|
|
161
166
|
for (const config of yarnConfigs) {
|
|
@@ -169,7 +174,10 @@ async function loadRegistries(
|
|
|
169
174
|
}
|
|
170
175
|
registryMap.set(normalizedUrl, {url: normalizedUrl, token});
|
|
171
176
|
}
|
|
172
|
-
|
|
177
|
+
const registries = Array.from(registryMap.values());
|
|
178
|
+
const https = proxyConfig.https;
|
|
179
|
+
const basePath = removeEndingSlashAndForceStartingSlash(proxyConfig.basePath);
|
|
180
|
+
return {registries, https, basePath};
|
|
173
181
|
}
|
|
174
182
|
|
|
175
183
|
export async function startProxyServer(
|
|
@@ -178,13 +186,13 @@ export async function startProxyServer(
|
|
|
178
186
|
globalYarnConfigPath?: string,
|
|
179
187
|
port: number = 0
|
|
180
188
|
): Promise<HttpServer | HttpsServer> {
|
|
181
|
-
const
|
|
182
|
-
const registries =
|
|
183
|
-
const basePathPrefixedWithSlash: string =
|
|
189
|
+
const proxyInfo = await loadProxyInfo(proxyConfigPath, localYarnConfigPath, globalYarnConfigPath);
|
|
190
|
+
const registries = proxyInfo.registries;
|
|
191
|
+
const basePathPrefixedWithSlash: string = removeEndingSlashAndForceStartingSlash(proxyInfo.basePath);
|
|
184
192
|
|
|
185
193
|
console.log('Active registries:', registries.map(r => r.url));
|
|
186
194
|
console.log('Proxy base path:', basePathPrefixedWithSlash);
|
|
187
|
-
console.log('HTTPS:', !!
|
|
195
|
+
console.log('HTTPS:', !!proxyInfo.https);
|
|
188
196
|
|
|
189
197
|
let proxyPort: number;
|
|
190
198
|
|
|
@@ -195,16 +203,15 @@ export async function startProxyServer(
|
|
|
195
203
|
return;
|
|
196
204
|
}
|
|
197
205
|
|
|
198
|
-
const fullUrl = new URL(req.url, `${
|
|
206
|
+
const fullUrl = new URL(req.url, `${proxyInfo.https ? 'https' : 'http'}://${req.headers.host}`);
|
|
207
|
+
console.log(`Proxy server received request on ${fullUrl.toString()}`)
|
|
199
208
|
if (!fullUrl.pathname.startsWith(basePathPrefixedWithSlash)) {
|
|
200
209
|
console.error(`Path ${fullUrl.pathname} does not match basePath ${basePathPrefixedWithSlash}`);
|
|
201
210
|
res.writeHead(404).end('Not Found');
|
|
202
211
|
return;
|
|
203
212
|
}
|
|
204
213
|
|
|
205
|
-
const relativePathPrefixedWithSlash = basePathPrefixedWithSlash
|
|
206
|
-
? fullUrl.pathname.slice(basePathPrefixedWithSlash.length)
|
|
207
|
-
: fullUrl.pathname;
|
|
214
|
+
const relativePathPrefixedWithSlash = basePathPrefixedWithSlash === '/' ? fullUrl.pathname : fullUrl.pathname.slice(basePathPrefixedWithSlash.length);
|
|
208
215
|
console.log(`Proxying: ${relativePathPrefixedWithSlash}`);
|
|
209
216
|
|
|
210
217
|
const fetchPromises = registries.map(async ({url, token}) => {
|
|
@@ -240,7 +247,7 @@ export async function startProxyServer(
|
|
|
240
247
|
if (data.versions) {
|
|
241
248
|
const requestHeadersHostFromYarnClient = req.headers.host || 'localhost:' + proxyPort;
|
|
242
249
|
console.log("Request headers.host from yarn client is", requestHeadersHostFromYarnClient);
|
|
243
|
-
const proxyBaseUrlNoSuffixedWithSlash = `${
|
|
250
|
+
const proxyBaseUrlNoSuffixedWithSlash = `${proxyInfo.https ? 'https' : 'http'}://${requestHeadersHostFromYarnClient}${basePathPrefixedWithSlash === '/' ? '' : basePathPrefixedWithSlash}`;
|
|
244
251
|
console.log("proxyBaseUrlNoSuffixedWithSlash", proxyBaseUrlNoSuffixedWithSlash);
|
|
245
252
|
for (const version in data.versions) {
|
|
246
253
|
const dist = data.versions[version]?.dist;
|
|
@@ -278,8 +285,8 @@ export async function startProxyServer(
|
|
|
278
285
|
};
|
|
279
286
|
|
|
280
287
|
let server: HttpServer | HttpsServer;
|
|
281
|
-
if (
|
|
282
|
-
const {key, cert} =
|
|
288
|
+
if (proxyInfo.https) {
|
|
289
|
+
const {key, cert} = proxyInfo.https;
|
|
283
290
|
const keyPath = resolvePath(key);
|
|
284
291
|
const certPath = resolvePath(cert);
|
|
285
292
|
try {
|
|
@@ -312,7 +319,7 @@ export async function startProxyServer(
|
|
|
312
319
|
proxyPort = address.port;
|
|
313
320
|
const portFile = join(process.env.PROJECT_ROOT || process.cwd(), '.registry-proxy-port');
|
|
314
321
|
writeFile(portFile, proxyPort.toString()).catch(e => console.error('Failed to write port file:', e));
|
|
315
|
-
console.log(`Proxy server running on ${
|
|
322
|
+
console.log(`Proxy server running on ${proxyInfo.https ? 'https' : 'http'}://localhost:${proxyPort}${basePathPrefixedWithSlash}`);
|
|
316
323
|
resolve(server);
|
|
317
324
|
});
|
|
318
325
|
});
|