@vltpkg/registry-client 0.0.0-3 → 0.0.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/README.md +50 -53
- package/dist/esm/cache-entry.d.ts +84 -14
- package/dist/esm/cache-entry.d.ts.map +1 -1
- package/dist/esm/cache-entry.js +284 -90
- package/dist/esm/cache-entry.js.map +1 -1
- package/dist/esm/cache-revalidate.d.ts +2 -0
- package/dist/esm/cache-revalidate.d.ts.map +1 -0
- package/dist/esm/cache-revalidate.js +66 -0
- package/dist/esm/cache-revalidate.js.map +1 -0
- package/dist/esm/handle-304-response.js +1 -1
- package/dist/esm/handle-304-response.js.map +1 -1
- package/dist/esm/index.d.ts +40 -9
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +97 -54
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/otplease.d.ts.map +1 -1
- package/dist/esm/otplease.js +33 -25
- package/dist/esm/otplease.js.map +1 -1
- package/dist/esm/raw-header.d.ts +3 -3
- package/dist/esm/raw-header.d.ts.map +1 -1
- package/dist/esm/raw-header.js +12 -11
- package/dist/esm/raw-header.js.map +1 -1
- package/dist/esm/redirect.d.ts +1 -1
- package/dist/esm/redirect.d.ts.map +1 -1
- package/dist/esm/redirect.js +5 -1
- package/dist/esm/redirect.js.map +1 -1
- package/dist/esm/revalidate.d.ts +5 -0
- package/dist/esm/revalidate.d.ts.map +1 -0
- package/dist/esm/revalidate.js +55 -0
- package/dist/esm/revalidate.js.map +1 -0
- package/dist/esm/set-raw-header.d.ts +1 -1
- package/dist/esm/set-raw-header.d.ts.map +1 -1
- package/dist/esm/set-raw-header.js +6 -4
- package/dist/esm/set-raw-header.js.map +1 -1
- package/dist/esm/string-encoding.d.ts +9 -0
- package/dist/esm/string-encoding.d.ts.map +1 -0
- package/dist/esm/string-encoding.js +25 -0
- package/dist/esm/string-encoding.js.map +1 -0
- package/dist/esm/token-response.d.ts +1 -1
- package/dist/esm/token-response.d.ts.map +1 -1
- package/dist/esm/token-response.js +5 -2
- package/dist/esm/token-response.js.map +1 -1
- package/dist/esm/web-auth-challenge.d.ts +2 -2
- package/dist/esm/web-auth-challenge.d.ts.map +1 -1
- package/dist/esm/web-auth-challenge.js +13 -6
- package/dist/esm/web-auth-challenge.js.map +1 -1
- package/package.json +20 -20
package/dist/esm/index.js
CHANGED
|
@@ -1,23 +1,28 @@
|
|
|
1
1
|
import { Cache } from '@vltpkg/cache';
|
|
2
|
-
import { register } from '@vltpkg/cache-unzip';
|
|
2
|
+
import { register as cacheUnzipRegister } from '@vltpkg/cache-unzip';
|
|
3
3
|
import { error } from '@vltpkg/error-cause';
|
|
4
|
+
import { asError } from '@vltpkg/types';
|
|
5
|
+
import { logRequest } from '@vltpkg/output';
|
|
4
6
|
import { urlOpen } from '@vltpkg/url-open';
|
|
5
7
|
import { XDG } from '@vltpkg/xdg';
|
|
8
|
+
import { dirname, resolve } from 'node:path';
|
|
6
9
|
import { setTimeout } from 'node:timers/promises';
|
|
7
10
|
import { loadPackageJson } from 'package-json-from-dist';
|
|
8
11
|
import { Agent, RetryAgent } from 'undici';
|
|
9
12
|
import { addHeader } from "./add-header.js";
|
|
10
13
|
import { deleteToken, getKC, getToken, isToken, keychains, setToken, } from "./auth.js";
|
|
11
14
|
import { CacheEntry } from "./cache-entry.js";
|
|
15
|
+
import { register } from "./cache-revalidate.js";
|
|
12
16
|
import { bun, deno, node } from "./env.js";
|
|
13
17
|
import { handle304Response } from "./handle-304-response.js";
|
|
14
18
|
import { otplease } from "./otplease.js";
|
|
15
19
|
import { isRedirect, redirect } from "./redirect.js";
|
|
16
20
|
import { setCacheHeaders } from "./set-cache-headers.js";
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
20
|
-
export {
|
|
21
|
+
import { getTokenResponse } from "./token-response.js";
|
|
22
|
+
import { getWebAuthChallenge } from "./web-auth-challenge.js";
|
|
23
|
+
import { getEncondedValue } from "./string-encoding.js";
|
|
24
|
+
export { CacheEntry, deleteToken, getKC, isToken, keychains, setToken, };
|
|
25
|
+
export const isCacheableMethod = (m) => m === 'GET' || m === 'HEAD';
|
|
21
26
|
const { version } = loadPackageJson(import.meta.filename, process.env.__VLT_INTERNAL_REGISTRY_CLIENT_PACKAGE_JSON);
|
|
22
27
|
const nua = globalThis.navigator?.userAgent ??
|
|
23
28
|
(bun ? `Bun/${bun}`
|
|
@@ -45,14 +50,18 @@ export class RegistryClient {
|
|
|
45
50
|
agent;
|
|
46
51
|
cache;
|
|
47
52
|
identity;
|
|
53
|
+
staleWhileRevalidateFactor;
|
|
48
54
|
constructor(options) {
|
|
49
|
-
const { cache = xdg.cache(
|
|
55
|
+
const { cache = xdg.cache(), 'fetch-retry-factor': timeoutFactor = 2, 'fetch-retry-mintimeout': minTimeout = 0, 'fetch-retry-maxtimeout': maxTimeout = 30_000, 'fetch-retries': maxRetries = 3, identity = '', 'stale-while-revalidate-factor': staleWhileRevalidateFactor = 60, } = options;
|
|
50
56
|
this.identity = identity;
|
|
57
|
+
this.staleWhileRevalidateFactor = staleWhileRevalidateFactor;
|
|
58
|
+
const path = resolve(cache, 'registry-client');
|
|
51
59
|
this.cache = new Cache({
|
|
52
|
-
path
|
|
60
|
+
path,
|
|
53
61
|
onDiskWrite(_path, key, data) {
|
|
54
|
-
if (CacheEntry.
|
|
55
|
-
|
|
62
|
+
if (CacheEntry.isGzipEntry(data)) {
|
|
63
|
+
cacheUnzipRegister(path, key);
|
|
64
|
+
}
|
|
56
65
|
},
|
|
57
66
|
});
|
|
58
67
|
const dispatch = new Agent(agentOptions);
|
|
@@ -103,11 +112,11 @@ export class RegistryClient {
|
|
|
103
112
|
const s = tok.replace(/^(Bearer|Basic) /i, '');
|
|
104
113
|
const tokensUrl = new URL('-/npm/v1/tokens', registry);
|
|
105
114
|
const record = await this.seek(tokensUrl, ({ token }) => s.startsWith(token), {
|
|
106
|
-
|
|
115
|
+
useCache: false,
|
|
107
116
|
}).catch(() => undefined);
|
|
108
117
|
if (record) {
|
|
109
118
|
const { key } = record;
|
|
110
|
-
await this.request(new URL(`-/npm/v1/tokens/token/${key}`, registry), {
|
|
119
|
+
await this.request(new URL(`-/npm/v1/tokens/token/${key}`, registry), { useCache: false, method: 'DELETE' });
|
|
111
120
|
}
|
|
112
121
|
await deleteToken(registry, this.identity);
|
|
113
122
|
}
|
|
@@ -120,15 +129,15 @@ export class RegistryClient {
|
|
|
120
129
|
async login(registry) {
|
|
121
130
|
// - make POST to '/-/v1/login'
|
|
122
131
|
// - include a body of {} and npm-auth-type:web
|
|
123
|
-
// - get a {doneUrl,
|
|
124
|
-
// - open the
|
|
132
|
+
// - get a {doneUrl, authUrl}
|
|
133
|
+
// - open the authUrl
|
|
125
134
|
// - hang on the doneUrl until done
|
|
126
135
|
//
|
|
127
136
|
// if that fails: fall back to couchdb login
|
|
128
137
|
const webLoginURL = new URL('-/v1/login', registry);
|
|
129
138
|
const response = await this.request(webLoginURL, {
|
|
130
139
|
method: 'POST',
|
|
131
|
-
|
|
140
|
+
useCache: false,
|
|
132
141
|
headers: {
|
|
133
142
|
'content-type': 'application/json',
|
|
134
143
|
'npm-auth-type': 'web',
|
|
@@ -136,8 +145,8 @@ export class RegistryClient {
|
|
|
136
145
|
body: '{}',
|
|
137
146
|
});
|
|
138
147
|
if (response.statusCode === 200) {
|
|
139
|
-
const challenge = response.json();
|
|
140
|
-
if (
|
|
148
|
+
const challenge = getWebAuthChallenge(response.json());
|
|
149
|
+
if (challenge) {
|
|
141
150
|
const result = await this.webAuthOpener(challenge);
|
|
142
151
|
await setToken(registry, `Bearer ${result.token}`, this.identity);
|
|
143
152
|
return;
|
|
@@ -149,10 +158,10 @@ export class RegistryClient {
|
|
|
149
158
|
}
|
|
150
159
|
/* c8 ignore stop */
|
|
151
160
|
/**
|
|
152
|
-
* Given a {@link WebAuthChallenge}, open the `
|
|
161
|
+
* Given a {@link WebAuthChallenge}, open the `authUrl` in a browser and
|
|
153
162
|
* hang on the `doneUrl` until it returns a {@link TokenResponse} object.
|
|
154
163
|
*/
|
|
155
|
-
async webAuthOpener({ doneUrl,
|
|
164
|
+
async webAuthOpener({ doneUrl, authUrl }) {
|
|
156
165
|
const ac = new AbortController();
|
|
157
166
|
const { signal } = ac;
|
|
158
167
|
/* c8 ignore start - race condition */
|
|
@@ -161,8 +170,8 @@ export class RegistryClient {
|
|
|
161
170
|
ac.abort();
|
|
162
171
|
return result;
|
|
163
172
|
}),
|
|
164
|
-
urlOpen(
|
|
165
|
-
if (er.name === 'AbortError')
|
|
173
|
+
urlOpen(authUrl, { signal }).catch((er) => {
|
|
174
|
+
if (asError(er).name === 'AbortError')
|
|
166
175
|
return;
|
|
167
176
|
ac.abort();
|
|
168
177
|
throw er;
|
|
@@ -174,21 +183,21 @@ export class RegistryClient {
|
|
|
174
183
|
async #checkLogin(url, options = {}) {
|
|
175
184
|
const response = await this.request(url, {
|
|
176
185
|
...options,
|
|
177
|
-
|
|
186
|
+
useCache: false,
|
|
178
187
|
});
|
|
179
188
|
const { signal } = options;
|
|
180
189
|
if (response.statusCode === 202) {
|
|
181
|
-
const rt = response.
|
|
182
|
-
const retryAfter = rt ? Number(rt
|
|
190
|
+
const rt = response.getHeaderString('retry-after');
|
|
191
|
+
const retryAfter = rt ? Number(rt) : -1;
|
|
183
192
|
if (retryAfter > 0) {
|
|
184
193
|
await setTimeout(retryAfter * 1000, null, { signal });
|
|
185
194
|
}
|
|
186
195
|
return await this.#checkLogin(url, options);
|
|
187
196
|
}
|
|
188
197
|
if (response.statusCode === 200) {
|
|
189
|
-
const
|
|
190
|
-
if (
|
|
191
|
-
return
|
|
198
|
+
const token = getTokenResponse(response.json());
|
|
199
|
+
if (token)
|
|
200
|
+
return token;
|
|
192
201
|
}
|
|
193
202
|
throw error('Invalid response from web login endpoint', {
|
|
194
203
|
response,
|
|
@@ -197,22 +206,27 @@ export class RegistryClient {
|
|
|
197
206
|
async request(url, options = {}) {
|
|
198
207
|
logRequest(url, 'start');
|
|
199
208
|
const u = typeof url === 'string' ? new URL(url) : url;
|
|
200
|
-
const { method = 'GET', integrity, redirections = new Set(), signal, otp = (process.env.VLT_OTP ?? '').trim(), } = options;
|
|
201
|
-
|
|
209
|
+
const { method = 'GET', integrity, redirections = new Set(), signal, otp = (process.env.VLT_OTP ?? '').trim(), staleWhileRevalidate = true, } = options;
|
|
210
|
+
let { trustIntegrity } = options;
|
|
211
|
+
const m = isCacheableMethod(method) ? method : undefined;
|
|
212
|
+
const { useCache = !!m } = options;
|
|
202
213
|
signal?.throwIfAborted();
|
|
203
214
|
// first, try to get from the cache before making any request.
|
|
204
|
-
const { origin
|
|
205
|
-
const key =
|
|
206
|
-
const buffer =
|
|
215
|
+
const { origin } = u;
|
|
216
|
+
const key = `${method !== 'GET' ? method + ' ' : ''}${u}`;
|
|
217
|
+
const buffer = useCache ?
|
|
207
218
|
await this.cache.fetch(key, { context: { integrity } })
|
|
208
219
|
: undefined;
|
|
209
220
|
const entry = buffer ? CacheEntry.decode(buffer) : undefined;
|
|
210
|
-
if (entry?.valid)
|
|
221
|
+
if (entry?.valid) {
|
|
222
|
+
return entry;
|
|
223
|
+
}
|
|
224
|
+
if (staleWhileRevalidate && entry?.staleWhileRevalidate && m) {
|
|
225
|
+
// revalidate while returning the stale entry
|
|
226
|
+
register(dirname(this.cache.path()), m, url);
|
|
211
227
|
return entry;
|
|
212
|
-
|
|
213
|
-
//
|
|
214
|
-
// in the background without waiting for it.
|
|
215
|
-
// either no cache entry, or need to revalidate it.
|
|
228
|
+
}
|
|
229
|
+
// either no cache entry, or need to revalidate before use.
|
|
216
230
|
setCacheHeaders(options, entry);
|
|
217
231
|
redirections.add(String(url));
|
|
218
232
|
Object.assign(options, {
|
|
@@ -224,12 +238,41 @@ export class RegistryClient {
|
|
|
224
238
|
if (otp) {
|
|
225
239
|
options.headers = addHeader(options.headers, 'npm-otp', otp);
|
|
226
240
|
}
|
|
241
|
+
if (integrity) {
|
|
242
|
+
options.headers = addHeader(options.headers, 'accept-integrity', integrity);
|
|
243
|
+
}
|
|
227
244
|
options.method = options.method ?? 'GET';
|
|
228
245
|
// will remove if we don't have a token.
|
|
229
246
|
options.headers = addHeader(options.headers, 'authorization', await getToken(origin, this.identity));
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
this.
|
|
247
|
+
let response = null;
|
|
248
|
+
try {
|
|
249
|
+
response = await this.agent.request(options);
|
|
250
|
+
/* c8 ignore start */
|
|
251
|
+
}
|
|
252
|
+
catch (er) {
|
|
253
|
+
// Rethrow so we get a better stack trace
|
|
254
|
+
throw error('Request failed', {
|
|
255
|
+
code: 'EREQUEST',
|
|
256
|
+
cause: er,
|
|
257
|
+
url,
|
|
258
|
+
method,
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
/* c8 ignore stop */
|
|
262
|
+
const result = await this.#handleResponse(u, options, response, entry);
|
|
263
|
+
if (result.getHeader('integrity')) {
|
|
264
|
+
trustIntegrity = true;
|
|
265
|
+
}
|
|
266
|
+
if (result.isGzip && !trustIntegrity) {
|
|
267
|
+
result.checkIntegrity({ url });
|
|
268
|
+
}
|
|
269
|
+
if (useCache) {
|
|
270
|
+
// Get the encoded buffer from the cache entry
|
|
271
|
+
const buffer = result.encode();
|
|
272
|
+
this.cache.set(key, Buffer.from(buffer.buffer, buffer.byteOffset, buffer.byteLength), {
|
|
273
|
+
integrity: result.integrity,
|
|
274
|
+
});
|
|
275
|
+
}
|
|
233
276
|
return result;
|
|
234
277
|
}
|
|
235
278
|
async #handleResponse(url, options, response, entry) {
|
|
@@ -244,31 +287,31 @@ export class RegistryClient {
|
|
|
244
287
|
for (const [key, value] of Object.entries(response.headers)) {
|
|
245
288
|
/* c8 ignore start - theoretical */
|
|
246
289
|
if (Array.isArray(value)) {
|
|
247
|
-
h.push(
|
|
290
|
+
h.push(getEncondedValue(key), getEncondedValue(value.join(', ')));
|
|
248
291
|
/* c8 ignore stop */
|
|
249
292
|
}
|
|
250
293
|
else if (typeof value === 'string') {
|
|
251
|
-
h.push(
|
|
294
|
+
h.push(getEncondedValue(key), getEncondedValue(value));
|
|
252
295
|
}
|
|
253
296
|
}
|
|
297
|
+
const { integrity, trustIntegrity } = options;
|
|
254
298
|
const result = new CacheEntry(
|
|
255
299
|
/* c8 ignore next - should always have a status code */
|
|
256
|
-
response.statusCode || 200, h,
|
|
300
|
+
response.statusCode || 200, h, {
|
|
301
|
+
integrity,
|
|
302
|
+
trustIntegrity,
|
|
303
|
+
'stale-while-revalidate-factor': this.staleWhileRevalidateFactor,
|
|
304
|
+
contentLength: response.headers['content-length'] ?
|
|
305
|
+
Number(response.headers['content-length'])
|
|
306
|
+
: /* c8 ignore next */ undefined,
|
|
307
|
+
});
|
|
257
308
|
if (isRedirect(result)) {
|
|
258
309
|
response.body.resume();
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
if (nextOptions && nextURL) {
|
|
263
|
-
return await this.request(nextURL, nextOptions);
|
|
264
|
-
}
|
|
265
|
-
return result;
|
|
266
|
-
}
|
|
267
|
-
catch (er) {
|
|
268
|
-
/* c8 ignore start */
|
|
269
|
-
throw er instanceof Error ? er : (new Error(typeof er === 'string' ? er : 'Unknown error'));
|
|
270
|
-
/* c8 ignore stop */
|
|
310
|
+
const [nextURL, nextOptions] = redirect(options, result, url);
|
|
311
|
+
if (nextOptions && nextURL) {
|
|
312
|
+
return await this.request(nextURL, nextOptions);
|
|
271
313
|
}
|
|
314
|
+
return result;
|
|
272
315
|
}
|
|
273
316
|
response.body.on('data', (chunk) => result.addBody(chunk));
|
|
274
317
|
return await new Promise((res, rej) => {
|
package/dist/esm/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["import { Cache } from '@vltpkg/cache'\nimport { register } from '@vltpkg/cache-unzip'\nimport { error } from '@vltpkg/error-cause'\nimport type { Integrity } from '@vltpkg/types'\nimport { urlOpen } from '@vltpkg/url-open'\nimport { XDG } from '@vltpkg/xdg'\nimport { setTimeout } from 'node:timers/promises'\nimport { loadPackageJson } from 'package-json-from-dist'\nimport { Agent, RetryAgent } from 'undici'\nimport type { Dispatcher } from 'undici'\nimport { addHeader } from './add-header.ts'\nimport {\n deleteToken,\n getKC,\n getToken,\n isToken,\n keychains,\n setToken,\n} from './auth.ts'\nimport type { Token } from './auth.ts'\nimport { CacheEntry } from './cache-entry.ts'\nimport type { JSONObj } from './cache-entry.ts'\nimport { bun, deno, node } from './env.ts'\nimport { handle304Response } from './handle-304-response.ts'\nimport { otplease } from './otplease.ts'\nimport { isRedirect, redirect } from './redirect.ts'\nimport { setCacheHeaders } from './set-cache-headers.ts'\nimport { logRequest } from '@vltpkg/output'\nimport { isTokenResponse } from './token-response.ts'\nimport type { TokenResponse } from './token-response.ts'\nimport { isWebAuthChallenge } from './web-auth-challenge.ts'\nimport type { WebAuthChallenge } from './web-auth-challenge.ts'\nexport {\n type JSONObj,\n type CacheEntry,\n type Token,\n type WebAuthChallenge,\n type TokenResponse,\n}\nexport { keychains, getKC, setToken, deleteToken, isToken }\n\nexport type RegistryClientOptions = {\n /**\n * Path on disk where the cache should be stored\n * @default `$HOME/.config/vlt/cache`\n */\n cache?: string\n /**\n * Number of retries to perform when encountering network errors or\n * likely-transient errors from git hosts.\n */\n 'fetch-retries'?: number\n /** The exponential backoff factor to use when retrying git hosts */\n 'fetch-retry-factor'?: number\n /** Number of milliseconds before starting first retry */\n 'fetch-retry-mintimeout'?: number\n /** Maximum number of milliseconds between two retries */\n 'fetch-retry-maxtimeout'?: number\n\n /** the identity to use for storing auth tokens */\n identity?: string\n}\n\nexport type RegistryClientRequestOptions = Omit<\n Dispatcher.RequestOptions,\n 'method' | 'path'\n> & {\n /**\n * `path` should not be set when using the RegistryClient.\n * It will be overwritten with the path on the URL being requested.\n * This only here for compliance with the DispatchOptions base type.\n * @deprecated\n */\n path?: string\n\n /**\n * Method is optional, defaults to 'GET'\n */\n method?: Dispatcher.DispatchOptions['method']\n /**\n * Provide an SRI string to verify integrity of the item being fetched.\n *\n * This is only relevant when it must make a request to the registry. Once in\n * the local disk cache, items are assumed to be trustworthy.\n */\n integrity?: Integrity\n\n /**\n * Follow up to 10 redirections by default. Set this to 0 to just return\n * the 3xx response. If the max redirections are expired, and we still get\n * a redirection response, then fail the request. Redirection cycles are\n * always treated as an error.\n */\n maxRedirections?: number\n\n /**\n * the number of redirections that have already been seen. This is used\n * internally, and should always start at 0.\n * @internal\n */\n redirections?: Set<string>\n\n /**\n * Set to `false` to suppress ANY lookups from cache. This will also\n * prevent storing the result to the cache.\n */\n cache?: false\n\n /**\n * Set to pass an `npm-otp` header on the request.\n *\n * This should not be set except by the RegistryClient itself, when\n * we receive a 401 response with an OTP challenge.\n * @internal\n */\n otp?: string\n}\n\nconst { version } = loadPackageJson(\n import.meta.filename,\n process.env.__VLT_INTERNAL_REGISTRY_CLIENT_PACKAGE_JSON,\n) as {\n version: string\n}\nconst nua =\n (globalThis.navigator as Navigator | undefined)?.userAgent ??\n (bun ? `Bun/${bun}`\n : deno ? `Deno/${deno}`\n : node ? `Node.js/${node}`\n : '(unknown platform)')\nexport const userAgent = `@vltpkg/registry-client/${version} ${nua}`\n\nconst agentOptions: Agent.Options = {\n bodyTimeout: 600_000,\n headersTimeout: 600_000,\n keepAliveMaxTimeout: 1_200_000,\n keepAliveTimeout: 600_000,\n keepAliveTimeoutThreshold: 30_000,\n connect: {\n timeout: 600_000,\n keepAlive: true,\n keepAliveInitialDelay: 30_000,\n sessionTimeout: 600,\n },\n connections: 128,\n pipelining: 10,\n}\n\nconst xdg = new XDG('vlt')\n\nexport class RegistryClient {\n agent: RetryAgent\n cache: Cache\n identity: string\n\n constructor(options: RegistryClientOptions) {\n const {\n cache = xdg.cache('registry-client'),\n 'fetch-retry-factor': timeoutFactor = 2,\n 'fetch-retry-mintimeout': minTimeout = 0,\n 'fetch-retry-maxtimeout': maxTimeout = 30_000,\n 'fetch-retries': maxRetries = 3,\n identity = '',\n } = options\n this.identity = identity\n this.cache = new Cache({\n path: cache,\n onDiskWrite(_path, key, data) {\n if (CacheEntry.decode(data).isGzip) register(cache, key)\n },\n })\n const dispatch = new Agent(agentOptions)\n this.agent = new RetryAgent(dispatch, {\n maxRetries,\n timeoutFactor,\n minTimeout,\n maxTimeout,\n retryAfter: true,\n errorCodes: [\n 'ECONNREFUSED',\n 'ECONNRESET',\n 'EHOSTDOWN',\n 'ENETDOWN',\n 'ENETUNREACH',\n 'ENOTFOUND',\n 'EPIPE',\n 'UND_ERR_SOCKET',\n ],\n })\n }\n\n /**\n * Fetch the entire set of a paginated list of objects\n */\n async scroll<T>(\n url: URL | string,\n options: RegistryClientRequestOptions = {},\n seek?: (obj: T) => boolean,\n ): Promise<T[]> {\n const resp = await this.request(url, options)\n const { objects, urls } = resp.json() as {\n objects: T[]\n urls: { next?: string }\n }\n // if we have more, and haven't found our target, fetch more\n return urls.next && !(seek && objects.some(seek)) ?\n objects.concat(await this.scroll<T>(urls.next, options, seek))\n : objects\n }\n\n /**\n * find a given item in a paginated set\n */\n async seek<T>(\n url: URL | string,\n seek: (obj: T) => boolean,\n options: RegistryClientRequestOptions = {},\n ): Promise<T | undefined> {\n return (await this.scroll(url, options, seek)).find(seek)\n }\n\n /**\n * Log out from the registry specified, attempting to destroy the\n * token if the registry supports that endpoint.\n */\n async logout(registry: string) {\n // if we have no token for that registry, nothing to do\n const tok = await getToken(registry, this.identity)\n if (!tok) return\n\n const s = tok.replace(/^(Bearer|Basic) /i, '')\n\n const tokensUrl = new URL('-/npm/v1/tokens', registry)\n const record = await this.seek<{\n key: string\n token: string\n }>(tokensUrl, ({ token }) => s.startsWith(token), {\n cache: false,\n }).catch(() => undefined)\n\n if (record) {\n const { key } = record\n await this.request(\n new URL(`-/npm/v1/tokens/token/${key}`, registry),\n { cache: false, method: 'DELETE' },\n )\n }\n\n await deleteToken(registry, this.identity)\n }\n\n /**\n * Log into the registry specified\n *\n * Does not return the token or expose it, just saves to the auth keychain\n * and returns void if it worked. Otherwise, error is raised.\n */\n async login(registry: string) {\n // - make POST to '/-/v1/login'\n // - include a body of {} and npm-auth-type:web\n // - get a {doneUrl, loginUrl}\n // - open the loginUrl\n // - hang on the doneUrl until done\n //\n // if that fails: fall back to couchdb login\n const webLoginURL = new URL('-/v1/login', registry)\n const response = await this.request(webLoginURL, {\n method: 'POST',\n cache: false,\n headers: {\n 'content-type': 'application/json',\n 'npm-auth-type': 'web',\n },\n body: '{}',\n })\n\n if (response.statusCode === 200) {\n const challenge = response.json()\n if (isWebAuthChallenge(challenge)) {\n const result = await this.webAuthOpener(challenge)\n await setToken(\n registry,\n `Bearer ${result.token}`,\n this.identity,\n )\n return\n }\n }\n /* c8 ignore start */\n // TODO: fall back to username/password login, and/or couchdb PUT login\n throw error('Failed to perform web login', { response })\n }\n /* c8 ignore stop */\n\n /**\n * Given a {@link WebAuthChallenge}, open the `loginUrl` in a browser and\n * hang on the `doneUrl` until it returns a {@link TokenResponse} object.\n */\n async webAuthOpener({ doneUrl, loginUrl }: WebAuthChallenge) {\n const ac = new AbortController()\n const { signal } = ac\n /* c8 ignore start - race condition */\n const [result] = await Promise.all([\n this.#checkLogin(doneUrl, { signal }).then(result => {\n ac.abort()\n return result\n }),\n urlOpen(loginUrl, { signal }).catch((er: unknown) => {\n if ((er as Error).name === 'AbortError') return\n ac.abort()\n throw er\n }),\n ])\n /* c8 ignore stop */\n return result\n }\n\n async #checkLogin(\n url: URL | string,\n options: RegistryClientRequestOptions = {},\n ): Promise<TokenResponse> {\n const response = await this.request(url, {\n ...options,\n cache: false,\n })\n const { signal } = options as { signal?: AbortSignal }\n if (response.statusCode === 202) {\n const rt = response.getHeader('retry-after')\n const retryAfter = rt ? Number(rt.toString()) : -1\n if (retryAfter > 0) {\n await setTimeout(retryAfter * 1000, null, { signal })\n }\n return await this.#checkLogin(url, options)\n }\n if (response.statusCode === 200) {\n const body = response.json()\n if (isTokenResponse(body)) return body\n }\n throw error('Invalid response from web login endpoint', {\n response,\n })\n }\n\n async request(\n url: URL | string,\n options: RegistryClientRequestOptions = {},\n ): Promise<CacheEntry> {\n logRequest(url, 'start')\n\n const u = typeof url === 'string' ? new URL(url) : url\n const {\n method = 'GET',\n integrity,\n redirections = new Set(),\n signal,\n otp = (process.env.VLT_OTP ?? '').trim(),\n } = options\n\n const { cache = method === 'GET' || method === 'HEAD' } = options\n\n ;(signal as AbortSignal | null)?.throwIfAborted()\n\n // first, try to get from the cache before making any request.\n const { origin, pathname } = u\n const key = JSON.stringify([origin, method, pathname])\n const buffer =\n cache ?\n await this.cache.fetch(key, { context: { integrity } })\n : undefined\n\n const entry = buffer ? CacheEntry.decode(buffer) : undefined\n if (entry?.valid) return entry\n // TODO: stale-while-revalidate timeout, say 1 day, where we'll\n // use the cached response even if it's invalid, and validate\n // in the background without waiting for it.\n\n // either no cache entry, or need to revalidate it.\n setCacheHeaders(options, entry)\n\n redirections.add(String(url))\n\n Object.assign(options, {\n path: u.pathname.replace(/\\/+$/, '') + u.search,\n ...agentOptions,\n })\n\n options.origin = u.origin\n options.headers = addHeader(\n addHeader(\n options.headers,\n 'accept-encoding',\n 'gzip;q=1.0, identity;q=0.5',\n ),\n 'user-agent',\n userAgent,\n )\n if (otp) {\n options.headers = addHeader(options.headers, 'npm-otp', otp)\n }\n options.method = options.method ?? 'GET'\n\n // will remove if we don't have a token.\n options.headers = addHeader(\n options.headers,\n 'authorization',\n await getToken(origin, this.identity),\n )\n\n const result = await this.#handleResponse(\n u,\n options,\n await this.agent.request(options as Dispatcher.RequestOptions),\n entry,\n )\n\n if (cache) this.cache.set(key, result.encode())\n return result\n }\n\n async #handleResponse(\n url: URL,\n options: RegistryClientRequestOptions,\n response: Dispatcher.ResponseData,\n entry?: CacheEntry,\n ): Promise<CacheEntry> {\n if (handle304Response(response, entry)) return entry\n\n if (response.statusCode === 401) {\n const repeatRequest = await otplease(this, options, response)\n if (repeatRequest) return await this.request(url, repeatRequest)\n }\n\n const h: Buffer[] = []\n for (const [key, value] of Object.entries(response.headers)) {\n /* c8 ignore start - theoretical */\n if (Array.isArray(value)) {\n h.push(Buffer.from(key), Buffer.from(value.join(', ')))\n /* c8 ignore stop */\n } else if (typeof value === 'string') {\n h.push(Buffer.from(key), Buffer.from(value))\n }\n }\n\n const result = new CacheEntry(\n /* c8 ignore next - should always have a status code */\n response.statusCode || 200,\n h,\n options.integrity,\n )\n\n if (isRedirect(result)) {\n response.body.resume()\n // remove the try/catch once rebasing onto main with Luke's error-cause stuff\n try {\n const [nextURL, nextOptions] = redirect(options, result, url)\n if (nextOptions && nextURL) {\n return await this.request(nextURL, nextOptions)\n }\n return result\n } catch (er) {\n /* c8 ignore start */\n throw er instanceof Error ? er : (\n new Error(typeof er === 'string' ? er : 'Unknown error')\n )\n /* c8 ignore stop */\n }\n }\n\n response.body.on('data', (chunk: Buffer) => result.addBody(chunk))\n return await new Promise<CacheEntry>((res, rej) => {\n response.body.on('error', rej)\n response.body.on('end', () => res(result))\n })\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["import { Cache } from '@vltpkg/cache'\nimport { register as cacheUnzipRegister } from '@vltpkg/cache-unzip'\nimport { error } from '@vltpkg/error-cause'\nimport { asError } from '@vltpkg/types'\nimport { logRequest } from '@vltpkg/output'\nimport type { Integrity } from '@vltpkg/types'\nimport { urlOpen } from '@vltpkg/url-open'\nimport { XDG } from '@vltpkg/xdg'\nimport { dirname, resolve } from 'node:path'\nimport { setTimeout } from 'node:timers/promises'\nimport { loadPackageJson } from 'package-json-from-dist'\nimport type { Dispatcher } from 'undici'\nimport { Agent, RetryAgent } from 'undici'\nimport { addHeader } from './add-header.ts'\nimport type { Token } from './auth.ts'\nimport {\n deleteToken,\n getKC,\n getToken,\n isToken,\n keychains,\n setToken,\n} from './auth.ts'\nimport type { JSONObj } from './cache-entry.ts'\nimport { CacheEntry } from './cache-entry.ts'\nimport { register } from './cache-revalidate.ts'\nimport { bun, deno, node } from './env.ts'\nimport { handle304Response } from './handle-304-response.ts'\nimport { otplease } from './otplease.ts'\nimport { isRedirect, redirect } from './redirect.ts'\nimport { setCacheHeaders } from './set-cache-headers.ts'\nimport type { TokenResponse } from './token-response.ts'\nimport { getTokenResponse } from './token-response.ts'\nimport type { WebAuthChallenge } from './web-auth-challenge.ts'\nimport { getWebAuthChallenge } from './web-auth-challenge.ts'\nimport { getEncondedValue } from './string-encoding.ts'\nexport {\n CacheEntry,\n deleteToken,\n getKC,\n isToken,\n keychains,\n setToken,\n type JSONObj,\n type Token,\n type TokenResponse,\n type WebAuthChallenge,\n}\n\nexport type CacheableMethod = 'GET' | 'HEAD'\nexport const isCacheableMethod = (m: unknown): m is CacheableMethod =>\n m === 'GET' || m === 'HEAD'\n\nexport type RegistryClientOptions = {\n /**\n * Path on disk where the cache should be stored\n *\n * Defaults to the XDG cache folder for `vlt/registry-client`\n */\n cache?: string\n /**\n * Number of retries to perform when encountering network errors or\n * likely-transient errors from git hosts.\n */\n 'fetch-retries'?: number\n /** The exponential backoff factor to use when retrying git hosts */\n 'fetch-retry-factor'?: number\n /** Number of milliseconds before starting first retry */\n 'fetch-retry-mintimeout'?: number\n /** Maximum number of milliseconds between two retries */\n 'fetch-retry-maxtimeout'?: number\n\n /** the identity to use for storing auth tokens */\n identity?: string\n\n /**\n * If the server does not serve a `stale-while-revalidate` value in the\n * `cache-control` header, then this multiplier is applied to the `max-age`\n * or `s-maxage` values.\n *\n * By default, this is `60`, so for example a response that is cacheable for\n * 5 minutes will allow a stale response while revalidating for up to 5\n * hours.\n *\n * If the server *does* provide a `stale-while-revalidate` value, then that\n * is always used.\n *\n * Set to 0 to prevent any `stale-while-revalidate` behavior unless\n * explicitly allowed by the server's `cache-control` header.\n */\n 'stale-while-revalidate-factor'?: number\n}\n\nexport type RegistryClientRequestOptions = Omit<\n Dispatcher.RequestOptions,\n 'method' | 'path'\n> & {\n /**\n * `path` should not be set when using the RegistryClient.\n * It will be overwritten with the path on the URL being requested.\n * This only here for compliance with the DispatchOptions base type.\n * @deprecated\n */\n path?: string\n\n /**\n * Method is optional, defaults to 'GET'\n */\n method?: Dispatcher.DispatchOptions['method']\n /**\n * Provide an SRI string to verify integrity of the item being fetched.\n *\n * This is only relevant when it must make a request to the registry. Once in\n * the local disk cache, items are assumed to be trustworthy.\n */\n integrity?: Integrity\n\n /**\n * Set to true if the integrity should be trusted implicitly without\n * a recalculation, for example if it comes from a trusted registry that\n * also serves the tarball itself.\n */\n trustIntegrity?: boolean\n\n /**\n * Follow up to 10 redirections by default. Set this to 0 to just return\n * the 3xx response. If the max redirections are expired, and we still get\n * a redirection response, then fail the request. Redirection cycles are\n * always treated as an error.\n */\n maxRedirections?: number\n\n /**\n * the number of redirections that have already been seen. This is used\n * internally, and should always start at 0.\n * @internal\n */\n redirections?: Set<string>\n\n /**\n * Set to `false` to suppress ANY lookups from cache. This will also\n * prevent storing the result to the cache.\n */\n useCache?: false\n\n /**\n * Set to pass an `npm-otp` header on the request.\n *\n * This should not be set except by the RegistryClient itself, when\n * we receive a 401 response with an OTP challenge.\n * @internal\n */\n otp?: string\n\n /**\n * Set to false to explicitly prevent `stale-while-revalidate` behavior,\n * for use in revalidating while stale.\n * @internal\n */\n staleWhileRevalidate?: false\n}\n\nconst { version } = loadPackageJson(\n import.meta.filename,\n process.env.__VLT_INTERNAL_REGISTRY_CLIENT_PACKAGE_JSON,\n) as {\n version: string\n}\n\nconst nua =\n (globalThis.navigator as Navigator | undefined)?.userAgent ??\n (bun ? `Bun/${bun}`\n : deno ? `Deno/${deno}`\n : node ? `Node.js/${node}`\n : '(unknown platform)')\n\nexport const userAgent = `@vltpkg/registry-client/${version} ${nua}`\n\nconst agentOptions: Agent.Options = {\n bodyTimeout: 600_000,\n headersTimeout: 600_000,\n keepAliveMaxTimeout: 1_200_000,\n keepAliveTimeout: 600_000,\n keepAliveTimeoutThreshold: 30_000,\n connect: {\n timeout: 600_000,\n keepAlive: true,\n keepAliveInitialDelay: 30_000,\n sessionTimeout: 600,\n },\n connections: 128,\n pipelining: 10,\n}\n\nconst xdg = new XDG('vlt')\n\nexport class RegistryClient {\n agent: RetryAgent\n cache: Cache\n identity: string\n staleWhileRevalidateFactor: number\n\n constructor(options: RegistryClientOptions) {\n const {\n cache = xdg.cache(),\n 'fetch-retry-factor': timeoutFactor = 2,\n 'fetch-retry-mintimeout': minTimeout = 0,\n 'fetch-retry-maxtimeout': maxTimeout = 30_000,\n 'fetch-retries': maxRetries = 3,\n identity = '',\n 'stale-while-revalidate-factor':\n staleWhileRevalidateFactor = 60,\n } = options\n this.identity = identity\n this.staleWhileRevalidateFactor = staleWhileRevalidateFactor\n const path = resolve(cache, 'registry-client')\n this.cache = new Cache({\n path,\n onDiskWrite(_path, key, data) {\n if (CacheEntry.isGzipEntry(data)) {\n cacheUnzipRegister(path, key)\n }\n },\n })\n const dispatch = new Agent(agentOptions)\n this.agent = new RetryAgent(dispatch, {\n maxRetries,\n timeoutFactor,\n minTimeout,\n maxTimeout,\n retryAfter: true,\n errorCodes: [\n 'ECONNREFUSED',\n 'ECONNRESET',\n 'EHOSTDOWN',\n 'ENETDOWN',\n 'ENETUNREACH',\n 'ENOTFOUND',\n 'EPIPE',\n 'UND_ERR_SOCKET',\n ],\n })\n }\n\n /**\n * Fetch the entire set of a paginated list of objects\n */\n async scroll<T>(\n url: URL | string,\n options: RegistryClientRequestOptions = {},\n seek?: (obj: T) => boolean,\n ): Promise<T[]> {\n const resp = await this.request(url, options)\n const { objects, urls } = resp.json() as {\n objects: T[]\n urls: { next?: string }\n }\n // if we have more, and haven't found our target, fetch more\n return urls.next && !(seek && objects.some(seek)) ?\n objects.concat(await this.scroll<T>(urls.next, options, seek))\n : objects\n }\n\n /**\n * find a given item in a paginated set\n */\n async seek<T>(\n url: URL | string,\n seek: (obj: T) => boolean,\n options: RegistryClientRequestOptions = {},\n ): Promise<T | undefined> {\n return (await this.scroll(url, options, seek)).find(seek)\n }\n\n /**\n * Log out from the registry specified, attempting to destroy the\n * token if the registry supports that endpoint.\n */\n async logout(registry: string) {\n // if we have no token for that registry, nothing to do\n const tok = await getToken(registry, this.identity)\n if (!tok) return\n\n const s = tok.replace(/^(Bearer|Basic) /i, '')\n\n const tokensUrl = new URL('-/npm/v1/tokens', registry)\n const record = await this.seek<{\n key: string\n token: string\n }>(tokensUrl, ({ token }) => s.startsWith(token), {\n useCache: false,\n }).catch(() => undefined)\n\n if (record) {\n const { key } = record\n await this.request(\n new URL(`-/npm/v1/tokens/token/${key}`, registry),\n { useCache: false, method: 'DELETE' },\n )\n }\n\n await deleteToken(registry, this.identity)\n }\n\n /**\n * Log into the registry specified\n *\n * Does not return the token or expose it, just saves to the auth keychain\n * and returns void if it worked. Otherwise, error is raised.\n */\n async login(registry: string) {\n // - make POST to '/-/v1/login'\n // - include a body of {} and npm-auth-type:web\n // - get a {doneUrl, authUrl}\n // - open the authUrl\n // - hang on the doneUrl until done\n //\n // if that fails: fall back to couchdb login\n const webLoginURL = new URL('-/v1/login', registry)\n const response = await this.request(webLoginURL, {\n method: 'POST',\n useCache: false,\n headers: {\n 'content-type': 'application/json',\n 'npm-auth-type': 'web',\n },\n body: '{}',\n })\n\n if (response.statusCode === 200) {\n const challenge = getWebAuthChallenge(response.json())\n if (challenge) {\n const result = await this.webAuthOpener(challenge)\n await setToken(\n registry,\n `Bearer ${result.token}`,\n this.identity,\n )\n return\n }\n }\n /* c8 ignore start */\n // TODO: fall back to username/password login, and/or couchdb PUT login\n throw error('Failed to perform web login', { response })\n }\n /* c8 ignore stop */\n\n /**\n * Given a {@link WebAuthChallenge}, open the `authUrl` in a browser and\n * hang on the `doneUrl` until it returns a {@link TokenResponse} object.\n */\n async webAuthOpener({ doneUrl, authUrl }: WebAuthChallenge) {\n const ac = new AbortController()\n const { signal } = ac\n /* c8 ignore start - race condition */\n const [result] = await Promise.all([\n this.#checkLogin(doneUrl, { signal }).then(result => {\n ac.abort()\n return result\n }),\n urlOpen(authUrl, { signal }).catch((er: unknown) => {\n if (asError(er).name === 'AbortError') return\n ac.abort()\n throw er\n }),\n ])\n /* c8 ignore stop */\n return result\n }\n\n async #checkLogin(\n url: URL | string,\n options: RegistryClientRequestOptions = {},\n ): Promise<TokenResponse> {\n const response = await this.request(url, {\n ...options,\n useCache: false,\n })\n const { signal } = options as { signal?: AbortSignal }\n if (response.statusCode === 202) {\n const rt = response.getHeaderString('retry-after')\n const retryAfter = rt ? Number(rt) : -1\n if (retryAfter > 0) {\n await setTimeout(retryAfter * 1000, null, { signal })\n }\n return await this.#checkLogin(url, options)\n }\n if (response.statusCode === 200) {\n const token = getTokenResponse(response.json())\n if (token) return token\n }\n throw error('Invalid response from web login endpoint', {\n response,\n })\n }\n\n async request(\n url: URL | string,\n options: RegistryClientRequestOptions = {},\n ): Promise<CacheEntry> {\n logRequest(url, 'start')\n\n const u = typeof url === 'string' ? new URL(url) : url\n const {\n method = 'GET',\n integrity,\n redirections = new Set(),\n signal,\n otp = (process.env.VLT_OTP ?? '').trim(),\n staleWhileRevalidate = true,\n } = options\n let { trustIntegrity } = options\n\n const m = isCacheableMethod(method) ? method : undefined\n const { useCache = !!m } = options\n\n ;(signal as AbortSignal | null)?.throwIfAborted()\n\n // first, try to get from the cache before making any request.\n const { origin } = u\n const key = `${method !== 'GET' ? method + ' ' : ''}${u}`\n const buffer =\n useCache ?\n await this.cache.fetch(key, { context: { integrity } })\n : undefined\n\n const entry = buffer ? CacheEntry.decode(buffer) : undefined\n if (entry?.valid) {\n return entry\n }\n\n if (staleWhileRevalidate && entry?.staleWhileRevalidate && m) {\n // revalidate while returning the stale entry\n register(dirname(this.cache.path()), m, url)\n return entry\n }\n\n // either no cache entry, or need to revalidate before use.\n setCacheHeaders(options, entry)\n\n redirections.add(String(url))\n\n Object.assign(options, {\n path: u.pathname.replace(/\\/+$/, '') + u.search,\n ...agentOptions,\n })\n\n options.origin = u.origin\n options.headers = addHeader(\n addHeader(\n options.headers,\n 'accept-encoding',\n 'gzip;q=1.0, identity;q=0.5',\n ),\n 'user-agent',\n userAgent,\n )\n if (otp) {\n options.headers = addHeader(options.headers, 'npm-otp', otp)\n }\n if (integrity) {\n options.headers = addHeader(\n options.headers,\n 'accept-integrity',\n integrity,\n )\n }\n options.method = options.method ?? 'GET'\n\n // will remove if we don't have a token.\n options.headers = addHeader(\n options.headers,\n 'authorization',\n await getToken(origin, this.identity),\n )\n\n let response: Dispatcher.ResponseData | null = null\n try {\n response = await this.agent.request(\n options as Dispatcher.RequestOptions,\n )\n /* c8 ignore start */\n } catch (er) {\n // Rethrow so we get a better stack trace\n throw error('Request failed', {\n code: 'EREQUEST',\n cause: er,\n url,\n method,\n })\n }\n /* c8 ignore stop */\n\n const result = await this.#handleResponse(\n u,\n options,\n response,\n entry,\n )\n\n if (result.getHeader('integrity')) {\n trustIntegrity = true\n }\n\n if (result.isGzip && !trustIntegrity) {\n result.checkIntegrity({ url })\n }\n if (useCache) {\n // Get the encoded buffer from the cache entry\n const buffer = result.encode()\n this.cache.set(\n key,\n Buffer.from(\n buffer.buffer,\n buffer.byteOffset,\n buffer.byteLength,\n ),\n {\n integrity: result.integrity,\n },\n )\n }\n return result\n }\n\n async #handleResponse(\n url: URL,\n options: RegistryClientRequestOptions,\n response: Dispatcher.ResponseData,\n entry?: CacheEntry,\n ): Promise<CacheEntry> {\n if (handle304Response(response, entry)) return entry\n\n if (response.statusCode === 401) {\n const repeatRequest = await otplease(this, options, response)\n if (repeatRequest) return await this.request(url, repeatRequest)\n }\n\n const h: Uint8Array[] = []\n for (const [key, value] of Object.entries(response.headers)) {\n /* c8 ignore start - theoretical */\n if (Array.isArray(value)) {\n h.push(\n getEncondedValue(key),\n getEncondedValue(value.join(', ')),\n )\n /* c8 ignore stop */\n } else if (typeof value === 'string') {\n h.push(getEncondedValue(key), getEncondedValue(value))\n }\n }\n\n const { integrity, trustIntegrity } = options\n const result = new CacheEntry(\n /* c8 ignore next - should always have a status code */\n response.statusCode || 200,\n h,\n {\n integrity,\n trustIntegrity,\n 'stale-while-revalidate-factor':\n this.staleWhileRevalidateFactor,\n contentLength:\n response.headers['content-length'] ?\n Number(response.headers['content-length'])\n : /* c8 ignore next */ undefined,\n },\n )\n\n if (isRedirect(result)) {\n response.body.resume()\n const [nextURL, nextOptions] = redirect(options, result, url)\n if (nextOptions && nextURL) {\n return await this.request(nextURL, nextOptions)\n }\n return result\n }\n\n response.body.on('data', (chunk: Uint8Array) =>\n result.addBody(chunk),\n )\n return await new Promise<CacheEntry>((res, rej) => {\n response.body.on('error', rej)\n response.body.on('end', () => res(result))\n })\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"otplease.d.ts","sourceRoot":"","sources":["../../src/otplease.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAA;AACxC,OAAO,KAAK,EACV,cAAc,EACd,4BAA4B,EAC7B,MAAM,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"otplease.d.ts","sourceRoot":"","sources":["../../src/otplease.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAA;AACxC,OAAO,KAAK,EACV,cAAc,EACd,4BAA4B,EAC7B,MAAM,YAAY,CAAA;AAqBnB,eAAO,MAAM,QAAQ,WACX,cAAc,WACb,4BAA4B,YAC3B,UAAU,CAAC,YAAY,KAChC,OAAO,CAAC,4BAA4B,GAAG,SAAS,CAuDlD,CAAA"}
|
package/dist/esm/otplease.js
CHANGED
|
@@ -1,7 +1,18 @@
|
|
|
1
1
|
import { error } from '@vltpkg/error-cause';
|
|
2
|
-
import {
|
|
2
|
+
import { getWebAuthChallenge } from "./web-auth-challenge.js";
|
|
3
3
|
import { urlOpen } from '@vltpkg/url-open';
|
|
4
4
|
import { createInterface } from 'node:readline/promises';
|
|
5
|
+
// eslint-disable-next-line no-console
|
|
6
|
+
const log = (msg) => console.error(msg);
|
|
7
|
+
const question = async (text) => {
|
|
8
|
+
const rl = createInterface({
|
|
9
|
+
input: process.stdin,
|
|
10
|
+
output: process.stdout,
|
|
11
|
+
});
|
|
12
|
+
const answer = await rl.question(text);
|
|
13
|
+
rl.close();
|
|
14
|
+
return answer;
|
|
15
|
+
};
|
|
5
16
|
const otpChallengeNotice = /^Open ([^ ]+) to use your security key for authentication or enter OTP from your authenticator app/i;
|
|
6
17
|
export const otplease = async (client, options, response) => {
|
|
7
18
|
const waHeader = String(response.headers['www-authenticate'] ?? '');
|
|
@@ -13,43 +24,40 @@ export const otplease = async (client, options, response) => {
|
|
|
13
24
|
}
|
|
14
25
|
if (wwwAuth.has('otp')) {
|
|
15
26
|
// do a web auth opener to get otp token
|
|
16
|
-
const challenge = await response.body.json();
|
|
17
|
-
if (
|
|
27
|
+
const challenge = getWebAuthChallenge(await response.body.json().catch(() => null));
|
|
28
|
+
if (challenge) {
|
|
18
29
|
return {
|
|
19
30
|
...options,
|
|
20
31
|
otp: (await client.webAuthOpener(challenge)).token,
|
|
21
32
|
};
|
|
22
33
|
}
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
return { ...options, otp };
|
|
35
|
-
}
|
|
34
|
+
const { 'npm-notice': npmNotice } = response.headers;
|
|
35
|
+
if (npmNotice) {
|
|
36
|
+
const notice = String(npmNotice);
|
|
37
|
+
const match = otpChallengeNotice.exec(notice);
|
|
38
|
+
if (match?.[1]) {
|
|
39
|
+
await urlOpen(match[1]);
|
|
40
|
+
log(notice);
|
|
41
|
+
return {
|
|
42
|
+
...options,
|
|
43
|
+
otp: await question('OTP: '),
|
|
44
|
+
};
|
|
36
45
|
}
|
|
37
|
-
throw error('Unrecognized OTP authentication challenge', {
|
|
38
|
-
response,
|
|
39
|
-
});
|
|
40
46
|
}
|
|
47
|
+
throw error('Unrecognized OTP authentication challenge', {
|
|
48
|
+
response,
|
|
49
|
+
});
|
|
41
50
|
}
|
|
42
51
|
if (wwwAuth.size) {
|
|
43
52
|
throw error('Unknown authentication challenge', { response });
|
|
44
53
|
}
|
|
45
54
|
// see if the body is prompting for otp
|
|
46
|
-
const text = await response.body.text();
|
|
55
|
+
const text = await response.body.text().catch(() => '');
|
|
47
56
|
if (text.toLowerCase().includes('one-time pass')) {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
}
|
|
52
|
-
return { ...options, otp };
|
|
57
|
+
return {
|
|
58
|
+
...options,
|
|
59
|
+
otp: await question(text),
|
|
60
|
+
};
|
|
53
61
|
}
|
|
54
62
|
};
|
|
55
63
|
//# sourceMappingURL=otplease.js.map
|
package/dist/esm/otplease.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"otplease.js","sourceRoot":"","sources":["../../src/otplease.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAA;AAM3C,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"otplease.js","sourceRoot":"","sources":["../../src/otplease.ts"],"names":[],"mappings":"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","sourcesContent":["import { error } from '@vltpkg/error-cause'\nimport type { Dispatcher } from 'undici'\nimport type {\n RegistryClient,\n RegistryClientRequestOptions,\n} from './index.ts'\nimport { getWebAuthChallenge } from './web-auth-challenge.ts'\nimport { urlOpen } from '@vltpkg/url-open'\nimport { createInterface } from 'node:readline/promises'\n\n// eslint-disable-next-line no-console\nconst log = (msg: string) => console.error(msg)\n\nconst question = async (text: string): Promise<string> => {\n const rl = createInterface({\n input: process.stdin,\n output: process.stdout,\n })\n const answer = await rl.question(text)\n rl.close()\n return answer\n}\n\nconst otpChallengeNotice =\n /^Open ([^ ]+) to use your security key for authentication or enter OTP from your authenticator app/i\n\nexport const otplease = async (\n client: RegistryClient,\n options: RegistryClientRequestOptions,\n response: Dispatcher.ResponseData,\n): Promise<RegistryClientRequestOptions | undefined> => {\n const waHeader = String(response.headers['www-authenticate'] ?? '')\n const wwwAuth = new Set(\n waHeader ? waHeader.toLowerCase().split(/,\\s*/) : [],\n )\n\n if (wwwAuth.has('ipaddress')) {\n throw error('Authorization is not allowed from your ip address', {\n response,\n })\n }\n\n if (wwwAuth.has('otp')) {\n // do a web auth opener to get otp token\n const challenge = getWebAuthChallenge(\n await response.body.json().catch(() => null),\n )\n if (challenge) {\n return {\n ...options,\n otp: (await client.webAuthOpener(challenge)).token,\n }\n }\n\n const { 'npm-notice': npmNotice } = response.headers\n if (npmNotice) {\n const notice = String(npmNotice)\n const match = otpChallengeNotice.exec(notice)\n if (match?.[1]) {\n await urlOpen(match[1])\n log(notice)\n return {\n ...options,\n otp: await question('OTP: '),\n }\n }\n }\n\n throw error('Unrecognized OTP authentication challenge', {\n response,\n })\n }\n\n if (wwwAuth.size) {\n throw error('Unknown authentication challenge', { response })\n }\n\n // see if the body is prompting for otp\n const text = await response.body.text().catch(() => '')\n if (text.toLowerCase().includes('one-time pass')) {\n return {\n ...options,\n otp: await question(text),\n }\n }\n}\n"]}
|
package/dist/esm/raw-header.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Give it a key, and it'll return the
|
|
2
|
+
* Give it a key, and it'll return the value of that header as a Uint8Array
|
|
3
3
|
*/
|
|
4
|
-
export declare const getRawHeader: (headers:
|
|
4
|
+
export declare const getRawHeader: (headers: Uint8Array[], key: string) => Uint8Array | undefined;
|
|
5
5
|
/**
|
|
6
6
|
* Give it a key and value, and it'll overwrite or add the header entry
|
|
7
7
|
*/
|
|
8
|
-
export declare const setRawHeader: (headers:
|
|
8
|
+
export declare const setRawHeader: (headers: Uint8Array[], key: string, value: Uint8Array | string) => Uint8Array[];
|
|
9
9
|
//# sourceMappingURL=raw-header.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"raw-header.d.ts","sourceRoot":"","sources":["../../src/raw-header.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"raw-header.d.ts","sourceRoot":"","sources":["../../src/raw-header.ts"],"names":[],"mappings":"AAKA;;GAEG;AACH,eAAO,MAAM,YAAY,YACd,UAAU,EAAE,OAChB,MAAM,KACV,UAAU,GAAG,SAYf,CAAA;AAED;;GAEG;AACH,eAAO,MAAM,YAAY,YACd,UAAU,EAAE,OAChB,MAAM,SACJ,UAAU,GAAG,MAAM,KACzB,UAAU,EAmBZ,CAAA"}
|
package/dist/esm/raw-header.js
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
|
+
import { getDecodedValue, getEncondedValue, } from "./string-encoding.js";
|
|
1
2
|
/**
|
|
2
|
-
* Give it a key, and it'll return the
|
|
3
|
+
* Give it a key, and it'll return the value of that header as a Uint8Array
|
|
3
4
|
*/
|
|
4
|
-
export const getRawHeader = (headers,
|
|
5
|
-
k =
|
|
5
|
+
export const getRawHeader = (headers, key) => {
|
|
6
|
+
const k = key.toLowerCase();
|
|
6
7
|
for (let i = 0; i < headers.length; i += 2) {
|
|
7
8
|
const name = headers[i];
|
|
8
9
|
if (name &&
|
|
9
|
-
name.length ===
|
|
10
|
-
name
|
|
10
|
+
name.length === key.length &&
|
|
11
|
+
getDecodedValue(name).toLowerCase() === k) {
|
|
11
12
|
return headers[i + 1];
|
|
12
13
|
}
|
|
13
14
|
}
|
|
@@ -15,21 +16,21 @@ export const getRawHeader = (headers, k) => {
|
|
|
15
16
|
/**
|
|
16
17
|
* Give it a key and value, and it'll overwrite or add the header entry
|
|
17
18
|
*/
|
|
18
|
-
export const setRawHeader = (headers,
|
|
19
|
-
k =
|
|
20
|
-
const
|
|
19
|
+
export const setRawHeader = (headers, key, value) => {
|
|
20
|
+
const k = key.toLowerCase();
|
|
21
|
+
const encVal = typeof value === 'string' ? getEncondedValue(value) : value;
|
|
21
22
|
for (let i = 0; i < headers.length; i += 2) {
|
|
22
23
|
const name = headers[i];
|
|
23
24
|
if (name &&
|
|
24
25
|
name.length === k.length &&
|
|
25
|
-
name
|
|
26
|
+
getDecodedValue(name).toLowerCase() === k) {
|
|
26
27
|
return [
|
|
27
28
|
...headers.slice(0, i + 1),
|
|
28
|
-
|
|
29
|
+
encVal,
|
|
29
30
|
...headers.slice(i + 2),
|
|
30
31
|
];
|
|
31
32
|
}
|
|
32
33
|
}
|
|
33
|
-
return [...headers,
|
|
34
|
+
return [...headers, getEncondedValue(k), encVal];
|
|
34
35
|
};
|
|
35
36
|
//# sourceMappingURL=raw-header.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"raw-header.js","sourceRoot":"","sources":["../../src/raw-header.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,
|
|
1
|
+
{"version":3,"file":"raw-header.js","sourceRoot":"","sources":["../../src/raw-header.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,eAAe,EACf,gBAAgB,GACjB,MAAM,sBAAsB,CAAA;AAE7B;;GAEG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,CAC1B,OAAqB,EACrB,GAAW,EACa,EAAE;IAC1B,MAAM,CAAC,GAAG,GAAG,CAAC,WAAW,EAAE,CAAA;IAC3B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QAC3C,MAAM,IAAI,GAAG,OAAO,CAAC,CAAC,CAAC,CAAA;QACvB,IACE,IAAI;YACJ,IAAI,CAAC,MAAM,KAAK,GAAG,CAAC,MAAM;YAC1B,eAAe,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,KAAK,CAAC,EACzC,CAAC;YACD,OAAO,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,CAAA;QACvB,CAAC;IACH,CAAC;AACH,CAAC,CAAA;AAED;;GAEG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,CAC1B,OAAqB,EACrB,GAAW,EACX,KAA0B,EACZ,EAAE;IAChB,MAAM,CAAC,GAAG,GAAG,CAAC,WAAW,EAAE,CAAA;IAC3B,MAAM,MAAM,GACV,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAA;IAC7D,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QAC3C,MAAM,IAAI,GAAG,OAAO,CAAC,CAAC,CAAC,CAAA;QACvB,IACE,IAAI;YACJ,IAAI,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM;YACxB,eAAe,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,KAAK,CAAC,EACzC,CAAC;YACD,OAAO;gBACL,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC;gBAC1B,MAAM;gBACN,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC;aACxB,CAAA;QACH,CAAC;IACH,CAAC;IACD,OAAO,CAAC,GAAG,OAAO,EAAE,gBAAgB,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,CAAA;AAClD,CAAC,CAAA","sourcesContent":["import {\n getDecodedValue,\n getEncondedValue,\n} from './string-encoding.ts'\n\n/**\n * Give it a key, and it'll return the value of that header as a Uint8Array\n */\nexport const getRawHeader = (\n headers: Uint8Array[],\n key: string,\n): Uint8Array | undefined => {\n const k = key.toLowerCase()\n for (let i = 0; i < headers.length; i += 2) {\n const name = headers[i]\n if (\n name &&\n name.length === key.length &&\n getDecodedValue(name).toLowerCase() === k\n ) {\n return headers[i + 1]\n }\n }\n}\n\n/**\n * Give it a key and value, and it'll overwrite or add the header entry\n */\nexport const setRawHeader = (\n headers: Uint8Array[],\n key: string,\n value: Uint8Array | string,\n): Uint8Array[] => {\n const k = key.toLowerCase()\n const encVal =\n typeof value === 'string' ? getEncondedValue(value) : value\n for (let i = 0; i < headers.length; i += 2) {\n const name = headers[i]\n if (\n name &&\n name.length === k.length &&\n getDecodedValue(name).toLowerCase() === k\n ) {\n return [\n ...headers.slice(0, i + 1),\n encVal,\n ...headers.slice(i + 2),\n ]\n }\n }\n return [...headers, getEncondedValue(k), encVal]\n}\n"]}
|
package/dist/esm/redirect.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import type { RegistryClientRequestOptions } from './index.ts';
|
|
|
3
3
|
export type RedirectStatus = 301 | 302 | 303 | 307 | 308;
|
|
4
4
|
export type RedirectResponse = CacheEntry & {
|
|
5
5
|
statusCode: RedirectStatus;
|
|
6
|
-
getHeader(key: 'location'):
|
|
6
|
+
getHeader(key: 'location'): Uint8Array | undefined;
|
|
7
7
|
};
|
|
8
8
|
export declare const isRedirect: (response: CacheEntry) => response is RedirectResponse;
|
|
9
9
|
/**
|