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.
- package/dist/index.js +37 -28
- package/package.json +1 -1
- 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 {
|
|
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,38 +104,46 @@ 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
|
-
for (const [
|
|
114
|
-
const
|
|
115
|
-
let token =
|
|
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
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
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(
|
|
133
|
+
registryMap.set(normalizedProxiedRegUrl, { url: normalizedProxiedRegUrl, token });
|
|
128
134
|
}
|
|
129
|
-
|
|
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
|
|
133
|
-
const registries =
|
|
134
|
-
const basePathPrefixedWithSlash = removeEndingSlashAndForceStartingSlash(
|
|
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:', !!
|
|
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, `${
|
|
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 = `${
|
|
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 (
|
|
229
|
-
const { key, cert } =
|
|
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 ${
|
|
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
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
|
}
|
|
@@ -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,36 +147,42 @@ 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
|
-
for (const [
|
|
156
|
-
const
|
|
157
|
-
let token =
|
|
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
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
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(
|
|
180
|
+
registryMap.set(normalizedProxiedRegUrl, {url: normalizedProxiedRegUrl, token});
|
|
171
181
|
}
|
|
172
|
-
|
|
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
|
|
182
|
-
const registries =
|
|
183
|
-
const basePathPrefixedWithSlash: string = removeEndingSlashAndForceStartingSlash(
|
|
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:', !!
|
|
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, `${
|
|
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 = `${
|
|
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 (
|
|
281
|
-
const {key, cert} =
|
|
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 ${
|
|
327
|
+
console.log(`Proxy server running on ${proxyInfo.https ? 'https' : 'http'}://localhost:${proxyPort}${basePathPrefixedWithSlash}`);
|
|
315
328
|
resolve(server);
|
|
316
329
|
});
|
|
317
330
|
});
|