@vltpkg/registry-client 0.0.0-0.1730724342581 → 0.0.0-11

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 (67) hide show
  1. package/README.md +50 -53
  2. package/dist/esm/add-header.d.ts +1 -1
  3. package/dist/esm/add-header.d.ts.map +1 -1
  4. package/dist/esm/add-header.js +4 -1
  5. package/dist/esm/add-header.js.map +1 -1
  6. package/dist/esm/auth.d.ts +9 -0
  7. package/dist/esm/auth.d.ts.map +1 -0
  8. package/dist/esm/auth.js +39 -0
  9. package/dist/esm/auth.js.map +1 -0
  10. package/dist/esm/cache-entry.d.ts +59 -13
  11. package/dist/esm/cache-entry.d.ts.map +1 -1
  12. package/dist/esm/cache-entry.js +155 -54
  13. package/dist/esm/cache-entry.js.map +1 -1
  14. package/dist/esm/cache-revalidate.d.ts +2 -0
  15. package/dist/esm/cache-revalidate.d.ts.map +1 -0
  16. package/dist/esm/cache-revalidate.js +66 -0
  17. package/dist/esm/cache-revalidate.js.map +1 -0
  18. package/dist/esm/delete-header.d.ts +2 -0
  19. package/dist/esm/delete-header.d.ts.map +1 -0
  20. package/dist/esm/delete-header.js +32 -0
  21. package/dist/esm/delete-header.js.map +1 -0
  22. package/dist/esm/env.d.ts +0 -4
  23. package/dist/esm/env.d.ts.map +1 -1
  24. package/dist/esm/env.js +0 -3
  25. package/dist/esm/env.js.map +1 -1
  26. package/dist/esm/handle-304-response.d.ts +2 -2
  27. package/dist/esm/handle-304-response.d.ts.map +1 -1
  28. package/dist/esm/handle-304-response.js.map +1 -1
  29. package/dist/esm/index.d.ts +99 -8
  30. package/dist/esm/index.d.ts.map +1 -1
  31. package/dist/esm/index.js +265 -69
  32. package/dist/esm/index.js.map +1 -1
  33. package/dist/esm/is-iterable.d.ts +2 -0
  34. package/dist/esm/is-iterable.d.ts.map +1 -0
  35. package/dist/esm/is-iterable.js +2 -0
  36. package/dist/esm/is-iterable.js.map +1 -0
  37. package/dist/esm/otplease.d.ts +4 -0
  38. package/dist/esm/otplease.d.ts.map +1 -0
  39. package/dist/esm/otplease.js +55 -0
  40. package/dist/esm/otplease.js.map +1 -0
  41. package/dist/esm/raw-header.d.ts +1 -1
  42. package/dist/esm/raw-header.d.ts.map +1 -1
  43. package/dist/esm/redirect.d.ts +2 -2
  44. package/dist/esm/redirect.d.ts.map +1 -1
  45. package/dist/esm/redirect.js +1 -0
  46. package/dist/esm/redirect.js.map +1 -1
  47. package/dist/esm/revalidate.d.ts +5 -0
  48. package/dist/esm/revalidate.d.ts.map +1 -0
  49. package/dist/esm/revalidate.js +49 -0
  50. package/dist/esm/revalidate.js.map +1 -0
  51. package/dist/esm/set-cache-headers.d.ts +2 -2
  52. package/dist/esm/set-cache-headers.d.ts.map +1 -1
  53. package/dist/esm/set-cache-headers.js +1 -1
  54. package/dist/esm/set-cache-headers.js.map +1 -1
  55. package/dist/esm/token-response.d.ts +5 -0
  56. package/dist/esm/token-response.d.ts.map +1 -0
  57. package/dist/esm/token-response.js +5 -0
  58. package/dist/esm/token-response.js.map +1 -0
  59. package/dist/esm/web-auth-challenge.d.ts +6 -0
  60. package/dist/esm/web-auth-challenge.d.ts.map +1 -0
  61. package/dist/esm/web-auth-challenge.js +7 -0
  62. package/dist/esm/web-auth-challenge.js.map +1 -0
  63. package/package.json +31 -21
  64. package/dist/esm/serdes.d.ts +0 -15
  65. package/dist/esm/serdes.d.ts.map +0 -1
  66. package/dist/esm/serdes.js +0 -19
  67. package/dist/esm/serdes.js.map +0 -1
@@ -20,11 +20,10 @@
20
20
  // of the file.
21
21
  import { error } from '@vltpkg/error-cause';
22
22
  import ccp from 'cache-control-parser';
23
- import { createHash } from 'crypto';
24
- import { inspect } from 'util';
25
- import { gunzipSync } from 'zlib';
26
- import { getRawHeader, setRawHeader } from './raw-header.js';
27
- import { deserialize, serialize, serializedHeader } from './serdes.js';
23
+ import { createHash } from 'node:crypto';
24
+ import { inspect } from 'node:util';
25
+ import { gunzipSync } from 'node:zlib';
26
+ import { getRawHeader, setRawHeader } from "./raw-header.js";
28
27
  const readSize = (buf, offset) => {
29
28
  const a = buf[offset];
30
29
  const b = buf[offset + 1];
@@ -52,10 +51,15 @@ export class CacheEntry {
52
51
  #integrity;
53
52
  #integrityActual;
54
53
  #json;
55
- constructor(statusCode, headers, integrity) {
56
- this.#integrity = integrity;
57
- this.#statusCode = statusCode;
54
+ #trustIntegrity;
55
+ #staleWhileRevalidateFactor;
56
+ constructor(statusCode, headers, { integrity, trustIntegrity = false, 'stale-while-revalidate-factor': staleWhileRevalidateFactor = 60, } = {}) {
58
57
  this.#headers = headers;
58
+ this.#statusCode = statusCode;
59
+ this.#trustIntegrity = trustIntegrity;
60
+ this.#staleWhileRevalidateFactor = staleWhileRevalidateFactor;
61
+ if (integrity)
62
+ this.integrity = integrity;
59
63
  }
60
64
  get #headersAsObject() {
61
65
  const ret = [];
@@ -66,42 +70,110 @@ export class CacheEntry {
66
70
  }
67
71
  return ret;
68
72
  }
69
- [kCustomInspect](depth, options) {
70
- const str = inspect({
71
- statusCode: this.statusCode,
73
+ toJSON() {
74
+ const { statusCode, valid, staleWhileRevalidate, cacheControl, date, contentType, integrity, maxAge, isGzip, isJSON, } = this;
75
+ /* c8 ignore start */
76
+ const age = date ?
77
+ Math.floor((Date.now() - date.getTime()) / 1000)
78
+ : undefined;
79
+ const expires = date ? new Date(date.getTime() + this.maxAge * 1000) : undefined;
80
+ /* c8 ignore end */
81
+ return Object.fromEntries(Object.entries({
82
+ statusCode,
72
83
  headers: this.#headersAsObject,
73
- text: this.text(),
74
- }, {
84
+ contentType,
85
+ integrity,
86
+ date,
87
+ expires,
88
+ cacheControl,
89
+ valid,
90
+ staleWhileRevalidate,
91
+ age,
92
+ maxAge,
93
+ isGzip,
94
+ isJSON,
95
+ }).filter(([_, v]) => v !== undefined));
96
+ }
97
+ [kCustomInspect](depth, options) {
98
+ const str = inspect(this.toJSON(), {
75
99
  depth,
76
100
  ...options,
77
101
  });
78
102
  return `@vltpkg/registry-client.CacheEntry ${str}`;
79
103
  }
104
+ #date;
105
+ get date() {
106
+ if (this.#date)
107
+ return this.#date;
108
+ const dh = this.getHeader('date')?.toString();
109
+ if (dh)
110
+ this.#date = new Date(dh);
111
+ return this.#date;
112
+ }
113
+ #maxAge;
114
+ get maxAge() {
115
+ if (this.#maxAge !== undefined)
116
+ return this.#maxAge;
117
+ // see if the max-age has not yet been crossed
118
+ // default to 5m if maxage is not set, as some registries
119
+ // do not set a cache control header at all.
120
+ const cc = this.cacheControl;
121
+ this.#maxAge = cc['max-age'] || cc['s-maxage'] || 300;
122
+ return this.#maxAge;
123
+ }
124
+ #cacheControl;
125
+ get cacheControl() {
126
+ if (this.#cacheControl)
127
+ return this.#cacheControl;
128
+ const cc = this.getHeader('cache-control')?.toString();
129
+ this.#cacheControl = cc ? ccp.parse(cc) : {};
130
+ return this.#cacheControl;
131
+ }
132
+ #staleWhileRevalidate;
133
+ get staleWhileRevalidate() {
134
+ if (this.#staleWhileRevalidate !== undefined)
135
+ return this.#staleWhileRevalidate;
136
+ if (this.valid || !this.date)
137
+ return true;
138
+ const swv = this.cacheControl['stale-while-revalidate'] ??
139
+ this.maxAge * this.#staleWhileRevalidateFactor;
140
+ this.#staleWhileRevalidate =
141
+ this.date.getTime() + swv * 1000 > Date.now();
142
+ return this.#staleWhileRevalidate;
143
+ }
144
+ #contentType;
145
+ get contentType() {
146
+ if (this.#contentType !== undefined)
147
+ return this.#contentType;
148
+ this.#contentType =
149
+ this.getHeader('content-type')?.toString() ?? '';
150
+ return this.#contentType;
151
+ }
80
152
  /**
81
153
  * `true` if the entry represents a cached response that is still
82
154
  * valid to use.
83
155
  */
156
+ #valid;
84
157
  get valid() {
85
- const cc_ = this.getHeader('cache-control')?.toString();
86
- const cc = cc_ ? ccp.parse(cc_) : {};
87
- const ct = this.getHeader('content-type')?.toString() ?? '';
88
- const dh = this.getHeader('date')?.toString();
158
+ if (this.#valid !== undefined)
159
+ return this.#valid;
89
160
  // immutable = never changes
90
- if (cc.immutable)
91
- return true;
161
+ if (this.cacheControl.immutable)
162
+ return (this.#valid = true);
92
163
  // some registries do text/json, some do application/json,
93
164
  // some do application/vnd.npm.install-v1+json
94
165
  // If it's NOT json, it's an immutable tarball
95
- if (ct !== '' && !/\bjson\b/.test(ct))
96
- return true;
166
+ const ct = this.contentType;
167
+ if (ct && !/\bjson\b/.test(ct))
168
+ return (this.#valid = true);
97
169
  // see if the max-age has not yet been crossed
98
170
  // default to 5m if maxage is not set, as some registries
99
171
  // do not set a cache control header at all.
100
- const ma = cc['max-age'] || cc['s-maxage'] || 300;
101
- if (ma && dh) {
102
- return Date.parse(dh) + ma * 1000 > Date.now();
103
- }
104
- return false;
172
+ if (!this.date)
173
+ return (this.#valid = false);
174
+ this.#valid =
175
+ this.date.getTime() + this.maxAge * 1000 > Date.now();
176
+ return this.#valid;
105
177
  }
106
178
  addBody(b) {
107
179
  this.#body.push(b);
@@ -114,18 +186,31 @@ export class CacheEntry {
114
186
  return this.#headers;
115
187
  }
116
188
  /**
117
- * check that the sri integrity string that was provided to the ctor
189
+ * Check that the sri integrity string that was provided to the ctor
118
190
  * matches the body that we actually received. This should only be called
119
191
  * AFTER the entire body has been completely downloaded.
120
192
  *
193
+ * This method **will throw** if the integrity values do not match.
194
+ *
121
195
  * Note that this will *usually* not be true if the value is coming out of
122
196
  * the cache, because the cache entries are un-gzipped in place. It should
123
197
  * _only_ be called for artifacts that come from an actual http response.
198
+ *
199
+ * Returns true if anything was actually verified.
124
200
  */
125
- checkIntegrity() {
201
+ checkIntegrity(context = {}) {
126
202
  if (!this.#integrity)
127
203
  return false;
128
- return this.integrityActual === this.#integrity;
204
+ if (this.integrityActual !== this.#integrity) {
205
+ throw error('Integrity check failure', {
206
+ code: 'EINTEGRITY',
207
+ response: this,
208
+ wanted: this.#integrity,
209
+ found: this.integrityActual,
210
+ ...context,
211
+ });
212
+ }
213
+ return true;
129
214
  }
130
215
  get integrityActual() {
131
216
  if (this.#integrityActual)
@@ -133,8 +218,20 @@ export class CacheEntry {
133
218
  const hash = createHash('sha512');
134
219
  for (const buf of this.#body)
135
220
  hash.update(buf);
136
- this.#integrityActual = `sha512-${hash.digest('base64')}`;
137
- return this.#integrityActual;
221
+ const i = `sha512-${hash.digest('base64')}`;
222
+ this.integrityActual = i;
223
+ return i;
224
+ }
225
+ set integrityActual(i) {
226
+ this.#integrityActual = i;
227
+ this.setHeader('integrity', i);
228
+ }
229
+ set integrity(i) {
230
+ if (!this.#integrity && i) {
231
+ this.#integrity = i;
232
+ if (this.#trustIntegrity)
233
+ this.integrityActual = i;
234
+ }
138
235
  }
139
236
  get integrity() {
140
237
  return this.#integrity;
@@ -173,13 +270,10 @@ export class CacheEntry {
173
270
  get isJSON() {
174
271
  if (this.#isJSON !== undefined)
175
272
  return this.#isJSON;
176
- const ser = serializedHeader && this.getHeader(serializedHeader);
177
- if (ser)
178
- return (this.#isJSON = true);
179
273
  const ct = this.getHeader('content-type')?.toString();
180
274
  // if it says it's json, assume json
181
275
  if (ct)
182
- return /\bjson\b/.test(ct);
276
+ return (this.#isJSON = /\bjson\b/.test(ct));
183
277
  const text = this.text();
184
278
  // don't cache, because we might just not have it yet.
185
279
  if (!text)
@@ -247,18 +341,9 @@ export class CacheEntry {
247
341
  json() {
248
342
  if (this.#json !== undefined)
249
343
  return this.#json;
250
- const ser = serializedHeader && this.getHeader(serializedHeader);
251
- if (ser) {
252
- /* c8 ignore start - very rare, but theoretically possible to throw */
253
- try {
254
- return (this.#json = deserialize(ser));
255
- }
256
- catch { }
257
- /* c8 ignore stop */
258
- }
259
- const obj = JSON.parse(this.text());
260
- if (serializedHeader)
261
- this.setHeader(serializedHeader, serialize(obj));
344
+ const text = this.text();
345
+ const obj = JSON.parse(text || '{}');
346
+ this.#json = obj;
262
347
  return obj;
263
348
  }
264
349
  /**
@@ -268,44 +353,59 @@ export class CacheEntry {
268
353
  */
269
354
  static decode(buffer) {
270
355
  if (buffer.length < 4) {
271
- return new CacheEntry(0, []);
356
+ return emptyCacheEntry;
272
357
  }
273
358
  const headSize = readSize(buffer, 0);
274
359
  if (buffer.length < headSize) {
275
- return new CacheEntry(0, []);
360
+ return emptyCacheEntry;
276
361
  }
277
362
  const statusCode = Number(buffer.subarray(4, 7).toString());
278
363
  const headersBuffer = buffer.subarray(7, headSize);
279
364
  // walk through the headers array, building up the rawHeaders Buffer[]
280
365
  const headers = [];
281
366
  let i = 0;
367
+ let integrity = undefined;
282
368
  while (i < headersBuffer.length - 4) {
283
369
  const size = readSize(headersBuffer, i);
284
- headers.push(headersBuffer.subarray(i + 4, i + size));
370
+ const val = headersBuffer.subarray(i + 4, i + size);
371
+ // if the last one was the key integrity, then this one is the value
372
+ if (headers.length % 2 === 1 &&
373
+ String(headers[headers.length - 1]) === 'integrity') {
374
+ integrity = String(val);
375
+ }
376
+ headers.push(val);
285
377
  i += size;
286
378
  }
287
- const c = new CacheEntry(statusCode, headers);
288
379
  const body = buffer.subarray(headSize);
380
+ const c = new CacheEntry(statusCode, setRawHeader(headers, 'content-length', String(body.byteLength)), {
381
+ integrity,
382
+ trustIntegrity: true,
383
+ });
289
384
  c.#body = [body];
290
385
  c.#bodyLength = body.byteLength;
291
- c.setHeader('content-length', String(c.#bodyLength));
292
386
  if (c.isJSON) {
293
387
  try {
294
388
  c.json();
295
389
  }
296
390
  catch {
297
- return new CacheEntry(0, []);
391
+ return emptyCacheEntry;
298
392
  }
299
393
  }
300
394
  return c;
301
395
  }
396
+ static isGzipEntry(buffer) {
397
+ if (buffer.length < 4)
398
+ return false;
399
+ const headSize = readSize(buffer, 0);
400
+ const gzipBytes = buffer.subarray(headSize, headSize + 2);
401
+ return gzipBytes[0] === 0x1f && gzipBytes[1] === 0x8b;
402
+ }
302
403
  /**
303
404
  * Encode the entry as a single Buffer for writing to the cache
304
405
  */
305
406
  // TODO: should this maybe not concat, and just return Buffer[]?
306
407
  // Then we can writev it to the cache file and save the memory copy
307
408
  encode() {
308
- // store json results as a serialized object.
309
409
  if (this.isJSON)
310
410
  this.json();
311
411
  const sb = Buffer.from(String(this.#statusCode));
@@ -335,4 +435,5 @@ export class CacheEntry {
335
435
  return Buffer.concat(chunks, headLength + this.#bodyLength);
336
436
  }
337
437
  }
438
+ const emptyCacheEntry = new CacheEntry(0, []);
338
439
  //# sourceMappingURL=cache-entry.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"cache-entry.js","sourceRoot":"","sources":["../../src/cache-entry.ts"],"names":[],"mappings":"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","sourcesContent":["// A response object in the cache.\n//\n// The cache stores Buffer objects, and it's convenient to have headers/body\n// together, so we have a simple data structure for this.\n//\n// The shape of it is:\n//\n// [head length]\n// <status code in ascii>\n// [headers]\n// [body]\n//\n// The [UInt32BE head length] is 4 bytes specifying the full length of the\n// status code plus all header keys and values.\n//\n// The [headers] section is key/value/key2/value2/... where each key and value\n// is a 4-byte Uint32BE length, followed by that many bytes.\n//\n// From there, the body can be of any indeterminate length, and is the rest\n// of the file.\n\nimport { error } from '@vltpkg/error-cause'\nimport { type Integrity, type JSONField } from '@vltpkg/types'\nimport ccp from 'cache-control-parser'\nimport { createHash } from 'crypto'\nimport { inspect, type InspectOptions } from 'util'\nimport { gunzipSync } from 'zlib'\nimport { getRawHeader, setRawHeader } from './raw-header.js'\nimport { deserialize, serialize, serializedHeader } from './serdes.js'\n\ntype JSONObj = Record<string, JSONField>\n\nconst readSize = (buf: Buffer, offset: number) => {\n const a = buf[offset]\n const b = buf[offset + 1]\n const c = buf[offset + 2]\n const d = buf[offset + 3]\n\n // not possible, we check the length\n /* c8 ignore start */\n if (\n a === undefined ||\n b === undefined ||\n c === undefined ||\n d === undefined\n ) {\n throw error('Invalid buffer, not long enough to readSize', {\n found: buf.length,\n })\n }\n /* c8 ignore stop */\n\n return (a << 24) | (b << 16) | (c << 8) | d\n}\n\nconst kCustomInspect = Symbol.for('nodejs.util.inspect.custom')\n\nexport class CacheEntry {\n #statusCode: number\n #headers: Buffer[]\n #body: Buffer[] = []\n #bodyLength = 0\n #integrity?: Integrity\n #integrityActual?: Integrity\n #json?: JSONObj\n\n constructor(\n statusCode: number,\n headers: Buffer[],\n integrity?: Integrity,\n ) {\n this.#integrity = integrity\n this.#statusCode = statusCode\n this.#headers = headers\n }\n\n get #headersAsObject(): [string, string][] {\n const ret: [string, string][] = []\n for (let i = 0; i < this.#headers.length - 1; i += 2) {\n const key = String(this.#headers[i])\n const val = String(this.#headers[i + 1])\n ret.push([key, val])\n }\n return ret\n }\n\n [kCustomInspect](depth: number, options: InspectOptions): string {\n const str = inspect(\n {\n statusCode: this.statusCode,\n headers: this.#headersAsObject,\n text: this.text(),\n },\n {\n depth,\n ...options,\n },\n )\n return `@vltpkg/registry-client.CacheEntry ${str}`\n }\n\n /**\n * `true` if the entry represents a cached response that is still\n * valid to use.\n */\n get valid(): boolean {\n const cc_ = this.getHeader('cache-control')?.toString()\n const cc = cc_ ? ccp.parse(cc_) : {}\n const ct = this.getHeader('content-type')?.toString() ?? ''\n const dh = this.getHeader('date')?.toString()\n\n // immutable = never changes\n if (cc.immutable) return true\n\n // some registries do text/json, some do application/json,\n // some do application/vnd.npm.install-v1+json\n // If it's NOT json, it's an immutable tarball\n if (ct !== '' && !/\\bjson\\b/.test(ct)) return true\n\n // see if the max-age has not yet been crossed\n // default to 5m if maxage is not set, as some registries\n // do not set a cache control header at all.\n const ma = cc['max-age'] || cc['s-maxage'] || 300\n if (ma && dh) {\n return Date.parse(dh) + ma * 1000 > Date.now()\n }\n return false\n }\n\n addBody(b: Buffer) {\n this.#body.push(b)\n this.#bodyLength += b.byteLength\n }\n\n get statusCode() {\n return this.#statusCode\n }\n get headers() {\n return this.#headers\n }\n\n /**\n * check that the sri integrity string that was provided to the ctor\n * matches the body that we actually received. This should only be called\n * AFTER the entire body has been completely downloaded.\n *\n * Note that this will *usually* not be true if the value is coming out of\n * the cache, because the cache entries are un-gzipped in place. It should\n * _only_ be called for artifacts that come from an actual http response.\n */\n checkIntegrity(): boolean {\n if (!this.#integrity) return false\n return this.integrityActual === this.#integrity\n }\n get integrityActual(): Integrity {\n if (this.#integrityActual) return this.#integrityActual\n const hash = createHash('sha512')\n for (const buf of this.#body) hash.update(buf)\n this.#integrityActual = `sha512-${hash.digest('base64')}`\n return this.#integrityActual\n }\n get integrity() {\n return this.#integrity\n }\n\n /**\n * Give it a key, and it'll return the buffer of that header value\n */\n getHeader(h: string) {\n return getRawHeader(this.#headers, h)\n }\n\n /**\n * Set a header to a specific value\n */\n setHeader(h: string, value: Buffer | string) {\n this.#headers = setRawHeader(this.#headers, h, value)\n }\n\n /**\n * Return the body of the entry as a Buffer\n */\n buffer(): Buffer {\n const b = this.#body[0]\n if (!b) return Buffer.allocUnsafe(0)\n if (this.#body.length === 1) return b\n const cat = Buffer.concat(this.#body, this.#bodyLength)\n this.#body = [cat]\n return cat\n }\n\n // return the buffer if it's a tarball, or the parsed\n // JSON if it's not.\n get body(): Buffer | Record<string, any> {\n return this.isJSON ? this.json() : this.buffer()\n }\n\n #isJSON?: boolean\n get isJSON(): boolean {\n if (this.#isJSON !== undefined) return this.#isJSON\n const ser = serializedHeader && this.getHeader(serializedHeader)\n if (ser) return (this.#isJSON = true)\n const ct = this.getHeader('content-type')?.toString()\n // if it says it's json, assume json\n if (ct) return /\\bjson\\b/.test(ct)\n const text = this.text()\n // don't cache, because we might just not have it yet.\n if (!text) return false\n // all registry json starts with {, and no tarball ever can.\n this.#isJSON = text.startsWith('{')\n if (this.#isJSON) this.setHeader('content-type', 'text/json')\n return this.#isJSON\n }\n\n #isGzip?: boolean\n get isGzip(): boolean {\n if (this.#isGzip !== undefined) return this.#isGzip\n const ce = this.getHeader('content-encoding')?.toString()\n if (ce && !/\\bgzip\\b/.test(ce)) return (this.#isGzip = false)\n const buf = this.buffer()\n if (buf.length < 2) return false\n this.#isGzip = buf[0] === 0x1f && buf[1] === 0x8b\n if (this.#isGzip) {\n this.setHeader('content-encoding', 'gzip')\n } else {\n this.setHeader('content-encoding', 'identity')\n this.setHeader('content-length', String(this.#bodyLength))\n }\n return this.#isGzip\n }\n\n /**\n * Un-gzip encode the body.\n * Returns true if it was previously gzip (so something was done), otherwise\n * returns false.\n */\n unzip() {\n if (this.isGzip) {\n // we know that if we know it's gzip, that the body has been\n // flattened to a single buffer, so save the extra call.\n /* c8 ignore start */\n if (this.#body[0] == null)\n throw error('Invalid buffer, cant unzip')\n /* c8 ignore stop */\n const b = gunzipSync(this.#body[0])\n this.setHeader('content-encoding', 'identity')\n this.#body = [b]\n this.#bodyLength = b.byteLength\n this.setHeader('content-length', String(this.#bodyLength))\n this.#isGzip = false\n return true\n }\n return false\n }\n\n /**\n * Return the body of the entry as utf8 text\n * Automatically unzips if the content is gzip encoded\n */\n text() {\n this.unzip()\n return this.buffer().toString()\n }\n\n /**\n * Parse the entry body as JSON and return the result\n */\n json(): JSONObj {\n if (this.#json !== undefined) return this.#json\n const ser = serializedHeader && this.getHeader(serializedHeader)\n if (ser) {\n /* c8 ignore start - very rare, but theoretically possible to throw */\n try {\n return (this.#json = deserialize(ser) as JSONObj)\n } catch {}\n /* c8 ignore stop */\n }\n const obj = JSON.parse(this.text()) as JSONObj\n if (serializedHeader)\n this.setHeader(serializedHeader, serialize(obj))\n return obj\n }\n\n /**\n * Pass the contents of a @vltpkg/cache.Cache object as a buffer,\n * and this static method will decode it into a CacheEntry representing\n * the cached response.\n */\n static decode(buffer: Buffer): CacheEntry {\n if (buffer.length < 4) {\n return new CacheEntry(0, [])\n }\n const headSize = readSize(buffer, 0)\n if (buffer.length < headSize) {\n return new CacheEntry(0, [])\n }\n const statusCode = Number(buffer.subarray(4, 7).toString())\n const headersBuffer = buffer.subarray(7, headSize)\n // walk through the headers array, building up the rawHeaders Buffer[]\n const headers: Buffer[] = []\n let i = 0\n while (i < headersBuffer.length - 4) {\n const size = readSize(headersBuffer, i)\n headers.push(headersBuffer.subarray(i + 4, i + size))\n i += size\n }\n const c = new CacheEntry(statusCode, headers)\n const body = buffer.subarray(headSize)\n c.#body = [body]\n c.#bodyLength = body.byteLength\n c.setHeader('content-length', String(c.#bodyLength))\n if (c.isJSON) {\n try {\n c.json()\n } catch {\n return new CacheEntry(0, [])\n }\n }\n return c\n }\n\n /**\n * Encode the entry as a single Buffer for writing to the cache\n */\n // TODO: should this maybe not concat, and just return Buffer[]?\n // Then we can writev it to the cache file and save the memory copy\n encode(): Buffer {\n // store json results as a serialized object.\n if (this.isJSON) this.json()\n const sb = Buffer.from(String(this.#statusCode))\n const chunks: Buffer[] = [sb]\n let headLength = sb.byteLength + 4\n for (const h of this.#headers) {\n const hlBuf = Buffer.allocUnsafe(4)\n const hl = h.byteLength + 4\n headLength += hl\n hlBuf.set(\n [\n (hl >> 24) & 0xff,\n (hl >> 16) & 0xff,\n (hl >> 8) & 0xff,\n hl & 0xff,\n ],\n 0,\n )\n chunks.push(hlBuf, h)\n }\n\n const hlBuf = Buffer.allocUnsafe(4)\n hlBuf.set(\n [\n (headLength >> 24) & 0xff,\n (headLength >> 16) & 0xff,\n (headLength >> 8) & 0xff,\n headLength & 0xff,\n ],\n 0,\n )\n chunks.unshift(hlBuf)\n chunks.push(...this.#body)\n return Buffer.concat(chunks, headLength + this.#bodyLength)\n }\n}\n"]}
1
+ {"version":3,"file":"cache-entry.js","sourceRoot":"","sources":["../../src/cache-entry.ts"],"names":[],"mappings":"AAAA,kCAAkC;AAClC,EAAE;AACF,4EAA4E;AAC5E,yDAAyD;AACzD,EAAE;AACF,sBAAsB;AACtB,EAAE;AACF,gBAAgB;AAChB,yBAAyB;AACzB,YAAY;AACZ,SAAS;AACT,EAAE;AACF,0EAA0E;AAC1E,+CAA+C;AAC/C,EAAE;AACF,8EAA8E;AAC9E,4DAA4D;AAC5D,EAAE;AACF,2EAA2E;AAC3E,eAAe;AAGf,OAAO,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAA;AAE3C,OAAO,GAAG,MAAM,sBAAsB,CAAA;AACtC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAExC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AACtC,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAI5D,MAAM,QAAQ,GAAG,CAAC,GAAW,EAAE,MAAc,EAAE,EAAE;IAC/C,MAAM,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC,CAAA;IACrB,MAAM,CAAC,GAAG,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAA;IACzB,MAAM,CAAC,GAAG,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAA;IACzB,MAAM,CAAC,GAAG,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAA;IAEzB,oCAAoC;IACpC,qBAAqB;IACrB,IACE,CAAC,KAAK,SAAS;QACf,CAAC,KAAK,SAAS;QACf,CAAC,KAAK,SAAS;QACf,CAAC,KAAK,SAAS,EACf,CAAC;QACD,MAAM,KAAK,CAAC,6CAA6C,EAAE;YACzD,KAAK,EAAE,GAAG,CAAC,MAAM;SAClB,CAAC,CAAA;IACJ,CAAC;IACD,oBAAoB;IAEpB,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAA;AAC7C,CAAC,CAAA;AAED,MAAM,cAAc,GAAG,MAAM,CAAC,GAAG,CAAC,4BAA4B,CAAC,CAAA;AAmC/D,MAAM,OAAO,UAAU;IACrB,WAAW,CAAQ;IACnB,QAAQ,CAAU;IAClB,KAAK,GAAa,EAAE,CAAA;IACpB,WAAW,GAAG,CAAC,CAAA;IACf,UAAU,CAAY;IACtB,gBAAgB,CAAY;IAC5B,KAAK,CAAU;IACf,eAAe,CAAA;IACf,2BAA2B,CAAA;IAE3B,YACE,UAAkB,EAClB,OAAiB,EACjB,EACE,SAAS,EACT,cAAc,GAAG,KAAK,EACtB,+BAA+B,EAC7B,0BAA0B,GAAG,EAAE,MACZ,EAAE;QAEzB,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAA;QACvB,IAAI,CAAC,WAAW,GAAG,UAAU,CAAA;QAC7B,IAAI,CAAC,eAAe,GAAG,cAAc,CAAA;QACrC,IAAI,CAAC,2BAA2B,GAAG,0BAA0B,CAAA;QAC7D,IAAI,SAAS;YAAE,IAAI,CAAC,SAAS,GAAG,SAAS,CAAA;IAC3C,CAAC;IAED,IAAI,gBAAgB;QAClB,MAAM,GAAG,GAAuB,EAAE,CAAA;QAClC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;YACrD,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAA;YACpC,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAA;YACxC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAA;QACtB,CAAC;QACD,OAAO,GAAG,CAAA;IACZ,CAAC;IAED,MAAM;QACJ,MAAM,EACJ,UAAU,EACV,KAAK,EACL,oBAAoB,EACpB,YAAY,EACZ,IAAI,EACJ,WAAW,EACX,SAAS,EACT,MAAM,EACN,MAAM,EACN,MAAM,GACP,GAAG,IAAI,CAAA;QACR,qBAAqB;QACrB,MAAM,GAAG,GACP,IAAI,CAAC,CAAC;YACJ,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC,GAAG,IAAI,CAAC;YAClD,CAAC,CAAC,SAAS,CAAA;QACb,MAAM,OAAO,GACX,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;QAClE,mBAAmB;QACnB,OAAO,MAAM,CAAC,WAAW,CACvB,MAAM,CAAC,OAAO,CAAC;YACb,UAAU;YACV,OAAO,EAAE,IAAI,CAAC,gBAAgB;YAC9B,WAAW;YACX,SAAS;YACT,IAAI;YACJ,OAAO;YACP,YAAY;YACZ,KAAK;YACL,oBAAoB;YACpB,GAAG;YACH,MAAM;YACN,MAAM;YACN,MAAM;SACP,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,SAAS,CAAC,CACvC,CAAA;IACH,CAAC;IAED,CAAC,cAAc,CAAC,CAAC,KAAa,EAAE,OAAuB;QACrD,MAAM,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE;YACjC,KAAK;YACL,GAAG,OAAO;SACX,CAAC,CAAA;QACF,OAAO,sCAAsC,GAAG,EAAE,CAAA;IACpD,CAAC;IAED,KAAK,CAAO;IACZ,IAAI,IAAI;QACN,IAAI,IAAI,CAAC,KAAK;YAAE,OAAO,IAAI,CAAC,KAAK,CAAA;QACjC,MAAM,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,CAAA;QAC7C,IAAI,EAAE;YAAE,IAAI,CAAC,KAAK,GAAG,IAAI,IAAI,CAAC,EAAE,CAAC,CAAA;QACjC,OAAO,IAAI,CAAC,KAAK,CAAA;IACnB,CAAC;IAED,OAAO,CAAS;IAChB,IAAI,MAAM;QACR,IAAI,IAAI,CAAC,OAAO,KAAK,SAAS;YAAE,OAAO,IAAI,CAAC,OAAO,CAAA;QACnD,8CAA8C;QAC9C,yDAAyD;QACzD,4CAA4C;QAC5C,MAAM,EAAE,GAAG,IAAI,CAAC,YAAY,CAAA;QAC5B,IAAI,CAAC,OAAO,GAAG,EAAE,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,UAAU,CAAC,IAAI,GAAG,CAAA;QACrD,OAAO,IAAI,CAAC,OAAO,CAAA;IACrB,CAAC;IAED,aAAa,CAAmB;IAChC,IAAI,YAAY;QACd,IAAI,IAAI,CAAC,aAAa;YAAE,OAAO,IAAI,CAAC,aAAa,CAAA;QACjD,MAAM,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,eAAe,CAAC,EAAE,QAAQ,EAAE,CAAA;QACtD,IAAI,CAAC,aAAa,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAA;QAC5C,OAAO,IAAI,CAAC,aAAa,CAAA;IAC3B,CAAC;IAED,qBAAqB,CAAU;IAC/B,IAAI,oBAAoB;QACtB,IAAI,IAAI,CAAC,qBAAqB,KAAK,SAAS;YAC1C,OAAO,IAAI,CAAC,qBAAqB,CAAA;QACnC,IAAI,IAAI,CAAC,KAAK,IAAI,CAAC,IAAI,CAAC,IAAI;YAAE,OAAO,IAAI,CAAA;QACzC,MAAM,GAAG,GACP,IAAI,CAAC,YAAY,CAAC,wBAAwB,CAAC;YAC3C,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,2BAA2B,CAAA;QAEhD,IAAI,CAAC,qBAAqB;YACxB,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,GAAG,GAAG,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;QAC/C,OAAO,IAAI,CAAC,qBAAqB,CAAA;IACnC,CAAC;IAED,YAAY,CAAS;IACrB,IAAI,WAAW;QACb,IAAI,IAAI,CAAC,YAAY,KAAK,SAAS;YAAE,OAAO,IAAI,CAAC,YAAY,CAAA;QAC7D,IAAI,CAAC,YAAY;YACf,IAAI,CAAC,SAAS,CAAC,cAAc,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAA;QAClD,OAAO,IAAI,CAAC,YAAY,CAAA;IAC1B,CAAC;IAED;;;OAGG;IACH,MAAM,CAAU;IAChB,IAAI,KAAK;QACP,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS;YAAE,OAAO,IAAI,CAAC,MAAM,CAAA;QAEjD,4BAA4B;QAC5B,IAAI,IAAI,CAAC,YAAY,CAAC,SAAS;YAAE,OAAO,CAAC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,CAAA;QAE5D,0DAA0D;QAC1D,8CAA8C;QAC9C,8CAA8C;QAC9C,MAAM,EAAE,GAAG,IAAI,CAAC,WAAW,CAAA;QAC3B,IAAI,EAAE,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;YAAE,OAAO,CAAC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,CAAA;QAE3D,8CAA8C;QAC9C,yDAAyD;QACzD,4CAA4C;QAC5C,IAAI,CAAC,IAAI,CAAC,IAAI;YAAE,OAAO,CAAC,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC,CAAA;QAC5C,IAAI,CAAC,MAAM;YACT,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,MAAM,GAAG,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;QACvD,OAAO,IAAI,CAAC,MAAM,CAAA;IACpB,CAAC;IAED,OAAO,CAAC,CAAS;QACf,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;QAClB,IAAI,CAAC,WAAW,IAAI,CAAC,CAAC,UAAU,CAAA;IAClC,CAAC;IAED,IAAI,UAAU;QACZ,OAAO,IAAI,CAAC,WAAW,CAAA;IACzB,CAAC;IACD,IAAI,OAAO;QACT,OAAO,IAAI,CAAC,QAAQ,CAAA;IACtB,CAAC;IAED;;;;;;;;;;;;OAYG;IACH,cAAc,CACZ,UAA6B,EAAE;QAE/B,IAAI,CAAC,IAAI,CAAC,UAAU;YAAE,OAAO,KAAK,CAAA;QAClC,IAAI,IAAI,CAAC,eAAe,KAAK,IAAI,CAAC,UAAU,EAAE,CAAC;YAC7C,MAAM,KAAK,CAAC,yBAAyB,EAAE;gBACrC,IAAI,EAAE,YAAY;gBAClB,QAAQ,EAAE,IAAI;gBACd,MAAM,EAAE,IAAI,CAAC,UAAU;gBACvB,KAAK,EAAE,IAAI,CAAC,eAAe;gBAC3B,GAAG,OAAO;aACX,CAAC,CAAA;QACJ,CAAC;QACD,OAAO,IAAI,CAAA;IACb,CAAC;IAED,IAAI,eAAe;QACjB,IAAI,IAAI,CAAC,gBAAgB;YAAE,OAAO,IAAI,CAAC,gBAAgB,CAAA;QACvD,MAAM,IAAI,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAA;QACjC,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,KAAK;YAAE,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;QAC9C,MAAM,CAAC,GAAc,UAAU,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAA;QACtD,IAAI,CAAC,eAAe,GAAG,CAAC,CAAA;QACxB,OAAO,CAAC,CAAA;IACV,CAAC;IAED,IAAI,eAAe,CAAC,CAAY;QAC9B,IAAI,CAAC,gBAAgB,GAAG,CAAC,CAAA;QACzB,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE,CAAC,CAAC,CAAA;IAChC,CAAC;IAED,IAAI,SAAS,CAAC,CAAwB;QACpC,IAAI,CAAC,IAAI,CAAC,UAAU,IAAI,CAAC,EAAE,CAAC;YAC1B,IAAI,CAAC,UAAU,GAAG,CAAC,CAAA;YACnB,IAAI,IAAI,CAAC,eAAe;gBAAE,IAAI,CAAC,eAAe,GAAG,CAAC,CAAA;QACpD,CAAC;IACH,CAAC;IACD,IAAI,SAAS;QACX,OAAO,IAAI,CAAC,UAAU,CAAA;IACxB,CAAC;IAED;;OAEG;IACH,SAAS,CAAC,CAAS;QACjB,OAAO,YAAY,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAA;IACvC,CAAC;IAED;;OAEG;IACH,SAAS,CAAC,CAAS,EAAE,KAAsB;QACzC,IAAI,CAAC,QAAQ,GAAG,YAAY,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,EAAE,KAAK,CAAC,CAAA;IACvD,CAAC;IAED;;OAEG;IACH,MAAM;QACJ,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;QACvB,IAAI,CAAC,CAAC;YAAE,OAAO,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,CAAA;QACpC,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,CAAC,CAAA;QACrC,MAAM,GAAG,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,WAAW,CAAC,CAAA;QACvD,IAAI,CAAC,KAAK,GAAG,CAAC,GAAG,CAAC,CAAA;QAClB,OAAO,GAAG,CAAA;IACZ,CAAC;IAED,qDAAqD;IACrD,oBAAoB;IACpB,IAAI,IAAI;QACN,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,EAAE,CAAA;IAClD,CAAC;IAED,OAAO,CAAU;IACjB,IAAI,MAAM;QACR,IAAI,IAAI,CAAC,OAAO,KAAK,SAAS;YAAE,OAAO,IAAI,CAAC,OAAO,CAAA;QACnD,MAAM,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,cAAc,CAAC,EAAE,QAAQ,EAAE,CAAA;QACrD,oCAAoC;QACpC,IAAI,EAAE;YAAE,OAAO,CAAC,IAAI,CAAC,OAAO,GAAG,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAA;QACnD,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,CAAA;QACxB,sDAAsD;QACtD,IAAI,CAAC,IAAI;YAAE,OAAO,KAAK,CAAA;QACvB,4DAA4D;QAC5D,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAA;QACnC,IAAI,IAAI,CAAC,OAAO;YAAE,IAAI,CAAC,SAAS,CAAC,cAAc,EAAE,WAAW,CAAC,CAAA;QAC7D,OAAO,IAAI,CAAC,OAAO,CAAA;IACrB,CAAC;IAED,OAAO,CAAU;IACjB,IAAI,MAAM;QACR,IAAI,IAAI,CAAC,OAAO,KAAK,SAAS;YAAE,OAAO,IAAI,CAAC,OAAO,CAAA;QACnD,MAAM,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,kBAAkB,CAAC,EAAE,QAAQ,EAAE,CAAA;QACzD,IAAI,EAAE,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;YAAE,OAAO,CAAC,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC,CAAA;QAC7D,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,EAAE,CAAA;QACzB,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC;YAAE,OAAO,KAAK,CAAA;QAChC,IAAI,CAAC,OAAO,GAAG,GAAG,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,GAAG,CAAC,CAAC,CAAC,KAAK,IAAI,CAAA;QACjD,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACjB,IAAI,CAAC,SAAS,CAAC,kBAAkB,EAAE,MAAM,CAAC,CAAA;QAC5C,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,SAAS,CAAC,kBAAkB,EAAE,UAAU,CAAC,CAAA;YAC9C,IAAI,CAAC,SAAS,CAAC,gBAAgB,EAAE,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAA;QAC5D,CAAC;QACD,OAAO,IAAI,CAAC,OAAO,CAAA;IACrB,CAAC;IAED;;;;OAIG;IACH,KAAK;QACH,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YAChB,4DAA4D;YAC5D,wDAAwD;YACxD,qBAAqB;YACrB,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,IAAI;gBACvB,MAAM,KAAK,CAAC,4BAA4B,CAAC,CAAA;YAC3C,oBAAoB;YACpB,MAAM,CAAC,GAAG,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAA;YACnC,IAAI,CAAC,SAAS,CAAC,kBAAkB,EAAE,UAAU,CAAC,CAAA;YAC9C,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAA;YAChB,IAAI,CAAC,WAAW,GAAG,CAAC,CAAC,UAAU,CAAA;YAC/B,IAAI,CAAC,SAAS,CAAC,gBAAgB,EAAE,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAA;YAC1D,IAAI,CAAC,OAAO,GAAG,KAAK,CAAA;YACpB,OAAO,IAAI,CAAA;QACb,CAAC;QACD,OAAO,KAAK,CAAA;IACd,CAAC;IAED;;;OAGG;IACH,IAAI;QACF,IAAI,CAAC,KAAK,EAAE,CAAA;QACZ,OAAO,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAA;IACjC,CAAC;IAED;;OAEG;IACH,IAAI;QACF,IAAI,IAAI,CAAC,KAAK,KAAK,SAAS;YAAE,OAAO,IAAI,CAAC,KAAK,CAAA;QAC/C,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,CAAA;QACxB,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,IAAI,IAAI,CAAY,CAAA;QAC/C,IAAI,CAAC,KAAK,GAAG,GAAG,CAAA;QAChB,OAAO,GAAG,CAAA;IACZ,CAAC;IAED;;;;OAIG;IACH,MAAM,CAAC,MAAM,CAAC,MAAc;QAC1B,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACtB,OAAO,eAAe,CAAA;QACxB,CAAC;QACD,MAAM,QAAQ,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,CAAA;QACpC,IAAI,MAAM,CAAC,MAAM,GAAG,QAAQ,EAAE,CAAC;YAC7B,OAAO,eAAe,CAAA;QACxB,CAAC;QACD,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAA;QAC3D,MAAM,aAAa,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAA;QAClD,sEAAsE;QACtE,MAAM,OAAO,GAAa,EAAE,CAAA;QAC5B,IAAI,CAAC,GAAG,CAAC,CAAA;QACT,IAAI,SAAS,GAA0B,SAAS,CAAA;QAChD,OAAO,CAAC,GAAG,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACpC,MAAM,IAAI,GAAG,QAAQ,CAAC,aAAa,EAAE,CAAC,CAAC,CAAA;YACvC,MAAM,GAAG,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,CAAA;YACnD,oEAAoE;YACpE,IACE,OAAO,CAAC,MAAM,GAAG,CAAC,KAAK,CAAC;gBACxB,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,KAAK,WAAW,EACnD,CAAC;gBACD,SAAS,GAAG,MAAM,CAAC,GAAG,CAAc,CAAA;YACtC,CAAC;YACD,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;YACjB,CAAC,IAAI,IAAI,CAAA;QACX,CAAC;QACD,MAAM,IAAI,GAAG,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAA;QAEtC,MAAM,CAAC,GAAG,IAAI,UAAU,CACtB,UAAU,EACV,YAAY,CACV,OAAO,EACP,gBAAgB,EAChB,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CACxB,EACD;YACE,SAAS;YACT,cAAc,EAAE,IAAI;SACrB,CACF,CAAA;QAED,CAAC,CAAC,KAAK,GAAG,CAAC,IAAI,CAAC,CAAA;QAChB,CAAC,CAAC,WAAW,GAAG,IAAI,CAAC,UAAU,CAAA;QAC/B,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC;YACb,IAAI,CAAC;gBACH,CAAC,CAAC,IAAI,EAAE,CAAA;YACV,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,eAAe,CAAA;YACxB,CAAC;QACH,CAAC;QACD,OAAO,CAAC,CAAA;IACV,CAAC;IAED,MAAM,CAAC,WAAW,CAAC,MAAc;QAC/B,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC;YAAE,OAAO,KAAK,CAAA;QACnC,MAAM,QAAQ,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,CAAA;QACpC,MAAM,SAAS,GAAG,MAAM,CAAC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,GAAG,CAAC,CAAC,CAAA;QACzD,OAAO,SAAS,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,SAAS,CAAC,CAAC,CAAC,KAAK,IAAI,CAAA;IACvD,CAAC;IAED;;OAEG;IACH,gEAAgE;IAChE,mEAAmE;IACnE,MAAM;QACJ,IAAI,IAAI,CAAC,MAAM;YAAE,IAAI,CAAC,IAAI,EAAE,CAAA;QAC5B,MAAM,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAA;QAChD,MAAM,MAAM,GAAa,CAAC,EAAE,CAAC,CAAA;QAC7B,IAAI,UAAU,GAAG,EAAE,CAAC,UAAU,GAAG,CAAC,CAAA;QAClC,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAC9B,MAAM,KAAK,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,CAAA;YACnC,MAAM,EAAE,GAAG,CAAC,CAAC,UAAU,GAAG,CAAC,CAAA;YAC3B,UAAU,IAAI,EAAE,CAAA;YAChB,KAAK,CAAC,GAAG,CACP;gBACE,CAAC,EAAE,IAAI,EAAE,CAAC,GAAG,IAAI;gBACjB,CAAC,EAAE,IAAI,EAAE,CAAC,GAAG,IAAI;gBACjB,CAAC,EAAE,IAAI,CAAC,CAAC,GAAG,IAAI;gBAChB,EAAE,GAAG,IAAI;aACV,EACD,CAAC,CACF,CAAA;YACD,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,CAAA;QACvB,CAAC;QAED,MAAM,KAAK,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,CAAA;QACnC,KAAK,CAAC,GAAG,CACP;YACE,CAAC,UAAU,IAAI,EAAE,CAAC,GAAG,IAAI;YACzB,CAAC,UAAU,IAAI,EAAE,CAAC,GAAG,IAAI;YACzB,CAAC,UAAU,IAAI,CAAC,CAAC,GAAG,IAAI;YACxB,UAAU,GAAG,IAAI;SAClB,EACD,CAAC,CACF,CAAA;QACD,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAA;QACrB,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAA;QAC1B,OAAO,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI,CAAC,WAAW,CAAC,CAAA;IAC7D,CAAC;CACF;AAED,MAAM,eAAe,GAAG,IAAI,UAAU,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA","sourcesContent":["// A response object in the cache.\n//\n// The cache stores Buffer objects, and it's convenient to have headers/body\n// together, so we have a simple data structure for this.\n//\n// The shape of it is:\n//\n// [head length]\n// <status code in ascii>\n// [headers]\n// [body]\n//\n// The [UInt32BE head length] is 4 bytes specifying the full length of the\n// status code plus all header keys and values.\n//\n// The [headers] section is key/value/key2/value2/... where each key and value\n// is a 4-byte Uint32BE length, followed by that many bytes.\n//\n// From there, the body can be of any indeterminate length, and is the rest\n// of the file.\n\nimport type { ErrorCauseOptions } from '@vltpkg/error-cause'\nimport { error } from '@vltpkg/error-cause'\nimport type { Integrity, JSONField } from '@vltpkg/types'\nimport ccp from 'cache-control-parser'\nimport { createHash } from 'node:crypto'\nimport type { InspectOptions } from 'node:util'\nimport { inspect } from 'node:util'\nimport { gunzipSync } from 'node:zlib'\nimport { getRawHeader, setRawHeader } from './raw-header.ts'\n\nexport type JSONObj = Record<string, JSONField>\n\nconst readSize = (buf: Buffer, offset: number) => {\n const a = buf[offset]\n const b = buf[offset + 1]\n const c = buf[offset + 2]\n const d = buf[offset + 3]\n\n // not possible, we check the length\n /* c8 ignore start */\n if (\n a === undefined ||\n b === undefined ||\n c === undefined ||\n d === undefined\n ) {\n throw error('Invalid buffer, not long enough to readSize', {\n found: buf.length,\n })\n }\n /* c8 ignore stop */\n\n return (a << 24) | (b << 16) | (c << 8) | d\n}\n\nconst kCustomInspect = Symbol.for('nodejs.util.inspect.custom')\n\nexport type CacheEntryOptions = {\n /**\n * The expected integrity value for this response body\n */\n integrity?: Integrity\n /**\n * Whether to trust the integrity, or calculate the actual value.\n *\n * This indicates that we just accept whatever the integrity is as the actual\n * integrity for saving back to the cache, because it's coming directly from\n * the registry that we fetched a packument from, and is an initial gzipped\n * artifact request.\n */\n trustIntegrity?: boolean\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 class CacheEntry {\n #statusCode: number\n #headers: Buffer[]\n #body: Buffer[] = []\n #bodyLength = 0\n #integrity?: Integrity\n #integrityActual?: Integrity\n #json?: JSONObj\n #trustIntegrity\n #staleWhileRevalidateFactor\n\n constructor(\n statusCode: number,\n headers: Buffer[],\n {\n integrity,\n trustIntegrity = false,\n 'stale-while-revalidate-factor':\n staleWhileRevalidateFactor = 60,\n }: CacheEntryOptions = {},\n ) {\n this.#headers = headers\n this.#statusCode = statusCode\n this.#trustIntegrity = trustIntegrity\n this.#staleWhileRevalidateFactor = staleWhileRevalidateFactor\n if (integrity) this.integrity = integrity\n }\n\n get #headersAsObject(): [string, string][] {\n const ret: [string, string][] = []\n for (let i = 0; i < this.#headers.length - 1; i += 2) {\n const key = String(this.#headers[i])\n const val = String(this.#headers[i + 1])\n ret.push([key, val])\n }\n return ret\n }\n\n toJSON() {\n const {\n statusCode,\n valid,\n staleWhileRevalidate,\n cacheControl,\n date,\n contentType,\n integrity,\n maxAge,\n isGzip,\n isJSON,\n } = this\n /* c8 ignore start */\n const age =\n date ?\n Math.floor((Date.now() - date.getTime()) / 1000)\n : undefined\n const expires =\n date ? new Date(date.getTime() + this.maxAge * 1000) : undefined\n /* c8 ignore end */\n return Object.fromEntries(\n Object.entries({\n statusCode,\n headers: this.#headersAsObject,\n contentType,\n integrity,\n date,\n expires,\n cacheControl,\n valid,\n staleWhileRevalidate,\n age,\n maxAge,\n isGzip,\n isJSON,\n }).filter(([_, v]) => v !== undefined),\n )\n }\n\n [kCustomInspect](depth: number, options: InspectOptions): string {\n const str = inspect(this.toJSON(), {\n depth,\n ...options,\n })\n return `@vltpkg/registry-client.CacheEntry ${str}`\n }\n\n #date?: Date\n get date(): Date | undefined {\n if (this.#date) return this.#date\n const dh = this.getHeader('date')?.toString()\n if (dh) this.#date = new Date(dh)\n return this.#date\n }\n\n #maxAge?: number\n get maxAge(): number {\n if (this.#maxAge !== undefined) return this.#maxAge\n // see if the max-age has not yet been crossed\n // default to 5m if maxage is not set, as some registries\n // do not set a cache control header at all.\n const cc = this.cacheControl\n this.#maxAge = cc['max-age'] || cc['s-maxage'] || 300\n return this.#maxAge\n }\n\n #cacheControl?: ccp.CacheControl\n get cacheControl(): ccp.CacheControl {\n if (this.#cacheControl) return this.#cacheControl\n const cc = this.getHeader('cache-control')?.toString()\n this.#cacheControl = cc ? ccp.parse(cc) : {}\n return this.#cacheControl\n }\n\n #staleWhileRevalidate?: boolean\n get staleWhileRevalidate(): boolean {\n if (this.#staleWhileRevalidate !== undefined)\n return this.#staleWhileRevalidate\n if (this.valid || !this.date) return true\n const swv =\n this.cacheControl['stale-while-revalidate'] ??\n this.maxAge * this.#staleWhileRevalidateFactor\n\n this.#staleWhileRevalidate =\n this.date.getTime() + swv * 1000 > Date.now()\n return this.#staleWhileRevalidate\n }\n\n #contentType?: string\n get contentType() {\n if (this.#contentType !== undefined) return this.#contentType\n this.#contentType =\n this.getHeader('content-type')?.toString() ?? ''\n return this.#contentType\n }\n\n /**\n * `true` if the entry represents a cached response that is still\n * valid to use.\n */\n #valid?: boolean\n get valid(): boolean {\n if (this.#valid !== undefined) return this.#valid\n\n // immutable = never changes\n if (this.cacheControl.immutable) return (this.#valid = true)\n\n // some registries do text/json, some do application/json,\n // some do application/vnd.npm.install-v1+json\n // If it's NOT json, it's an immutable tarball\n const ct = this.contentType\n if (ct && !/\\bjson\\b/.test(ct)) return (this.#valid = true)\n\n // see if the max-age has not yet been crossed\n // default to 5m if maxage is not set, as some registries\n // do not set a cache control header at all.\n if (!this.date) return (this.#valid = false)\n this.#valid =\n this.date.getTime() + this.maxAge * 1000 > Date.now()\n return this.#valid\n }\n\n addBody(b: Buffer) {\n this.#body.push(b)\n this.#bodyLength += b.byteLength\n }\n\n get statusCode() {\n return this.#statusCode\n }\n get headers() {\n return this.#headers\n }\n\n /**\n * Check that the sri integrity string that was provided to the ctor\n * matches the body that we actually received. This should only be called\n * AFTER the entire body has been completely downloaded.\n *\n * This method **will throw** if the integrity values do not match.\n *\n * Note that this will *usually* not be true if the value is coming out of\n * the cache, because the cache entries are un-gzipped in place. It should\n * _only_ be called for artifacts that come from an actual http response.\n *\n * Returns true if anything was actually verified.\n */\n checkIntegrity(\n context: ErrorCauseOptions = {},\n ): this is CacheEntry & { integrity: Integrity } {\n if (!this.#integrity) return false\n if (this.integrityActual !== this.#integrity) {\n throw error('Integrity check failure', {\n code: 'EINTEGRITY',\n response: this,\n wanted: this.#integrity,\n found: this.integrityActual,\n ...context,\n })\n }\n return true\n }\n\n get integrityActual(): Integrity {\n if (this.#integrityActual) return this.#integrityActual\n const hash = createHash('sha512')\n for (const buf of this.#body) hash.update(buf)\n const i: Integrity = `sha512-${hash.digest('base64')}`\n this.integrityActual = i\n return i\n }\n\n set integrityActual(i: Integrity) {\n this.#integrityActual = i\n this.setHeader('integrity', i)\n }\n\n set integrity(i: Integrity | undefined) {\n if (!this.#integrity && i) {\n this.#integrity = i\n if (this.#trustIntegrity) this.integrityActual = i\n }\n }\n get integrity() {\n return this.#integrity\n }\n\n /**\n * Give it a key, and it'll return the buffer of that header value\n */\n getHeader(h: string) {\n return getRawHeader(this.#headers, h)\n }\n\n /**\n * Set a header to a specific value\n */\n setHeader(h: string, value: Buffer | string) {\n this.#headers = setRawHeader(this.#headers, h, value)\n }\n\n /**\n * Return the body of the entry as a Buffer\n */\n buffer(): Buffer {\n const b = this.#body[0]\n if (!b) return Buffer.allocUnsafe(0)\n if (this.#body.length === 1) return b\n const cat = Buffer.concat(this.#body, this.#bodyLength)\n this.#body = [cat]\n return cat\n }\n\n // return the buffer if it's a tarball, or the parsed\n // JSON if it's not.\n get body(): Buffer | Record<string, any> {\n return this.isJSON ? this.json() : this.buffer()\n }\n\n #isJSON?: boolean\n get isJSON(): boolean {\n if (this.#isJSON !== undefined) return this.#isJSON\n const ct = this.getHeader('content-type')?.toString()\n // if it says it's json, assume json\n if (ct) return (this.#isJSON = /\\bjson\\b/.test(ct))\n const text = this.text()\n // don't cache, because we might just not have it yet.\n if (!text) return false\n // all registry json starts with {, and no tarball ever can.\n this.#isJSON = text.startsWith('{')\n if (this.#isJSON) this.setHeader('content-type', 'text/json')\n return this.#isJSON\n }\n\n #isGzip?: boolean\n get isGzip(): boolean {\n if (this.#isGzip !== undefined) return this.#isGzip\n const ce = this.getHeader('content-encoding')?.toString()\n if (ce && !/\\bgzip\\b/.test(ce)) return (this.#isGzip = false)\n const buf = this.buffer()\n if (buf.length < 2) return false\n this.#isGzip = buf[0] === 0x1f && buf[1] === 0x8b\n if (this.#isGzip) {\n this.setHeader('content-encoding', 'gzip')\n } else {\n this.setHeader('content-encoding', 'identity')\n this.setHeader('content-length', String(this.#bodyLength))\n }\n return this.#isGzip\n }\n\n /**\n * Un-gzip encode the body.\n * Returns true if it was previously gzip (so something was done), otherwise\n * returns false.\n */\n unzip() {\n if (this.isGzip) {\n // we know that if we know it's gzip, that the body has been\n // flattened to a single buffer, so save the extra call.\n /* c8 ignore start */\n if (this.#body[0] == null)\n throw error('Invalid buffer, cant unzip')\n /* c8 ignore stop */\n const b = gunzipSync(this.#body[0])\n this.setHeader('content-encoding', 'identity')\n this.#body = [b]\n this.#bodyLength = b.byteLength\n this.setHeader('content-length', String(this.#bodyLength))\n this.#isGzip = false\n return true\n }\n return false\n }\n\n /**\n * Return the body of the entry as utf8 text\n * Automatically unzips if the content is gzip encoded\n */\n text() {\n this.unzip()\n return this.buffer().toString()\n }\n\n /**\n * Parse the entry body as JSON and return the result\n */\n json(): JSONObj {\n if (this.#json !== undefined) return this.#json\n const text = this.text()\n const obj = JSON.parse(text || '{}') as JSONObj\n this.#json = obj\n return obj\n }\n\n /**\n * Pass the contents of a @vltpkg/cache.Cache object as a buffer,\n * and this static method will decode it into a CacheEntry representing\n * the cached response.\n */\n static decode(buffer: Buffer): CacheEntry {\n if (buffer.length < 4) {\n return emptyCacheEntry\n }\n const headSize = readSize(buffer, 0)\n if (buffer.length < headSize) {\n return emptyCacheEntry\n }\n const statusCode = Number(buffer.subarray(4, 7).toString())\n const headersBuffer = buffer.subarray(7, headSize)\n // walk through the headers array, building up the rawHeaders Buffer[]\n const headers: Buffer[] = []\n let i = 0\n let integrity: Integrity | undefined = undefined\n while (i < headersBuffer.length - 4) {\n const size = readSize(headersBuffer, i)\n const val = headersBuffer.subarray(i + 4, i + size)\n // if the last one was the key integrity, then this one is the value\n if (\n headers.length % 2 === 1 &&\n String(headers[headers.length - 1]) === 'integrity'\n ) {\n integrity = String(val) as Integrity\n }\n headers.push(val)\n i += size\n }\n const body = buffer.subarray(headSize)\n\n const c = new CacheEntry(\n statusCode,\n setRawHeader(\n headers,\n 'content-length',\n String(body.byteLength),\n ),\n {\n integrity,\n trustIntegrity: true,\n },\n )\n\n c.#body = [body]\n c.#bodyLength = body.byteLength\n if (c.isJSON) {\n try {\n c.json()\n } catch {\n return emptyCacheEntry\n }\n }\n return c\n }\n\n static isGzipEntry(buffer: Buffer): boolean {\n if (buffer.length < 4) return false\n const headSize = readSize(buffer, 0)\n const gzipBytes = buffer.subarray(headSize, headSize + 2)\n return gzipBytes[0] === 0x1f && gzipBytes[1] === 0x8b\n }\n\n /**\n * Encode the entry as a single Buffer for writing to the cache\n */\n // TODO: should this maybe not concat, and just return Buffer[]?\n // Then we can writev it to the cache file and save the memory copy\n encode(): Buffer {\n if (this.isJSON) this.json()\n const sb = Buffer.from(String(this.#statusCode))\n const chunks: Buffer[] = [sb]\n let headLength = sb.byteLength + 4\n for (const h of this.#headers) {\n const hlBuf = Buffer.allocUnsafe(4)\n const hl = h.byteLength + 4\n headLength += hl\n hlBuf.set(\n [\n (hl >> 24) & 0xff,\n (hl >> 16) & 0xff,\n (hl >> 8) & 0xff,\n hl & 0xff,\n ],\n 0,\n )\n chunks.push(hlBuf, h)\n }\n\n const hlBuf = Buffer.allocUnsafe(4)\n hlBuf.set(\n [\n (headLength >> 24) & 0xff,\n (headLength >> 16) & 0xff,\n (headLength >> 8) & 0xff,\n headLength & 0xff,\n ],\n 0,\n )\n chunks.unshift(hlBuf)\n chunks.push(...this.#body)\n return Buffer.concat(chunks, headLength + this.#bodyLength)\n }\n}\n\nconst emptyCacheEntry = new CacheEntry(0, [])\n"]}
@@ -0,0 +1,2 @@
1
+ export declare const register: (path: string, method: "HEAD" | "GET", url: string | URL) => void;
2
+ //# sourceMappingURL=cache-revalidate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache-revalidate.d.ts","sourceRoot":"","sources":["../../src/cache-revalidate.ts"],"names":[],"mappings":"AAUA,eAAO,MAAM,QAAQ,SACb,MAAM,UACJ,MAAM,GAAG,KAAK,OACjB,MAAM,GAAG,GAAG,KAChB,IASF,CAAA"}
@@ -0,0 +1,66 @@
1
+ import { spawn } from 'node:child_process';
2
+ import { __CODE_SPLIT_SCRIPT_NAME } from "./revalidate.js";
3
+ import { pathToFileURL } from 'node:url';
4
+ const isDeno = globalThis.Deno != undefined;
5
+ let didProcessBeforeExitHook = false;
6
+ const registered = new Map();
7
+ export const register = (path, method, url) => {
8
+ const r = registered.get(path) ?? new Set();
9
+ const key = `${method} ${url}`;
10
+ r.add(key);
11
+ registered.set(path, r);
12
+ if (!didProcessBeforeExitHook) {
13
+ didProcessBeforeExitHook = true;
14
+ process.on('beforeExit', handleBeforeExit);
15
+ }
16
+ };
17
+ const handleBeforeExit = () => {
18
+ for (const [path, r] of registered) {
19
+ /* c8 ignore next */
20
+ if (!r.size)
21
+ return;
22
+ const env = { ...process.env };
23
+ const args = [];
24
+ /* c8 ignore start */
25
+ // When compiled the script to be run is passed as an
26
+ // environment variable and then routed by the main entry point
27
+ if (process.env.__VLT_INTERNAL_COMPILED) {
28
+ env.__VLT_INTERNAL_MAIN = pathToFileURL(__CODE_SPLIT_SCRIPT_NAME).toString();
29
+ args.push(path);
30
+ }
31
+ else {
32
+ // If we are running deno from source we need to add the
33
+ // unstable flags we need. The '-A' flag does not need
34
+ // to be passed in as Deno supplies that automatically.
35
+ if (isDeno) {
36
+ args.push('--unstable-node-globals', '--unstable-bare-node-builtins');
37
+ }
38
+ /* c8 ignore stop */
39
+ args.push(__CODE_SPLIT_SCRIPT_NAME, path);
40
+ }
41
+ registered.delete(path);
42
+ // Deno on Windows does not support detached processes
43
+ // https://github.com/denoland/deno/issues/25867
44
+ // TODO: figure out something better to do here?
45
+ /* c8 ignore next */
46
+ const detached = !(isDeno && process.platform === 'win32');
47
+ const proc = spawn(process.execPath, args, {
48
+ detached,
49
+ stdio: ['pipe', 'ignore', 'ignore'],
50
+ env,
51
+ });
52
+ for (const key of r) {
53
+ proc.stdin.write(`${key}\0`);
54
+ }
55
+ proc.stdin.end();
56
+ // Another Deno oddity. Calling unref on a spawned process will kill the
57
+ // process unless it is detached. https://github.com/denoland/deno/issues/21446
58
+ // So in this case Deno on Windows will be slower to exit the main process
59
+ // since it will wait for the child process to exit.
60
+ // TODO: figure out something better to do here?
61
+ if (detached) {
62
+ proc.unref();
63
+ }
64
+ }
65
+ };
66
+ //# sourceMappingURL=cache-revalidate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache-revalidate.js","sourceRoot":"","sources":["../../src/cache-revalidate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAA;AAC1C,OAAO,EAAE,wBAAwB,EAAE,MAAM,iBAAiB,CAAA;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAExC,MAAM,MAAM,GACT,UAAiD,CAAC,IAAI,IAAI,SAAS,CAAA;AAEtE,IAAI,wBAAwB,GAAG,KAAK,CAAA;AACpC,MAAM,UAAU,GAAG,IAAI,GAAG,EAAuB,CAAA;AAEjD,MAAM,CAAC,MAAM,QAAQ,GAAG,CACtB,IAAY,EACZ,MAAsB,EACtB,GAAiB,EACX,EAAE;IACR,MAAM,CAAC,GAAG,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,IAAI,GAAG,EAAU,CAAA;IACnD,MAAM,GAAG,GAAG,GAAG,MAAM,IAAI,GAAG,EAAE,CAAA;IAC9B,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;IACV,UAAU,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,CAAA;IACvB,IAAI,CAAC,wBAAwB,EAAE,CAAC;QAC9B,wBAAwB,GAAG,IAAI,CAAA;QAC/B,OAAO,CAAC,EAAE,CAAC,YAAY,EAAE,gBAAgB,CAAC,CAAA;IAC5C,CAAC;AACH,CAAC,CAAA;AAED,MAAM,gBAAgB,GAAG,GAAG,EAAE;IAC5B,KAAK,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,UAAU,EAAE,CAAC;QACnC,oBAAoB;QACpB,IAAI,CAAC,CAAC,CAAC,IAAI;YAAE,OAAM;QACnB,MAAM,GAAG,GAAG,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,CAAA;QAC9B,MAAM,IAAI,GAAG,EAAE,CAAA;QACf,qBAAqB;QACrB,qDAAqD;QACrD,+DAA+D;QAC/D,IAAI,OAAO,CAAC,GAAG,CAAC,uBAAuB,EAAE,CAAC;YACxC,GAAG,CAAC,mBAAmB,GAAG,aAAa,CACrC,wBAAwB,CACzB,CAAC,QAAQ,EAAE,CAAA;YACZ,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QACjB,CAAC;aAAM,CAAC;YACN,wDAAwD;YACxD,sDAAsD;YACtD,uDAAuD;YACvD,IAAI,MAAM,EAAE,CAAC;gBACX,IAAI,CAAC,IAAI,CACP,yBAAyB,EACzB,+BAA+B,CAChC,CAAA;YACH,CAAC;YACD,oBAAoB;YACpB,IAAI,CAAC,IAAI,CAAC,wBAAwB,EAAE,IAAI,CAAC,CAAA;QAC3C,CAAC;QACD,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;QACvB,sDAAsD;QACtD,gDAAgD;QAChD,gDAAgD;QAChD,oBAAoB;QACpB,MAAM,QAAQ,GAAG,CAAC,CAAC,MAAM,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAA;QAC1D,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,QAAQ,EAAE,IAAI,EAAE;YACzC,QAAQ;YACR,KAAK,EAAE,CAAC,MAAM,EAAE,QAAQ,EAAE,QAAQ,CAAC;YACnC,GAAG;SACJ,CAAC,CAAA;QACF,KAAK,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC;YACpB,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,GAAG,IAAI,CAAC,CAAA;QAC9B,CAAC;QACD,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,CAAA;QAChB,wEAAwE;QACxE,+EAA+E;QAC/E,0EAA0E;QAC1E,oDAAoD;QACpD,gDAAgD;QAChD,IAAI,QAAQ,EAAE,CAAC;YACb,IAAI,CAAC,KAAK,EAAE,CAAA;QACd,CAAC;IACH,CAAC;AACH,CAAC,CAAA","sourcesContent":["import { spawn } from 'node:child_process'\nimport { __CODE_SPLIT_SCRIPT_NAME } from './revalidate.ts'\nimport { pathToFileURL } from 'node:url'\n\nconst isDeno =\n (globalThis as typeof globalThis & { Deno?: any }).Deno != undefined\n\nlet didProcessBeforeExitHook = false\nconst registered = new Map<string, Set<string>>()\n\nexport const register = (\n path: string,\n method: 'HEAD' | 'GET',\n url: string | URL,\n): void => {\n const r = registered.get(path) ?? new Set<string>()\n const key = `${method} ${url}`\n r.add(key)\n registered.set(path, r)\n if (!didProcessBeforeExitHook) {\n didProcessBeforeExitHook = true\n process.on('beforeExit', handleBeforeExit)\n }\n}\n\nconst handleBeforeExit = () => {\n for (const [path, r] of registered) {\n /* c8 ignore next */\n if (!r.size) return\n const env = { ...process.env }\n const args = []\n /* c8 ignore start */\n // When compiled the script to be run is passed as an\n // environment variable and then routed by the main entry point\n if (process.env.__VLT_INTERNAL_COMPILED) {\n env.__VLT_INTERNAL_MAIN = pathToFileURL(\n __CODE_SPLIT_SCRIPT_NAME,\n ).toString()\n args.push(path)\n } else {\n // If we are running deno from source we need to add the\n // unstable flags we need. The '-A' flag does not need\n // to be passed in as Deno supplies that automatically.\n if (isDeno) {\n args.push(\n '--unstable-node-globals',\n '--unstable-bare-node-builtins',\n )\n }\n /* c8 ignore stop */\n args.push(__CODE_SPLIT_SCRIPT_NAME, path)\n }\n registered.delete(path)\n // Deno on Windows does not support detached processes\n // https://github.com/denoland/deno/issues/25867\n // TODO: figure out something better to do here?\n /* c8 ignore next */\n const detached = !(isDeno && process.platform === 'win32')\n const proc = spawn(process.execPath, args, {\n detached,\n stdio: ['pipe', 'ignore', 'ignore'],\n env,\n })\n for (const key of r) {\n proc.stdin.write(`${key}\\0`)\n }\n proc.stdin.end()\n // Another Deno oddity. Calling unref on a spawned process will kill the\n // process unless it is detached. https://github.com/denoland/deno/issues/21446\n // So in this case Deno on Windows will be slower to exit the main process\n // since it will wait for the child process to exit.\n // TODO: figure out something better to do here?\n if (detached) {\n proc.unref()\n }\n }\n}\n"]}
@@ -0,0 +1,2 @@
1
+ export declare const deleteHeader: <H extends [string, string[] | string][] | Iterable<[string, string[] | string | undefined]> | Record<string, string[] | string | undefined> | string[]>(headers: H | null | undefined, key: string) => H;
2
+ //# sourceMappingURL=delete-header.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delete-header.d.ts","sourceRoot":"","sources":["../../src/delete-header.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,YAAY,GACvB,CAAC,SACG,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC,EAAE,GAC7B,QAAQ,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,SAAS,CAAC,CAAC,GACjD,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,SAAS,CAAC,GAC7C,MAAM,EAAE,WAEH,CAAC,GAAG,IAAI,GAAG,SAAS,OACxB,MAAM,KACV,CA2BF,CAAA"}
@@ -0,0 +1,32 @@
1
+ import { isIterable } from "./is-iterable.js";
2
+ export const deleteHeader = (headers, key) => {
3
+ if (!headers)
4
+ return {};
5
+ if (Array.isArray(headers)) {
6
+ if (!headers.length)
7
+ return headers;
8
+ if (Array.isArray(headers[0])) {
9
+ const index = headers.findIndex(([k]) => k.toLowerCase() === key.toLowerCase());
10
+ if (index !== -1)
11
+ headers.splice(index, 1);
12
+ }
13
+ else {
14
+ const h = headers;
15
+ for (let i = 0; i < h.length; i += 2) {
16
+ if (h[i]?.toLowerCase() === key.toLowerCase()) {
17
+ headers.splice(i, 2);
18
+ break;
19
+ }
20
+ }
21
+ }
22
+ return headers;
23
+ }
24
+ else if (isIterable(headers)) {
25
+ return deleteHeader([...headers], key);
26
+ }
27
+ else {
28
+ delete headers[key];
29
+ return headers;
30
+ }
31
+ };
32
+ //# sourceMappingURL=delete-header.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delete-header.js","sourceRoot":"","sources":["../../src/delete-header.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAE7C,MAAM,CAAC,MAAM,YAAY,GAAG,CAO1B,OAA6B,EAC7B,GAAW,EACR,EAAE;IACL,IAAI,CAAC,OAAO;QAAE,OAAO,EAAO,CAAA;IAC5B,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QAC3B,IAAI,CAAC,OAAO,CAAC,MAAM;YAAE,OAAO,OAAO,CAAA;QACnC,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YAC9B,MAAM,KAAK,GAAI,OAA8B,CAAC,SAAS,CACrD,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,KAAK,GAAG,CAAC,WAAW,EAAE,CAC/C,CAAA;YACD,IAAI,KAAK,KAAK,CAAC,CAAC;gBAAE,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAA;QAC5C,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,GAAG,OAAmB,CAAA;YAC7B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;gBACrC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,KAAK,GAAG,CAAC,WAAW,EAAE,EAAE,CAAC;oBAC9C,OAAO,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;oBACpB,MAAK;gBACP,CAAC;YACH,CAAC;QACH,CAAC;QACD,OAAO,OAAO,CAAA;IAChB,CAAC;SAAM,IACL,UAAU,CAA0C,OAAO,CAAC,EAC5D,CAAC;QACD,OAAO,YAAY,CAAC,CAAC,GAAG,OAAO,CAAiB,EAAE,GAAG,CAAC,CAAA;IACxD,CAAC;SAAM,CAAC;QACN,OAAO,OAAO,CAAC,GAAG,CAAC,CAAA;QACnB,OAAO,OAAO,CAAA;IAChB,CAAC;AACH,CAAC,CAAA","sourcesContent":["import { isIterable } from './is-iterable.ts'\n\nexport const deleteHeader = <\n H extends\n | [string, string[] | string][]\n | Iterable<[string, string[] | string | undefined]>\n | Record<string, string[] | string | undefined>\n | string[],\n>(\n headers: H | null | undefined,\n key: string,\n): H => {\n if (!headers) return {} as H\n if (Array.isArray(headers)) {\n if (!headers.length) return headers\n if (Array.isArray(headers[0])) {\n const index = (headers as [string, string][]).findIndex(\n ([k]) => k.toLowerCase() === key.toLowerCase(),\n )\n if (index !== -1) headers.splice(index, 1)\n } else {\n const h = headers as string[]\n for (let i = 0; i < h.length; i += 2) {\n if (h[i]?.toLowerCase() === key.toLowerCase()) {\n headers.splice(i, 2)\n break\n }\n }\n }\n return headers\n } else if (\n isIterable<[string, string[] | string | undefined]>(headers)\n ) {\n return deleteHeader([...headers] as unknown as H, key)\n } else {\n delete headers[key]\n return headers\n }\n}\n"]}
package/dist/esm/env.d.ts CHANGED
@@ -4,8 +4,4 @@ export declare const isNode: boolean;
4
4
  export declare const bun: string | undefined;
5
5
  export declare const deno: string | undefined;
6
6
  export declare const node: string | undefined;
7
- export declare const engine: {
8
- name: string;
9
- version: string;
10
- } | undefined;
11
7
  //# sourceMappingURL=env.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../../src/env.ts"],"names":[],"mappings":"AASA,eAAO,MAAM,MAAM,SAAc,CAAA;AACjC,eAAO,MAAM,KAAK,SAAwB,CAAA;AAG1C,eAAO,MAAM,MAAM,SAA+C,CAAA;AAGlE,eAAO,MAAM,GAAG,oBAAwC,CAAA;AACxD,eAAO,MAAM,IAAI,oBAA0C,CAAA;AAC3D,eAAO,MAAM,IAAI,oBAA0C,CAAA;AAE3D,eAAO,MAAM,MAAM;;;aAGN,CAAA"}
1
+ {"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../../src/env.ts"],"names":[],"mappings":"AASA,eAAO,MAAM,MAAM,SAAc,CAAA;AACjC,eAAO,MAAM,KAAK,SAAwB,CAAA;AAG1C,eAAO,MAAM,MAAM,SAA+C,CAAA;AAGlE,eAAO,MAAM,GAAG,oBAAwC,CAAA;AACxD,eAAO,MAAM,IAAI,oBAA0C,CAAA;AAC3D,eAAO,MAAM,IAAI,oBAA0C,CAAA"}
package/dist/esm/env.js CHANGED
@@ -10,7 +10,4 @@ export const isNode = !isDeno && !isBun && 'node' in proc.versions;
10
10
  export const bun = isBun ? proc.versions.bun : undefined;
11
11
  export const deno = isDeno ? proc.versions.deno : undefined;
12
12
  export const node = isNode ? proc.versions.node : undefined;
13
- export const engine = isNode || isDeno ? { name: 'v8', version: proc.versions.v8 }
14
- : isBun && bun ? { name: 'bun', version: bun }
15
- : undefined;
16
13
  //# sourceMappingURL=env.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"env.js","sourceRoot":"","sources":["../../src/env.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,cAAc,CAAA;AAE/B,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,UAGrB,CAAA;AAED,MAAM,KAAK,GAAG,CAAC,CAAU,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,CAAC,CAAA;AAE1D,MAAM,CAAC,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,CAAA;AACjC,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,MAAM,IAAI,KAAK,CAAC,GAAG,CAAC,CAAA;AAC1C,kEAAkE;AAClE,gCAAgC;AAChC,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,MAAM,IAAI,CAAC,KAAK,IAAI,MAAM,IAAI,IAAI,CAAC,QAAQ,CAAA;AAElE,4DAA4D;AAC5D,MAAM,CAAC,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAA;AACxD,MAAM,CAAC,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAA;AAC3D,MAAM,CAAC,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAA;AAE3D,MAAM,CAAC,MAAM,MAAM,GACjB,MAAM,IAAI,MAAM,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE;IAC5D,CAAC,CAAC,KAAK,IAAI,GAAG,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE;QAC9C,CAAC,CAAC,SAAS,CAAA","sourcesContent":["import proc from 'node:process'\n\nconst { Deno, Bun } = globalThis as typeof globalThis & {\n Deno: undefined | object\n Bun: undefined | object\n}\n\nconst isObj = (v: unknown) => typeof v === 'object' && !!v\n\nexport const isDeno = isObj(Deno)\nexport const isBun = !isDeno && isObj(Bun)\n// bun and deno also report 'node' in process.versions so its only\n// node if it is not bun or deno\nexport const isNode = !isDeno && !isBun && 'node' in proc.versions\n\n// All the runtimes put their versions into process.versions\nexport const bun = isBun ? proc.versions.bun : undefined\nexport const deno = isDeno ? proc.versions.deno : undefined\nexport const node = isNode ? proc.versions.node : undefined\n\nexport const engine =\n isNode || isDeno ? { name: 'v8', version: proc.versions.v8 }\n : isBun && bun ? { name: 'bun', version: bun }\n : undefined\n"]}
1
+ {"version":3,"file":"env.js","sourceRoot":"","sources":["../../src/env.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,cAAc,CAAA;AAE/B,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,UAGrB,CAAA;AAED,MAAM,KAAK,GAAG,CAAC,CAAU,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,CAAC,CAAA;AAE1D,MAAM,CAAC,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,CAAA;AACjC,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,MAAM,IAAI,KAAK,CAAC,GAAG,CAAC,CAAA;AAC1C,kEAAkE;AAClE,gCAAgC;AAChC,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,MAAM,IAAI,CAAC,KAAK,IAAI,MAAM,IAAI,IAAI,CAAC,QAAQ,CAAA;AAElE,4DAA4D;AAC5D,MAAM,CAAC,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAA;AACxD,MAAM,CAAC,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAA;AAC3D,MAAM,CAAC,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAA","sourcesContent":["import proc from 'node:process'\n\nconst { Deno, Bun } = globalThis as typeof globalThis & {\n Deno: undefined | object\n Bun: undefined | object\n}\n\nconst isObj = (v: unknown) => typeof v === 'object' && !!v\n\nexport const isDeno = isObj(Deno)\nexport const isBun = !isDeno && isObj(Bun)\n// bun and deno also report 'node' in process.versions so its only\n// node if it is not bun or deno\nexport const isNode = !isDeno && !isBun && 'node' in proc.versions\n\n// All the runtimes put their versions into process.versions\nexport const bun = isBun ? proc.versions.bun : undefined\nexport const deno = isDeno ? proc.versions.deno : undefined\nexport const node = isNode ? proc.versions.node : undefined\n"]}
@@ -1,4 +1,4 @@
1
- import { type Dispatcher } from 'undici';
2
- import { type CacheEntry } from './cache-entry.js';
1
+ import type { Dispatcher } from 'undici';
2
+ import type { CacheEntry } from './cache-entry.ts';
3
3
  export declare const handle304Response: (resp: Dispatcher.ResponseData, entry?: CacheEntry) => entry is CacheEntry;
4
4
  //# sourceMappingURL=handle-304-response.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"handle-304-response.d.ts","sourceRoot":"","sources":["../../src/handle-304-response.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,QAAQ,CAAA;AACxC,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAElD,eAAO,MAAM,iBAAiB,SACtB,UAAU,CAAC,YAAY,UACrB,UAAU,KACjB,KAAK,IAAI,UASX,CAAA"}
1
+ {"version":3,"file":"handle-304-response.d.ts","sourceRoot":"","sources":["../../src/handle-304-response.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAA;AACxC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAElD,eAAO,MAAM,iBAAiB,SACtB,UAAU,CAAC,YAAY,UACrB,UAAU,KACjB,KAAK,IAAI,UASX,CAAA"}